blob: 2fb996133a14ddd9b26919368a5808477d72a021 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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/ast/scopes.h"
8#include "src/code-factory.h"
9#include "src/code-stubs.h"
10#include "src/codegen.h"
11#include "src/debug/debug.h"
12#include "src/full-codegen/full-codegen.h"
13#include "src/ic/ic.h"
14#include "src/parsing/parser.h"
15#include "src/x87/frames-x87.h"
16
17namespace v8 {
18namespace internal {
19
Ben Murdoch097c5b22016-05-18 11:27:45 +010020#define __ ACCESS_MASM(masm())
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000021
22class JumpPatchSite BASE_EMBEDDED {
23 public:
24 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
25#ifdef DEBUG
26 info_emitted_ = false;
27#endif
28 }
29
30 ~JumpPatchSite() {
31 DCHECK(patch_site_.is_bound() == info_emitted_);
32 }
33
34 void EmitJumpIfNotSmi(Register reg,
35 Label* target,
36 Label::Distance distance = Label::kFar) {
37 __ test(reg, Immediate(kSmiTagMask));
38 EmitJump(not_carry, target, distance); // Always taken before patched.
39 }
40
41 void EmitJumpIfSmi(Register reg,
42 Label* target,
43 Label::Distance distance = Label::kFar) {
44 __ test(reg, Immediate(kSmiTagMask));
45 EmitJump(carry, target, distance); // Never taken before patched.
46 }
47
48 void EmitPatchInfo() {
49 if (patch_site_.is_bound()) {
50 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
51 DCHECK(is_uint8(delta_to_patch_site));
52 __ test(eax, Immediate(delta_to_patch_site));
53#ifdef DEBUG
54 info_emitted_ = true;
55#endif
56 } else {
57 __ nop(); // Signals no inlined code.
58 }
59 }
60
61 private:
62 // jc will be patched with jz, jnc will become jnz.
63 void EmitJump(Condition cc, Label* target, Label::Distance distance) {
64 DCHECK(!patch_site_.is_bound() && !info_emitted_);
65 DCHECK(cc == carry || cc == not_carry);
66 __ bind(&patch_site_);
67 __ j(cc, target, distance);
68 }
69
Ben Murdoch097c5b22016-05-18 11:27:45 +010070 MacroAssembler* masm() { return masm_; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000071 MacroAssembler* masm_;
72 Label patch_site_;
73#ifdef DEBUG
74 bool info_emitted_;
75#endif
76};
77
78
79// Generate code for a JS function. On entry to the function the receiver
80// and arguments have been pushed on the stack left to right, with the
81// return address on top of them. The actual argument count matches the
82// formal parameter count expected by the function.
83//
84// The live registers are:
85// o edi: the JS function object being called (i.e. ourselves)
86// o edx: the new target value
87// o esi: our context
88// o ebp: our caller's frame pointer
89// o esp: stack pointer (pointing to return address)
90//
91// The function builds a JS frame. Please see JavaScriptFrameConstants in
92// frames-x87.h for its layout.
93void FullCodeGenerator::Generate() {
94 CompilationInfo* info = info_;
95 profiling_counter_ = isolate()->factory()->NewCell(
96 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
97 SetFunctionPosition(literal());
98 Comment cmnt(masm_, "[ function compiled by full code generator");
99
100 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
101
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000102 if (FLAG_debug_code && info->ExpectsJSReceiverAsReceiver()) {
103 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
104 __ mov(ecx, Operand(esp, receiver_offset));
105 __ AssertNotSmi(ecx);
106 __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ecx);
107 __ Assert(above_equal, kSloppyFunctionExpectsJSReceiverReceiver);
108 }
109
110 // Open a frame scope to indicate that there is a frame on the stack. The
111 // MANUAL indicates that the scope shouldn't actually generate code to set up
112 // the frame (that is done below).
113 FrameScope frame_scope(masm_, StackFrame::MANUAL);
114
115 info->set_prologue_offset(masm_->pc_offset());
116 __ Prologue(info->GeneratePreagedPrologue());
117
118 { Comment cmnt(masm_, "[ Allocate locals");
119 int locals_count = info->scope()->num_stack_slots();
120 // Generators allocate locals, if any, in context slots.
121 DCHECK(!IsGeneratorFunction(literal()->kind()) || locals_count == 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100122 OperandStackDepthIncrement(locals_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000123 if (locals_count == 1) {
124 __ push(Immediate(isolate()->factory()->undefined_value()));
125 } else if (locals_count > 1) {
126 if (locals_count >= 128) {
127 Label ok;
128 __ mov(ecx, esp);
129 __ sub(ecx, Immediate(locals_count * kPointerSize));
130 ExternalReference stack_limit =
131 ExternalReference::address_of_real_stack_limit(isolate());
132 __ cmp(ecx, Operand::StaticVariable(stack_limit));
133 __ j(above_equal, &ok, Label::kNear);
134 __ CallRuntime(Runtime::kThrowStackOverflow);
135 __ bind(&ok);
136 }
137 __ mov(eax, Immediate(isolate()->factory()->undefined_value()));
138 const int kMaxPushes = 32;
139 if (locals_count >= kMaxPushes) {
140 int loop_iterations = locals_count / kMaxPushes;
141 __ mov(ecx, loop_iterations);
142 Label loop_header;
143 __ bind(&loop_header);
144 // Do pushes.
145 for (int i = 0; i < kMaxPushes; i++) {
146 __ push(eax);
147 }
148 __ dec(ecx);
149 __ j(not_zero, &loop_header, Label::kNear);
150 }
151 int remaining = locals_count % kMaxPushes;
152 // Emit the remaining pushes.
153 for (int i = 0; i < remaining; i++) {
154 __ push(eax);
155 }
156 }
157 }
158
159 bool function_in_register = true;
160
161 // Possibly allocate a local context.
162 if (info->scope()->num_heap_slots() > 0) {
163 Comment cmnt(masm_, "[ Allocate context");
164 bool need_write_barrier = true;
165 int slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
166 // Argument to NewContext is the function, which is still in edi.
167 if (info->scope()->is_script_scope()) {
168 __ push(edi);
169 __ Push(info->scope()->GetScopeInfo(info->isolate()));
170 __ CallRuntime(Runtime::kNewScriptContext);
Ben Murdochc5610432016-08-08 18:44:38 +0100171 PrepareForBailoutForId(BailoutId::ScriptContext(),
172 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000173 // The new target value is not used, clobbering is safe.
174 DCHECK_NULL(info->scope()->new_target_var());
175 } else {
176 if (info->scope()->new_target_var() != nullptr) {
177 __ push(edx); // Preserve new target.
178 }
179 if (slots <= FastNewContextStub::kMaximumSlots) {
180 FastNewContextStub stub(isolate(), slots);
181 __ CallStub(&stub);
182 // Result of FastNewContextStub is always in new space.
183 need_write_barrier = false;
184 } else {
185 __ push(edi);
186 __ CallRuntime(Runtime::kNewFunctionContext);
187 }
188 if (info->scope()->new_target_var() != nullptr) {
189 __ pop(edx); // Restore new target.
190 }
191 }
192 function_in_register = false;
193 // Context is returned in eax. It replaces the context passed to us.
194 // It's saved in the stack and kept live in esi.
195 __ mov(esi, eax);
196 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), eax);
197
198 // Copy parameters into context if necessary.
199 int num_parameters = info->scope()->num_parameters();
200 int first_parameter = info->scope()->has_this_declaration() ? -1 : 0;
201 for (int i = first_parameter; i < num_parameters; i++) {
202 Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i);
203 if (var->IsContextSlot()) {
204 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
205 (num_parameters - 1 - i) * kPointerSize;
206 // Load parameter from stack.
207 __ mov(eax, Operand(ebp, parameter_offset));
208 // Store it in the context.
209 int context_offset = Context::SlotOffset(var->index());
210 __ mov(Operand(esi, context_offset), eax);
211 // Update the write barrier. This clobbers eax and ebx.
212 if (need_write_barrier) {
213 __ RecordWriteContextSlot(esi, context_offset, eax, ebx,
214 kDontSaveFPRegs);
215 } else if (FLAG_debug_code) {
216 Label done;
217 __ JumpIfInNewSpace(esi, eax, &done, Label::kNear);
218 __ Abort(kExpectedNewSpaceObject);
219 __ bind(&done);
220 }
221 }
222 }
223 }
224
225 // Register holding this function and new target are both trashed in case we
226 // bailout here. But since that can happen only when new target is not used
227 // and we allocate a context, the value of |function_in_register| is correct.
Ben Murdochc5610432016-08-08 18:44:38 +0100228 PrepareForBailoutForId(BailoutId::FunctionContext(),
229 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000230
231 // Possibly set up a local binding to the this function which is used in
232 // derived constructors with super calls.
233 Variable* this_function_var = scope()->this_function_var();
234 if (this_function_var != nullptr) {
235 Comment cmnt(masm_, "[ This function");
236 if (!function_in_register) {
237 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
238 // The write barrier clobbers register again, keep it marked as such.
239 }
240 SetVar(this_function_var, edi, ebx, ecx);
241 }
242
243 // Possibly set up a local binding to the new target value.
244 Variable* new_target_var = scope()->new_target_var();
245 if (new_target_var != nullptr) {
246 Comment cmnt(masm_, "[ new.target");
247 SetVar(new_target_var, edx, ebx, ecx);
248 }
249
250 // Possibly allocate RestParameters
251 int rest_index;
252 Variable* rest_param = scope()->rest_parameter(&rest_index);
253 if (rest_param) {
254 Comment cmnt(masm_, "[ Allocate rest parameter array");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100255 if (!function_in_register) {
256 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
257 }
258 FastNewRestParameterStub stub(isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000259 __ CallStub(&stub);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100260 function_in_register = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000261 SetVar(rest_param, eax, ebx, edx);
262 }
263
264 Variable* arguments = scope()->arguments();
265 if (arguments != NULL) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100266 // Arguments object must be allocated after the context object, in
267 // case the "arguments" or ".arguments" variables are in the context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000268 Comment cmnt(masm_, "[ Allocate arguments object");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000269 if (!function_in_register) {
270 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
271 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100272 if (is_strict(language_mode()) || !has_simple_parameters()) {
273 FastNewStrictArgumentsStub stub(isolate());
274 __ CallStub(&stub);
275 } else if (literal()->has_duplicate_parameters()) {
276 __ Push(edi);
277 __ CallRuntime(Runtime::kNewSloppyArguments_Generic);
278 } else {
279 FastNewSloppyArgumentsStub stub(isolate());
280 __ CallStub(&stub);
281 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000282
283 SetVar(arguments, eax, ebx, edx);
284 }
285
286 if (FLAG_trace) {
287 __ CallRuntime(Runtime::kTraceEnter);
288 }
289
Ben Murdochda12d292016-06-02 14:46:10 +0100290 // Visit the declarations and body.
Ben Murdochc5610432016-08-08 18:44:38 +0100291 PrepareForBailoutForId(BailoutId::FunctionEntry(),
292 BailoutState::NO_REGISTERS);
Ben Murdochda12d292016-06-02 14:46:10 +0100293 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000294 Comment cmnt(masm_, "[ Declarations");
Ben Murdochda12d292016-06-02 14:46:10 +0100295 VisitDeclarations(scope()->declarations());
296 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000297
Ben Murdochda12d292016-06-02 14:46:10 +0100298 // Assert that the declarations do not use ICs. Otherwise the debugger
299 // won't be able to redirect a PC at an IC to the correct IC in newly
300 // recompiled code.
301 DCHECK_EQ(0, ic_total_count_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000302
Ben Murdochda12d292016-06-02 14:46:10 +0100303 {
304 Comment cmnt(masm_, "[ Stack check");
Ben Murdochc5610432016-08-08 18:44:38 +0100305 PrepareForBailoutForId(BailoutId::Declarations(),
306 BailoutState::NO_REGISTERS);
Ben Murdochda12d292016-06-02 14:46:10 +0100307 Label ok;
308 ExternalReference stack_limit =
309 ExternalReference::address_of_stack_limit(isolate());
310 __ cmp(esp, Operand::StaticVariable(stack_limit));
311 __ j(above_equal, &ok, Label::kNear);
312 __ call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
313 __ bind(&ok);
314 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000315
Ben Murdochda12d292016-06-02 14:46:10 +0100316 {
317 Comment cmnt(masm_, "[ Body");
318 DCHECK(loop_depth() == 0);
319 VisitStatements(literal()->body());
320 DCHECK(loop_depth() == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000321 }
322
323 // Always emit a 'return undefined' in case control fell off the end of
324 // the body.
325 { Comment cmnt(masm_, "[ return <undefined>;");
326 __ mov(eax, isolate()->factory()->undefined_value());
327 EmitReturnSequence();
328 }
329}
330
331
332void FullCodeGenerator::ClearAccumulator() {
333 __ Move(eax, Immediate(Smi::FromInt(0)));
334}
335
336
337void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
338 __ mov(ebx, Immediate(profiling_counter_));
339 __ sub(FieldOperand(ebx, Cell::kValueOffset),
340 Immediate(Smi::FromInt(delta)));
341}
342
343
344void FullCodeGenerator::EmitProfilingCounterReset() {
345 int reset_value = FLAG_interrupt_budget;
346 __ mov(ebx, Immediate(profiling_counter_));
347 __ mov(FieldOperand(ebx, Cell::kValueOffset),
348 Immediate(Smi::FromInt(reset_value)));
349}
350
351
352void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
353 Label* back_edge_target) {
354 Comment cmnt(masm_, "[ Back edge bookkeeping");
355 Label ok;
356
357 DCHECK(back_edge_target->is_bound());
358 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
359 int weight = Min(kMaxBackEdgeWeight,
360 Max(1, distance / kCodeSizeMultiplier));
361 EmitProfilingCounterDecrement(weight);
362 __ j(positive, &ok, Label::kNear);
363 __ call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
364
365 // Record a mapping of this PC offset to the OSR id. This is used to find
366 // the AST id from the unoptimized code in order to use it as a key into
367 // the deoptimization input data found in the optimized code.
368 RecordBackEdge(stmt->OsrEntryId());
369
370 EmitProfilingCounterReset();
371
372 __ bind(&ok);
Ben Murdochc5610432016-08-08 18:44:38 +0100373 PrepareForBailoutForId(stmt->EntryId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000374 // Record a mapping of the OSR id to this PC. This is used if the OSR
375 // entry becomes the target of a bailout. We don't expect it to be, but
376 // we want it to work if it is.
Ben Murdochc5610432016-08-08 18:44:38 +0100377 PrepareForBailoutForId(stmt->OsrEntryId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000378}
379
Ben Murdoch097c5b22016-05-18 11:27:45 +0100380void FullCodeGenerator::EmitProfilingCounterHandlingForReturnSequence(
381 bool is_tail_call) {
382 // Pretend that the exit is a backwards jump to the entry.
383 int weight = 1;
384 if (info_->ShouldSelfOptimize()) {
385 weight = FLAG_interrupt_budget / FLAG_self_opt_count;
386 } else {
387 int distance = masm_->pc_offset();
388 weight = Min(kMaxBackEdgeWeight, Max(1, distance / kCodeSizeMultiplier));
389 }
390 EmitProfilingCounterDecrement(weight);
391 Label ok;
392 __ j(positive, &ok, Label::kNear);
393 // Don't need to save result register if we are going to do a tail call.
394 if (!is_tail_call) {
395 __ push(eax);
396 }
397 __ call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
398 if (!is_tail_call) {
399 __ pop(eax);
400 }
401 EmitProfilingCounterReset();
402 __ bind(&ok);
403}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000404
405void FullCodeGenerator::EmitReturnSequence() {
406 Comment cmnt(masm_, "[ Return sequence");
407 if (return_label_.is_bound()) {
408 __ jmp(&return_label_);
409 } else {
410 // Common return label
411 __ bind(&return_label_);
412 if (FLAG_trace) {
413 __ push(eax);
414 __ CallRuntime(Runtime::kTraceExit);
415 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100416 EmitProfilingCounterHandlingForReturnSequence(false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000417
418 SetReturnPosition(literal());
419 __ leave();
420
421 int arg_count = info_->scope()->num_parameters() + 1;
422 int arguments_bytes = arg_count * kPointerSize;
423 __ Ret(arguments_bytes, ecx);
424 }
425}
426
Ben Murdochc5610432016-08-08 18:44:38 +0100427void FullCodeGenerator::RestoreContext() {
428 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
429}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000430
431void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
432 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
433 MemOperand operand = codegen()->VarOperand(var, result_register());
434 // Memory operands can be pushed directly.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100435 codegen()->PushOperand(operand);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000436}
437
438
439void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
440 UNREACHABLE(); // Not used on X87.
441}
442
443
444void FullCodeGenerator::AccumulatorValueContext::Plug(
445 Heap::RootListIndex index) const {
446 UNREACHABLE(); // Not used on X87.
447}
448
449
450void FullCodeGenerator::StackValueContext::Plug(
451 Heap::RootListIndex index) const {
452 UNREACHABLE(); // Not used on X87.
453}
454
455
456void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
457 UNREACHABLE(); // Not used on X87.
458}
459
460
461void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
462}
463
464
465void FullCodeGenerator::AccumulatorValueContext::Plug(
466 Handle<Object> lit) const {
467 if (lit->IsSmi()) {
468 __ SafeMove(result_register(), Immediate(lit));
469 } else {
470 __ Move(result_register(), Immediate(lit));
471 }
472}
473
474
475void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100476 codegen()->OperandStackDepthIncrement(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000477 if (lit->IsSmi()) {
478 __ SafePush(Immediate(lit));
479 } else {
480 __ push(Immediate(lit));
481 }
482}
483
484
485void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
486 codegen()->PrepareForBailoutBeforeSplit(condition(),
487 true,
488 true_label_,
489 false_label_);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100490 DCHECK(lit->IsNull(isolate()) || lit->IsUndefined(isolate()) ||
491 !lit->IsUndetectable());
492 if (lit->IsUndefined(isolate()) || lit->IsNull(isolate()) ||
493 lit->IsFalse(isolate())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000494 if (false_label_ != fall_through_) __ jmp(false_label_);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100495 } else if (lit->IsTrue(isolate()) || lit->IsJSObject()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000496 if (true_label_ != fall_through_) __ jmp(true_label_);
497 } else if (lit->IsString()) {
498 if (String::cast(*lit)->length() == 0) {
499 if (false_label_ != fall_through_) __ jmp(false_label_);
500 } else {
501 if (true_label_ != fall_through_) __ jmp(true_label_);
502 }
503 } else if (lit->IsSmi()) {
504 if (Smi::cast(*lit)->value() == 0) {
505 if (false_label_ != fall_through_) __ jmp(false_label_);
506 } else {
507 if (true_label_ != fall_through_) __ jmp(true_label_);
508 }
509 } else {
510 // For simplicity we always test the accumulator register.
511 __ mov(result_register(), lit);
512 codegen()->DoTest(this);
513 }
514}
515
516
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000517void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
518 Register reg) const {
519 DCHECK(count > 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100520 if (count > 1) codegen()->DropOperands(count - 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000521 __ mov(Operand(esp, 0), reg);
522}
523
524
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000525void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
526 Label* materialize_false) const {
527 DCHECK(materialize_true == materialize_false);
528 __ bind(materialize_true);
529}
530
531
532void FullCodeGenerator::AccumulatorValueContext::Plug(
533 Label* materialize_true,
534 Label* materialize_false) const {
535 Label done;
536 __ bind(materialize_true);
537 __ mov(result_register(), isolate()->factory()->true_value());
538 __ jmp(&done, Label::kNear);
539 __ bind(materialize_false);
540 __ mov(result_register(), isolate()->factory()->false_value());
541 __ bind(&done);
542}
543
544
545void FullCodeGenerator::StackValueContext::Plug(
546 Label* materialize_true,
547 Label* materialize_false) const {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100548 codegen()->OperandStackDepthIncrement(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000549 Label done;
550 __ bind(materialize_true);
551 __ push(Immediate(isolate()->factory()->true_value()));
552 __ jmp(&done, Label::kNear);
553 __ bind(materialize_false);
554 __ push(Immediate(isolate()->factory()->false_value()));
555 __ bind(&done);
556}
557
558
559void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
560 Label* materialize_false) const {
561 DCHECK(materialize_true == true_label_);
562 DCHECK(materialize_false == false_label_);
563}
564
565
566void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
567 Handle<Object> value = flag
568 ? isolate()->factory()->true_value()
569 : isolate()->factory()->false_value();
570 __ mov(result_register(), value);
571}
572
573
574void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100575 codegen()->OperandStackDepthIncrement(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000576 Handle<Object> value = flag
577 ? isolate()->factory()->true_value()
578 : isolate()->factory()->false_value();
579 __ push(Immediate(value));
580}
581
582
583void FullCodeGenerator::TestContext::Plug(bool flag) const {
584 codegen()->PrepareForBailoutBeforeSplit(condition(),
585 true,
586 true_label_,
587 false_label_);
588 if (flag) {
589 if (true_label_ != fall_through_) __ jmp(true_label_);
590 } else {
591 if (false_label_ != fall_through_) __ jmp(false_label_);
592 }
593}
594
595
596void FullCodeGenerator::DoTest(Expression* condition,
597 Label* if_true,
598 Label* if_false,
599 Label* fall_through) {
Ben Murdochda12d292016-06-02 14:46:10 +0100600 Handle<Code> ic = ToBooleanICStub::GetUninitialized(isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000601 CallIC(ic, condition->test_id());
602 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex);
603 Split(equal, if_true, if_false, fall_through);
604}
605
606
607void FullCodeGenerator::Split(Condition cc,
608 Label* if_true,
609 Label* if_false,
610 Label* fall_through) {
611 if (if_false == fall_through) {
612 __ j(cc, if_true);
613 } else if (if_true == fall_through) {
614 __ j(NegateCondition(cc), if_false);
615 } else {
616 __ j(cc, if_true);
617 __ jmp(if_false);
618 }
619}
620
621
622MemOperand FullCodeGenerator::StackOperand(Variable* var) {
623 DCHECK(var->IsStackAllocated());
624 // Offset is negative because higher indexes are at lower addresses.
625 int offset = -var->index() * kPointerSize;
626 // Adjust by a (parameter or local) base offset.
627 if (var->IsParameter()) {
628 offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
629 } else {
630 offset += JavaScriptFrameConstants::kLocal0Offset;
631 }
632 return Operand(ebp, offset);
633}
634
635
636MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
637 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
638 if (var->IsContextSlot()) {
639 int context_chain_length = scope()->ContextChainLength(var->scope());
640 __ LoadContext(scratch, context_chain_length);
641 return ContextOperand(scratch, var->index());
642 } else {
643 return StackOperand(var);
644 }
645}
646
647
648void FullCodeGenerator::GetVar(Register dest, Variable* var) {
649 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
650 MemOperand location = VarOperand(var, dest);
651 __ mov(dest, location);
652}
653
654
655void FullCodeGenerator::SetVar(Variable* var,
656 Register src,
657 Register scratch0,
658 Register scratch1) {
659 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
660 DCHECK(!scratch0.is(src));
661 DCHECK(!scratch0.is(scratch1));
662 DCHECK(!scratch1.is(src));
663 MemOperand location = VarOperand(var, scratch0);
664 __ mov(location, src);
665
666 // Emit the write barrier code if the location is in the heap.
667 if (var->IsContextSlot()) {
668 int offset = Context::SlotOffset(var->index());
669 DCHECK(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi));
670 __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
671 }
672}
673
674
675void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
676 bool should_normalize,
677 Label* if_true,
678 Label* if_false) {
679 // Only prepare for bailouts before splits if we're in a test
680 // context. Otherwise, we let the Visit function deal with the
681 // preparation to avoid preparing with the same AST id twice.
682 if (!context()->IsTest()) return;
683
684 Label skip;
685 if (should_normalize) __ jmp(&skip, Label::kNear);
Ben Murdochc5610432016-08-08 18:44:38 +0100686 PrepareForBailout(expr, BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000687 if (should_normalize) {
688 __ cmp(eax, isolate()->factory()->true_value());
689 Split(equal, if_true, if_false, NULL);
690 __ bind(&skip);
691 }
692}
693
694
695void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
696 // The variable in the declaration always resides in the current context.
697 DCHECK_EQ(0, scope()->ContextChainLength(variable->scope()));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100698 if (FLAG_debug_code) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000699 // Check that we're not inside a with or catch context.
700 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
701 __ cmp(ebx, isolate()->factory()->with_context_map());
702 __ Check(not_equal, kDeclarationInWithContext);
703 __ cmp(ebx, isolate()->factory()->catch_context_map());
704 __ Check(not_equal, kDeclarationInCatchContext);
705 }
706}
707
708
709void FullCodeGenerator::VisitVariableDeclaration(
710 VariableDeclaration* declaration) {
711 // If it was not possible to allocate the variable at compile time, we
712 // need to "declare" it at runtime to make sure it actually exists in the
713 // local context.
714 VariableProxy* proxy = declaration->proxy();
715 VariableMode mode = declaration->mode();
716 Variable* variable = proxy->var();
Ben Murdochc5610432016-08-08 18:44:38 +0100717 bool hole_init = mode == LET || mode == CONST;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000718 switch (variable->location()) {
719 case VariableLocation::GLOBAL:
720 case VariableLocation::UNALLOCATED:
Ben Murdochc5610432016-08-08 18:44:38 +0100721 DCHECK(!variable->binding_needs_init());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000722 globals_->Add(variable->name(), zone());
Ben Murdochc5610432016-08-08 18:44:38 +0100723 globals_->Add(isolate()->factory()->undefined_value(), zone());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000724 break;
725
726 case VariableLocation::PARAMETER:
727 case VariableLocation::LOCAL:
728 if (hole_init) {
729 Comment cmnt(masm_, "[ VariableDeclaration");
730 __ mov(StackOperand(variable),
731 Immediate(isolate()->factory()->the_hole_value()));
732 }
733 break;
734
735 case VariableLocation::CONTEXT:
736 if (hole_init) {
737 Comment cmnt(masm_, "[ VariableDeclaration");
738 EmitDebugCheckDeclarationContext(variable);
739 __ mov(ContextOperand(esi, variable->index()),
740 Immediate(isolate()->factory()->the_hole_value()));
741 // No write barrier since the hole value is in old space.
Ben Murdochc5610432016-08-08 18:44:38 +0100742 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000743 }
744 break;
745
746 case VariableLocation::LOOKUP: {
747 Comment cmnt(masm_, "[ VariableDeclaration");
Ben Murdoch61f157c2016-09-16 13:49:30 +0100748 DCHECK_EQ(VAR, mode);
749 DCHECK(!hole_init);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000750 __ push(Immediate(variable->name()));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100751 __ CallRuntime(Runtime::kDeclareEvalVar);
Ben Murdochc5610432016-08-08 18:44:38 +0100752 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000753 break;
754 }
755 }
756}
757
758void FullCodeGenerator::VisitFunctionDeclaration(
759 FunctionDeclaration* declaration) {
760 VariableProxy* proxy = declaration->proxy();
761 Variable* variable = proxy->var();
762 switch (variable->location()) {
763 case VariableLocation::GLOBAL:
764 case VariableLocation::UNALLOCATED: {
765 globals_->Add(variable->name(), zone());
766 Handle<SharedFunctionInfo> function =
767 Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
768 // Check for stack-overflow exception.
769 if (function.is_null()) return SetStackOverflow();
770 globals_->Add(function, zone());
771 break;
772 }
773
774 case VariableLocation::PARAMETER:
775 case VariableLocation::LOCAL: {
776 Comment cmnt(masm_, "[ FunctionDeclaration");
777 VisitForAccumulatorValue(declaration->fun());
778 __ mov(StackOperand(variable), result_register());
779 break;
780 }
781
782 case VariableLocation::CONTEXT: {
783 Comment cmnt(masm_, "[ FunctionDeclaration");
784 EmitDebugCheckDeclarationContext(variable);
785 VisitForAccumulatorValue(declaration->fun());
786 __ mov(ContextOperand(esi, variable->index()), result_register());
787 // We know that we have written a function, which is not a smi.
788 __ RecordWriteContextSlot(esi, Context::SlotOffset(variable->index()),
789 result_register(), ecx, kDontSaveFPRegs,
790 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
Ben Murdochc5610432016-08-08 18:44:38 +0100791 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000792 break;
793 }
794
795 case VariableLocation::LOOKUP: {
796 Comment cmnt(masm_, "[ FunctionDeclaration");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100797 PushOperand(variable->name());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000798 VisitForStackValue(declaration->fun());
Ben Murdoch61f157c2016-09-16 13:49:30 +0100799 CallRuntimeWithOperands(Runtime::kDeclareEvalFunction);
Ben Murdochc5610432016-08-08 18:44:38 +0100800 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000801 break;
802 }
803 }
804}
805
806
807void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
808 // Call the runtime to declare the globals.
809 __ Push(pairs);
810 __ Push(Smi::FromInt(DeclareGlobalsFlags()));
811 __ CallRuntime(Runtime::kDeclareGlobals);
812 // Return value is ignored.
813}
814
815
816void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) {
817 // Call the runtime to declare the modules.
818 __ Push(descriptions);
819 __ CallRuntime(Runtime::kDeclareModules);
820 // Return value is ignored.
821}
822
823
824void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
825 Comment cmnt(masm_, "[ SwitchStatement");
826 Breakable nested_statement(this, stmt);
827 SetStatementPosition(stmt);
828
829 // Keep the switch value on the stack until a case matches.
830 VisitForStackValue(stmt->tag());
Ben Murdochc5610432016-08-08 18:44:38 +0100831 PrepareForBailoutForId(stmt->EntryId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000832
833 ZoneList<CaseClause*>* clauses = stmt->cases();
834 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
835
836 Label next_test; // Recycled for each test.
837 // Compile all the tests with branches to their bodies.
838 for (int i = 0; i < clauses->length(); i++) {
839 CaseClause* clause = clauses->at(i);
840 clause->body_target()->Unuse();
841
842 // The default is not a test, but remember it as final fall through.
843 if (clause->is_default()) {
844 default_clause = clause;
845 continue;
846 }
847
848 Comment cmnt(masm_, "[ Case comparison");
849 __ bind(&next_test);
850 next_test.Unuse();
851
852 // Compile the label expression.
853 VisitForAccumulatorValue(clause->label());
854
855 // Perform the comparison as if via '==='.
856 __ mov(edx, Operand(esp, 0)); // Switch value.
857 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
858 JumpPatchSite patch_site(masm_);
859 if (inline_smi_code) {
860 Label slow_case;
861 __ mov(ecx, edx);
862 __ or_(ecx, eax);
863 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
864
865 __ cmp(edx, eax);
866 __ j(not_equal, &next_test);
867 __ Drop(1); // Switch value is no longer needed.
868 __ jmp(clause->body_target());
869 __ bind(&slow_case);
870 }
871
872 SetExpressionPosition(clause);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100873 Handle<Code> ic =
874 CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000875 CallIC(ic, clause->CompareId());
876 patch_site.EmitPatchInfo();
877
878 Label skip;
879 __ jmp(&skip, Label::kNear);
Ben Murdochc5610432016-08-08 18:44:38 +0100880 PrepareForBailout(clause, BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000881 __ cmp(eax, isolate()->factory()->true_value());
882 __ j(not_equal, &next_test);
883 __ Drop(1);
884 __ jmp(clause->body_target());
885 __ bind(&skip);
886
887 __ test(eax, eax);
888 __ j(not_equal, &next_test);
889 __ Drop(1); // Switch value is no longer needed.
890 __ jmp(clause->body_target());
891 }
892
893 // Discard the test value and jump to the default if present, otherwise to
894 // the end of the statement.
895 __ bind(&next_test);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100896 DropOperands(1); // Switch value is no longer needed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000897 if (default_clause == NULL) {
898 __ jmp(nested_statement.break_label());
899 } else {
900 __ jmp(default_clause->body_target());
901 }
902
903 // Compile all the case bodies.
904 for (int i = 0; i < clauses->length(); i++) {
905 Comment cmnt(masm_, "[ Case body");
906 CaseClause* clause = clauses->at(i);
907 __ bind(clause->body_target());
Ben Murdochc5610432016-08-08 18:44:38 +0100908 PrepareForBailoutForId(clause->EntryId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000909 VisitStatements(clause->statements());
910 }
911
912 __ bind(nested_statement.break_label());
Ben Murdochc5610432016-08-08 18:44:38 +0100913 PrepareForBailoutForId(stmt->ExitId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000914}
915
916
917void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
918 Comment cmnt(masm_, "[ ForInStatement");
919 SetStatementPosition(stmt, SKIP_BREAK);
920
921 FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
922
Ben Murdoch097c5b22016-05-18 11:27:45 +0100923 // Get the object to enumerate over.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000924 SetExpressionAsStatementPosition(stmt->enumerable());
925 VisitForAccumulatorValue(stmt->enumerable());
Ben Murdochda12d292016-06-02 14:46:10 +0100926 OperandStackDepthIncrement(5);
927
928 Label loop, exit;
929 Iteration loop_statement(this, stmt);
930 increment_loop_depth();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000931
Ben Murdoch097c5b22016-05-18 11:27:45 +0100932 // If the object is null or undefined, skip over the loop, otherwise convert
933 // it to a JS receiver. See ECMA-262 version 5, section 12.6.4.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000934 Label convert, done_convert;
935 __ JumpIfSmi(eax, &convert, Label::kNear);
936 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx);
937 __ j(above_equal, &done_convert, Label::kNear);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100938 __ cmp(eax, isolate()->factory()->undefined_value());
939 __ j(equal, &exit);
940 __ cmp(eax, isolate()->factory()->null_value());
941 __ j(equal, &exit);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000942 __ bind(&convert);
943 ToObjectStub stub(isolate());
944 __ CallStub(&stub);
945 __ bind(&done_convert);
Ben Murdochc5610432016-08-08 18:44:38 +0100946 PrepareForBailoutForId(stmt->ToObjectId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000947 __ push(eax);
948
Ben Murdochc5610432016-08-08 18:44:38 +0100949 // Check cache validity in generated code. If we cannot guarantee cache
950 // validity, call the runtime system to check cache validity or get the
951 // property names in a fixed array. Note: Proxies never have an enum cache,
952 // so will always take the slow path.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100953 Label call_runtime, use_cache, fixed_array;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000954 __ CheckEnumCache(&call_runtime);
955
956 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
957 __ jmp(&use_cache, Label::kNear);
958
959 // Get the set of properties to enumerate.
960 __ bind(&call_runtime);
961 __ push(eax);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100962 __ CallRuntime(Runtime::kForInEnumerate);
Ben Murdochc5610432016-08-08 18:44:38 +0100963 PrepareForBailoutForId(stmt->EnumId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000964 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
965 isolate()->factory()->meta_map());
966 __ j(not_equal, &fixed_array);
967
968
969 // We got a map in register eax. Get the enumeration cache from it.
970 Label no_descriptors;
971 __ bind(&use_cache);
972
973 __ EnumLength(edx, eax);
974 __ cmp(edx, Immediate(Smi::FromInt(0)));
975 __ j(equal, &no_descriptors);
976
977 __ LoadInstanceDescriptors(eax, ecx);
978 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheOffset));
979 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
980
981 // Set up the four remaining stack slots.
982 __ push(eax); // Map.
983 __ push(ecx); // Enumeration cache.
984 __ push(edx); // Number of valid entries for the map in the enum cache.
985 __ push(Immediate(Smi::FromInt(0))); // Initial index.
986 __ jmp(&loop);
987
988 __ bind(&no_descriptors);
989 __ add(esp, Immediate(kPointerSize));
990 __ jmp(&exit);
991
992 // We got a fixed array in register eax. Iterate through that.
993 __ bind(&fixed_array);
994
Ben Murdochc5610432016-08-08 18:44:38 +0100995 __ push(Immediate(Smi::FromInt(1))); // Smi(1) indicates slow check
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000996 __ push(eax); // Array
997 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
998 __ push(eax); // Fixed array length (as smi).
Ben Murdochc5610432016-08-08 18:44:38 +0100999 PrepareForBailoutForId(stmt->PrepareId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001000 __ push(Immediate(Smi::FromInt(0))); // Initial index.
1001
1002 // Generate code for doing the condition check.
1003 __ bind(&loop);
1004 SetExpressionAsStatementPosition(stmt->each());
1005
1006 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
1007 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
1008 __ j(above_equal, loop_statement.break_label());
1009
1010 // Get the current entry of the array into register ebx.
1011 __ mov(ebx, Operand(esp, 2 * kPointerSize));
1012 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
1013
1014 // Get the expected map from the stack or a smi in the
1015 // permanent slow case into register edx.
1016 __ mov(edx, Operand(esp, 3 * kPointerSize));
1017
1018 // Check if the expected map still matches that of the enumerable.
1019 // If not, we may have to filter the key.
1020 Label update_each;
1021 __ mov(ecx, Operand(esp, 4 * kPointerSize));
1022 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
1023 __ j(equal, &update_each, Label::kNear);
1024
Ben Murdochda12d292016-06-02 14:46:10 +01001025 // We need to filter the key, record slow-path here.
1026 int const vector_index = SmiFromSlot(slot)->value();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001027 __ EmitLoadTypeFeedbackVector(edx);
1028 __ mov(FieldOperand(edx, FixedArray::OffsetOfElementAt(vector_index)),
1029 Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate())));
1030
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001031 // Convert the entry to a string or null if it isn't a property
1032 // anymore. If the property has been removed while iterating, we
1033 // just skip it.
1034 __ push(ecx); // Enumerable.
1035 __ push(ebx); // Current entry.
1036 __ CallRuntime(Runtime::kForInFilter);
Ben Murdochc5610432016-08-08 18:44:38 +01001037 PrepareForBailoutForId(stmt->FilterId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001038 __ cmp(eax, isolate()->factory()->undefined_value());
1039 __ j(equal, loop_statement.continue_label());
1040 __ mov(ebx, eax);
1041
1042 // Update the 'each' property or variable from the possibly filtered
1043 // entry in register ebx.
1044 __ bind(&update_each);
1045 __ mov(result_register(), ebx);
1046 // Perform the assignment as if via '='.
1047 { EffectContext context(this);
1048 EmitAssignment(stmt->each(), stmt->EachFeedbackSlot());
Ben Murdochc5610432016-08-08 18:44:38 +01001049 PrepareForBailoutForId(stmt->AssignmentId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001050 }
1051
1052 // Both Crankshaft and Turbofan expect BodyId to be right before stmt->body().
Ben Murdochc5610432016-08-08 18:44:38 +01001053 PrepareForBailoutForId(stmt->BodyId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001054 // Generate code for the body of the loop.
1055 Visit(stmt->body());
1056
1057 // Generate code for going to the next element by incrementing the
1058 // index (smi) stored on top of the stack.
1059 __ bind(loop_statement.continue_label());
1060 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
1061
1062 EmitBackEdgeBookkeeping(stmt, &loop);
1063 __ jmp(&loop);
1064
1065 // Remove the pointers stored on the stack.
1066 __ bind(loop_statement.break_label());
Ben Murdochda12d292016-06-02 14:46:10 +01001067 DropOperands(5);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001068
1069 // Exit and decrement the loop depth.
Ben Murdochc5610432016-08-08 18:44:38 +01001070 PrepareForBailoutForId(stmt->ExitId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001071 __ bind(&exit);
1072 decrement_loop_depth();
1073}
1074
1075
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001076void FullCodeGenerator::EmitSetHomeObject(Expression* initializer, int offset,
1077 FeedbackVectorSlot slot) {
1078 DCHECK(NeedsHomeObject(initializer));
1079 __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0));
1080 __ mov(StoreDescriptor::NameRegister(),
1081 Immediate(isolate()->factory()->home_object_symbol()));
1082 __ mov(StoreDescriptor::ValueRegister(), Operand(esp, offset * kPointerSize));
1083 EmitLoadStoreICSlot(slot);
1084 CallStoreIC();
1085}
1086
1087
1088void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer,
1089 int offset,
1090 FeedbackVectorSlot slot) {
1091 DCHECK(NeedsHomeObject(initializer));
1092 __ mov(StoreDescriptor::ReceiverRegister(), eax);
1093 __ mov(StoreDescriptor::NameRegister(),
1094 Immediate(isolate()->factory()->home_object_symbol()));
1095 __ mov(StoreDescriptor::ValueRegister(), Operand(esp, offset * kPointerSize));
1096 EmitLoadStoreICSlot(slot);
1097 CallStoreIC();
1098}
1099
1100
1101void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
1102 TypeofMode typeof_mode,
1103 Label* slow) {
1104 Register context = esi;
1105 Register temp = edx;
1106
1107 Scope* s = scope();
1108 while (s != NULL) {
1109 if (s->num_heap_slots() > 0) {
1110 if (s->calls_sloppy_eval()) {
1111 // Check that extension is "the hole".
1112 __ JumpIfNotRoot(ContextOperand(context, Context::EXTENSION_INDEX),
1113 Heap::kTheHoleValueRootIndex, slow);
1114 }
1115 // Load next context in chain.
1116 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
1117 // Walk the rest of the chain without clobbering esi.
1118 context = temp;
1119 }
1120 // If no outer scope calls eval, we do not need to check more
1121 // context extensions. If we have reached an eval scope, we check
1122 // all extensions from this point.
1123 if (!s->outer_scope_calls_sloppy_eval() || s->is_eval_scope()) break;
1124 s = s->outer_scope();
1125 }
1126
1127 if (s != NULL && s->is_eval_scope()) {
1128 // Loop up the context chain. There is no frame effect so it is
1129 // safe to use raw labels here.
1130 Label next, fast;
1131 if (!context.is(temp)) {
1132 __ mov(temp, context);
1133 }
1134 __ bind(&next);
1135 // Terminate at native context.
1136 __ cmp(FieldOperand(temp, HeapObject::kMapOffset),
1137 Immediate(isolate()->factory()->native_context_map()));
1138 __ j(equal, &fast, Label::kNear);
1139 // Check that extension is "the hole".
1140 __ JumpIfNotRoot(ContextOperand(temp, Context::EXTENSION_INDEX),
1141 Heap::kTheHoleValueRootIndex, slow);
1142 // Load next context in chain.
1143 __ mov(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
1144 __ jmp(&next);
1145 __ bind(&fast);
1146 }
1147
1148 // All extension objects were empty and it is safe to use a normal global
1149 // load machinery.
1150 EmitGlobalVariableLoad(proxy, typeof_mode);
1151}
1152
1153
1154MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1155 Label* slow) {
1156 DCHECK(var->IsContextSlot());
1157 Register context = esi;
1158 Register temp = ebx;
1159
1160 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
1161 if (s->num_heap_slots() > 0) {
1162 if (s->calls_sloppy_eval()) {
1163 // Check that extension is "the hole".
1164 __ JumpIfNotRoot(ContextOperand(context, Context::EXTENSION_INDEX),
1165 Heap::kTheHoleValueRootIndex, slow);
1166 }
1167 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
1168 // Walk the rest of the chain without clobbering esi.
1169 context = temp;
1170 }
1171 }
1172 // Check that last extension is "the hole".
1173 __ JumpIfNotRoot(ContextOperand(context, Context::EXTENSION_INDEX),
1174 Heap::kTheHoleValueRootIndex, slow);
1175
1176 // This function is used only for loads, not stores, so it's safe to
1177 // return an esi-based operand (the write barrier cannot be allowed to
1178 // destroy the esi register).
1179 return ContextOperand(context, var->index());
1180}
1181
1182
1183void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy,
1184 TypeofMode typeof_mode,
1185 Label* slow, Label* done) {
1186 // Generate fast-case code for variables that might be shadowed by
1187 // eval-introduced variables. Eval is used a lot without
1188 // introducing variables. In those cases, we do not want to
1189 // perform a runtime call for all variables in the scope
1190 // containing the eval.
1191 Variable* var = proxy->var();
1192 if (var->mode() == DYNAMIC_GLOBAL) {
1193 EmitLoadGlobalCheckExtensions(proxy, typeof_mode, slow);
1194 __ jmp(done);
1195 } else if (var->mode() == DYNAMIC_LOCAL) {
1196 Variable* local = var->local_if_not_shadowed();
1197 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow));
Ben Murdochc5610432016-08-08 18:44:38 +01001198 if (local->mode() == LET || local->mode() == CONST) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001199 __ cmp(eax, isolate()->factory()->the_hole_value());
1200 __ j(not_equal, done);
Ben Murdochc5610432016-08-08 18:44:38 +01001201 __ push(Immediate(var->name()));
1202 __ CallRuntime(Runtime::kThrowReferenceError);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001203 }
1204 __ jmp(done);
1205 }
1206}
1207
1208
1209void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy,
1210 TypeofMode typeof_mode) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001211#ifdef DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001212 Variable* var = proxy->var();
1213 DCHECK(var->IsUnallocatedOrGlobalSlot() ||
1214 (var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001215#endif
1216 __ mov(LoadGlobalDescriptor::SlotRegister(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001217 Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001218 CallLoadGlobalIC(typeof_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001219}
1220
1221
1222void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy,
1223 TypeofMode typeof_mode) {
1224 SetExpressionPosition(proxy);
Ben Murdochc5610432016-08-08 18:44:38 +01001225 PrepareForBailoutForId(proxy->BeforeId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001226 Variable* var = proxy->var();
1227
1228 // Three cases: global variables, lookup variables, and all other types of
1229 // variables.
1230 switch (var->location()) {
1231 case VariableLocation::GLOBAL:
1232 case VariableLocation::UNALLOCATED: {
1233 Comment cmnt(masm_, "[ Global variable");
1234 EmitGlobalVariableLoad(proxy, typeof_mode);
1235 context()->Plug(eax);
1236 break;
1237 }
1238
1239 case VariableLocation::PARAMETER:
1240 case VariableLocation::LOCAL:
1241 case VariableLocation::CONTEXT: {
1242 DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode);
1243 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
1244 : "[ Stack variable");
1245
1246 if (NeedsHoleCheckForLoad(proxy)) {
1247 // Let and const need a read barrier.
1248 Label done;
1249 GetVar(eax, var);
1250 __ cmp(eax, isolate()->factory()->the_hole_value());
1251 __ j(not_equal, &done, Label::kNear);
1252 if (var->mode() == LET || var->mode() == CONST) {
1253 // Throw a reference error when using an uninitialized let/const
1254 // binding in harmony mode.
1255 __ push(Immediate(var->name()));
1256 __ CallRuntime(Runtime::kThrowReferenceError);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001257 }
1258 __ bind(&done);
1259 context()->Plug(eax);
1260 break;
1261 }
1262 context()->Plug(var);
1263 break;
1264 }
1265
1266 case VariableLocation::LOOKUP: {
1267 Comment cmnt(masm_, "[ Lookup variable");
1268 Label done, slow;
1269 // Generate code for loading from variables potentially shadowed
1270 // by eval-introduced variables.
1271 EmitDynamicLookupFastCase(proxy, typeof_mode, &slow, &done);
1272 __ bind(&slow);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001273 __ push(Immediate(var->name()));
1274 Runtime::FunctionId function_id =
1275 typeof_mode == NOT_INSIDE_TYPEOF
1276 ? Runtime::kLoadLookupSlot
Ben Murdoch097c5b22016-05-18 11:27:45 +01001277 : Runtime::kLoadLookupSlotInsideTypeof;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001278 __ CallRuntime(function_id);
1279 __ bind(&done);
1280 context()->Plug(eax);
1281 break;
1282 }
1283 }
1284}
1285
1286
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001287void FullCodeGenerator::EmitAccessor(ObjectLiteralProperty* property) {
1288 Expression* expression = (property == NULL) ? NULL : property->value();
1289 if (expression == NULL) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001290 PushOperand(isolate()->factory()->null_value());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001291 } else {
1292 VisitForStackValue(expression);
1293 if (NeedsHomeObject(expression)) {
1294 DCHECK(property->kind() == ObjectLiteral::Property::GETTER ||
1295 property->kind() == ObjectLiteral::Property::SETTER);
1296 int offset = property->kind() == ObjectLiteral::Property::GETTER ? 2 : 3;
1297 EmitSetHomeObject(expression, offset, property->GetSlot());
1298 }
1299 }
1300}
1301
1302
1303void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1304 Comment cmnt(masm_, "[ ObjectLiteral");
1305
1306 Handle<FixedArray> constant_properties = expr->constant_properties();
1307 int flags = expr->ComputeFlags();
1308 // If any of the keys would store to the elements array, then we shouldn't
1309 // allow it.
1310 if (MustCreateObjectLiteralWithRuntime(expr)) {
1311 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1312 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1313 __ push(Immediate(constant_properties));
1314 __ push(Immediate(Smi::FromInt(flags)));
1315 __ CallRuntime(Runtime::kCreateObjectLiteral);
1316 } else {
1317 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1318 __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
1319 __ mov(ecx, Immediate(constant_properties));
1320 __ mov(edx, Immediate(Smi::FromInt(flags)));
1321 FastCloneShallowObjectStub stub(isolate(), expr->properties_count());
1322 __ CallStub(&stub);
Ben Murdochc5610432016-08-08 18:44:38 +01001323 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001324 }
Ben Murdochc5610432016-08-08 18:44:38 +01001325 PrepareForBailoutForId(expr->CreateLiteralId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001326
1327 // If result_saved is true the result is on top of the stack. If
1328 // result_saved is false the result is in eax.
1329 bool result_saved = false;
1330
1331 AccessorTable accessor_table(zone());
1332 int property_index = 0;
1333 for (; property_index < expr->properties()->length(); property_index++) {
1334 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1335 if (property->is_computed_name()) break;
1336 if (property->IsCompileTimeValue()) continue;
1337
1338 Literal* key = property->key()->AsLiteral();
1339 Expression* value = property->value();
1340 if (!result_saved) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001341 PushOperand(eax); // Save result on the stack
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001342 result_saved = true;
1343 }
1344 switch (property->kind()) {
1345 case ObjectLiteral::Property::CONSTANT:
1346 UNREACHABLE();
1347 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1348 DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
1349 // Fall through.
1350 case ObjectLiteral::Property::COMPUTED:
1351 // It is safe to use [[Put]] here because the boilerplate already
1352 // contains computed properties with an uninitialized value.
1353 if (key->value()->IsInternalizedString()) {
1354 if (property->emit_store()) {
1355 VisitForAccumulatorValue(value);
1356 DCHECK(StoreDescriptor::ValueRegister().is(eax));
1357 __ mov(StoreDescriptor::NameRegister(), Immediate(key->value()));
1358 __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0));
1359 EmitLoadStoreICSlot(property->GetSlot(0));
1360 CallStoreIC();
Ben Murdochc5610432016-08-08 18:44:38 +01001361 PrepareForBailoutForId(key->id(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001362 if (NeedsHomeObject(value)) {
1363 EmitSetHomeObjectAccumulator(value, 0, property->GetSlot(1));
1364 }
1365 } else {
1366 VisitForEffect(value);
1367 }
1368 break;
1369 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001370 PushOperand(Operand(esp, 0)); // Duplicate receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001371 VisitForStackValue(key);
1372 VisitForStackValue(value);
1373 if (property->emit_store()) {
1374 if (NeedsHomeObject(value)) {
1375 EmitSetHomeObject(value, 2, property->GetSlot());
1376 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001377 PushOperand(Smi::FromInt(SLOPPY)); // Language mode
1378 CallRuntimeWithOperands(Runtime::kSetProperty);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001379 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001380 DropOperands(3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001381 }
1382 break;
1383 case ObjectLiteral::Property::PROTOTYPE:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001384 PushOperand(Operand(esp, 0)); // Duplicate receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001385 VisitForStackValue(value);
1386 DCHECK(property->emit_store());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001387 CallRuntimeWithOperands(Runtime::kInternalSetPrototype);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001388 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index),
Ben Murdochc5610432016-08-08 18:44:38 +01001389 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001390 break;
1391 case ObjectLiteral::Property::GETTER:
1392 if (property->emit_store()) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001393 AccessorTable::Iterator it = accessor_table.lookup(key);
1394 it->second->bailout_id = expr->GetIdForPropertySet(property_index);
1395 it->second->getter = property;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001396 }
1397 break;
1398 case ObjectLiteral::Property::SETTER:
1399 if (property->emit_store()) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001400 AccessorTable::Iterator it = accessor_table.lookup(key);
1401 it->second->bailout_id = expr->GetIdForPropertySet(property_index);
1402 it->second->setter = property;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001403 }
1404 break;
1405 }
1406 }
1407
1408 // Emit code to define accessors, using only a single call to the runtime for
1409 // each pair of corresponding getters and setters.
1410 for (AccessorTable::Iterator it = accessor_table.begin();
1411 it != accessor_table.end();
1412 ++it) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001413 PushOperand(Operand(esp, 0)); // Duplicate receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001414 VisitForStackValue(it->first);
1415
1416 EmitAccessor(it->second->getter);
1417 EmitAccessor(it->second->setter);
1418
Ben Murdoch097c5b22016-05-18 11:27:45 +01001419 PushOperand(Smi::FromInt(NONE));
1420 CallRuntimeWithOperands(Runtime::kDefineAccessorPropertyUnchecked);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001421 PrepareForBailoutForId(it->second->bailout_id, BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001422 }
1423
1424 // Object literals have two parts. The "static" part on the left contains no
1425 // computed property names, and so we can compute its map ahead of time; see
1426 // runtime.cc::CreateObjectLiteralBoilerplate. The second "dynamic" part
1427 // starts with the first computed property name, and continues with all
1428 // properties to its right. All the code from above initializes the static
1429 // component of the object literal, and arranges for the map of the result to
1430 // reflect the static order in which the keys appear. For the dynamic
1431 // properties, we compile them into a series of "SetOwnProperty" runtime
1432 // calls. This will preserve insertion order.
1433 for (; property_index < expr->properties()->length(); property_index++) {
1434 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1435
1436 Expression* value = property->value();
1437 if (!result_saved) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001438 PushOperand(eax); // Save result on the stack
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001439 result_saved = true;
1440 }
1441
Ben Murdoch097c5b22016-05-18 11:27:45 +01001442 PushOperand(Operand(esp, 0)); // Duplicate receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001443
1444 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
1445 DCHECK(!property->is_computed_name());
1446 VisitForStackValue(value);
1447 DCHECK(property->emit_store());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001448 CallRuntimeWithOperands(Runtime::kInternalSetPrototype);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001449 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index),
Ben Murdochc5610432016-08-08 18:44:38 +01001450 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001451 } else {
1452 EmitPropertyKey(property, expr->GetIdForPropertyName(property_index));
1453 VisitForStackValue(value);
1454 if (NeedsHomeObject(value)) {
1455 EmitSetHomeObject(value, 2, property->GetSlot());
1456 }
1457
1458 switch (property->kind()) {
1459 case ObjectLiteral::Property::CONSTANT:
1460 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1461 case ObjectLiteral::Property::COMPUTED:
1462 if (property->emit_store()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001463 PushOperand(Smi::FromInt(NONE));
1464 PushOperand(Smi::FromInt(property->NeedsSetFunctionName()));
1465 CallRuntimeWithOperands(Runtime::kDefineDataPropertyInLiteral);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001466 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index),
1467 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001468 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001469 DropOperands(3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001470 }
1471 break;
1472
1473 case ObjectLiteral::Property::PROTOTYPE:
1474 UNREACHABLE();
1475 break;
1476
1477 case ObjectLiteral::Property::GETTER:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001478 PushOperand(Smi::FromInt(NONE));
1479 CallRuntimeWithOperands(Runtime::kDefineGetterPropertyUnchecked);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001480 break;
1481
1482 case ObjectLiteral::Property::SETTER:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001483 PushOperand(Smi::FromInt(NONE));
1484 CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001485 break;
1486 }
1487 }
1488 }
1489
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001490 if (result_saved) {
1491 context()->PlugTOS();
1492 } else {
1493 context()->Plug(eax);
1494 }
1495}
1496
1497
1498void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1499 Comment cmnt(masm_, "[ ArrayLiteral");
1500
1501 Handle<FixedArray> constant_elements = expr->constant_elements();
1502 bool has_constant_fast_elements =
1503 IsFastObjectElementsKind(expr->constant_elements_kind());
1504
1505 AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
1506 if (has_constant_fast_elements && !FLAG_allocation_site_pretenuring) {
1507 // If the only customer of allocation sites is transitioning, then
1508 // we can turn it off if we don't have anywhere else to transition to.
1509 allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
1510 }
1511
1512 if (MustCreateArrayLiteralWithRuntime(expr)) {
1513 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1514 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1515 __ push(Immediate(constant_elements));
1516 __ push(Immediate(Smi::FromInt(expr->ComputeFlags())));
1517 __ CallRuntime(Runtime::kCreateArrayLiteral);
1518 } else {
1519 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1520 __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
1521 __ mov(ecx, Immediate(constant_elements));
1522 FastCloneShallowArrayStub stub(isolate(), allocation_site_mode);
1523 __ CallStub(&stub);
1524 }
Ben Murdochc5610432016-08-08 18:44:38 +01001525 PrepareForBailoutForId(expr->CreateLiteralId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001526
1527 bool result_saved = false; // Is the result saved to the stack?
1528 ZoneList<Expression*>* subexprs = expr->values();
1529 int length = subexprs->length();
1530
1531 // Emit code to evaluate all the non-constant subexpressions and to store
1532 // them into the newly cloned array.
1533 int array_index = 0;
1534 for (; array_index < length; array_index++) {
1535 Expression* subexpr = subexprs->at(array_index);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001536 DCHECK(!subexpr->IsSpread());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001537
1538 // If the subexpression is a literal or a simple materialized literal it
1539 // is already set in the cloned array.
1540 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
1541
1542 if (!result_saved) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001543 PushOperand(eax); // array literal.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001544 result_saved = true;
1545 }
1546 VisitForAccumulatorValue(subexpr);
1547
1548 __ mov(StoreDescriptor::NameRegister(),
1549 Immediate(Smi::FromInt(array_index)));
1550 __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0));
1551 EmitLoadStoreICSlot(expr->LiteralFeedbackSlot());
1552 Handle<Code> ic =
1553 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
1554 CallIC(ic);
Ben Murdochc5610432016-08-08 18:44:38 +01001555 PrepareForBailoutForId(expr->GetIdForElement(array_index),
1556 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001557 }
1558
1559 // In case the array literal contains spread expressions it has two parts. The
1560 // first part is the "static" array which has a literal index is handled
1561 // above. The second part is the part after the first spread expression
1562 // (inclusive) and these elements gets appended to the array. Note that the
1563 // number elements an iterable produces is unknown ahead of time.
1564 if (array_index < length && result_saved) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001565 PopOperand(eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001566 result_saved = false;
1567 }
1568 for (; array_index < length; array_index++) {
1569 Expression* subexpr = subexprs->at(array_index);
1570
Ben Murdoch097c5b22016-05-18 11:27:45 +01001571 PushOperand(eax);
1572 DCHECK(!subexpr->IsSpread());
1573 VisitForStackValue(subexpr);
1574 CallRuntimeWithOperands(Runtime::kAppendElement);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001575
Ben Murdochc5610432016-08-08 18:44:38 +01001576 PrepareForBailoutForId(expr->GetIdForElement(array_index),
1577 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001578 }
1579
1580 if (result_saved) {
1581 context()->PlugTOS();
1582 } else {
1583 context()->Plug(eax);
1584 }
1585}
1586
1587
1588void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1589 DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
1590
1591 Comment cmnt(masm_, "[ Assignment");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001592
1593 Property* property = expr->target()->AsProperty();
1594 LhsKind assign_type = Property::GetAssignType(property);
1595
1596 // Evaluate LHS expression.
1597 switch (assign_type) {
1598 case VARIABLE:
1599 // Nothing to do here.
1600 break;
1601 case NAMED_SUPER_PROPERTY:
1602 VisitForStackValue(
1603 property->obj()->AsSuperPropertyReference()->this_var());
1604 VisitForAccumulatorValue(
1605 property->obj()->AsSuperPropertyReference()->home_object());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001606 PushOperand(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001607 if (expr->is_compound()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001608 PushOperand(MemOperand(esp, kPointerSize));
1609 PushOperand(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001610 }
1611 break;
1612 case NAMED_PROPERTY:
1613 if (expr->is_compound()) {
1614 // We need the receiver both on the stack and in the register.
1615 VisitForStackValue(property->obj());
1616 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
1617 } else {
1618 VisitForStackValue(property->obj());
1619 }
1620 break;
1621 case KEYED_SUPER_PROPERTY:
1622 VisitForStackValue(
1623 property->obj()->AsSuperPropertyReference()->this_var());
1624 VisitForStackValue(
1625 property->obj()->AsSuperPropertyReference()->home_object());
1626 VisitForAccumulatorValue(property->key());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001627 PushOperand(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001628 if (expr->is_compound()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001629 PushOperand(MemOperand(esp, 2 * kPointerSize));
1630 PushOperand(MemOperand(esp, 2 * kPointerSize));
1631 PushOperand(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001632 }
1633 break;
1634 case KEYED_PROPERTY: {
1635 if (expr->is_compound()) {
1636 VisitForStackValue(property->obj());
1637 VisitForStackValue(property->key());
1638 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, kPointerSize));
1639 __ mov(LoadDescriptor::NameRegister(), Operand(esp, 0));
1640 } else {
1641 VisitForStackValue(property->obj());
1642 VisitForStackValue(property->key());
1643 }
1644 break;
1645 }
1646 }
1647
1648 // For compound assignments we need another deoptimization point after the
1649 // variable/property load.
1650 if (expr->is_compound()) {
1651 AccumulatorValueContext result_context(this);
1652 { AccumulatorValueContext left_operand_context(this);
1653 switch (assign_type) {
1654 case VARIABLE:
1655 EmitVariableLoad(expr->target()->AsVariableProxy());
Ben Murdochc5610432016-08-08 18:44:38 +01001656 PrepareForBailout(expr->target(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001657 break;
1658 case NAMED_SUPER_PROPERTY:
1659 EmitNamedSuperPropertyLoad(property);
Ben Murdochc5610432016-08-08 18:44:38 +01001660 PrepareForBailoutForId(property->LoadId(),
1661 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001662 break;
1663 case NAMED_PROPERTY:
1664 EmitNamedPropertyLoad(property);
Ben Murdochc5610432016-08-08 18:44:38 +01001665 PrepareForBailoutForId(property->LoadId(),
1666 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001667 break;
1668 case KEYED_SUPER_PROPERTY:
1669 EmitKeyedSuperPropertyLoad(property);
Ben Murdochc5610432016-08-08 18:44:38 +01001670 PrepareForBailoutForId(property->LoadId(),
1671 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001672 break;
1673 case KEYED_PROPERTY:
1674 EmitKeyedPropertyLoad(property);
Ben Murdochc5610432016-08-08 18:44:38 +01001675 PrepareForBailoutForId(property->LoadId(),
1676 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001677 break;
1678 }
1679 }
1680
1681 Token::Value op = expr->binary_op();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001682 PushOperand(eax); // Left operand goes on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001683 VisitForAccumulatorValue(expr->value());
1684
1685 if (ShouldInlineSmiCase(op)) {
1686 EmitInlineSmiBinaryOp(expr->binary_operation(),
1687 op,
1688 expr->target(),
1689 expr->value());
1690 } else {
1691 EmitBinaryOp(expr->binary_operation(), op);
1692 }
1693
1694 // Deoptimization point in case the binary operation may have side effects.
Ben Murdochc5610432016-08-08 18:44:38 +01001695 PrepareForBailout(expr->binary_operation(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001696 } else {
1697 VisitForAccumulatorValue(expr->value());
1698 }
1699
1700 SetExpressionPosition(expr);
1701
1702 // Store the value.
1703 switch (assign_type) {
1704 case VARIABLE:
1705 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
1706 expr->op(), expr->AssignmentSlot());
Ben Murdochc5610432016-08-08 18:44:38 +01001707 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001708 context()->Plug(eax);
1709 break;
1710 case NAMED_PROPERTY:
1711 EmitNamedPropertyAssignment(expr);
1712 break;
1713 case NAMED_SUPER_PROPERTY:
1714 EmitNamedSuperPropertyStore(property);
1715 context()->Plug(result_register());
1716 break;
1717 case KEYED_SUPER_PROPERTY:
1718 EmitKeyedSuperPropertyStore(property);
1719 context()->Plug(result_register());
1720 break;
1721 case KEYED_PROPERTY:
1722 EmitKeyedPropertyAssignment(expr);
1723 break;
1724 }
1725}
1726
1727
1728void FullCodeGenerator::VisitYield(Yield* expr) {
1729 Comment cmnt(masm_, "[ Yield");
1730 SetExpressionPosition(expr);
1731
1732 // Evaluate yielded value first; the initial iterator definition depends on
1733 // this. It stays on the stack while we update the iterator.
1734 VisitForStackValue(expr->expression());
1735
Ben Murdochc5610432016-08-08 18:44:38 +01001736 Label suspend, continuation, post_runtime, resume, exception;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001737
Ben Murdochda12d292016-06-02 14:46:10 +01001738 __ jmp(&suspend);
1739 __ bind(&continuation);
Ben Murdochc5610432016-08-08 18:44:38 +01001740 // When we arrive here, eax holds the generator object.
Ben Murdochda12d292016-06-02 14:46:10 +01001741 __ RecordGeneratorContinuation();
Ben Murdochc5610432016-08-08 18:44:38 +01001742 __ mov(ebx, FieldOperand(eax, JSGeneratorObject::kResumeModeOffset));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001743 __ mov(eax, FieldOperand(eax, JSGeneratorObject::kInputOrDebugPosOffset));
Ben Murdochc5610432016-08-08 18:44:38 +01001744 STATIC_ASSERT(JSGeneratorObject::kNext < JSGeneratorObject::kReturn);
1745 STATIC_ASSERT(JSGeneratorObject::kThrow > JSGeneratorObject::kReturn);
1746 __ cmp(ebx, Immediate(Smi::FromInt(JSGeneratorObject::kReturn)));
1747 __ j(less, &resume);
1748 __ Push(result_register());
1749 __ j(greater, &exception);
Ben Murdochda12d292016-06-02 14:46:10 +01001750 EmitCreateIteratorResult(true);
1751 EmitUnwindAndReturn();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001752
Ben Murdochc5610432016-08-08 18:44:38 +01001753 __ bind(&exception);
1754 __ CallRuntime(Runtime::kThrow);
1755
Ben Murdochda12d292016-06-02 14:46:10 +01001756 __ bind(&suspend);
1757 OperandStackDepthIncrement(1); // Not popped on this path.
1758 VisitForAccumulatorValue(expr->generator_object());
1759 DCHECK(continuation.pos() > 0 && Smi::IsValid(continuation.pos()));
1760 __ mov(FieldOperand(eax, JSGeneratorObject::kContinuationOffset),
1761 Immediate(Smi::FromInt(continuation.pos())));
1762 __ mov(FieldOperand(eax, JSGeneratorObject::kContextOffset), esi);
1763 __ mov(ecx, esi);
1764 __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx,
1765 kDontSaveFPRegs);
1766 __ lea(ebx, Operand(ebp, StandardFrameConstants::kExpressionsOffset));
1767 __ cmp(esp, ebx);
1768 __ j(equal, &post_runtime);
1769 __ push(eax); // generator object
1770 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
Ben Murdochc5610432016-08-08 18:44:38 +01001771 RestoreContext();
Ben Murdochda12d292016-06-02 14:46:10 +01001772 __ bind(&post_runtime);
1773 PopOperand(result_register());
1774 EmitReturnSequence();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001775
Ben Murdochda12d292016-06-02 14:46:10 +01001776 __ bind(&resume);
1777 context()->Plug(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001778}
1779
Ben Murdoch097c5b22016-05-18 11:27:45 +01001780void FullCodeGenerator::PushOperand(MemOperand operand) {
1781 OperandStackDepthIncrement(1);
1782 __ Push(operand);
1783}
1784
1785void FullCodeGenerator::EmitOperandStackDepthCheck() {
1786 if (FLAG_debug_code) {
1787 int expected_diff = StandardFrameConstants::kFixedFrameSizeFromFp +
1788 operand_stack_depth_ * kPointerSize;
1789 __ mov(eax, ebp);
1790 __ sub(eax, esp);
1791 __ cmp(eax, Immediate(expected_diff));
1792 __ Assert(equal, kUnexpectedStackDepth);
1793 }
1794}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001795
1796void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
1797 Label allocate, done_allocate;
1798
Ben Murdochc5610432016-08-08 18:44:38 +01001799 __ Allocate(JSIteratorResult::kSize, eax, ecx, edx, &allocate,
1800 NO_ALLOCATION_FLAGS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001801 __ jmp(&done_allocate, Label::kNear);
1802
1803 __ bind(&allocate);
1804 __ Push(Smi::FromInt(JSIteratorResult::kSize));
1805 __ CallRuntime(Runtime::kAllocateInNewSpace);
1806
1807 __ bind(&done_allocate);
1808 __ mov(ebx, NativeContextOperand());
1809 __ mov(ebx, ContextOperand(ebx, Context::ITERATOR_RESULT_MAP_INDEX));
1810 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ebx);
1811 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
1812 isolate()->factory()->empty_fixed_array());
1813 __ mov(FieldOperand(eax, JSObject::kElementsOffset),
1814 isolate()->factory()->empty_fixed_array());
1815 __ pop(FieldOperand(eax, JSIteratorResult::kValueOffset));
1816 __ mov(FieldOperand(eax, JSIteratorResult::kDoneOffset),
1817 isolate()->factory()->ToBoolean(done));
1818 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
Ben Murdochda12d292016-06-02 14:46:10 +01001819 OperandStackDepthDecrement(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001820}
1821
1822
1823void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
1824 Token::Value op,
1825 Expression* left,
1826 Expression* right) {
1827 // Do combined smi check of the operands. Left operand is on the
1828 // stack. Right operand is in eax.
1829 Label smi_case, done, stub_call;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001830 PopOperand(edx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001831 __ mov(ecx, eax);
1832 __ or_(eax, edx);
1833 JumpPatchSite patch_site(masm_);
1834 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear);
1835
1836 __ bind(&stub_call);
1837 __ mov(eax, ecx);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001838 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001839 CallIC(code, expr->BinaryOperationFeedbackId());
1840 patch_site.EmitPatchInfo();
1841 __ jmp(&done, Label::kNear);
1842
1843 // Smi case.
1844 __ bind(&smi_case);
1845 __ mov(eax, edx); // Copy left operand in case of a stub call.
1846
1847 switch (op) {
1848 case Token::SAR:
1849 __ SmiUntag(ecx);
1850 __ sar_cl(eax); // No checks of result necessary
1851 __ and_(eax, Immediate(~kSmiTagMask));
1852 break;
1853 case Token::SHL: {
1854 Label result_ok;
1855 __ SmiUntag(eax);
1856 __ SmiUntag(ecx);
1857 __ shl_cl(eax);
1858 // Check that the *signed* result fits in a smi.
1859 __ cmp(eax, 0xc0000000);
1860 __ j(positive, &result_ok);
1861 __ SmiTag(ecx);
1862 __ jmp(&stub_call);
1863 __ bind(&result_ok);
1864 __ SmiTag(eax);
1865 break;
1866 }
1867 case Token::SHR: {
1868 Label result_ok;
1869 __ SmiUntag(eax);
1870 __ SmiUntag(ecx);
1871 __ shr_cl(eax);
1872 __ test(eax, Immediate(0xc0000000));
1873 __ j(zero, &result_ok);
1874 __ SmiTag(ecx);
1875 __ jmp(&stub_call);
1876 __ bind(&result_ok);
1877 __ SmiTag(eax);
1878 break;
1879 }
1880 case Token::ADD:
1881 __ add(eax, ecx);
1882 __ j(overflow, &stub_call);
1883 break;
1884 case Token::SUB:
1885 __ sub(eax, ecx);
1886 __ j(overflow, &stub_call);
1887 break;
1888 case Token::MUL: {
1889 __ SmiUntag(eax);
1890 __ imul(eax, ecx);
1891 __ j(overflow, &stub_call);
1892 __ test(eax, eax);
1893 __ j(not_zero, &done, Label::kNear);
1894 __ mov(ebx, edx);
1895 __ or_(ebx, ecx);
1896 __ j(negative, &stub_call);
1897 break;
1898 }
1899 case Token::BIT_OR:
1900 __ or_(eax, ecx);
1901 break;
1902 case Token::BIT_AND:
1903 __ and_(eax, ecx);
1904 break;
1905 case Token::BIT_XOR:
1906 __ xor_(eax, ecx);
1907 break;
1908 default:
1909 UNREACHABLE();
1910 }
1911
1912 __ bind(&done);
1913 context()->Plug(eax);
1914}
1915
1916
1917void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001918 for (int i = 0; i < lit->properties()->length(); i++) {
1919 ObjectLiteral::Property* property = lit->properties()->at(i);
1920 Expression* value = property->value();
1921
1922 if (property->is_static()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001923 PushOperand(Operand(esp, kPointerSize)); // constructor
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001924 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001925 PushOperand(Operand(esp, 0)); // prototype
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001926 }
1927 EmitPropertyKey(property, lit->GetIdForProperty(i));
1928
1929 // The static prototype property is read only. We handle the non computed
1930 // property name case in the parser. Since this is the only case where we
1931 // need to check for an own read only property we special case this so we do
1932 // not need to do this for every property.
1933 if (property->is_static() && property->is_computed_name()) {
1934 __ CallRuntime(Runtime::kThrowIfStaticPrototype);
1935 __ push(eax);
1936 }
1937
1938 VisitForStackValue(value);
1939 if (NeedsHomeObject(value)) {
1940 EmitSetHomeObject(value, 2, property->GetSlot());
1941 }
1942
1943 switch (property->kind()) {
1944 case ObjectLiteral::Property::CONSTANT:
1945 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1946 case ObjectLiteral::Property::PROTOTYPE:
1947 UNREACHABLE();
1948 case ObjectLiteral::Property::COMPUTED:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001949 PushOperand(Smi::FromInt(DONT_ENUM));
1950 PushOperand(Smi::FromInt(property->NeedsSetFunctionName()));
1951 CallRuntimeWithOperands(Runtime::kDefineDataPropertyInLiteral);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001952 break;
1953
1954 case ObjectLiteral::Property::GETTER:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001955 PushOperand(Smi::FromInt(DONT_ENUM));
1956 CallRuntimeWithOperands(Runtime::kDefineGetterPropertyUnchecked);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001957 break;
1958
1959 case ObjectLiteral::Property::SETTER:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001960 PushOperand(Smi::FromInt(DONT_ENUM));
1961 CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001962 break;
1963 }
1964 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001965}
1966
1967
1968void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001969 PopOperand(edx);
1970 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001971 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
1972 CallIC(code, expr->BinaryOperationFeedbackId());
1973 patch_site.EmitPatchInfo();
1974 context()->Plug(eax);
1975}
1976
1977
1978void FullCodeGenerator::EmitAssignment(Expression* expr,
1979 FeedbackVectorSlot slot) {
1980 DCHECK(expr->IsValidReferenceExpressionOrThis());
1981
1982 Property* prop = expr->AsProperty();
1983 LhsKind assign_type = Property::GetAssignType(prop);
1984
1985 switch (assign_type) {
1986 case VARIABLE: {
1987 Variable* var = expr->AsVariableProxy()->var();
1988 EffectContext context(this);
1989 EmitVariableAssignment(var, Token::ASSIGN, slot);
1990 break;
1991 }
1992 case NAMED_PROPERTY: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001993 PushOperand(eax); // Preserve value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001994 VisitForAccumulatorValue(prop->obj());
1995 __ Move(StoreDescriptor::ReceiverRegister(), eax);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001996 PopOperand(StoreDescriptor::ValueRegister()); // Restore value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001997 __ mov(StoreDescriptor::NameRegister(),
1998 prop->key()->AsLiteral()->value());
1999 EmitLoadStoreICSlot(slot);
2000 CallStoreIC();
2001 break;
2002 }
2003 case NAMED_SUPER_PROPERTY: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002004 PushOperand(eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002005 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
2006 VisitForAccumulatorValue(
2007 prop->obj()->AsSuperPropertyReference()->home_object());
2008 // stack: value, this; eax: home_object
2009 Register scratch = ecx;
2010 Register scratch2 = edx;
2011 __ mov(scratch, result_register()); // home_object
2012 __ mov(eax, MemOperand(esp, kPointerSize)); // value
2013 __ mov(scratch2, MemOperand(esp, 0)); // this
2014 __ mov(MemOperand(esp, kPointerSize), scratch2); // this
2015 __ mov(MemOperand(esp, 0), scratch); // home_object
2016 // stack: this, home_object. eax: value
2017 EmitNamedSuperPropertyStore(prop);
2018 break;
2019 }
2020 case KEYED_SUPER_PROPERTY: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002021 PushOperand(eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002022 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
2023 VisitForStackValue(
2024 prop->obj()->AsSuperPropertyReference()->home_object());
2025 VisitForAccumulatorValue(prop->key());
2026 Register scratch = ecx;
2027 Register scratch2 = edx;
2028 __ mov(scratch2, MemOperand(esp, 2 * kPointerSize)); // value
2029 // stack: value, this, home_object; eax: key, edx: value
2030 __ mov(scratch, MemOperand(esp, kPointerSize)); // this
2031 __ mov(MemOperand(esp, 2 * kPointerSize), scratch);
2032 __ mov(scratch, MemOperand(esp, 0)); // home_object
2033 __ mov(MemOperand(esp, kPointerSize), scratch);
2034 __ mov(MemOperand(esp, 0), eax);
2035 __ mov(eax, scratch2);
2036 // stack: this, home_object, key; eax: value.
2037 EmitKeyedSuperPropertyStore(prop);
2038 break;
2039 }
2040 case KEYED_PROPERTY: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002041 PushOperand(eax); // Preserve value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002042 VisitForStackValue(prop->obj());
2043 VisitForAccumulatorValue(prop->key());
2044 __ Move(StoreDescriptor::NameRegister(), eax);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002045 PopOperand(StoreDescriptor::ReceiverRegister()); // Receiver.
2046 PopOperand(StoreDescriptor::ValueRegister()); // Restore value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002047 EmitLoadStoreICSlot(slot);
2048 Handle<Code> ic =
2049 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
2050 CallIC(ic);
2051 break;
2052 }
2053 }
2054 context()->Plug(eax);
2055}
2056
2057
2058void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
2059 Variable* var, MemOperand location) {
2060 __ mov(location, eax);
2061 if (var->IsContextSlot()) {
2062 __ mov(edx, eax);
2063 int offset = Context::SlotOffset(var->index());
2064 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
2065 }
2066}
2067
2068
2069void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
2070 FeedbackVectorSlot slot) {
2071 if (var->IsUnallocated()) {
2072 // Global var, const, or let.
2073 __ mov(StoreDescriptor::NameRegister(), var->name());
2074 __ mov(StoreDescriptor::ReceiverRegister(), NativeContextOperand());
2075 __ mov(StoreDescriptor::ReceiverRegister(),
2076 ContextOperand(StoreDescriptor::ReceiverRegister(),
2077 Context::EXTENSION_INDEX));
2078 EmitLoadStoreICSlot(slot);
2079 CallStoreIC();
2080
2081 } else if (var->mode() == LET && op != Token::INIT) {
2082 // Non-initializing assignment to let variable needs a write barrier.
2083 DCHECK(!var->IsLookupSlot());
2084 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2085 Label assign;
2086 MemOperand location = VarOperand(var, ecx);
2087 __ mov(edx, location);
2088 __ cmp(edx, isolate()->factory()->the_hole_value());
2089 __ j(not_equal, &assign, Label::kNear);
2090 __ push(Immediate(var->name()));
2091 __ CallRuntime(Runtime::kThrowReferenceError);
2092 __ bind(&assign);
2093 EmitStoreToStackLocalOrContextSlot(var, location);
2094
2095 } else if (var->mode() == CONST && op != Token::INIT) {
2096 // Assignment to const variable needs a write barrier.
2097 DCHECK(!var->IsLookupSlot());
2098 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2099 Label const_error;
2100 MemOperand location = VarOperand(var, ecx);
2101 __ mov(edx, location);
2102 __ cmp(edx, isolate()->factory()->the_hole_value());
2103 __ j(not_equal, &const_error, Label::kNear);
2104 __ push(Immediate(var->name()));
2105 __ CallRuntime(Runtime::kThrowReferenceError);
2106 __ bind(&const_error);
2107 __ CallRuntime(Runtime::kThrowConstAssignError);
2108
2109 } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) {
2110 // Initializing assignment to const {this} needs a write barrier.
2111 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2112 Label uninitialized_this;
2113 MemOperand location = VarOperand(var, ecx);
2114 __ mov(edx, location);
2115 __ cmp(edx, isolate()->factory()->the_hole_value());
2116 __ j(equal, &uninitialized_this);
2117 __ push(Immediate(var->name()));
2118 __ CallRuntime(Runtime::kThrowReferenceError);
2119 __ bind(&uninitialized_this);
2120 EmitStoreToStackLocalOrContextSlot(var, location);
2121
Ben Murdochc5610432016-08-08 18:44:38 +01002122 } else if (!var->is_const_mode() || op == Token::INIT) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002123 if (var->IsLookupSlot()) {
2124 // Assignment to var.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002125 __ Push(Immediate(var->name()));
2126 __ Push(eax);
2127 __ CallRuntime(is_strict(language_mode())
2128 ? Runtime::kStoreLookupSlot_Strict
2129 : Runtime::kStoreLookupSlot_Sloppy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002130 } else {
2131 // Assignment to var or initializing assignment to let/const in harmony
2132 // mode.
2133 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2134 MemOperand location = VarOperand(var, ecx);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002135 if (FLAG_debug_code && var->mode() == LET && op == Token::INIT) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002136 // Check for an uninitialized let binding.
2137 __ mov(edx, location);
2138 __ cmp(edx, isolate()->factory()->the_hole_value());
2139 __ Check(equal, kLetBindingReInitialization);
2140 }
2141 EmitStoreToStackLocalOrContextSlot(var, location);
2142 }
2143
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002144 } else {
2145 DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT);
2146 if (is_strict(language_mode())) {
2147 __ CallRuntime(Runtime::kThrowConstAssignError);
2148 }
2149 // Silently ignore store in sloppy mode.
2150 }
2151}
2152
2153
2154void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
2155 // Assignment to a property, using a named store IC.
2156 // eax : value
2157 // esp[0] : receiver
2158 Property* prop = expr->target()->AsProperty();
2159 DCHECK(prop != NULL);
2160 DCHECK(prop->key()->IsLiteral());
2161
2162 __ mov(StoreDescriptor::NameRegister(), prop->key()->AsLiteral()->value());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002163 PopOperand(StoreDescriptor::ReceiverRegister());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002164 EmitLoadStoreICSlot(expr->AssignmentSlot());
2165 CallStoreIC();
Ben Murdochc5610432016-08-08 18:44:38 +01002166 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002167 context()->Plug(eax);
2168}
2169
2170
2171void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
2172 // Assignment to named property of super.
2173 // eax : value
2174 // stack : receiver ('this'), home_object
2175 DCHECK(prop != NULL);
2176 Literal* key = prop->key()->AsLiteral();
2177 DCHECK(key != NULL);
2178
Ben Murdoch097c5b22016-05-18 11:27:45 +01002179 PushOperand(key->value());
2180 PushOperand(eax);
2181 CallRuntimeWithOperands(is_strict(language_mode())
2182 ? Runtime::kStoreToSuper_Strict
2183 : Runtime::kStoreToSuper_Sloppy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002184}
2185
2186
2187void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
2188 // Assignment to named property of super.
2189 // eax : value
2190 // stack : receiver ('this'), home_object, key
2191
Ben Murdoch097c5b22016-05-18 11:27:45 +01002192 PushOperand(eax);
2193 CallRuntimeWithOperands(is_strict(language_mode())
2194 ? Runtime::kStoreKeyedToSuper_Strict
2195 : Runtime::kStoreKeyedToSuper_Sloppy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002196}
2197
2198
2199void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
2200 // Assignment to a property, using a keyed store IC.
2201 // eax : value
2202 // esp[0] : key
2203 // esp[kPointerSize] : receiver
2204
Ben Murdoch097c5b22016-05-18 11:27:45 +01002205 PopOperand(StoreDescriptor::NameRegister()); // Key.
2206 PopOperand(StoreDescriptor::ReceiverRegister());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002207 DCHECK(StoreDescriptor::ValueRegister().is(eax));
2208 Handle<Code> ic =
2209 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
2210 EmitLoadStoreICSlot(expr->AssignmentSlot());
2211 CallIC(ic);
Ben Murdochc5610432016-08-08 18:44:38 +01002212 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002213 context()->Plug(eax);
2214}
2215
2216
2217void FullCodeGenerator::CallIC(Handle<Code> code,
2218 TypeFeedbackId ast_id) {
2219 ic_total_count_++;
2220 __ call(code, RelocInfo::CODE_TARGET, ast_id);
2221}
2222
2223
2224// Code common for calls using the IC.
2225void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
2226 Expression* callee = expr->expression();
2227
2228 // Get the target function.
2229 ConvertReceiverMode convert_mode;
2230 if (callee->IsVariableProxy()) {
2231 { StackValueContext context(this);
2232 EmitVariableLoad(callee->AsVariableProxy());
Ben Murdochc5610432016-08-08 18:44:38 +01002233 PrepareForBailout(callee, BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002234 }
2235 // Push undefined as receiver. This is patched in the method prologue if it
2236 // is a sloppy mode method.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002237 PushOperand(isolate()->factory()->undefined_value());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002238 convert_mode = ConvertReceiverMode::kNullOrUndefined;
2239 } else {
2240 // Load the function from the receiver.
2241 DCHECK(callee->IsProperty());
2242 DCHECK(!callee->AsProperty()->IsSuperAccess());
2243 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
2244 EmitNamedPropertyLoad(callee->AsProperty());
Ben Murdochc5610432016-08-08 18:44:38 +01002245 PrepareForBailoutForId(callee->AsProperty()->LoadId(),
2246 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002247 // Push the target function under the receiver.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002248 PushOperand(Operand(esp, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002249 __ mov(Operand(esp, kPointerSize), eax);
2250 convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
2251 }
2252
2253 EmitCall(expr, convert_mode);
2254}
2255
2256
2257void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
2258 SetExpressionPosition(expr);
2259 Expression* callee = expr->expression();
2260 DCHECK(callee->IsProperty());
2261 Property* prop = callee->AsProperty();
2262 DCHECK(prop->IsSuperAccess());
2263
2264 Literal* key = prop->key()->AsLiteral();
2265 DCHECK(!key->value()->IsSmi());
2266 // Load the function from the receiver.
2267 SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference();
2268 VisitForStackValue(super_ref->home_object());
2269 VisitForAccumulatorValue(super_ref->this_var());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002270 PushOperand(eax);
2271 PushOperand(eax);
2272 PushOperand(Operand(esp, kPointerSize * 2));
2273 PushOperand(key->value());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002274 // Stack here:
2275 // - home_object
2276 // - this (receiver)
2277 // - this (receiver) <-- LoadFromSuper will pop here and below.
2278 // - home_object
2279 // - key
Ben Murdoch097c5b22016-05-18 11:27:45 +01002280 CallRuntimeWithOperands(Runtime::kLoadFromSuper);
Ben Murdochc5610432016-08-08 18:44:38 +01002281 PrepareForBailoutForId(prop->LoadId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002282
2283 // Replace home_object with target function.
2284 __ mov(Operand(esp, kPointerSize), eax);
2285
2286 // Stack here:
2287 // - target function
2288 // - this (receiver)
2289 EmitCall(expr);
2290}
2291
2292
2293// Code common for calls using the IC.
2294void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
2295 Expression* key) {
2296 // Load the key.
2297 VisitForAccumulatorValue(key);
2298
2299 Expression* callee = expr->expression();
2300
2301 // Load the function from the receiver.
2302 DCHECK(callee->IsProperty());
2303 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
2304 __ mov(LoadDescriptor::NameRegister(), eax);
2305 EmitKeyedPropertyLoad(callee->AsProperty());
Ben Murdochc5610432016-08-08 18:44:38 +01002306 PrepareForBailoutForId(callee->AsProperty()->LoadId(),
2307 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002308
2309 // Push the target function under the receiver.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002310 PushOperand(Operand(esp, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002311 __ mov(Operand(esp, kPointerSize), eax);
2312
2313 EmitCall(expr, ConvertReceiverMode::kNotNullOrUndefined);
2314}
2315
2316
2317void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
2318 Expression* callee = expr->expression();
2319 DCHECK(callee->IsProperty());
2320 Property* prop = callee->AsProperty();
2321 DCHECK(prop->IsSuperAccess());
2322
2323 SetExpressionPosition(prop);
2324 // Load the function from the receiver.
2325 SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference();
2326 VisitForStackValue(super_ref->home_object());
2327 VisitForAccumulatorValue(super_ref->this_var());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002328 PushOperand(eax);
2329 PushOperand(eax);
2330 PushOperand(Operand(esp, kPointerSize * 2));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002331 VisitForStackValue(prop->key());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002332 // Stack here:
2333 // - home_object
2334 // - this (receiver)
2335 // - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
2336 // - home_object
2337 // - key
Ben Murdoch097c5b22016-05-18 11:27:45 +01002338 CallRuntimeWithOperands(Runtime::kLoadKeyedFromSuper);
Ben Murdochc5610432016-08-08 18:44:38 +01002339 PrepareForBailoutForId(prop->LoadId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002340
2341 // Replace home_object with target function.
2342 __ mov(Operand(esp, kPointerSize), eax);
2343
2344 // Stack here:
2345 // - target function
2346 // - this (receiver)
2347 EmitCall(expr);
2348}
2349
2350
2351void FullCodeGenerator::EmitCall(Call* expr, ConvertReceiverMode mode) {
2352 // Load the arguments.
2353 ZoneList<Expression*>* args = expr->arguments();
2354 int arg_count = args->length();
2355 for (int i = 0; i < arg_count; i++) {
2356 VisitForStackValue(args->at(i));
2357 }
2358
Ben Murdochc5610432016-08-08 18:44:38 +01002359 PrepareForBailoutForId(expr->CallId(), BailoutState::NO_REGISTERS);
Ben Murdochda12d292016-06-02 14:46:10 +01002360 SetCallPosition(expr, expr->tail_call_mode());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002361 if (expr->tail_call_mode() == TailCallMode::kAllow) {
2362 if (FLAG_trace) {
2363 __ CallRuntime(Runtime::kTraceTailCall);
2364 }
2365 // Update profiling counters before the tail call since we will
2366 // not return to this function.
2367 EmitProfilingCounterHandlingForReturnSequence(true);
2368 }
2369 Handle<Code> ic =
2370 CodeFactory::CallIC(isolate(), arg_count, mode, expr->tail_call_mode())
2371 .code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002372 __ Move(edx, Immediate(SmiFromSlot(expr->CallFeedbackICSlot())));
2373 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
2374 // Don't assign a type feedback id to the IC, since type feedback is provided
2375 // by the vector above.
2376 CallIC(ic);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002377 OperandStackDepthDecrement(arg_count + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002378
2379 RecordJSReturnSite(expr);
Ben Murdochc5610432016-08-08 18:44:38 +01002380 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002381 context()->DropAndPlug(1, eax);
2382}
2383
Ben Murdochc5610432016-08-08 18:44:38 +01002384void FullCodeGenerator::EmitResolvePossiblyDirectEval(Call* expr) {
2385 int arg_count = expr->arguments()->length();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002386 // Push copy of the first argument or undefined if it doesn't exist.
2387 if (arg_count > 0) {
2388 __ push(Operand(esp, arg_count * kPointerSize));
2389 } else {
2390 __ push(Immediate(isolate()->factory()->undefined_value()));
2391 }
2392
2393 // Push the enclosing function.
2394 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
2395
2396 // Push the language mode.
2397 __ push(Immediate(Smi::FromInt(language_mode())));
2398
2399 // Push the start position of the scope the calls resides in.
2400 __ push(Immediate(Smi::FromInt(scope()->start_position())));
2401
Ben Murdochc5610432016-08-08 18:44:38 +01002402 // Push the source position of the eval call.
2403 __ push(Immediate(Smi::FromInt(expr->position())));
2404
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002405 // Do the runtime call.
2406 __ CallRuntime(Runtime::kResolvePossiblyDirectEval);
2407}
2408
2409
2410// See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls.
2411void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) {
2412 VariableProxy* callee = expr->expression()->AsVariableProxy();
2413 if (callee->var()->IsLookupSlot()) {
2414 Label slow, done;
2415 SetExpressionPosition(callee);
2416 // Generate code for loading from variables potentially shadowed by
2417 // eval-introduced variables.
2418 EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done);
2419
2420 __ bind(&slow);
2421 // Call the runtime to find the function to call (returned in eax) and
2422 // the object holding it (returned in edx).
Ben Murdoch097c5b22016-05-18 11:27:45 +01002423 __ Push(callee->name());
2424 __ CallRuntime(Runtime::kLoadLookupSlotForCall);
2425 PushOperand(eax); // Function.
2426 PushOperand(edx); // Receiver.
Ben Murdochc5610432016-08-08 18:44:38 +01002427 PrepareForBailoutForId(expr->LookupId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002428
2429 // If fast case code has been generated, emit code to push the function
2430 // and receiver and have the slow path jump around this code.
2431 if (done.is_linked()) {
2432 Label call;
2433 __ jmp(&call, Label::kNear);
2434 __ bind(&done);
2435 // Push function.
2436 __ push(eax);
2437 // The receiver is implicitly the global receiver. Indicate this by
2438 // passing the hole to the call function stub.
2439 __ push(Immediate(isolate()->factory()->undefined_value()));
2440 __ bind(&call);
2441 }
2442 } else {
2443 VisitForStackValue(callee);
2444 // refEnv.WithBaseObject()
Ben Murdoch097c5b22016-05-18 11:27:45 +01002445 PushOperand(isolate()->factory()->undefined_value());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002446 }
2447}
2448
2449
2450void FullCodeGenerator::EmitPossiblyEvalCall(Call* expr) {
Ben Murdochc5610432016-08-08 18:44:38 +01002451 // In a call to eval, we first call Runtime_ResolvePossiblyDirectEval
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002452 // to resolve the function we need to call. Then we call the resolved
2453 // function using the given arguments.
2454 ZoneList<Expression*>* args = expr->arguments();
2455 int arg_count = args->length();
2456
2457 PushCalleeAndWithBaseObject(expr);
2458
2459 // Push the arguments.
2460 for (int i = 0; i < arg_count; i++) {
2461 VisitForStackValue(args->at(i));
2462 }
2463
2464 // Push a copy of the function (found below the arguments) and
2465 // resolve eval.
2466 __ push(Operand(esp, (arg_count + 1) * kPointerSize));
Ben Murdochc5610432016-08-08 18:44:38 +01002467 EmitResolvePossiblyDirectEval(expr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002468
2469 // Touch up the stack with the resolved function.
2470 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
2471
Ben Murdochc5610432016-08-08 18:44:38 +01002472 PrepareForBailoutForId(expr->EvalId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002473
2474 SetCallPosition(expr);
2475 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
2476 __ Set(eax, arg_count);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002477 __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kAny,
2478 expr->tail_call_mode()),
2479 RelocInfo::CODE_TARGET);
2480 OperandStackDepthDecrement(arg_count + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002481 RecordJSReturnSite(expr);
Ben Murdochc5610432016-08-08 18:44:38 +01002482 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002483 context()->DropAndPlug(1, eax);
2484}
2485
2486
2487void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2488 Comment cmnt(masm_, "[ CallNew");
2489 // According to ECMA-262, section 11.2.2, page 44, the function
2490 // expression in new calls must be evaluated before the
2491 // arguments.
2492
2493 // Push constructor on the stack. If it's not a function it's used as
2494 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2495 // ignored.
2496 DCHECK(!expr->expression()->IsSuperPropertyReference());
2497 VisitForStackValue(expr->expression());
2498
2499 // Push the arguments ("left-to-right") on the stack.
2500 ZoneList<Expression*>* args = expr->arguments();
2501 int arg_count = args->length();
2502 for (int i = 0; i < arg_count; i++) {
2503 VisitForStackValue(args->at(i));
2504 }
2505
2506 // Call the construct call builtin that handles allocation and
2507 // constructor invocation.
2508 SetConstructCallPosition(expr);
2509
2510 // Load function and argument count into edi and eax.
2511 __ Move(eax, Immediate(arg_count));
2512 __ mov(edi, Operand(esp, arg_count * kPointerSize));
2513
2514 // Record call targets in unoptimized code.
2515 __ EmitLoadTypeFeedbackVector(ebx);
2516 __ mov(edx, Immediate(SmiFromSlot(expr->CallNewFeedbackSlot())));
2517
2518 CallConstructStub stub(isolate());
2519 __ call(stub.GetCode(), RelocInfo::CODE_TARGET);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002520 OperandStackDepthDecrement(arg_count + 1);
Ben Murdochc5610432016-08-08 18:44:38 +01002521 PrepareForBailoutForId(expr->ReturnId(), BailoutState::TOS_REGISTER);
2522 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002523 context()->Plug(eax);
2524}
2525
2526
2527void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
2528 SuperCallReference* super_call_ref =
2529 expr->expression()->AsSuperCallReference();
2530 DCHECK_NOT_NULL(super_call_ref);
2531
2532 // Push the super constructor target on the stack (may be null,
2533 // but the Construct builtin can deal with that properly).
2534 VisitForAccumulatorValue(super_call_ref->this_function_var());
2535 __ AssertFunction(result_register());
2536 __ mov(result_register(),
2537 FieldOperand(result_register(), HeapObject::kMapOffset));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002538 PushOperand(FieldOperand(result_register(), Map::kPrototypeOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002539
2540 // Push the arguments ("left-to-right") on the stack.
2541 ZoneList<Expression*>* args = expr->arguments();
2542 int arg_count = args->length();
2543 for (int i = 0; i < arg_count; i++) {
2544 VisitForStackValue(args->at(i));
2545 }
2546
2547 // Call the construct call builtin that handles allocation and
2548 // constructor invocation.
2549 SetConstructCallPosition(expr);
2550
2551 // Load new target into edx.
2552 VisitForAccumulatorValue(super_call_ref->new_target_var());
2553 __ mov(edx, result_register());
2554
2555 // Load function and argument count into edi and eax.
2556 __ Move(eax, Immediate(arg_count));
2557 __ mov(edi, Operand(esp, arg_count * kPointerSize));
2558
2559 __ Call(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002560 OperandStackDepthDecrement(arg_count + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002561
2562 RecordJSReturnSite(expr);
Ben Murdochc5610432016-08-08 18:44:38 +01002563 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002564 context()->Plug(eax);
2565}
2566
2567
2568void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
2569 ZoneList<Expression*>* args = expr->arguments();
2570 DCHECK(args->length() == 1);
2571
2572 VisitForAccumulatorValue(args->at(0));
2573
2574 Label materialize_true, materialize_false;
2575 Label* if_true = NULL;
2576 Label* if_false = NULL;
2577 Label* fall_through = NULL;
2578 context()->PrepareTest(&materialize_true, &materialize_false,
2579 &if_true, &if_false, &fall_through);
2580
2581 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2582 __ test(eax, Immediate(kSmiTagMask));
2583 Split(zero, if_true, if_false, fall_through);
2584
2585 context()->Plug(if_true, if_false);
2586}
2587
2588
2589void FullCodeGenerator::EmitIsJSReceiver(CallRuntime* expr) {
2590 ZoneList<Expression*>* args = expr->arguments();
2591 DCHECK(args->length() == 1);
2592
2593 VisitForAccumulatorValue(args->at(0));
2594
2595 Label materialize_true, materialize_false;
2596 Label* if_true = NULL;
2597 Label* if_false = NULL;
2598 Label* fall_through = NULL;
2599 context()->PrepareTest(&materialize_true, &materialize_false,
2600 &if_true, &if_false, &fall_through);
2601
2602 __ JumpIfSmi(eax, if_false);
2603 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ebx);
2604 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2605 Split(above_equal, if_true, if_false, fall_through);
2606
2607 context()->Plug(if_true, if_false);
2608}
2609
2610
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002611void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
2612 ZoneList<Expression*>* args = expr->arguments();
2613 DCHECK(args->length() == 1);
2614
2615 VisitForAccumulatorValue(args->at(0));
2616
2617 Label materialize_true, materialize_false;
2618 Label* if_true = NULL;
2619 Label* if_false = NULL;
2620 Label* fall_through = NULL;
2621 context()->PrepareTest(&materialize_true, &materialize_false,
2622 &if_true, &if_false, &fall_through);
2623
2624 __ JumpIfSmi(eax, if_false);
2625 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
2626 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2627 Split(equal, if_true, if_false, fall_through);
2628
2629 context()->Plug(if_true, if_false);
2630}
2631
2632
2633void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) {
2634 ZoneList<Expression*>* args = expr->arguments();
2635 DCHECK(args->length() == 1);
2636
2637 VisitForAccumulatorValue(args->at(0));
2638
2639 Label materialize_true, materialize_false;
2640 Label* if_true = NULL;
2641 Label* if_false = NULL;
2642 Label* fall_through = NULL;
2643 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
2644 &if_false, &fall_through);
2645
2646 __ JumpIfSmi(eax, if_false);
2647 __ CmpObjectType(eax, JS_TYPED_ARRAY_TYPE, ebx);
2648 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2649 Split(equal, if_true, if_false, fall_through);
2650
2651 context()->Plug(if_true, if_false);
2652}
2653
2654
2655void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
2656 ZoneList<Expression*>* args = expr->arguments();
2657 DCHECK(args->length() == 1);
2658
2659 VisitForAccumulatorValue(args->at(0));
2660
2661 Label materialize_true, materialize_false;
2662 Label* if_true = NULL;
2663 Label* if_false = NULL;
2664 Label* fall_through = NULL;
2665 context()->PrepareTest(&materialize_true, &materialize_false,
2666 &if_true, &if_false, &fall_through);
2667
2668 __ JumpIfSmi(eax, if_false);
2669 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
2670 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2671 Split(equal, if_true, if_false, fall_through);
2672
2673 context()->Plug(if_true, if_false);
2674}
2675
2676
2677void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
2678 ZoneList<Expression*>* args = expr->arguments();
2679 DCHECK(args->length() == 1);
2680
2681 VisitForAccumulatorValue(args->at(0));
2682
2683 Label materialize_true, materialize_false;
2684 Label* if_true = NULL;
2685 Label* if_false = NULL;
2686 Label* fall_through = NULL;
2687 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
2688 &if_false, &fall_through);
2689
2690 __ JumpIfSmi(eax, if_false);
2691 __ CmpObjectType(eax, JS_PROXY_TYPE, ebx);
2692 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2693 Split(equal, if_true, if_false, fall_through);
2694
2695 context()->Plug(if_true, if_false);
2696}
2697
2698
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002699void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
2700 ZoneList<Expression*>* args = expr->arguments();
2701 DCHECK(args->length() == 1);
2702 Label done, null, function, non_function_constructor;
2703
2704 VisitForAccumulatorValue(args->at(0));
2705
2706 // If the object is not a JSReceiver, we return null.
2707 __ JumpIfSmi(eax, &null, Label::kNear);
2708 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2709 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, eax);
2710 __ j(below, &null, Label::kNear);
2711
Ben Murdochda12d292016-06-02 14:46:10 +01002712 // Return 'Function' for JSFunction and JSBoundFunction objects.
2713 __ CmpInstanceType(eax, FIRST_FUNCTION_TYPE);
2714 STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE);
2715 __ j(above_equal, &function, Label::kNear);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002716
2717 // Check if the constructor in the map is a JS function.
2718 __ GetMapConstructor(eax, eax, ebx);
2719 __ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
2720 __ j(not_equal, &non_function_constructor, Label::kNear);
2721
2722 // eax now contains the constructor function. Grab the
2723 // instance class name from there.
2724 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
2725 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
2726 __ jmp(&done, Label::kNear);
2727
2728 // Non-JS objects have class null.
2729 __ bind(&null);
2730 __ mov(eax, isolate()->factory()->null_value());
2731 __ jmp(&done, Label::kNear);
2732
2733 // Functions have class 'Function'.
2734 __ bind(&function);
2735 __ mov(eax, isolate()->factory()->Function_string());
2736 __ jmp(&done, Label::kNear);
2737
2738 // Objects with a non-function constructor have class 'Object'.
2739 __ bind(&non_function_constructor);
2740 __ mov(eax, isolate()->factory()->Object_string());
2741
2742 // All done.
2743 __ bind(&done);
2744
2745 context()->Plug(eax);
2746}
2747
2748
2749void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
2750 ZoneList<Expression*>* args = expr->arguments();
2751 DCHECK(args->length() == 1);
2752
2753 VisitForAccumulatorValue(args->at(0)); // Load the object.
2754
2755 Label done;
2756 // If the object is a smi return the object.
2757 __ JumpIfSmi(eax, &done, Label::kNear);
2758 // If the object is not a value type, return the object.
2759 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
2760 __ j(not_equal, &done, Label::kNear);
2761 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
2762
2763 __ bind(&done);
2764 context()->Plug(eax);
2765}
2766
2767
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002768void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
2769 ZoneList<Expression*>* args = expr->arguments();
2770 DCHECK(args->length() == 1);
2771
2772 VisitForAccumulatorValue(args->at(0));
2773
2774 Label done;
2775 StringCharFromCodeGenerator generator(eax, ebx);
2776 generator.GenerateFast(masm_);
2777 __ jmp(&done);
2778
2779 NopRuntimeCallHelper call_helper;
2780 generator.GenerateSlow(masm_, call_helper);
2781
2782 __ bind(&done);
2783 context()->Plug(ebx);
2784}
2785
2786
2787void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
2788 ZoneList<Expression*>* args = expr->arguments();
2789 DCHECK(args->length() == 2);
2790
2791 VisitForStackValue(args->at(0));
2792 VisitForAccumulatorValue(args->at(1));
2793
2794 Register object = ebx;
2795 Register index = eax;
2796 Register result = edx;
2797
Ben Murdoch097c5b22016-05-18 11:27:45 +01002798 PopOperand(object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002799
2800 Label need_conversion;
2801 Label index_out_of_range;
2802 Label done;
Ben Murdoch61f157c2016-09-16 13:49:30 +01002803 StringCharCodeAtGenerator generator(object, index, result, &need_conversion,
2804 &need_conversion, &index_out_of_range);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002805 generator.GenerateFast(masm_);
2806 __ jmp(&done);
2807
2808 __ bind(&index_out_of_range);
2809 // When the index is out of range, the spec requires us to return
2810 // NaN.
2811 __ Move(result, Immediate(isolate()->factory()->nan_value()));
2812 __ jmp(&done);
2813
2814 __ bind(&need_conversion);
2815 // Move the undefined value into the result register, which will
2816 // trigger conversion.
2817 __ Move(result, Immediate(isolate()->factory()->undefined_value()));
2818 __ jmp(&done);
2819
2820 NopRuntimeCallHelper call_helper;
2821 generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
2822
2823 __ bind(&done);
2824 context()->Plug(result);
2825}
2826
2827
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002828void FullCodeGenerator::EmitCall(CallRuntime* expr) {
2829 ZoneList<Expression*>* args = expr->arguments();
2830 DCHECK_LE(2, args->length());
2831 // Push target, receiver and arguments onto the stack.
2832 for (Expression* const arg : *args) {
2833 VisitForStackValue(arg);
2834 }
Ben Murdochc5610432016-08-08 18:44:38 +01002835 PrepareForBailoutForId(expr->CallId(), BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002836 // Move target to edi.
2837 int const argc = args->length() - 2;
2838 __ mov(edi, Operand(esp, (argc + 1) * kPointerSize));
2839 // Call the target.
2840 __ mov(eax, Immediate(argc));
2841 __ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002842 OperandStackDepthDecrement(argc + 1);
Ben Murdochc5610432016-08-08 18:44:38 +01002843 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002844 // Discard the function left on TOS.
2845 context()->DropAndPlug(1, eax);
2846}
2847
2848
2849void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
2850 ZoneList<Expression*>* args = expr->arguments();
2851 DCHECK(args->length() == 1);
2852
2853 VisitForAccumulatorValue(args->at(0));
2854
2855 __ AssertString(eax);
2856
2857 Label materialize_true, materialize_false;
2858 Label* if_true = NULL;
2859 Label* if_false = NULL;
2860 Label* fall_through = NULL;
2861 context()->PrepareTest(&materialize_true, &materialize_false,
2862 &if_true, &if_false, &fall_through);
2863
2864 __ test(FieldOperand(eax, String::kHashFieldOffset),
2865 Immediate(String::kContainsCachedArrayIndexMask));
2866 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2867 Split(zero, if_true, if_false, fall_through);
2868
2869 context()->Plug(if_true, if_false);
2870}
2871
2872
2873void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
2874 ZoneList<Expression*>* args = expr->arguments();
2875 DCHECK(args->length() == 1);
2876 VisitForAccumulatorValue(args->at(0));
2877
2878 __ AssertString(eax);
2879
2880 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
2881 __ IndexFromHash(eax, eax);
2882
2883 context()->Plug(eax);
2884}
2885
2886
2887void FullCodeGenerator::EmitGetSuperConstructor(CallRuntime* expr) {
2888 ZoneList<Expression*>* args = expr->arguments();
2889 DCHECK_EQ(1, args->length());
2890 VisitForAccumulatorValue(args->at(0));
2891 __ AssertFunction(eax);
2892 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
2893 __ mov(eax, FieldOperand(eax, Map::kPrototypeOffset));
2894 context()->Plug(eax);
2895}
2896
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002897void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
2898 DCHECK(expr->arguments()->length() == 0);
2899 ExternalReference debug_is_active =
2900 ExternalReference::debug_is_active_address(isolate());
2901 __ movzx_b(eax, Operand::StaticVariable(debug_is_active));
2902 __ SmiTag(eax);
2903 context()->Plug(eax);
2904}
2905
2906
2907void FullCodeGenerator::EmitCreateIterResultObject(CallRuntime* expr) {
2908 ZoneList<Expression*>* args = expr->arguments();
2909 DCHECK_EQ(2, args->length());
2910 VisitForStackValue(args->at(0));
2911 VisitForStackValue(args->at(1));
2912
2913 Label runtime, done;
2914
Ben Murdochc5610432016-08-08 18:44:38 +01002915 __ Allocate(JSIteratorResult::kSize, eax, ecx, edx, &runtime,
2916 NO_ALLOCATION_FLAGS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002917 __ mov(ebx, NativeContextOperand());
2918 __ mov(ebx, ContextOperand(ebx, Context::ITERATOR_RESULT_MAP_INDEX));
2919 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ebx);
2920 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
2921 isolate()->factory()->empty_fixed_array());
2922 __ mov(FieldOperand(eax, JSObject::kElementsOffset),
2923 isolate()->factory()->empty_fixed_array());
2924 __ pop(FieldOperand(eax, JSIteratorResult::kDoneOffset));
2925 __ pop(FieldOperand(eax, JSIteratorResult::kValueOffset));
2926 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
2927 __ jmp(&done, Label::kNear);
2928
2929 __ bind(&runtime);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002930 CallRuntimeWithOperands(Runtime::kCreateIterResultObject);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002931
2932 __ bind(&done);
2933 context()->Plug(eax);
2934}
2935
2936
2937void FullCodeGenerator::EmitLoadJSRuntimeFunction(CallRuntime* expr) {
Ben Murdochda12d292016-06-02 14:46:10 +01002938 // Push function.
2939 __ LoadGlobalFunction(expr->context_index(), eax);
2940 PushOperand(eax);
2941
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002942 // Push undefined as receiver.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002943 PushOperand(isolate()->factory()->undefined_value());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002944}
2945
2946
2947void FullCodeGenerator::EmitCallJSRuntimeFunction(CallRuntime* expr) {
2948 ZoneList<Expression*>* args = expr->arguments();
2949 int arg_count = args->length();
2950
2951 SetCallPosition(expr);
2952 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
2953 __ Set(eax, arg_count);
2954 __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kNullOrUndefined),
2955 RelocInfo::CODE_TARGET);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002956 OperandStackDepthDecrement(arg_count + 1);
Ben Murdochc5610432016-08-08 18:44:38 +01002957 RestoreContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002958}
2959
2960
2961void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
2962 switch (expr->op()) {
2963 case Token::DELETE: {
2964 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
2965 Property* property = expr->expression()->AsProperty();
2966 VariableProxy* proxy = expr->expression()->AsVariableProxy();
2967
2968 if (property != NULL) {
2969 VisitForStackValue(property->obj());
2970 VisitForStackValue(property->key());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002971 CallRuntimeWithOperands(is_strict(language_mode())
2972 ? Runtime::kDeleteProperty_Strict
2973 : Runtime::kDeleteProperty_Sloppy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002974 context()->Plug(eax);
2975 } else if (proxy != NULL) {
2976 Variable* var = proxy->var();
2977 // Delete of an unqualified identifier is disallowed in strict mode but
2978 // "delete this" is allowed.
2979 bool is_this = var->HasThisName(isolate());
2980 DCHECK(is_sloppy(language_mode()) || is_this);
2981 if (var->IsUnallocatedOrGlobalSlot()) {
2982 __ mov(eax, NativeContextOperand());
2983 __ push(ContextOperand(eax, Context::EXTENSION_INDEX));
2984 __ push(Immediate(var->name()));
2985 __ CallRuntime(Runtime::kDeleteProperty_Sloppy);
2986 context()->Plug(eax);
2987 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
2988 // Result of deleting non-global variables is false. 'this' is
2989 // not really a variable, though we implement it as one. The
2990 // subexpression does not have side effects.
2991 context()->Plug(is_this);
2992 } else {
2993 // Non-global variable. Call the runtime to try to delete from the
2994 // context where the variable was introduced.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002995 __ Push(var->name());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002996 __ CallRuntime(Runtime::kDeleteLookupSlot);
2997 context()->Plug(eax);
2998 }
2999 } else {
3000 // Result of deleting non-property, non-variable reference is true.
3001 // The subexpression may have side effects.
3002 VisitForEffect(expr->expression());
3003 context()->Plug(true);
3004 }
3005 break;
3006 }
3007
3008 case Token::VOID: {
3009 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3010 VisitForEffect(expr->expression());
3011 context()->Plug(isolate()->factory()->undefined_value());
3012 break;
3013 }
3014
3015 case Token::NOT: {
3016 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
3017 if (context()->IsEffect()) {
3018 // Unary NOT has no side effects so it's only necessary to visit the
3019 // subexpression. Match the optimizing compiler by not branching.
3020 VisitForEffect(expr->expression());
3021 } else if (context()->IsTest()) {
3022 const TestContext* test = TestContext::cast(context());
3023 // The labels are swapped for the recursive call.
3024 VisitForControl(expr->expression(),
3025 test->false_label(),
3026 test->true_label(),
3027 test->fall_through());
3028 context()->Plug(test->true_label(), test->false_label());
3029 } else {
3030 // We handle value contexts explicitly rather than simply visiting
3031 // for control and plugging the control flow into the context,
3032 // because we need to prepare a pair of extra administrative AST ids
3033 // for the optimizing compiler.
3034 DCHECK(context()->IsAccumulatorValue() || context()->IsStackValue());
3035 Label materialize_true, materialize_false, done;
3036 VisitForControl(expr->expression(),
3037 &materialize_false,
3038 &materialize_true,
3039 &materialize_true);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003040 if (!context()->IsAccumulatorValue()) OperandStackDepthIncrement(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003041 __ bind(&materialize_true);
Ben Murdochc5610432016-08-08 18:44:38 +01003042 PrepareForBailoutForId(expr->MaterializeTrueId(),
3043 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003044 if (context()->IsAccumulatorValue()) {
3045 __ mov(eax, isolate()->factory()->true_value());
3046 } else {
3047 __ Push(isolate()->factory()->true_value());
3048 }
3049 __ jmp(&done, Label::kNear);
3050 __ bind(&materialize_false);
Ben Murdochc5610432016-08-08 18:44:38 +01003051 PrepareForBailoutForId(expr->MaterializeFalseId(),
3052 BailoutState::NO_REGISTERS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003053 if (context()->IsAccumulatorValue()) {
3054 __ mov(eax, isolate()->factory()->false_value());
3055 } else {
3056 __ Push(isolate()->factory()->false_value());
3057 }
3058 __ bind(&done);
3059 }
3060 break;
3061 }
3062
3063 case Token::TYPEOF: {
3064 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
3065 {
3066 AccumulatorValueContext context(this);
3067 VisitForTypeofValue(expr->expression());
3068 }
3069 __ mov(ebx, eax);
3070 TypeofStub typeof_stub(isolate());
3071 __ CallStub(&typeof_stub);
3072 context()->Plug(eax);
3073 break;
3074 }
3075
3076 default:
3077 UNREACHABLE();
3078 }
3079}
3080
3081
3082void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
3083 DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
3084
3085 Comment cmnt(masm_, "[ CountOperation");
3086
3087 Property* prop = expr->expression()->AsProperty();
3088 LhsKind assign_type = Property::GetAssignType(prop);
3089
3090 // Evaluate expression and get value.
3091 if (assign_type == VARIABLE) {
3092 DCHECK(expr->expression()->AsVariableProxy()->var() != NULL);
3093 AccumulatorValueContext context(this);
3094 EmitVariableLoad(expr->expression()->AsVariableProxy());
3095 } else {
3096 // Reserve space for result of postfix operation.
3097 if (expr->is_postfix() && !context()->IsEffect()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003098 PushOperand(Smi::FromInt(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003099 }
3100 switch (assign_type) {
3101 case NAMED_PROPERTY: {
3102 // Put the object both on the stack and in the register.
3103 VisitForStackValue(prop->obj());
3104 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
3105 EmitNamedPropertyLoad(prop);
3106 break;
3107 }
3108
3109 case NAMED_SUPER_PROPERTY: {
3110 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
3111 VisitForAccumulatorValue(
3112 prop->obj()->AsSuperPropertyReference()->home_object());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003113 PushOperand(result_register());
3114 PushOperand(MemOperand(esp, kPointerSize));
3115 PushOperand(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003116 EmitNamedSuperPropertyLoad(prop);
3117 break;
3118 }
3119
3120 case KEYED_SUPER_PROPERTY: {
3121 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
3122 VisitForStackValue(
3123 prop->obj()->AsSuperPropertyReference()->home_object());
3124 VisitForAccumulatorValue(prop->key());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003125 PushOperand(result_register());
3126 PushOperand(MemOperand(esp, 2 * kPointerSize));
3127 PushOperand(MemOperand(esp, 2 * kPointerSize));
3128 PushOperand(result_register());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003129 EmitKeyedSuperPropertyLoad(prop);
3130 break;
3131 }
3132
3133 case KEYED_PROPERTY: {
3134 VisitForStackValue(prop->obj());
3135 VisitForStackValue(prop->key());
3136 __ mov(LoadDescriptor::ReceiverRegister(),
3137 Operand(esp, kPointerSize)); // Object.
3138 __ mov(LoadDescriptor::NameRegister(), Operand(esp, 0)); // Key.
3139 EmitKeyedPropertyLoad(prop);
3140 break;
3141 }
3142
3143 case VARIABLE:
3144 UNREACHABLE();
3145 }
3146 }
3147
3148 // We need a second deoptimization point after loading the value
3149 // in case evaluating the property load my have a side effect.
3150 if (assign_type == VARIABLE) {
Ben Murdochc5610432016-08-08 18:44:38 +01003151 PrepareForBailout(expr->expression(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003152 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01003153 PrepareForBailoutForId(prop->LoadId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003154 }
3155
3156 // Inline smi case if we are in a loop.
3157 Label done, stub_call;
3158 JumpPatchSite patch_site(masm_);
3159 if (ShouldInlineSmiCase(expr->op())) {
3160 Label slow;
3161 patch_site.EmitJumpIfNotSmi(eax, &slow, Label::kNear);
3162
3163 // Save result for postfix expressions.
3164 if (expr->is_postfix()) {
3165 if (!context()->IsEffect()) {
3166 // Save the result on the stack. If we have a named or keyed property
3167 // we store the result under the receiver that is currently on top
3168 // of the stack.
3169 switch (assign_type) {
3170 case VARIABLE:
3171 __ push(eax);
3172 break;
3173 case NAMED_PROPERTY:
3174 __ mov(Operand(esp, kPointerSize), eax);
3175 break;
3176 case NAMED_SUPER_PROPERTY:
3177 __ mov(Operand(esp, 2 * kPointerSize), eax);
3178 break;
3179 case KEYED_PROPERTY:
3180 __ mov(Operand(esp, 2 * kPointerSize), eax);
3181 break;
3182 case KEYED_SUPER_PROPERTY:
3183 __ mov(Operand(esp, 3 * kPointerSize), eax);
3184 break;
3185 }
3186 }
3187 }
3188
3189 if (expr->op() == Token::INC) {
3190 __ add(eax, Immediate(Smi::FromInt(1)));
3191 } else {
3192 __ sub(eax, Immediate(Smi::FromInt(1)));
3193 }
3194 __ j(no_overflow, &done, Label::kNear);
3195 // Call stub. Undo operation first.
3196 if (expr->op() == Token::INC) {
3197 __ sub(eax, Immediate(Smi::FromInt(1)));
3198 } else {
3199 __ add(eax, Immediate(Smi::FromInt(1)));
3200 }
3201 __ jmp(&stub_call, Label::kNear);
3202 __ bind(&slow);
3203 }
Ben Murdochda12d292016-06-02 14:46:10 +01003204
3205 // Convert old value into a number.
Ben Murdoch61f157c2016-09-16 13:49:30 +01003206 __ Call(isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
Ben Murdochc5610432016-08-08 18:44:38 +01003207 PrepareForBailoutForId(expr->ToNumberId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003208
3209 // Save result for postfix expressions.
3210 if (expr->is_postfix()) {
3211 if (!context()->IsEffect()) {
3212 // Save the result on the stack. If we have a named or keyed property
3213 // we store the result under the receiver that is currently on top
3214 // of the stack.
3215 switch (assign_type) {
3216 case VARIABLE:
Ben Murdoch097c5b22016-05-18 11:27:45 +01003217 PushOperand(eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003218 break;
3219 case NAMED_PROPERTY:
3220 __ mov(Operand(esp, kPointerSize), eax);
3221 break;
3222 case NAMED_SUPER_PROPERTY:
3223 __ mov(Operand(esp, 2 * kPointerSize), eax);
3224 break;
3225 case KEYED_PROPERTY:
3226 __ mov(Operand(esp, 2 * kPointerSize), eax);
3227 break;
3228 case KEYED_SUPER_PROPERTY:
3229 __ mov(Operand(esp, 3 * kPointerSize), eax);
3230 break;
3231 }
3232 }
3233 }
3234
3235 SetExpressionPosition(expr);
3236
3237 // Call stub for +1/-1.
3238 __ bind(&stub_call);
3239 __ mov(edx, eax);
3240 __ mov(eax, Immediate(Smi::FromInt(1)));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003241 Handle<Code> code =
3242 CodeFactory::BinaryOpIC(isolate(), expr->binary_op()).code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003243 CallIC(code, expr->CountBinOpFeedbackId());
3244 patch_site.EmitPatchInfo();
3245 __ bind(&done);
3246
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003247 // Store the value returned in eax.
3248 switch (assign_type) {
3249 case VARIABLE:
3250 if (expr->is_postfix()) {
3251 // Perform the assignment as if via '='.
3252 { EffectContext context(this);
3253 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3254 Token::ASSIGN, expr->CountSlot());
Ben Murdochc5610432016-08-08 18:44:38 +01003255 PrepareForBailoutForId(expr->AssignmentId(),
3256 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003257 context.Plug(eax);
3258 }
3259 // For all contexts except EffectContext We have the result on
3260 // top of the stack.
3261 if (!context()->IsEffect()) {
3262 context()->PlugTOS();
3263 }
3264 } else {
3265 // Perform the assignment as if via '='.
3266 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3267 Token::ASSIGN, expr->CountSlot());
Ben Murdochc5610432016-08-08 18:44:38 +01003268 PrepareForBailoutForId(expr->AssignmentId(),
3269 BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003270 context()->Plug(eax);
3271 }
3272 break;
3273 case NAMED_PROPERTY: {
3274 __ mov(StoreDescriptor::NameRegister(),
3275 prop->key()->AsLiteral()->value());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003276 PopOperand(StoreDescriptor::ReceiverRegister());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003277 EmitLoadStoreICSlot(expr->CountSlot());
3278 CallStoreIC();
Ben Murdochc5610432016-08-08 18:44:38 +01003279 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003280 if (expr->is_postfix()) {
3281 if (!context()->IsEffect()) {
3282 context()->PlugTOS();
3283 }
3284 } else {
3285 context()->Plug(eax);
3286 }
3287 break;
3288 }
3289 case NAMED_SUPER_PROPERTY: {
3290 EmitNamedSuperPropertyStore(prop);
3291 if (expr->is_postfix()) {
3292 if (!context()->IsEffect()) {
3293 context()->PlugTOS();
3294 }
3295 } else {
3296 context()->Plug(eax);
3297 }
3298 break;
3299 }
3300 case KEYED_SUPER_PROPERTY: {
3301 EmitKeyedSuperPropertyStore(prop);
3302 if (expr->is_postfix()) {
3303 if (!context()->IsEffect()) {
3304 context()->PlugTOS();
3305 }
3306 } else {
3307 context()->Plug(eax);
3308 }
3309 break;
3310 }
3311 case KEYED_PROPERTY: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003312 PopOperand(StoreDescriptor::NameRegister());
3313 PopOperand(StoreDescriptor::ReceiverRegister());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003314 Handle<Code> ic =
3315 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
3316 EmitLoadStoreICSlot(expr->CountSlot());
3317 CallIC(ic);
Ben Murdochc5610432016-08-08 18:44:38 +01003318 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003319 if (expr->is_postfix()) {
3320 // Result is on the stack
3321 if (!context()->IsEffect()) {
3322 context()->PlugTOS();
3323 }
3324 } else {
3325 context()->Plug(eax);
3326 }
3327 break;
3328 }
3329 }
3330}
3331
3332
3333void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
3334 Expression* sub_expr,
3335 Handle<String> check) {
3336 Label materialize_true, materialize_false;
3337 Label* if_true = NULL;
3338 Label* if_false = NULL;
3339 Label* fall_through = NULL;
3340 context()->PrepareTest(&materialize_true, &materialize_false,
3341 &if_true, &if_false, &fall_through);
3342
3343 { AccumulatorValueContext context(this);
3344 VisitForTypeofValue(sub_expr);
3345 }
3346 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3347
3348 Factory* factory = isolate()->factory();
3349 if (String::Equals(check, factory->number_string())) {
3350 __ JumpIfSmi(eax, if_true);
3351 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
3352 isolate()->factory()->heap_number_map());
3353 Split(equal, if_true, if_false, fall_through);
3354 } else if (String::Equals(check, factory->string_string())) {
3355 __ JumpIfSmi(eax, if_false);
3356 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
3357 Split(below, if_true, if_false, fall_through);
3358 } else if (String::Equals(check, factory->symbol_string())) {
3359 __ JumpIfSmi(eax, if_false);
3360 __ CmpObjectType(eax, SYMBOL_TYPE, edx);
3361 Split(equal, if_true, if_false, fall_through);
3362 } else if (String::Equals(check, factory->boolean_string())) {
3363 __ cmp(eax, isolate()->factory()->true_value());
3364 __ j(equal, if_true);
3365 __ cmp(eax, isolate()->factory()->false_value());
3366 Split(equal, if_true, if_false, fall_through);
3367 } else if (String::Equals(check, factory->undefined_string())) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003368 __ cmp(eax, isolate()->factory()->null_value());
3369 __ j(equal, if_false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003370 __ JumpIfSmi(eax, if_false);
3371 // Check for undetectable objects => true.
3372 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
3373 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
Ben Murdochda12d292016-06-02 14:46:10 +01003374 Immediate(1 << Map::kIsUndetectable));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003375 Split(not_zero, if_true, if_false, fall_through);
3376 } else if (String::Equals(check, factory->function_string())) {
3377 __ JumpIfSmi(eax, if_false);
3378 // Check for callable and not undetectable objects => true.
3379 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
3380 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
3381 __ and_(ecx, (1 << Map::kIsCallable) | (1 << Map::kIsUndetectable));
3382 __ cmp(ecx, 1 << Map::kIsCallable);
3383 Split(equal, if_true, if_false, fall_through);
3384 } else if (String::Equals(check, factory->object_string())) {
3385 __ JumpIfSmi(eax, if_false);
3386 __ cmp(eax, isolate()->factory()->null_value());
3387 __ j(equal, if_true);
3388 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
3389 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, edx);
3390 __ j(below, if_false);
3391 // Check for callable or undetectable objects => false.
3392 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
Ben Murdochda12d292016-06-02 14:46:10 +01003393 Immediate((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003394 Split(zero, if_true, if_false, fall_through);
3395// clang-format off
3396#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
3397 } else if (String::Equals(check, factory->type##_string())) { \
3398 __ JumpIfSmi(eax, if_false); \
3399 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), \
3400 isolate()->factory()->type##_map()); \
3401 Split(equal, if_true, if_false, fall_through);
3402 SIMD128_TYPES(SIMD128_TYPE)
3403#undef SIMD128_TYPE
3404 // clang-format on
3405 } else {
3406 if (if_false != fall_through) __ jmp(if_false);
3407 }
3408 context()->Plug(if_true, if_false);
3409}
3410
3411
3412void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
3413 Comment cmnt(masm_, "[ CompareOperation");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003414
3415 // First we try a fast inlined version of the compare when one of
3416 // the operands is a literal.
3417 if (TryLiteralCompare(expr)) return;
3418
3419 // Always perform the comparison for its control flow. Pack the result
3420 // into the expression's context after the comparison is performed.
3421 Label materialize_true, materialize_false;
3422 Label* if_true = NULL;
3423 Label* if_false = NULL;
3424 Label* fall_through = NULL;
3425 context()->PrepareTest(&materialize_true, &materialize_false,
3426 &if_true, &if_false, &fall_through);
3427
3428 Token::Value op = expr->op();
3429 VisitForStackValue(expr->left());
3430 switch (op) {
3431 case Token::IN:
3432 VisitForStackValue(expr->right());
Ben Murdochc5610432016-08-08 18:44:38 +01003433 SetExpressionPosition(expr);
3434 EmitHasProperty();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003435 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
3436 __ cmp(eax, isolate()->factory()->true_value());
3437 Split(equal, if_true, if_false, fall_through);
3438 break;
3439
3440 case Token::INSTANCEOF: {
3441 VisitForAccumulatorValue(expr->right());
Ben Murdochc5610432016-08-08 18:44:38 +01003442 SetExpressionPosition(expr);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003443 PopOperand(edx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003444 InstanceOfStub stub(isolate());
3445 __ CallStub(&stub);
3446 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
3447 __ cmp(eax, isolate()->factory()->true_value());
3448 Split(equal, if_true, if_false, fall_through);
3449 break;
3450 }
3451
3452 default: {
3453 VisitForAccumulatorValue(expr->right());
Ben Murdochc5610432016-08-08 18:44:38 +01003454 SetExpressionPosition(expr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003455 Condition cc = CompareIC::ComputeCondition(op);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003456 PopOperand(edx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003457
3458 bool inline_smi_code = ShouldInlineSmiCase(op);
3459 JumpPatchSite patch_site(masm_);
3460 if (inline_smi_code) {
3461 Label slow_case;
3462 __ mov(ecx, edx);
3463 __ or_(ecx, eax);
3464 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
3465 __ cmp(edx, eax);
3466 Split(cc, if_true, if_false, NULL);
3467 __ bind(&slow_case);
3468 }
3469
Ben Murdoch097c5b22016-05-18 11:27:45 +01003470 Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003471 CallIC(ic, expr->CompareOperationFeedbackId());
3472 patch_site.EmitPatchInfo();
3473
3474 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3475 __ test(eax, eax);
3476 Split(cc, if_true, if_false, fall_through);
3477 }
3478 }
3479
3480 // Convert the result of the comparison into one expected for this
3481 // expression's context.
3482 context()->Plug(if_true, if_false);
3483}
3484
3485
3486void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
3487 Expression* sub_expr,
3488 NilValue nil) {
3489 Label materialize_true, materialize_false;
3490 Label* if_true = NULL;
3491 Label* if_false = NULL;
3492 Label* fall_through = NULL;
3493 context()->PrepareTest(&materialize_true, &materialize_false,
3494 &if_true, &if_false, &fall_through);
3495
3496 VisitForAccumulatorValue(sub_expr);
3497 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3498
3499 Handle<Object> nil_value = nil == kNullValue
3500 ? isolate()->factory()->null_value()
3501 : isolate()->factory()->undefined_value();
3502 if (expr->op() == Token::EQ_STRICT) {
3503 __ cmp(eax, nil_value);
3504 Split(equal, if_true, if_false, fall_through);
3505 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01003506 __ JumpIfSmi(eax, if_false);
3507 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
3508 __ test_b(FieldOperand(eax, Map::kBitFieldOffset),
3509 Immediate(1 << Map::kIsUndetectable));
3510 Split(not_zero, if_true, if_false, fall_through);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003511 }
3512 context()->Plug(if_true, if_false);
3513}
3514
3515
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003516Register FullCodeGenerator::result_register() {
3517 return eax;
3518}
3519
3520
3521Register FullCodeGenerator::context_register() {
3522 return esi;
3523}
3524
Ben Murdochda12d292016-06-02 14:46:10 +01003525void FullCodeGenerator::LoadFromFrameField(int frame_offset, Register value) {
3526 DCHECK_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
3527 __ mov(value, Operand(ebp, frame_offset));
3528}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003529
3530void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
3531 DCHECK_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
3532 __ mov(Operand(ebp, frame_offset), value);
3533}
3534
3535
3536void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
3537 __ mov(dst, ContextOperand(esi, context_index));
3538}
3539
3540
3541void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
3542 Scope* closure_scope = scope()->ClosureScope();
3543 if (closure_scope->is_script_scope() ||
3544 closure_scope->is_module_scope()) {
3545 // Contexts nested in the native context have a canonical empty function
3546 // as their closure, not the anonymous closure containing the global
3547 // code.
3548 __ mov(eax, NativeContextOperand());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003549 PushOperand(ContextOperand(eax, Context::CLOSURE_INDEX));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003550 } else if (closure_scope->is_eval_scope()) {
3551 // Contexts nested inside eval code have the same closure as the context
3552 // calling eval, not the anonymous closure containing the eval code.
3553 // Fetch it from the context.
Ben Murdoch097c5b22016-05-18 11:27:45 +01003554 PushOperand(ContextOperand(esi, Context::CLOSURE_INDEX));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003555 } else {
3556 DCHECK(closure_scope->is_function_scope());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003557 PushOperand(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003558 }
3559}
3560
3561
3562// ----------------------------------------------------------------------------
3563// Non-local control flow support.
3564
3565void FullCodeGenerator::EnterFinallyBlock() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003566 // Store pending message while executing finally block.
3567 ExternalReference pending_message_obj =
3568 ExternalReference::address_of_pending_message_obj(isolate());
3569 __ mov(edx, Operand::StaticVariable(pending_message_obj));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003570 PushOperand(edx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003571
3572 ClearPendingMessage();
3573}
3574
3575
3576void FullCodeGenerator::ExitFinallyBlock() {
3577 DCHECK(!result_register().is(edx));
3578 // Restore pending message from stack.
Ben Murdoch097c5b22016-05-18 11:27:45 +01003579 PopOperand(edx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003580 ExternalReference pending_message_obj =
3581 ExternalReference::address_of_pending_message_obj(isolate());
3582 __ mov(Operand::StaticVariable(pending_message_obj), edx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003583}
3584
3585
3586void FullCodeGenerator::ClearPendingMessage() {
3587 DCHECK(!result_register().is(edx));
3588 ExternalReference pending_message_obj =
3589 ExternalReference::address_of_pending_message_obj(isolate());
3590 __ mov(edx, Immediate(isolate()->factory()->the_hole_value()));
3591 __ mov(Operand::StaticVariable(pending_message_obj), edx);
3592}
3593
3594
Ben Murdoch097c5b22016-05-18 11:27:45 +01003595void FullCodeGenerator::DeferredCommands::EmitCommands() {
3596 DCHECK(!result_register().is(edx));
3597 __ Pop(result_register()); // Restore the accumulator.
3598 __ Pop(edx); // Get the token.
3599 for (DeferredCommand cmd : commands_) {
3600 Label skip;
3601 __ cmp(edx, Immediate(Smi::FromInt(cmd.token)));
3602 __ j(not_equal, &skip);
3603 switch (cmd.command) {
3604 case kReturn:
3605 codegen_->EmitUnwindAndReturn();
3606 break;
3607 case kThrow:
3608 __ Push(result_register());
3609 __ CallRuntime(Runtime::kReThrow);
3610 break;
3611 case kContinue:
3612 codegen_->EmitContinue(cmd.target);
3613 break;
3614 case kBreak:
3615 codegen_->EmitBreak(cmd.target);
3616 break;
3617 }
3618 __ bind(&skip);
3619 }
3620}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003621
3622#undef __
3623
3624
3625static const byte kJnsInstruction = 0x79;
3626static const byte kJnsOffset = 0x11;
3627static const byte kNopByteOne = 0x66;
3628static const byte kNopByteTwo = 0x90;
3629#ifdef DEBUG
3630static const byte kCallInstruction = 0xe8;
3631#endif
3632
3633
3634void BackEdgeTable::PatchAt(Code* unoptimized_code,
3635 Address pc,
3636 BackEdgeState target_state,
3637 Code* replacement_code) {
3638 Address call_target_address = pc - kIntSize;
3639 Address jns_instr_address = call_target_address - 3;
3640 Address jns_offset_address = call_target_address - 2;
3641
3642 switch (target_state) {
3643 case INTERRUPT:
3644 // sub <profiling_counter>, <delta> ;; Not changed
3645 // jns ok
3646 // call <interrupt stub>
3647 // ok:
3648 *jns_instr_address = kJnsInstruction;
3649 *jns_offset_address = kJnsOffset;
3650 break;
3651 case ON_STACK_REPLACEMENT:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003652 // sub <profiling_counter>, <delta> ;; Not changed
3653 // nop
3654 // nop
3655 // call <on-stack replacment>
3656 // ok:
3657 *jns_instr_address = kNopByteOne;
3658 *jns_offset_address = kNopByteTwo;
3659 break;
3660 }
3661
3662 Assembler::set_target_address_at(unoptimized_code->GetIsolate(),
3663 call_target_address, unoptimized_code,
3664 replacement_code->entry());
3665 unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
3666 unoptimized_code, call_target_address, replacement_code);
3667}
3668
3669
3670BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
3671 Isolate* isolate,
3672 Code* unoptimized_code,
3673 Address pc) {
3674 Address call_target_address = pc - kIntSize;
3675 Address jns_instr_address = call_target_address - 3;
3676 DCHECK_EQ(kCallInstruction, *(call_target_address - 1));
3677
3678 if (*jns_instr_address == kJnsInstruction) {
3679 DCHECK_EQ(kJnsOffset, *(call_target_address - 2));
3680 DCHECK_EQ(isolate->builtins()->InterruptCheck()->entry(),
3681 Assembler::target_address_at(call_target_address,
3682 unoptimized_code));
3683 return INTERRUPT;
3684 }
3685
3686 DCHECK_EQ(kNopByteOne, *jns_instr_address);
3687 DCHECK_EQ(kNopByteTwo, *(call_target_address - 2));
3688
Ben Murdochda12d292016-06-02 14:46:10 +01003689 DCHECK_EQ(
3690 isolate->builtins()->OnStackReplacement()->entry(),
3691 Assembler::target_address_at(call_target_address, unoptimized_code));
3692 return ON_STACK_REPLACEMENT;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003693}
3694
3695
3696} // namespace internal
3697} // namespace v8
3698
3699#endif // V8_TARGET_ARCH_X87