blob: 1ba409571534ee945cf8a3d16e972c61c5bcb1c4 [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Steve Block3ce2e202009-11-05 08:53:23 +00004
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#include "src/v8.h"
Steve Block3ce2e202009-11-05 08:53:23 +00006
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#if V8_TARGET_ARCH_IA32
Leon Clarkef7060e22010-06-03 12:02:55 +01008
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009#include "src/code-factory.h"
10#include "src/code-stubs.h"
11#include "src/codegen.h"
12#include "src/compiler.h"
13#include "src/debug.h"
14#include "src/full-codegen.h"
15#include "src/ic/ic.h"
16#include "src/isolate-inl.h"
17#include "src/parser.h"
18#include "src/scopes.h"
Steve Block3ce2e202009-11-05 08:53:23 +000019
20namespace v8 {
21namespace internal {
22
23#define __ ACCESS_MASM(masm_)
24
Ben Murdochb0fe1622011-05-05 13:52:32 +010025
26class JumpPatchSite BASE_EMBEDDED {
27 public:
Steve Block1e0659c2011-05-24 12:43:12 +010028 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010029#ifdef DEBUG
30 info_emitted_ = false;
31#endif
32 }
33
34 ~JumpPatchSite() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035 DCHECK(patch_site_.is_bound() == info_emitted_);
Ben Murdochb0fe1622011-05-05 13:52:32 +010036 }
37
Ben Murdoch257744e2011-11-30 15:57:28 +000038 void EmitJumpIfNotSmi(Register reg,
39 Label* target,
40 Label::Distance distance = Label::kFar) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010041 __ test(reg, Immediate(kSmiTagMask));
Ben Murdoch257744e2011-11-30 15:57:28 +000042 EmitJump(not_carry, target, distance); // Always taken before patched.
Ben Murdochb0fe1622011-05-05 13:52:32 +010043 }
44
Ben Murdoch257744e2011-11-30 15:57:28 +000045 void EmitJumpIfSmi(Register reg,
46 Label* target,
47 Label::Distance distance = Label::kFar) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010048 __ test(reg, Immediate(kSmiTagMask));
Ben Murdoch257744e2011-11-30 15:57:28 +000049 EmitJump(carry, target, distance); // Never taken before patched.
Ben Murdochb0fe1622011-05-05 13:52:32 +010050 }
51
52 void EmitPatchInfo() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000053 if (patch_site_.is_bound()) {
54 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000055 DCHECK(is_uint8(delta_to_patch_site));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000056 __ test(eax, Immediate(delta_to_patch_site));
Ben Murdochb0fe1622011-05-05 13:52:32 +010057#ifdef DEBUG
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000058 info_emitted_ = true;
Ben Murdochb0fe1622011-05-05 13:52:32 +010059#endif
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000060 } else {
61 __ nop(); // Signals no inlined code.
62 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010063 }
64
Ben Murdochb0fe1622011-05-05 13:52:32 +010065 private:
66 // jc will be patched with jz, jnc will become jnz.
Ben Murdoch257744e2011-11-30 15:57:28 +000067 void EmitJump(Condition cc, Label* target, Label::Distance distance) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000068 DCHECK(!patch_site_.is_bound() && !info_emitted_);
69 DCHECK(cc == carry || cc == not_carry);
Ben Murdochb0fe1622011-05-05 13:52:32 +010070 __ bind(&patch_site_);
Ben Murdoch257744e2011-11-30 15:57:28 +000071 __ j(cc, target, distance);
Ben Murdochb0fe1622011-05-05 13:52:32 +010072 }
73
74 MacroAssembler* masm_;
75 Label patch_site_;
76#ifdef DEBUG
77 bool info_emitted_;
78#endif
79};
80
81
Steve Block3ce2e202009-11-05 08:53:23 +000082// Generate code for a JS function. On entry to the function the receiver
83// and arguments have been pushed on the stack left to right, with the
84// return address on top of them. The actual argument count matches the
85// formal parameter count expected by the function.
86//
87// The live registers are:
Ben Murdoch3ef787d2012-04-12 10:51:47 +010088// o edi: the JS function object being called (i.e. ourselves)
Steve Block3ce2e202009-11-05 08:53:23 +000089// o esi: our context
90// o ebp: our caller's frame pointer
91// o esp: stack pointer (pointing to return address)
92//
93// The function builds a JS frame. Please see JavaScriptFrameConstants in
94// frames-ia32.h for its layout.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010095void FullCodeGenerator::Generate() {
96 CompilationInfo* info = info_;
97 handler_table_ =
98 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000099
100 profiling_counter_ = isolate()->factory()->NewCell(
101 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
Andrei Popescu31002712010-02-23 13:46:05 +0000102 SetFunctionPosition(function());
Steve Block6ded16b2010-05-10 14:33:55 +0100103 Comment cmnt(masm_, "[ function compiled by full code generator");
Steve Block3ce2e202009-11-05 08:53:23 +0000104
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000105 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
106
Ben Murdochf87a2032010-10-22 12:50:53 +0100107#ifdef DEBUG
108 if (strlen(FLAG_stop_at) > 0 &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000109 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100110 __ int3();
111 }
112#endif
113
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000114 // Sloppy mode functions and builtins need to replace the receiver with the
115 // global proxy when called as functions (without an explicit receiver
116 // object).
117 if (info->strict_mode() == SLOPPY && !info->is_native()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000118 Label ok;
Ben Murdoch257744e2011-11-30 15:57:28 +0000119 // +1 for return address.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000120 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100121 __ mov(ecx, Operand(esp, receiver_offset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000122
123 __ cmp(ecx, isolate()->factory()->undefined_value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100124 __ j(not_equal, &ok, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000125
126 __ mov(ecx, GlobalObjectOperand());
127 __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalProxyOffset));
128
129 __ mov(Operand(esp, receiver_offset), ecx);
130
Ben Murdoch257744e2011-11-30 15:57:28 +0000131 __ bind(&ok);
132 }
133
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100134 // Open a frame scope to indicate that there is a frame on the stack. The
135 // MANUAL indicates that the scope shouldn't actually generate code to set up
136 // the frame (that is done below).
137 FrameScope frame_scope(masm_, StackFrame::MANUAL);
138
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000139 info->set_prologue_offset(masm_->pc_offset());
140 __ Prologue(info->IsCodePreAgingActive());
141 info->AddNoFrameRange(0, masm_->pc_offset());
Steve Block3ce2e202009-11-05 08:53:23 +0000142
Iain Merrick75681382010-08-19 15:07:18 +0100143 { Comment cmnt(masm_, "[ Allocate locals");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000144 int locals_count = info->scope()->num_stack_slots();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000145 // Generators allocate locals, if any, in context slots.
146 DCHECK(!info->function()->is_generator() || locals_count == 0);
Iain Merrick75681382010-08-19 15:07:18 +0100147 if (locals_count == 1) {
Steve Block44f0eee2011-05-26 01:26:41 +0100148 __ push(Immediate(isolate()->factory()->undefined_value()));
Iain Merrick75681382010-08-19 15:07:18 +0100149 } else if (locals_count > 1) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000150 if (locals_count >= 128) {
151 Label ok;
152 __ mov(ecx, esp);
153 __ sub(ecx, Immediate(locals_count * kPointerSize));
154 ExternalReference stack_limit =
155 ExternalReference::address_of_real_stack_limit(isolate());
156 __ cmp(ecx, Operand::StaticVariable(stack_limit));
157 __ j(above_equal, &ok, Label::kNear);
158 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
159 __ bind(&ok);
160 }
Steve Block44f0eee2011-05-26 01:26:41 +0100161 __ mov(eax, Immediate(isolate()->factory()->undefined_value()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000162 const int kMaxPushes = 32;
163 if (locals_count >= kMaxPushes) {
164 int loop_iterations = locals_count / kMaxPushes;
165 __ mov(ecx, loop_iterations);
166 Label loop_header;
167 __ bind(&loop_header);
168 // Do pushes.
169 for (int i = 0; i < kMaxPushes; i++) {
170 __ push(eax);
171 }
172 __ dec(ecx);
173 __ j(not_zero, &loop_header, Label::kNear);
174 }
175 int remaining = locals_count % kMaxPushes;
176 // Emit the remaining pushes.
177 for (int i = 0; i < remaining; i++) {
Iain Merrick75681382010-08-19 15:07:18 +0100178 __ push(eax);
Steve Blockd0582a62009-12-15 09:54:21 +0000179 }
Steve Block3ce2e202009-11-05 08:53:23 +0000180 }
Iain Merrick75681382010-08-19 15:07:18 +0100181 }
Steve Block3ce2e202009-11-05 08:53:23 +0000182
Iain Merrick75681382010-08-19 15:07:18 +0100183 bool function_in_register = true;
Steve Blockd0582a62009-12-15 09:54:21 +0000184
Iain Merrick75681382010-08-19 15:07:18 +0100185 // Possibly allocate a local context.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000186 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
Iain Merrick75681382010-08-19 15:07:18 +0100187 if (heap_slots > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000188 Comment cmnt(masm_, "[ Allocate context");
189 bool need_write_barrier = true;
Iain Merrick75681382010-08-19 15:07:18 +0100190 // Argument to NewContext is the function, which is still in edi.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400191 if (FLAG_harmony_scoping && info->scope()->is_script_scope()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000192 __ push(edi);
193 __ Push(info->scope()->GetScopeInfo());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400194 __ CallRuntime(Runtime::kNewScriptContext, 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000195 } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
196 FastNewContextStub stub(isolate(), heap_slots);
Leon Clarke4515c472010-02-03 11:58:03 +0000197 __ CallStub(&stub);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000198 // Result of FastNewContextStub is always in new space.
199 need_write_barrier = false;
Iain Merrick75681382010-08-19 15:07:18 +0100200 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000201 __ push(edi);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000202 __ CallRuntime(Runtime::kNewFunctionContext, 1);
Leon Clarke4515c472010-02-03 11:58:03 +0000203 }
Iain Merrick75681382010-08-19 15:07:18 +0100204 function_in_register = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000205 // Context is returned in eax. It replaces the context passed to us.
206 // It's saved in the stack and kept live in esi.
207 __ mov(esi, eax);
208 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), eax);
Iain Merrick75681382010-08-19 15:07:18 +0100209
210 // Copy parameters into context if necessary.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000211 int num_parameters = info->scope()->num_parameters();
Iain Merrick75681382010-08-19 15:07:18 +0100212 for (int i = 0; i < num_parameters; i++) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000213 Variable* var = scope()->parameter(i);
214 if (var->IsContextSlot()) {
Iain Merrick75681382010-08-19 15:07:18 +0100215 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
216 (num_parameters - 1 - i) * kPointerSize;
217 // Load parameter from stack.
218 __ mov(eax, Operand(ebp, parameter_offset));
219 // Store it in the context.
Ben Murdoch589d6972011-11-30 16:04:58 +0000220 int context_offset = Context::SlotOffset(var->index());
Iain Merrick75681382010-08-19 15:07:18 +0100221 __ mov(Operand(esi, context_offset), eax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100222 // Update the write barrier. This clobbers eax and ebx.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000223 if (need_write_barrier) {
224 __ RecordWriteContextSlot(esi,
225 context_offset,
226 eax,
227 ebx,
228 kDontSaveFPRegs);
229 } else if (FLAG_debug_code) {
230 Label done;
231 __ JumpIfInNewSpace(esi, eax, &done, Label::kNear);
232 __ Abort(kExpectedNewSpaceObject);
233 __ bind(&done);
234 }
Iain Merrick75681382010-08-19 15:07:18 +0100235 }
236 }
237 }
238
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100239 Variable* arguments = scope()->arguments();
Iain Merrick75681382010-08-19 15:07:18 +0100240 if (arguments != NULL) {
241 // Function uses arguments object.
242 Comment cmnt(masm_, "[ Allocate arguments object");
243 if (function_in_register) {
244 __ push(edi);
245 } else {
246 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
247 }
248 // Receiver is just before the parameters on the caller's stack.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000249 int num_parameters = info->scope()->num_parameters();
250 int offset = num_parameters * kPointerSize;
Iain Merrick75681382010-08-19 15:07:18 +0100251 __ lea(edx,
252 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
253 __ push(edx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000254 __ push(Immediate(Smi::FromInt(num_parameters)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100255 // Arguments to ArgumentsAccessStub:
Iain Merrick75681382010-08-19 15:07:18 +0100256 // function, receiver address, parameter count.
257 // The stub will rewrite receiver and parameter count if the previous
258 // stack frame was an arguments adapter frame.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000259 ArgumentsAccessStub::Type type;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000260 if (strict_mode() == STRICT) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000261 type = ArgumentsAccessStub::NEW_STRICT;
262 } else if (function()->has_duplicate_parameters()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000263 type = ArgumentsAccessStub::NEW_SLOPPY_SLOW;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000264 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000265 type = ArgumentsAccessStub::NEW_SLOPPY_FAST;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000266 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000267 ArgumentsAccessStub stub(isolate(), type);
Iain Merrick75681382010-08-19 15:07:18 +0100268 __ CallStub(&stub);
Steve Block44f0eee2011-05-26 01:26:41 +0100269
Ben Murdoch589d6972011-11-30 16:04:58 +0000270 SetVar(arguments, eax, ebx, edx);
Steve Blockd0582a62009-12-15 09:54:21 +0000271 }
272
Ben Murdochb0fe1622011-05-05 13:52:32 +0100273 if (FLAG_trace) {
274 __ CallRuntime(Runtime::kTraceEnter, 0);
275 }
276
Steve Block1e0659c2011-05-24 12:43:12 +0100277 // Visit the declarations and body unless there is an illegal
278 // redeclaration.
279 if (scope()->HasIllegalRedeclaration()) {
280 Comment cmnt(masm_, "[ Declarations");
281 scope()->VisitIllegalRedeclaration(this);
282
283 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000284 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS);
Steve Block1e0659c2011-05-24 12:43:12 +0100285 { Comment cmnt(masm_, "[ Declarations");
286 // For named function expressions, declare the function name as a
287 // constant.
288 if (scope()->is_function_scope() && scope()->function() != NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000289 VariableDeclaration* function = scope()->function();
290 DCHECK(function->proxy()->var()->mode() == CONST ||
291 function->proxy()->var()->mode() == CONST_LEGACY);
292 DCHECK(function->proxy()->var()->location() != Variable::UNALLOCATED);
293 VisitVariableDeclaration(function);
Steve Block1e0659c2011-05-24 12:43:12 +0100294 }
295 VisitDeclarations(scope()->declarations());
296 }
297
298 { Comment cmnt(masm_, "[ Stack check");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000299 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
Ben Murdoch257744e2011-11-30 15:57:28 +0000300 Label ok;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000301 ExternalReference stack_limit
302 = ExternalReference::address_of_stack_limit(isolate());
Steve Block1e0659c2011-05-24 12:43:12 +0100303 __ cmp(esp, Operand::StaticVariable(stack_limit));
Ben Murdoch257744e2011-11-30 15:57:28 +0000304 __ j(above_equal, &ok, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000305 __ call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
Steve Block1e0659c2011-05-24 12:43:12 +0100306 __ bind(&ok);
307 }
308
309 { Comment cmnt(masm_, "[ Body");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000310 DCHECK(loop_depth() == 0);
Steve Block1e0659c2011-05-24 12:43:12 +0100311 VisitStatements(function()->body());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000312 DCHECK(loop_depth() == 0);
Steve Block1e0659c2011-05-24 12:43:12 +0100313 }
Steve Block3ce2e202009-11-05 08:53:23 +0000314 }
315
Steve Block1e0659c2011-05-24 12:43:12 +0100316 // Always emit a 'return undefined' in case control fell off the end of
317 // the body.
Steve Block3ce2e202009-11-05 08:53:23 +0000318 { Comment cmnt(masm_, "[ return <undefined>;");
Steve Block44f0eee2011-05-26 01:26:41 +0100319 __ mov(eax, isolate()->factory()->undefined_value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100320 EmitReturnSequence();
Steve Blockd0582a62009-12-15 09:54:21 +0000321 }
322}
Steve Block3ce2e202009-11-05 08:53:23 +0000323
Steve Blockd0582a62009-12-15 09:54:21 +0000324
Ben Murdochdb5a90a2011-01-06 18:27:03 +0000325void FullCodeGenerator::ClearAccumulator() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000326 __ Move(eax, Immediate(Smi::FromInt(0)));
Ben Murdochdb5a90a2011-01-06 18:27:03 +0000327}
328
329
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100330void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
331 __ mov(ebx, Immediate(profiling_counter_));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000332 __ sub(FieldOperand(ebx, Cell::kValueOffset),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100333 Immediate(Smi::FromInt(delta)));
334}
335
336
337void FullCodeGenerator::EmitProfilingCounterReset() {
338 int reset_value = FLAG_interrupt_budget;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100339 __ mov(ebx, Immediate(profiling_counter_));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000340 __ mov(FieldOperand(ebx, Cell::kValueOffset),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100341 Immediate(Smi::FromInt(reset_value)));
342}
343
344
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000345void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
346 Label* back_edge_target) {
347 Comment cmnt(masm_, "[ Back edge bookkeeping");
Ben Murdoch257744e2011-11-30 15:57:28 +0000348 Label ok;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100349
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000350 DCHECK(back_edge_target->is_bound());
351 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
352 int weight = Min(kMaxBackEdgeWeight,
353 Max(1, distance / kCodeSizeMultiplier));
354 EmitProfilingCounterDecrement(weight);
355 __ j(positive, &ok, Label::kNear);
356 __ call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100357
Ben Murdoch086aeea2011-05-13 15:57:08 +0100358 // Record a mapping of this PC offset to the OSR id. This is used to find
359 // the AST id from the unoptimized code in order to use it as a key into
360 // the deoptimization input data found in the optimized code.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000361 RecordBackEdge(stmt->OsrEntryId());
Ben Murdoch086aeea2011-05-13 15:57:08 +0100362
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000363 EmitProfilingCounterReset();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100364
Ben Murdoch086aeea2011-05-13 15:57:08 +0100365 __ bind(&ok);
366 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
367 // Record a mapping of the OSR id to this PC. This is used if the OSR
368 // entry becomes the target of a bailout. We don't expect it to be, but
369 // we want it to work if it is.
370 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100371}
372
373
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100374void FullCodeGenerator::EmitReturnSequence() {
Steve Blockd0582a62009-12-15 09:54:21 +0000375 Comment cmnt(masm_, "[ Return sequence");
376 if (return_label_.is_bound()) {
377 __ jmp(&return_label_);
378 } else {
379 // Common return label
380 __ bind(&return_label_);
Steve Block3ce2e202009-11-05 08:53:23 +0000381 if (FLAG_trace) {
382 __ push(eax);
383 __ CallRuntime(Runtime::kTraceExit, 1);
384 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000385 // Pretend that the exit is a backwards jump to the entry.
386 int weight = 1;
387 if (info_->ShouldSelfOptimize()) {
388 weight = FLAG_interrupt_budget / FLAG_self_opt_count;
389 } else {
390 int distance = masm_->pc_offset();
391 weight = Min(kMaxBackEdgeWeight,
392 Max(1, distance / kCodeSizeMultiplier));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100393 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000394 EmitProfilingCounterDecrement(weight);
395 Label ok;
396 __ j(positive, &ok, Label::kNear);
397 __ push(eax);
398 __ call(isolate()->builtins()->InterruptCheck(),
399 RelocInfo::CODE_TARGET);
400 __ pop(eax);
401 EmitProfilingCounterReset();
402 __ bind(&ok);
Steve Blockd0582a62009-12-15 09:54:21 +0000403#ifdef DEBUG
404 // Add a label for checking the size of the code used for returning.
405 Label check_exit_codesize;
406 masm_->bind(&check_exit_codesize);
407#endif
Ben Murdochb0fe1622011-05-05 13:52:32 +0100408 SetSourcePosition(function()->end_position() - 1);
Steve Block3ce2e202009-11-05 08:53:23 +0000409 __ RecordJSReturn();
410 // Do not use the leave instruction here because it is too short to
411 // patch with the code required by the debugger.
412 __ mov(esp, ebp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000413 int no_frame_start = masm_->pc_offset();
Steve Block3ce2e202009-11-05 08:53:23 +0000414 __ pop(ebp);
Steve Block1e0659c2011-05-24 12:43:12 +0100415
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000416 int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize;
Steve Block1e0659c2011-05-24 12:43:12 +0100417 __ Ret(arguments_bytes, ecx);
Steve Block1e0659c2011-05-24 12:43:12 +0100418 // Check that the size of the code used for returning is large enough
419 // for the debugger's requirements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000420 DCHECK(Assembler::kJSReturnSequenceLength <=
Steve Block1e0659c2011-05-24 12:43:12 +0100421 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000422 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
Steve Blockd0582a62009-12-15 09:54:21 +0000423 }
424}
425
426
Ben Murdoch589d6972011-11-30 16:04:58 +0000427void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000428 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
Steve Blockd0582a62009-12-15 09:54:21 +0000429}
430
431
Ben Murdoch589d6972011-11-30 16:04:58 +0000432void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000433 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
Ben Murdoch589d6972011-11-30 16:04:58 +0000434 codegen()->GetVar(result_register(), var);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100435}
436
437
Ben Murdoch589d6972011-11-30 16:04:58 +0000438void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000439 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
Ben Murdoch589d6972011-11-30 16:04:58 +0000440 MemOperand operand = codegen()->VarOperand(var, result_register());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100441 // Memory operands can be pushed directly.
Ben Murdoch589d6972011-11-30 16:04:58 +0000442 __ push(operand);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100443}
444
445
Ben Murdoch589d6972011-11-30 16:04:58 +0000446void FullCodeGenerator::TestContext::Plug(Variable* var) const {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100447 // For simplicity we always test the accumulator register.
Ben Murdoch589d6972011-11-30 16:04:58 +0000448 codegen()->GetVar(result_register(), var);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100449 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000450 codegen()->DoTest(this);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100451}
452
453
454void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
455 UNREACHABLE(); // Not used on IA32.
456}
457
458
459void FullCodeGenerator::AccumulatorValueContext::Plug(
460 Heap::RootListIndex index) const {
461 UNREACHABLE(); // Not used on IA32.
462}
463
464
465void FullCodeGenerator::StackValueContext::Plug(
466 Heap::RootListIndex index) const {
467 UNREACHABLE(); // Not used on IA32.
468}
469
470
471void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
472 UNREACHABLE(); // Not used on IA32.
473}
474
475
476void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
477}
478
479
480void FullCodeGenerator::AccumulatorValueContext::Plug(
481 Handle<Object> lit) const {
Steve Block053d10c2011-06-13 19:13:29 +0100482 if (lit->IsSmi()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000483 __ SafeMove(result_register(), Immediate(lit));
Steve Block053d10c2011-06-13 19:13:29 +0100484 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000485 __ Move(result_register(), Immediate(lit));
Steve Block053d10c2011-06-13 19:13:29 +0100486 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100487}
488
489
490void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
Steve Block053d10c2011-06-13 19:13:29 +0100491 if (lit->IsSmi()) {
492 __ SafePush(Immediate(lit));
493 } else {
494 __ push(Immediate(lit));
495 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100496}
497
498
499void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100500 codegen()->PrepareForBailoutBeforeSplit(condition(),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100501 true,
502 true_label_,
503 false_label_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000504 DCHECK(!lit->IsUndetectableObject()); // There are no undetectable literals.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100505 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100506 if (false_label_ != fall_through_) __ jmp(false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100507 } else if (lit->IsTrue() || lit->IsJSObject()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100508 if (true_label_ != fall_through_) __ jmp(true_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100509 } else if (lit->IsString()) {
510 if (String::cast(*lit)->length() == 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100511 if (false_label_ != fall_through_) __ jmp(false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100512 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100513 if (true_label_ != fall_through_) __ jmp(true_label_);
Steve Blockd0582a62009-12-15 09:54:21 +0000514 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100515 } else if (lit->IsSmi()) {
516 if (Smi::cast(*lit)->value() == 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100517 if (false_label_ != fall_through_) __ jmp(false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100518 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100519 if (true_label_ != fall_through_) __ jmp(true_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100520 }
521 } else {
522 // For simplicity we always test the accumulator register.
523 __ mov(result_register(), lit);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000524 codegen()->DoTest(this);
Steve Blockd0582a62009-12-15 09:54:21 +0000525 }
526}
527
528
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100529void FullCodeGenerator::EffectContext::DropAndPlug(int count,
530 Register reg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000531 DCHECK(count > 0);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100532 __ Drop(count);
Leon Clarkef7060e22010-06-03 12:02:55 +0100533}
534
535
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100536void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
537 int count,
538 Register reg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000539 DCHECK(count > 0);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100540 __ Drop(count);
541 __ Move(result_register(), reg);
Leon Clarkee46be812010-01-19 14:06:41 +0000542}
543
544
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100545void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
546 Register reg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000547 DCHECK(count > 0);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100548 if (count > 1) __ Drop(count - 1);
549 __ mov(Operand(esp, 0), reg);
550}
551
552
553void FullCodeGenerator::TestContext::DropAndPlug(int count,
554 Register reg) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000555 DCHECK(count > 0);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100556 // For simplicity we always test the accumulator register.
557 __ Drop(count);
558 __ Move(result_register(), reg);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100559 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000560 codegen()->DoTest(this);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100561}
562
563
564void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
565 Label* materialize_false) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000566 DCHECK(materialize_true == materialize_false);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100567 __ bind(materialize_true);
568}
569
570
571void FullCodeGenerator::AccumulatorValueContext::Plug(
572 Label* materialize_true,
573 Label* materialize_false) const {
Ben Murdoch257744e2011-11-30 15:57:28 +0000574 Label done;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100575 __ bind(materialize_true);
Steve Block44f0eee2011-05-26 01:26:41 +0100576 __ mov(result_register(), isolate()->factory()->true_value());
Ben Murdoch257744e2011-11-30 15:57:28 +0000577 __ jmp(&done, Label::kNear);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100578 __ bind(materialize_false);
Steve Block44f0eee2011-05-26 01:26:41 +0100579 __ mov(result_register(), isolate()->factory()->false_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100580 __ bind(&done);
581}
582
583
584void FullCodeGenerator::StackValueContext::Plug(
585 Label* materialize_true,
586 Label* materialize_false) const {
Ben Murdoch257744e2011-11-30 15:57:28 +0000587 Label done;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100588 __ bind(materialize_true);
Steve Block44f0eee2011-05-26 01:26:41 +0100589 __ push(Immediate(isolate()->factory()->true_value()));
Ben Murdoch257744e2011-11-30 15:57:28 +0000590 __ jmp(&done, Label::kNear);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100591 __ bind(materialize_false);
Steve Block44f0eee2011-05-26 01:26:41 +0100592 __ push(Immediate(isolate()->factory()->false_value()));
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100593 __ bind(&done);
594}
595
596
597void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
598 Label* materialize_false) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000599 DCHECK(materialize_true == true_label_);
600 DCHECK(materialize_false == false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100601}
602
603
604void FullCodeGenerator::EffectContext::Plug(bool flag) const {
605}
606
607
608void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
Steve Block44f0eee2011-05-26 01:26:41 +0100609 Handle<Object> value = flag
610 ? isolate()->factory()->true_value()
611 : isolate()->factory()->false_value();
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100612 __ mov(result_register(), value);
613}
614
615
616void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
Steve Block44f0eee2011-05-26 01:26:41 +0100617 Handle<Object> value = flag
618 ? isolate()->factory()->true_value()
619 : isolate()->factory()->false_value();
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100620 __ push(Immediate(value));
621}
622
623
624void FullCodeGenerator::TestContext::Plug(bool flag) const {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100625 codegen()->PrepareForBailoutBeforeSplit(condition(),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100626 true,
627 true_label_,
628 false_label_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100629 if (flag) {
630 if (true_label_ != fall_through_) __ jmp(true_label_);
631 } else {
632 if (false_label_ != fall_through_) __ jmp(false_label_);
Leon Clarkef7060e22010-06-03 12:02:55 +0100633 }
634}
635
636
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000637void FullCodeGenerator::DoTest(Expression* condition,
638 Label* if_true,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100639 Label* if_false,
640 Label* fall_through) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000641 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
642 CallIC(ic, condition->test_id());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100643 __ test(result_register(), result_register());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100644 // The stub returns nonzero for true.
645 Split(not_zero, if_true, if_false, fall_through);
646}
Leon Clarkee46be812010-01-19 14:06:41 +0000647
Leon Clarkee46be812010-01-19 14:06:41 +0000648
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100649void FullCodeGenerator::Split(Condition cc,
650 Label* if_true,
651 Label* if_false,
652 Label* fall_through) {
653 if (if_false == fall_through) {
654 __ j(cc, if_true);
655 } else if (if_true == fall_through) {
656 __ j(NegateCondition(cc), if_false);
657 } else {
658 __ j(cc, if_true);
659 __ jmp(if_false);
Leon Clarkee46be812010-01-19 14:06:41 +0000660 }
661}
662
663
Ben Murdoch589d6972011-11-30 16:04:58 +0000664MemOperand FullCodeGenerator::StackOperand(Variable* var) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000665 DCHECK(var->IsStackAllocated());
Ben Murdoch589d6972011-11-30 16:04:58 +0000666 // Offset is negative because higher indexes are at lower addresses.
667 int offset = -var->index() * kPointerSize;
668 // Adjust by a (parameter or local) base offset.
669 if (var->IsParameter()) {
670 offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
671 } else {
672 offset += JavaScriptFrameConstants::kLocal0Offset;
Leon Clarkee46be812010-01-19 14:06:41 +0000673 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000674 return Operand(ebp, offset);
Leon Clarkee46be812010-01-19 14:06:41 +0000675}
676
677
Ben Murdoch589d6972011-11-30 16:04:58 +0000678MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000679 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
Ben Murdoch589d6972011-11-30 16:04:58 +0000680 if (var->IsContextSlot()) {
681 int context_chain_length = scope()->ContextChainLength(var->scope());
682 __ LoadContext(scratch, context_chain_length);
683 return ContextOperand(scratch, var->index());
684 } else {
685 return StackOperand(var);
686 }
Leon Clarkee46be812010-01-19 14:06:41 +0000687}
688
689
Ben Murdoch589d6972011-11-30 16:04:58 +0000690void FullCodeGenerator::GetVar(Register dest, Variable* var) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000691 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
Ben Murdoch589d6972011-11-30 16:04:58 +0000692 MemOperand location = VarOperand(var, dest);
693 __ mov(dest, location);
694}
695
696
697void FullCodeGenerator::SetVar(Variable* var,
698 Register src,
699 Register scratch0,
700 Register scratch1) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000701 DCHECK(var->IsContextSlot() || var->IsStackAllocated());
702 DCHECK(!scratch0.is(src));
703 DCHECK(!scratch0.is(scratch1));
704 DCHECK(!scratch1.is(src));
Ben Murdoch589d6972011-11-30 16:04:58 +0000705 MemOperand location = VarOperand(var, scratch0);
Leon Clarkee46be812010-01-19 14:06:41 +0000706 __ mov(location, src);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100707
Leon Clarkee46be812010-01-19 14:06:41 +0000708 // Emit the write barrier code if the location is in the heap.
Ben Murdoch589d6972011-11-30 16:04:58 +0000709 if (var->IsContextSlot()) {
710 int offset = Context::SlotOffset(var->index());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000711 DCHECK(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100712 __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
Steve Blockd0582a62009-12-15 09:54:21 +0000713 }
714}
715
716
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100717void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100718 bool should_normalize,
719 Label* if_true,
720 Label* if_false) {
721 // Only prepare for bailouts before splits if we're in a test
722 // context. Otherwise, we let the Visit function deal with the
723 // preparation to avoid preparing with the same AST id twice.
724 if (!context()->IsTest() || !info_->IsOptimizable()) return;
725
Ben Murdoch257744e2011-11-30 15:57:28 +0000726 Label skip;
727 if (should_normalize) __ jmp(&skip, Label::kNear);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100728 PrepareForBailout(expr, TOS_REG);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100729 if (should_normalize) {
Steve Block44f0eee2011-05-26 01:26:41 +0100730 __ cmp(eax, isolate()->factory()->true_value());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100731 Split(equal, if_true, if_false, NULL);
732 __ bind(&skip);
733 }
734}
735
736
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000737void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
738 // The variable in the declaration always resides in the current context.
739 DCHECK_EQ(0, scope()->ContextChainLength(variable->scope()));
740 if (generate_debug_code_) {
741 // Check that we're not inside a with or catch context.
742 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
743 __ cmp(ebx, isolate()->factory()->with_context_map());
744 __ Check(not_equal, kDeclarationInWithContext);
745 __ cmp(ebx, isolate()->factory()->catch_context_map());
746 __ Check(not_equal, kDeclarationInCatchContext);
747 }
748}
749
750
751void FullCodeGenerator::VisitVariableDeclaration(
752 VariableDeclaration* declaration) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000753 // If it was not possible to allocate the variable at compile time, we
754 // need to "declare" it at runtime to make sure it actually exists in the
755 // local context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000756 VariableProxy* proxy = declaration->proxy();
757 VariableMode mode = declaration->mode();
Ben Murdoch589d6972011-11-30 16:04:58 +0000758 Variable* variable = proxy->var();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000759 bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
Ben Murdoch589d6972011-11-30 16:04:58 +0000760 switch (variable->location()) {
761 case Variable::UNALLOCATED:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000762 globals_->Add(variable->name(), zone());
763 globals_->Add(variable->binding_needs_init()
764 ? isolate()->factory()->the_hole_value()
765 : isolate()->factory()->undefined_value(), zone());
Ben Murdoch589d6972011-11-30 16:04:58 +0000766 break;
767
768 case Variable::PARAMETER:
769 case Variable::LOCAL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000770 if (hole_init) {
771 Comment cmnt(masm_, "[ VariableDeclaration");
Ben Murdoch589d6972011-11-30 16:04:58 +0000772 __ mov(StackOperand(variable),
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000773 Immediate(isolate()->factory()->the_hole_value()));
Steve Blockd0582a62009-12-15 09:54:21 +0000774 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000775 break;
Steve Blockd0582a62009-12-15 09:54:21 +0000776
Ben Murdoch589d6972011-11-30 16:04:58 +0000777 case Variable::CONTEXT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000778 if (hole_init) {
779 Comment cmnt(masm_, "[ VariableDeclaration");
780 EmitDebugCheckDeclarationContext(variable);
Ben Murdoch589d6972011-11-30 16:04:58 +0000781 __ mov(ContextOperand(esi, variable->index()),
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000782 Immediate(isolate()->factory()->the_hole_value()));
783 // No write barrier since the hole value is in old space.
Ben Murdoch589d6972011-11-30 16:04:58 +0000784 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000785 }
786 break;
Steve Block1e0659c2011-05-24 12:43:12 +0100787
Ben Murdoch589d6972011-11-30 16:04:58 +0000788 case Variable::LOOKUP: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000789 Comment cmnt(masm_, "[ VariableDeclaration");
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000790 __ push(esi);
791 __ push(Immediate(variable->name()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000792 // VariableDeclaration nodes are always introduced in one of four modes.
793 DCHECK(IsDeclaredVariableMode(mode));
794 PropertyAttributes attr =
795 IsImmutableVariableMode(mode) ? READ_ONLY : NONE;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000796 __ push(Immediate(Smi::FromInt(attr)));
797 // Push initial value, if any.
798 // Note: For variables we must not push an initial value (such as
799 // 'undefined') because we may have a (legal) redeclaration and we
800 // must not destroy the current value.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000801 if (hole_init) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000802 __ push(Immediate(isolate()->factory()->the_hole_value()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000803 } else {
Ben Murdoch589d6972011-11-30 16:04:58 +0000804 __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000805 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000806 __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000807 break;
Steve Blockd0582a62009-12-15 09:54:21 +0000808 }
Steve Block3ce2e202009-11-05 08:53:23 +0000809 }
810}
811
812
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000813void FullCodeGenerator::VisitFunctionDeclaration(
814 FunctionDeclaration* declaration) {
815 VariableProxy* proxy = declaration->proxy();
816 Variable* variable = proxy->var();
817 switch (variable->location()) {
818 case Variable::UNALLOCATED: {
819 globals_->Add(variable->name(), zone());
820 Handle<SharedFunctionInfo> function =
821 Compiler::BuildFunctionInfo(declaration->fun(), script(), info_);
822 // Check for stack-overflow exception.
823 if (function.is_null()) return SetStackOverflow();
824 globals_->Add(function, zone());
825 break;
826 }
827
828 case Variable::PARAMETER:
829 case Variable::LOCAL: {
830 Comment cmnt(masm_, "[ FunctionDeclaration");
831 VisitForAccumulatorValue(declaration->fun());
832 __ mov(StackOperand(variable), result_register());
833 break;
834 }
835
836 case Variable::CONTEXT: {
837 Comment cmnt(masm_, "[ FunctionDeclaration");
838 EmitDebugCheckDeclarationContext(variable);
839 VisitForAccumulatorValue(declaration->fun());
840 __ mov(ContextOperand(esi, variable->index()), result_register());
841 // We know that we have written a function, which is not a smi.
842 __ RecordWriteContextSlot(esi,
843 Context::SlotOffset(variable->index()),
844 result_register(),
845 ecx,
846 kDontSaveFPRegs,
847 EMIT_REMEMBERED_SET,
848 OMIT_SMI_CHECK);
849 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
850 break;
851 }
852
853 case Variable::LOOKUP: {
854 Comment cmnt(masm_, "[ FunctionDeclaration");
855 __ push(esi);
856 __ push(Immediate(variable->name()));
857 __ push(Immediate(Smi::FromInt(NONE)));
858 VisitForStackValue(declaration->fun());
859 __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
860 break;
861 }
862 }
863}
864
865
866void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
867 Variable* variable = declaration->proxy()->var();
868 DCHECK(variable->location() == Variable::CONTEXT);
869 DCHECK(variable->interface()->IsFrozen());
870
871 Comment cmnt(masm_, "[ ModuleDeclaration");
872 EmitDebugCheckDeclarationContext(variable);
873
874 // Load instance object.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400875 __ LoadContext(eax, scope_->ContextChainLength(scope_->ScriptScope()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000876 __ mov(eax, ContextOperand(eax, variable->interface()->Index()));
877 __ mov(eax, ContextOperand(eax, Context::EXTENSION_INDEX));
878
879 // Assign it.
880 __ mov(ContextOperand(esi, variable->index()), eax);
881 // We know that we have written a module, which is not a smi.
882 __ RecordWriteContextSlot(esi,
883 Context::SlotOffset(variable->index()),
884 eax,
885 ecx,
886 kDontSaveFPRegs,
887 EMIT_REMEMBERED_SET,
888 OMIT_SMI_CHECK);
889 PrepareForBailoutForId(declaration->proxy()->id(), NO_REGISTERS);
890
891 // Traverse into body.
892 Visit(declaration->module());
893}
894
895
896void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
897 VariableProxy* proxy = declaration->proxy();
898 Variable* variable = proxy->var();
899 switch (variable->location()) {
900 case Variable::UNALLOCATED:
901 // TODO(rossberg)
902 break;
903
904 case Variable::CONTEXT: {
905 Comment cmnt(masm_, "[ ImportDeclaration");
906 EmitDebugCheckDeclarationContext(variable);
907 // TODO(rossberg)
908 break;
909 }
910
911 case Variable::PARAMETER:
912 case Variable::LOCAL:
913 case Variable::LOOKUP:
914 UNREACHABLE();
915 }
916}
917
918
919void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
920 // TODO(rossberg)
921}
922
923
Leon Clarked91b9f72010-01-27 17:25:45 +0000924void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
Steve Block3ce2e202009-11-05 08:53:23 +0000925 // Call the runtime to declare the globals.
926 __ push(esi); // The context is the first argument.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000927 __ Push(pairs);
928 __ Push(Smi::FromInt(DeclareGlobalsFlags()));
Ben Murdoch589d6972011-11-30 16:04:58 +0000929 __ CallRuntime(Runtime::kDeclareGlobals, 3);
Steve Block3ce2e202009-11-05 08:53:23 +0000930 // Return value is ignored.
931}
932
933
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000934void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) {
935 // Call the runtime to declare the modules.
936 __ Push(descriptions);
937 __ CallRuntime(Runtime::kDeclareModules, 1);
938 // Return value is ignored.
939}
940
941
Leon Clarkef7060e22010-06-03 12:02:55 +0100942void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
943 Comment cmnt(masm_, "[ SwitchStatement");
944 Breakable nested_statement(this, stmt);
945 SetStatementPosition(stmt);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100946
Leon Clarkef7060e22010-06-03 12:02:55 +0100947 // Keep the switch value on the stack until a case matches.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100948 VisitForStackValue(stmt->tag());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100949 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
Steve Block3ce2e202009-11-05 08:53:23 +0000950
Leon Clarkef7060e22010-06-03 12:02:55 +0100951 ZoneList<CaseClause*>* clauses = stmt->cases();
952 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
Steve Block3ce2e202009-11-05 08:53:23 +0000953
Leon Clarkef7060e22010-06-03 12:02:55 +0100954 Label next_test; // Recycled for each test.
955 // Compile all the tests with branches to their bodies.
956 for (int i = 0; i < clauses->length(); i++) {
957 CaseClause* clause = clauses->at(i);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100958 clause->body_target()->Unuse();
Steve Block1e0659c2011-05-24 12:43:12 +0100959
Leon Clarkef7060e22010-06-03 12:02:55 +0100960 // The default is not a test, but remember it as final fall through.
961 if (clause->is_default()) {
962 default_clause = clause;
963 continue;
964 }
965
966 Comment cmnt(masm_, "[ Case comparison");
967 __ bind(&next_test);
968 next_test.Unuse();
969
970 // Compile the label expression.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100971 VisitForAccumulatorValue(clause->label());
Leon Clarkef7060e22010-06-03 12:02:55 +0100972
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100973 // Perform the comparison as if via '==='.
Leon Clarkef7060e22010-06-03 12:02:55 +0100974 __ mov(edx, Operand(esp, 0)); // Switch value.
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100975 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100976 JumpPatchSite patch_site(masm_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100977 if (inline_smi_code) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000978 Label slow_case;
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100979 __ mov(ecx, edx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100980 __ or_(ecx, eax);
Ben Murdoch257744e2011-11-30 15:57:28 +0000981 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100982
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100983 __ cmp(edx, eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100984 __ j(not_equal, &next_test);
985 __ Drop(1); // Switch value is no longer needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100986 __ jmp(clause->body_target());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100987 __ bind(&slow_case);
988 }
Leon Clarkef7060e22010-06-03 12:02:55 +0100989
Ben Murdochb0fe1622011-05-05 13:52:32 +0100990 // Record position before stub call for type feedback.
991 SetSourcePosition(clause->position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000992 Handle<Code> ic =
993 CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
994 CallIC(ic, clause->CompareId());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000995 patch_site.EmitPatchInfo();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000996
997 Label skip;
998 __ jmp(&skip, Label::kNear);
999 PrepareForBailout(clause, TOS_REG);
1000 __ cmp(eax, isolate()->factory()->true_value());
1001 __ j(not_equal, &next_test);
1002 __ Drop(1);
1003 __ jmp(clause->body_target());
1004 __ bind(&skip);
1005
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001006 __ test(eax, eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01001007 __ j(not_equal, &next_test);
1008 __ Drop(1); // Switch value is no longer needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001009 __ jmp(clause->body_target());
Leon Clarkef7060e22010-06-03 12:02:55 +01001010 }
1011
1012 // Discard the test value and jump to the default if present, otherwise to
1013 // the end of the statement.
1014 __ bind(&next_test);
1015 __ Drop(1); // Switch value is no longer needed.
1016 if (default_clause == NULL) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001017 __ jmp(nested_statement.break_label());
Leon Clarkef7060e22010-06-03 12:02:55 +01001018 } else {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001019 __ jmp(default_clause->body_target());
Leon Clarkef7060e22010-06-03 12:02:55 +01001020 }
1021
1022 // Compile all the case bodies.
1023 for (int i = 0; i < clauses->length(); i++) {
1024 Comment cmnt(masm_, "[ Case body");
1025 CaseClause* clause = clauses->at(i);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001026 __ bind(clause->body_target());
Steve Block44f0eee2011-05-26 01:26:41 +01001027 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
Leon Clarkef7060e22010-06-03 12:02:55 +01001028 VisitStatements(clause->statements());
1029 }
1030
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001031 __ bind(nested_statement.break_label());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001032 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
Leon Clarkef7060e22010-06-03 12:02:55 +01001033}
1034
1035
1036void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
1037 Comment cmnt(masm_, "[ ForInStatement");
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001038 FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001039
Leon Clarkef7060e22010-06-03 12:02:55 +01001040 SetStatementPosition(stmt);
1041
1042 Label loop, exit;
1043 ForIn loop_statement(this, stmt);
1044 increment_loop_depth();
1045
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001046 // Get the object to enumerate over. If the object is null or undefined, skip
1047 // over the loop. See ECMA-262 version 5, section 12.6.4.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001048 SetExpressionPosition(stmt->enumerable());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001049 VisitForAccumulatorValue(stmt->enumerable());
Steve Block44f0eee2011-05-26 01:26:41 +01001050 __ cmp(eax, isolate()->factory()->undefined_value());
Leon Clarkef7060e22010-06-03 12:02:55 +01001051 __ j(equal, &exit);
Steve Block44f0eee2011-05-26 01:26:41 +01001052 __ cmp(eax, isolate()->factory()->null_value());
Leon Clarkef7060e22010-06-03 12:02:55 +01001053 __ j(equal, &exit);
1054
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001055 PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
1056
Leon Clarkef7060e22010-06-03 12:02:55 +01001057 // Convert the object to a JS object.
Ben Murdoch257744e2011-11-30 15:57:28 +00001058 Label convert, done_convert;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001059 __ JumpIfSmi(eax, &convert, Label::kNear);
1060 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
Ben Murdoch257744e2011-11-30 15:57:28 +00001061 __ j(above_equal, &done_convert, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01001062 __ bind(&convert);
1063 __ push(eax);
1064 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
1065 __ bind(&done_convert);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001066 PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
Leon Clarkef7060e22010-06-03 12:02:55 +01001067 __ push(eax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001068
1069 // Check for proxies.
1070 Label call_runtime, use_cache, fixed_array;
1071 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1072 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
1073 __ j(below_equal, &call_runtime);
Leon Clarkef7060e22010-06-03 12:02:55 +01001074
Steve Block59151502010-09-22 15:07:15 +01001075 // Check cache validity in generated code. This is a fast case for
1076 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
1077 // guarantee cache validity, call the runtime system to check cache
1078 // validity or get the property names in a fixed array.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001079 __ CheckEnumCache(&call_runtime);
Steve Block59151502010-09-22 15:07:15 +01001080
Steve Block59151502010-09-22 15:07:15 +01001081 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
Ben Murdoch257744e2011-11-30 15:57:28 +00001082 __ jmp(&use_cache, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01001083
1084 // Get the set of properties to enumerate.
Steve Block59151502010-09-22 15:07:15 +01001085 __ bind(&call_runtime);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001086 __ push(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01001087 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001088 PrepareForBailoutForId(stmt->EnumId(), TOS_REG);
Steve Block44f0eee2011-05-26 01:26:41 +01001089 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
1090 isolate()->factory()->meta_map());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001091 __ j(not_equal, &fixed_array);
1092
Leon Clarkef7060e22010-06-03 12:02:55 +01001093
1094 // We got a map in register eax. Get the enumeration cache from it.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001095 Label no_descriptors;
Steve Block59151502010-09-22 15:07:15 +01001096 __ bind(&use_cache);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001097
1098 __ EnumLength(edx, eax);
1099 __ cmp(edx, Immediate(Smi::FromInt(0)));
1100 __ j(equal, &no_descriptors);
1101
Ben Murdoch257744e2011-11-30 15:57:28 +00001102 __ LoadInstanceDescriptors(eax, ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001103 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheOffset));
1104 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +01001105
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001106 // Set up the four remaining stack slots.
Leon Clarkef7060e22010-06-03 12:02:55 +01001107 __ push(eax); // Map.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001108 __ push(ecx); // Enumeration cache.
1109 __ push(edx); // Number of valid entries for the map in the enum cache.
Leon Clarkef7060e22010-06-03 12:02:55 +01001110 __ push(Immediate(Smi::FromInt(0))); // Initial index.
1111 __ jmp(&loop);
1112
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001113 __ bind(&no_descriptors);
1114 __ add(esp, Immediate(kPointerSize));
1115 __ jmp(&exit);
1116
Leon Clarkef7060e22010-06-03 12:02:55 +01001117 // We got a fixed array in register eax. Iterate through that.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001118 Label non_proxy;
Leon Clarkef7060e22010-06-03 12:02:55 +01001119 __ bind(&fixed_array);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001120
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001121 // No need for a write barrier, we are storing a Smi in the feedback vector.
1122 __ LoadHeapObject(ebx, FeedbackVector());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001123 int vector_index = FeedbackVector()->GetIndex(slot);
1124 __ mov(FieldOperand(ebx, FixedArray::OffsetOfElementAt(vector_index)),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001125 Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate())));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001126
1127 __ mov(ebx, Immediate(Smi::FromInt(1))); // Smi indicates slow check
1128 __ mov(ecx, Operand(esp, 0 * kPointerSize)); // Get enumerated object
1129 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1130 __ CmpObjectType(ecx, LAST_JS_PROXY_TYPE, ecx);
1131 __ j(above, &non_proxy);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001132 __ Move(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001133 __ bind(&non_proxy);
1134 __ push(ebx); // Smi
1135 __ push(eax); // Array
Leon Clarkef7060e22010-06-03 12:02:55 +01001136 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +01001137 __ push(eax); // Fixed array length (as smi).
1138 __ push(Immediate(Smi::FromInt(0))); // Initial index.
1139
1140 // Generate code for doing the condition check.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001141 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
Leon Clarkef7060e22010-06-03 12:02:55 +01001142 __ bind(&loop);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001143 SetExpressionPosition(stmt->each());
1144
Leon Clarkef7060e22010-06-03 12:02:55 +01001145 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
1146 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001147 __ j(above_equal, loop_statement.break_label());
Leon Clarkef7060e22010-06-03 12:02:55 +01001148
1149 // Get the current entry of the array into register ebx.
1150 __ mov(ebx, Operand(esp, 2 * kPointerSize));
1151 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
1152
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001153 // Get the expected map from the stack or a smi in the
Leon Clarkef7060e22010-06-03 12:02:55 +01001154 // permanent slow case into register edx.
1155 __ mov(edx, Operand(esp, 3 * kPointerSize));
1156
1157 // Check if the expected map still matches that of the enumerable.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001158 // If not, we may have to filter the key.
Ben Murdoch257744e2011-11-30 15:57:28 +00001159 Label update_each;
Leon Clarkef7060e22010-06-03 12:02:55 +01001160 __ mov(ecx, Operand(esp, 4 * kPointerSize));
1161 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
Ben Murdoch257744e2011-11-30 15:57:28 +00001162 __ j(equal, &update_each, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01001163
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001164 // For proxies, no filtering is done.
1165 // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001166 DCHECK(Smi::FromInt(0) == 0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001167 __ test(edx, edx);
1168 __ j(zero, &update_each);
1169
Leon Clarkef7060e22010-06-03 12:02:55 +01001170 // Convert the entry to a string or null if it isn't a property
1171 // anymore. If the property has been removed while iterating, we
1172 // just skip it.
1173 __ push(ecx); // Enumerable.
1174 __ push(ebx); // Current entry.
1175 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001176 __ test(eax, eax);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001177 __ j(equal, loop_statement.continue_label());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001178 __ mov(ebx, eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01001179
1180 // Update the 'each' property or variable from the possibly filtered
1181 // entry in register ebx.
1182 __ bind(&update_each);
1183 __ mov(result_register(), ebx);
1184 // Perform the assignment as if via '='.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001185 { EffectContext context(this);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001186 EmitAssignment(stmt->each());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001187 }
Leon Clarkef7060e22010-06-03 12:02:55 +01001188
1189 // Generate code for the body of the loop.
Leon Clarkef7060e22010-06-03 12:02:55 +01001190 Visit(stmt->body());
1191
Leon Clarkef7060e22010-06-03 12:02:55 +01001192 // Generate code for going to the next element by incrementing the
1193 // index (smi) stored on top of the stack.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001194 __ bind(loop_statement.continue_label());
Leon Clarkef7060e22010-06-03 12:02:55 +01001195 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
Leon Clarkef7060e22010-06-03 12:02:55 +01001196
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001197 EmitBackEdgeBookkeeping(stmt, &loop);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001198 __ jmp(&loop);
Leon Clarkef7060e22010-06-03 12:02:55 +01001199
1200 // Remove the pointers stored on the stack.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001201 __ bind(loop_statement.break_label());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001202 __ add(esp, Immediate(5 * kPointerSize));
Leon Clarkef7060e22010-06-03 12:02:55 +01001203
1204 // Exit and decrement the loop depth.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001205 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
Leon Clarkef7060e22010-06-03 12:02:55 +01001206 __ bind(&exit);
1207 decrement_loop_depth();
1208}
1209
1210
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001211void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1212 bool pretenure) {
Leon Clarkef7060e22010-06-03 12:02:55 +01001213 // Use the fast case closure allocation code that allocates in new
Ben Murdochb0fe1622011-05-05 13:52:32 +01001214 // space for nested functions that don't need literals cloning. If
1215 // we're running with the --always-opt or the --prepare-always-opt
1216 // flag, we need to use the runtime function so that the new function
1217 // we are creating here gets a chance to have its code optimized and
1218 // doesn't just get a copy of the existing unoptimized code.
1219 if (!FLAG_always_opt &&
1220 !FLAG_prepare_always_opt &&
Steve Block44f0eee2011-05-26 01:26:41 +01001221 !pretenure &&
Ben Murdochb0fe1622011-05-05 13:52:32 +01001222 scope()->is_function_scope() &&
Steve Block44f0eee2011-05-26 01:26:41 +01001223 info->num_literals() == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001224 FastNewClosureStub stub(isolate(), info->strict_mode(), info->kind());
1225 __ mov(ebx, Immediate(info));
Leon Clarkef7060e22010-06-03 12:02:55 +01001226 __ CallStub(&stub);
1227 } else {
1228 __ push(esi);
1229 __ push(Immediate(info));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001230 __ push(Immediate(pretenure
Steve Block44f0eee2011-05-26 01:26:41 +01001231 ? isolate()->factory()->true_value()
1232 : isolate()->factory()->false_value()));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001233 __ CallRuntime(Runtime::kNewClosure, 3);
Leon Clarkef7060e22010-06-03 12:02:55 +01001234 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001235 context()->Plug(eax);
Steve Block3ce2e202009-11-05 08:53:23 +00001236}
1237
1238
Leon Clarked91b9f72010-01-27 17:25:45 +00001239void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
Steve Block3ce2e202009-11-05 08:53:23 +00001240 Comment cmnt(masm_, "[ VariableProxy");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001241 EmitVariableLoad(expr);
Leon Clarkee46be812010-01-19 14:06:41 +00001242}
1243
1244
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001245void FullCodeGenerator::EmitLoadHomeObject(SuperReference* expr) {
1246 Comment cnmt(masm_, "[ SuperReference ");
1247
1248 __ mov(LoadDescriptor::ReceiverRegister(),
1249 Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1250
1251 Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
1252 __ mov(LoadDescriptor::NameRegister(), home_object_symbol);
1253
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001254 if (FLAG_vector_ics) {
1255 __ mov(VectorLoadICDescriptor::SlotRegister(),
1256 Immediate(SmiFromSlot(expr->HomeObjectFeedbackSlot())));
1257 CallLoadIC(NOT_CONTEXTUAL);
1258 } else {
1259 CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
1260 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001261
1262 __ cmp(eax, isolate()->factory()->undefined_value());
1263 Label done;
1264 __ j(not_equal, &done);
1265 __ CallRuntime(Runtime::kThrowNonMethodError, 0);
1266 __ bind(&done);
1267}
1268
1269
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001270void FullCodeGenerator::EmitSetHomeObjectIfNeeded(Expression* initializer,
1271 int offset) {
1272 if (NeedsHomeObject(initializer)) {
1273 __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0));
1274 __ mov(StoreDescriptor::NameRegister(),
1275 Immediate(isolate()->factory()->home_object_symbol()));
1276 __ mov(StoreDescriptor::ValueRegister(),
1277 Operand(esp, offset * kPointerSize));
1278 CallStoreIC();
1279 }
1280}
1281
1282
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001283void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
Ben Murdoch589d6972011-11-30 16:04:58 +00001284 TypeofState typeof_state,
1285 Label* slow) {
Steve Block59151502010-09-22 15:07:15 +01001286 Register context = esi;
1287 Register temp = edx;
1288
1289 Scope* s = scope();
1290 while (s != NULL) {
1291 if (s->num_heap_slots() > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001292 if (s->calls_sloppy_eval()) {
Steve Block59151502010-09-22 15:07:15 +01001293 // Check that extension is NULL.
1294 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1295 Immediate(0));
1296 __ j(not_equal, slow);
1297 }
1298 // Load next context in chain.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001299 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
Steve Block59151502010-09-22 15:07:15 +01001300 // Walk the rest of the chain without clobbering esi.
1301 context = temp;
1302 }
1303 // If no outer scope calls eval, we do not need to check more
1304 // context extensions. If we have reached an eval scope, we check
1305 // all extensions from this point.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001306 if (!s->outer_scope_calls_sloppy_eval() || s->is_eval_scope()) break;
Steve Block59151502010-09-22 15:07:15 +01001307 s = s->outer_scope();
1308 }
1309
1310 if (s != NULL && s->is_eval_scope()) {
1311 // Loop up the context chain. There is no frame effect so it is
1312 // safe to use raw labels here.
Ben Murdoch257744e2011-11-30 15:57:28 +00001313 Label next, fast;
Steve Block59151502010-09-22 15:07:15 +01001314 if (!context.is(temp)) {
1315 __ mov(temp, context);
1316 }
1317 __ bind(&next);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001318 // Terminate at native context.
Steve Block59151502010-09-22 15:07:15 +01001319 __ cmp(FieldOperand(temp, HeapObject::kMapOffset),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001320 Immediate(isolate()->factory()->native_context_map()));
Ben Murdoch257744e2011-11-30 15:57:28 +00001321 __ j(equal, &fast, Label::kNear);
Steve Block59151502010-09-22 15:07:15 +01001322 // Check that extension is NULL.
1323 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
1324 __ j(not_equal, slow);
1325 // Load next context in chain.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001326 __ mov(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
Steve Block59151502010-09-22 15:07:15 +01001327 __ jmp(&next);
1328 __ bind(&fast);
1329 }
1330
1331 // All extension objects were empty and it is safe to use a global
1332 // load IC call.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001333 __ mov(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
1334 __ mov(LoadDescriptor::NameRegister(), proxy->var()->name());
1335 if (FLAG_vector_ics) {
1336 __ mov(VectorLoadICDescriptor::SlotRegister(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001337 Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001338 }
1339
1340 ContextualMode mode = (typeof_state == INSIDE_TYPEOF)
1341 ? NOT_CONTEXTUAL
1342 : CONTEXTUAL;
1343
1344 CallLoadIC(mode);
Steve Block59151502010-09-22 15:07:15 +01001345}
1346
1347
Ben Murdoch589d6972011-11-30 16:04:58 +00001348MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1349 Label* slow) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001350 DCHECK(var->IsContextSlot());
Steve Block59151502010-09-22 15:07:15 +01001351 Register context = esi;
1352 Register temp = ebx;
1353
Ben Murdoch589d6972011-11-30 16:04:58 +00001354 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
Steve Block59151502010-09-22 15:07:15 +01001355 if (s->num_heap_slots() > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001356 if (s->calls_sloppy_eval()) {
Steve Block59151502010-09-22 15:07:15 +01001357 // Check that extension is NULL.
1358 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1359 Immediate(0));
1360 __ j(not_equal, slow);
1361 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001362 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
Steve Block59151502010-09-22 15:07:15 +01001363 // Walk the rest of the chain without clobbering esi.
1364 context = temp;
1365 }
1366 }
1367 // Check that last extension is NULL.
1368 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1369 __ j(not_equal, slow);
Steve Block1e0659c2011-05-24 12:43:12 +01001370
1371 // This function is used only for loads, not stores, so it's safe to
1372 // return an esi-based operand (the write barrier cannot be allowed to
1373 // destroy the esi register).
Ben Murdoch589d6972011-11-30 16:04:58 +00001374 return ContextOperand(context, var->index());
Steve Block59151502010-09-22 15:07:15 +01001375}
1376
1377
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001378void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy,
Ben Murdoch589d6972011-11-30 16:04:58 +00001379 TypeofState typeof_state,
1380 Label* slow,
1381 Label* done) {
Steve Block59151502010-09-22 15:07:15 +01001382 // Generate fast-case code for variables that might be shadowed by
1383 // eval-introduced variables. Eval is used a lot without
1384 // introducing variables. In those cases, we do not want to
1385 // perform a runtime call for all variables in the scope
1386 // containing the eval.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001387 Variable* var = proxy->var();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001388 if (var->mode() == DYNAMIC_GLOBAL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001389 EmitLoadGlobalCheckExtensions(proxy, typeof_state, slow);
Steve Block59151502010-09-22 15:07:15 +01001390 __ jmp(done);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001391 } else if (var->mode() == DYNAMIC_LOCAL) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001392 Variable* local = var->local_if_not_shadowed();
1393 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001394 if (local->mode() == LET || local->mode() == CONST ||
1395 local->mode() == CONST_LEGACY) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001396 __ cmp(eax, isolate()->factory()->the_hole_value());
1397 __ j(not_equal, done);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001398 if (local->mode() == CONST_LEGACY) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001399 __ mov(eax, isolate()->factory()->undefined_value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001400 } else { // LET || CONST
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001401 __ push(Immediate(var->name()));
1402 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1403 }
Steve Block59151502010-09-22 15:07:15 +01001404 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001405 __ jmp(done);
Steve Block59151502010-09-22 15:07:15 +01001406 }
1407}
1408
1409
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001410void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
1411 // Record position before possible IC call.
1412 SetSourcePosition(proxy->position());
1413 Variable* var = proxy->var();
Leon Clarked91b9f72010-01-27 17:25:45 +00001414
Ben Murdoch589d6972011-11-30 16:04:58 +00001415 // Three cases: global variables, lookup variables, and all other types of
1416 // variables.
1417 switch (var->location()) {
1418 case Variable::UNALLOCATED: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001419 Comment cmnt(masm_, "[ Global variable");
1420 __ mov(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
1421 __ mov(LoadDescriptor::NameRegister(), var->name());
1422 if (FLAG_vector_ics) {
1423 __ mov(VectorLoadICDescriptor::SlotRegister(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001424 Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001425 }
1426 CallLoadIC(CONTEXTUAL);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001427 context()->Plug(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00001428 break;
1429 }
1430
1431 case Variable::PARAMETER:
1432 case Variable::LOCAL:
1433 case Variable::CONTEXT: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001434 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
1435 : "[ Stack variable");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001436 if (var->binding_needs_init()) {
1437 // var->scope() may be NULL when the proxy is located in eval code and
1438 // refers to a potential outside binding. Currently those bindings are
1439 // always looked up dynamically, i.e. in that case
1440 // var->location() == LOOKUP.
1441 // always holds.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001442 DCHECK(var->scope() != NULL);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001443
1444 // Check if the binding really needs an initialization check. The check
1445 // can be skipped in the following situation: we have a LET or CONST
1446 // binding in harmony mode, both the Variable and the VariableProxy have
1447 // the same declaration scope (i.e. they are both in global code, in the
1448 // same function or in the same eval code) and the VariableProxy is in
1449 // the source physically located after the initializer of the variable.
1450 //
1451 // We cannot skip any initialization checks for CONST in non-harmony
1452 // mode because const variables may be declared but never initialized:
1453 // if (false) { const x; }; var y = x;
1454 //
1455 // The condition on the declaration scopes is a conservative check for
1456 // nested functions that access a binding and are called before the
1457 // binding is initialized:
1458 // function() { f(); let x = 1; function f() { x = 2; } }
1459 //
1460 bool skip_init_check;
1461 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
1462 skip_init_check = false;
1463 } else {
1464 // Check that we always have valid source position.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001465 DCHECK(var->initializer_position() != RelocInfo::kNoPosition);
1466 DCHECK(proxy->position() != RelocInfo::kNoPosition);
1467 skip_init_check = var->mode() != CONST_LEGACY &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001468 var->initializer_position() < proxy->position();
Ben Murdoch589d6972011-11-30 16:04:58 +00001469 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001470
1471 if (!skip_init_check) {
1472 // Let and const need a read barrier.
1473 Label done;
1474 GetVar(eax, var);
1475 __ cmp(eax, isolate()->factory()->the_hole_value());
1476 __ j(not_equal, &done, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001477 if (var->mode() == LET || var->mode() == CONST) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001478 // Throw a reference error when using an uninitialized let/const
1479 // binding in harmony mode.
1480 __ push(Immediate(var->name()));
1481 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1482 } else {
1483 // Uninitalized const bindings outside of harmony mode are unholed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001484 DCHECK(var->mode() == CONST_LEGACY);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001485 __ mov(eax, isolate()->factory()->undefined_value());
1486 }
1487 __ bind(&done);
1488 context()->Plug(eax);
1489 break;
1490 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001491 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001492 context()->Plug(var);
Ben Murdoch589d6972011-11-30 16:04:58 +00001493 break;
1494 }
1495
1496 case Variable::LOOKUP: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001497 Comment cmnt(masm_, "[ Lookup variable");
Ben Murdoch589d6972011-11-30 16:04:58 +00001498 Label done, slow;
1499 // Generate code for loading from variables potentially shadowed
1500 // by eval-introduced variables.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001501 EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
Ben Murdoch589d6972011-11-30 16:04:58 +00001502 __ bind(&slow);
Ben Murdoch589d6972011-11-30 16:04:58 +00001503 __ push(esi); // Context.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001504 __ push(Immediate(var->name()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001505 __ CallRuntime(Runtime::kLoadLookupSlot, 2);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001506 __ bind(&done);
1507 context()->Plug(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00001508 break;
Leon Clarkef7060e22010-06-03 12:02:55 +01001509 }
Steve Block3ce2e202009-11-05 08:53:23 +00001510 }
1511}
1512
1513
Leon Clarked91b9f72010-01-27 17:25:45 +00001514void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001515 Comment cmnt(masm_, "[ RegExpLiteral");
Ben Murdoch257744e2011-11-30 15:57:28 +00001516 Label materialized;
Steve Block3ce2e202009-11-05 08:53:23 +00001517 // Registers will be used as follows:
1518 // edi = JS function.
Ben Murdochbb769b22010-08-11 14:56:33 +01001519 // ecx = literals array.
1520 // ebx = regexp literal.
1521 // eax = regexp literal clone.
Steve Block3ce2e202009-11-05 08:53:23 +00001522 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdochbb769b22010-08-11 14:56:33 +01001523 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
Steve Block3ce2e202009-11-05 08:53:23 +00001524 int literal_offset =
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001525 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
Ben Murdochbb769b22010-08-11 14:56:33 +01001526 __ mov(ebx, FieldOperand(ecx, literal_offset));
Steve Block44f0eee2011-05-26 01:26:41 +01001527 __ cmp(ebx, isolate()->factory()->undefined_value());
Ben Murdoch257744e2011-11-30 15:57:28 +00001528 __ j(not_equal, &materialized, Label::kNear);
Ben Murdochbb769b22010-08-11 14:56:33 +01001529
Steve Block3ce2e202009-11-05 08:53:23 +00001530 // Create regexp literal using runtime function
1531 // Result will be in eax.
Ben Murdochbb769b22010-08-11 14:56:33 +01001532 __ push(ecx);
Steve Block3ce2e202009-11-05 08:53:23 +00001533 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1534 __ push(Immediate(expr->pattern()));
1535 __ push(Immediate(expr->flags()));
1536 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
Ben Murdochbb769b22010-08-11 14:56:33 +01001537 __ mov(ebx, eax);
1538
1539 __ bind(&materialized);
1540 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1541 Label allocated, runtime_allocate;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001542 __ Allocate(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
Ben Murdochbb769b22010-08-11 14:56:33 +01001543 __ jmp(&allocated);
1544
1545 __ bind(&runtime_allocate);
1546 __ push(ebx);
1547 __ push(Immediate(Smi::FromInt(size)));
1548 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1549 __ pop(ebx);
1550
1551 __ bind(&allocated);
1552 // Copy the content into the newly allocated memory.
1553 // (Unroll copy loop once for better throughput).
1554 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1555 __ mov(edx, FieldOperand(ebx, i));
1556 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
1557 __ mov(FieldOperand(eax, i), edx);
1558 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
1559 }
1560 if ((size % (2 * kPointerSize)) != 0) {
1561 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
1562 __ mov(FieldOperand(eax, size - kPointerSize), edx);
1563 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001564 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00001565}
1566
1567
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001568void FullCodeGenerator::EmitAccessor(Expression* expression) {
1569 if (expression == NULL) {
1570 __ push(Immediate(isolate()->factory()->null_value()));
1571 } else {
1572 VisitForStackValue(expression);
1573 }
1574}
1575
1576
Leon Clarked91b9f72010-01-27 17:25:45 +00001577void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00001578 Comment cmnt(masm_, "[ ObjectLiteral");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001579
1580 expr->BuildConstantProperties(isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001581 Handle<FixedArray> constant_properties = expr->constant_properties();
Steve Block44f0eee2011-05-26 01:26:41 +01001582 int flags = expr->fast_elements()
1583 ? ObjectLiteral::kFastElements
1584 : ObjectLiteral::kNoFlags;
1585 flags |= expr->has_function()
1586 ? ObjectLiteral::kHasFunction
1587 : ObjectLiteral::kNoFlags;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001588 int properties_count = constant_properties->length() / 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001589 if (expr->may_store_doubles() || expr->depth() > 1 ||
1590 masm()->serializer_enabled() ||
1591 flags != ObjectLiteral::kFastElements ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001592 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001593 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1594 __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
1595 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1596 __ push(Immediate(constant_properties));
1597 __ push(Immediate(Smi::FromInt(flags)));
1598 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001599 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001600 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1601 __ mov(eax, FieldOperand(edi, JSFunction::kLiteralsOffset));
1602 __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
1603 __ mov(ecx, Immediate(constant_properties));
1604 __ mov(edx, Immediate(Smi::FromInt(flags)));
1605 FastCloneShallowObjectStub stub(isolate(), properties_count);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001606 __ CallStub(&stub);
Steve Blockd0582a62009-12-15 09:54:21 +00001607 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001608 PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
Steve Blockd0582a62009-12-15 09:54:21 +00001609
Leon Clarkee46be812010-01-19 14:06:41 +00001610 // If result_saved is true the result is on top of the stack. If
1611 // result_saved is false the result is in eax.
Steve Blockd0582a62009-12-15 09:54:21 +00001612 bool result_saved = false;
1613
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001614 // Mark all computed expressions that are bound to a key that
1615 // is shadowed by a later occurrence of the same key. For the
1616 // marked expressions, no store code is emitted.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001617 expr->CalculateEmitStore(zone());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001618
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001619 AccessorTable accessor_table(zone());
Steve Blockd0582a62009-12-15 09:54:21 +00001620 for (int i = 0; i < expr->properties()->length(); i++) {
1621 ObjectLiteral::Property* property = expr->properties()->at(i);
1622 if (property->IsCompileTimeValue()) continue;
1623
1624 Literal* key = property->key();
1625 Expression* value = property->value();
1626 if (!result_saved) {
1627 __ push(eax); // Save result on the stack
1628 result_saved = true;
1629 }
1630 switch (property->kind()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001631 case ObjectLiteral::Property::CONSTANT:
1632 UNREACHABLE();
Leon Clarkee46be812010-01-19 14:06:41 +00001633 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001634 DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
Leon Clarkee46be812010-01-19 14:06:41 +00001635 // Fall through.
Steve Blockd0582a62009-12-15 09:54:21 +00001636 case ObjectLiteral::Property::COMPUTED:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001637 // It is safe to use [[Put]] here because the boilerplate already
1638 // contains computed properties with an uninitialized value.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001639 if (key->value()->IsInternalizedString()) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001640 if (property->emit_store()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001641 VisitForAccumulatorValue(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001642 DCHECK(StoreDescriptor::ValueRegister().is(eax));
1643 __ mov(StoreDescriptor::NameRegister(), Immediate(key->value()));
1644 __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0));
1645 CallStoreIC(key->LiteralFeedbackId());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001646 PrepareForBailoutForId(key->id(), NO_REGISTERS);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001647
1648 if (NeedsHomeObject(value)) {
1649 __ mov(StoreDescriptor::ReceiverRegister(), eax);
1650 __ mov(StoreDescriptor::NameRegister(),
1651 Immediate(isolate()->factory()->home_object_symbol()));
1652 __ mov(StoreDescriptor::ValueRegister(), Operand(esp, 0));
1653 CallStoreIC();
1654 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001655 } else {
1656 VisitForEffect(value);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001657 }
Steve Blockd0582a62009-12-15 09:54:21 +00001658 break;
1659 }
Leon Clarkee46be812010-01-19 14:06:41 +00001660 __ push(Operand(esp, 0)); // Duplicate receiver.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001661 VisitForStackValue(key);
1662 VisitForStackValue(value);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001663 if (property->emit_store()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001664 EmitSetHomeObjectIfNeeded(value, 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001665 __ push(Immediate(Smi::FromInt(SLOPPY))); // Strict mode
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001666 __ CallRuntime(Runtime::kSetProperty, 4);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001667 } else {
1668 __ Drop(3);
1669 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001670 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001671 case ObjectLiteral::Property::PROTOTYPE:
1672 __ push(Operand(esp, 0)); // Duplicate receiver.
1673 VisitForStackValue(value);
1674 if (property->emit_store()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001675 __ CallRuntime(Runtime::kInternalSetPrototype, 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001676 } else {
1677 __ Drop(2);
1678 }
1679 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001680 case ObjectLiteral::Property::GETTER:
1681 accessor_table.lookup(key)->second->getter = value;
Steve Blockd0582a62009-12-15 09:54:21 +00001682 break;
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001683 case ObjectLiteral::Property::SETTER:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001684 accessor_table.lookup(key)->second->setter = value;
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001685 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001686 }
1687 }
Leon Clarkee46be812010-01-19 14:06:41 +00001688
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001689 // Emit code to define accessors, using only a single call to the runtime for
1690 // each pair of corresponding getters and setters.
1691 for (AccessorTable::Iterator it = accessor_table.begin();
1692 it != accessor_table.end();
1693 ++it) {
1694 __ push(Operand(esp, 0)); // Duplicate receiver.
1695 VisitForStackValue(it->first);
1696 EmitAccessor(it->second->getter);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001697 EmitSetHomeObjectIfNeeded(it->second->getter, 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001698 EmitAccessor(it->second->setter);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001699 EmitSetHomeObjectIfNeeded(it->second->setter, 3);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001700 __ push(Immediate(Smi::FromInt(NONE)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001701 __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001702 }
1703
Steve Block44f0eee2011-05-26 01:26:41 +01001704 if (expr->has_function()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001705 DCHECK(result_saved);
Steve Block44f0eee2011-05-26 01:26:41 +01001706 __ push(Operand(esp, 0));
1707 __ CallRuntime(Runtime::kToFastProperties, 1);
1708 }
1709
Leon Clarkee46be812010-01-19 14:06:41 +00001710 if (result_saved) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001711 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00001712 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001713 context()->Plug(eax);
Steve Block3ce2e202009-11-05 08:53:23 +00001714 }
1715}
1716
1717
Leon Clarked91b9f72010-01-27 17:25:45 +00001718void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Steve Block3ce2e202009-11-05 08:53:23 +00001719 Comment cmnt(masm_, "[ ArrayLiteral");
Leon Clarkef7060e22010-06-03 12:02:55 +01001720
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001721 expr->BuildConstantElements(isolate());
1722 int flags = expr->depth() == 1
1723 ? ArrayLiteral::kShallowElements
1724 : ArrayLiteral::kNoFlags;
1725
Leon Clarkef7060e22010-06-03 12:02:55 +01001726 ZoneList<Expression*>* subexprs = expr->values();
1727 int length = subexprs->length();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001728 Handle<FixedArray> constant_elements = expr->constant_elements();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001729 DCHECK_EQ(2, constant_elements->length());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001730 ElementsKind constant_elements_kind =
1731 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001732 bool has_constant_fast_elements =
1733 IsFastObjectElementsKind(constant_elements_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001734 Handle<FixedArrayBase> constant_elements_values(
1735 FixedArrayBase::cast(constant_elements->get(1)));
Leon Clarkef7060e22010-06-03 12:02:55 +01001736
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001737 AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
1738 if (has_constant_fast_elements && !FLAG_allocation_site_pretenuring) {
1739 // If the only customer of allocation sites is transitioning, then
1740 // we can turn it off if we don't have anywhere else to transition to.
1741 allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
1742 }
1743
1744 if (expr->depth() > 1 || length > JSObject::kInitialMaxFastElementArray) {
1745 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1746 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
1747 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1748 __ push(Immediate(constant_elements));
1749 __ push(Immediate(Smi::FromInt(flags)));
1750 __ CallRuntime(Runtime::kCreateArrayLiteral, 4);
Leon Clarkef7060e22010-06-03 12:02:55 +01001751 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001752 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1753 __ mov(eax, FieldOperand(ebx, JSFunction::kLiteralsOffset));
1754 __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
1755 __ mov(ecx, Immediate(constant_elements));
1756 FastCloneShallowArrayStub stub(isolate(), allocation_site_mode);
Leon Clarkef7060e22010-06-03 12:02:55 +01001757 __ CallStub(&stub);
Steve Block3ce2e202009-11-05 08:53:23 +00001758 }
1759
1760 bool result_saved = false; // Is the result saved to the stack?
1761
1762 // Emit code to evaluate all the non-constant subexpressions and to store
1763 // them into the newly cloned array.
Leon Clarkef7060e22010-06-03 12:02:55 +01001764 for (int i = 0; i < length; i++) {
Steve Block3ce2e202009-11-05 08:53:23 +00001765 Expression* subexpr = subexprs->at(i);
1766 // If the subexpression is a literal or a simple materialized literal it
1767 // is already set in the cloned array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001768 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
Steve Block3ce2e202009-11-05 08:53:23 +00001769
1770 if (!result_saved) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001771 __ push(eax); // array literal.
1772 __ push(Immediate(Smi::FromInt(expr->literal_index())));
Steve Block3ce2e202009-11-05 08:53:23 +00001773 result_saved = true;
1774 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001775 VisitForAccumulatorValue(subexpr);
Steve Block3ce2e202009-11-05 08:53:23 +00001776
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001777 if (IsFastObjectElementsKind(constant_elements_kind)) {
1778 // Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they
1779 // cannot transition and don't need to call the runtime stub.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001780 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001781 __ mov(ebx, Operand(esp, kPointerSize)); // Copy of array literal.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001782 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
1783 // Store the subexpression value in the array's elements.
1784 __ mov(FieldOperand(ebx, offset), result_register());
1785 // Update the write barrier for the array store.
1786 __ RecordWriteField(ebx, offset, result_register(), ecx,
1787 kDontSaveFPRegs,
1788 EMIT_REMEMBERED_SET,
1789 INLINE_SMI_CHECK);
1790 } else {
1791 // Store the subexpression value in the array's elements.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001792 __ mov(ecx, Immediate(Smi::FromInt(i)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001793 StoreArrayLiteralElementStub stub(isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001794 __ CallStub(&stub);
1795 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001796
1797 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
Steve Block3ce2e202009-11-05 08:53:23 +00001798 }
1799
Leon Clarkee46be812010-01-19 14:06:41 +00001800 if (result_saved) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001801 __ add(esp, Immediate(kPointerSize)); // literal index
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001802 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00001803 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001804 context()->Plug(eax);
Steve Block3ce2e202009-11-05 08:53:23 +00001805 }
1806}
1807
1808
Andrei Popescu402d9372010-02-26 13:31:12 +00001809void FullCodeGenerator::VisitAssignment(Assignment* expr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001810 DCHECK(expr->target()->IsValidReferenceExpression());
1811
Andrei Popescu402d9372010-02-26 13:31:12 +00001812 Comment cmnt(masm_, "[ Assignment");
Leon Clarkef7060e22010-06-03 12:02:55 +01001813
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001814 Property* property = expr->target()->AsProperty();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001815 LhsKind assign_type = GetAssignType(property);
Andrei Popescu402d9372010-02-26 13:31:12 +00001816
1817 // Evaluate LHS expression.
1818 switch (assign_type) {
1819 case VARIABLE:
1820 // Nothing to do here.
1821 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001822 case NAMED_SUPER_PROPERTY:
1823 VisitForStackValue(property->obj()->AsSuperReference()->this_var());
1824 EmitLoadHomeObject(property->obj()->AsSuperReference());
1825 __ push(result_register());
1826 if (expr->is_compound()) {
1827 __ push(MemOperand(esp, kPointerSize));
1828 __ push(result_register());
1829 }
1830 break;
Andrei Popescu402d9372010-02-26 13:31:12 +00001831 case NAMED_PROPERTY:
1832 if (expr->is_compound()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001833 // We need the receiver both on the stack and in the register.
1834 VisitForStackValue(property->obj());
1835 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
Andrei Popescu402d9372010-02-26 13:31:12 +00001836 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001837 VisitForStackValue(property->obj());
Andrei Popescu402d9372010-02-26 13:31:12 +00001838 }
1839 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001840 case KEYED_SUPER_PROPERTY:
1841 VisitForStackValue(property->obj()->AsSuperReference()->this_var());
1842 EmitLoadHomeObject(property->obj()->AsSuperReference());
1843 __ Push(result_register());
1844 VisitForAccumulatorValue(property->key());
1845 __ Push(result_register());
1846 if (expr->is_compound()) {
1847 __ push(MemOperand(esp, 2 * kPointerSize));
1848 __ push(MemOperand(esp, 2 * kPointerSize));
1849 __ push(result_register());
1850 }
1851 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001852 case KEYED_PROPERTY: {
Andrei Popescu402d9372010-02-26 13:31:12 +00001853 if (expr->is_compound()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001854 VisitForStackValue(property->obj());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001855 VisitForStackValue(property->key());
1856 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, kPointerSize));
1857 __ mov(LoadDescriptor::NameRegister(), Operand(esp, 0));
Andrei Popescu402d9372010-02-26 13:31:12 +00001858 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001859 VisitForStackValue(property->obj());
1860 VisitForStackValue(property->key());
Andrei Popescu402d9372010-02-26 13:31:12 +00001861 }
1862 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001863 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001864 }
1865
Ben Murdoch8b112d22011-06-08 16:22:53 +01001866 // For compound assignments we need another deoptimization point after the
1867 // variable/property load.
Andrei Popescu402d9372010-02-26 13:31:12 +00001868 if (expr->is_compound()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001869 AccumulatorValueContext result_context(this);
1870 { AccumulatorValueContext left_operand_context(this);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001871 switch (assign_type) {
1872 case VARIABLE:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001873 EmitVariableLoad(expr->target()->AsVariableProxy());
Ben Murdoch8b112d22011-06-08 16:22:53 +01001874 PrepareForBailout(expr->target(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001875 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001876 case NAMED_SUPER_PROPERTY:
1877 EmitNamedSuperPropertyLoad(property);
1878 PrepareForBailoutForId(property->LoadId(), TOS_REG);
1879 break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001880 case NAMED_PROPERTY:
1881 EmitNamedPropertyLoad(property);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001882 PrepareForBailoutForId(property->LoadId(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001883 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001884 case KEYED_SUPER_PROPERTY:
1885 EmitKeyedSuperPropertyLoad(property);
1886 PrepareForBailoutForId(property->LoadId(), TOS_REG);
1887 break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001888 case KEYED_PROPERTY:
1889 EmitKeyedPropertyLoad(property);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001890 PrepareForBailoutForId(property->LoadId(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001891 break;
1892 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001893 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001894
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001895 Token::Value op = expr->binary_op();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001896 __ push(eax); // Left operand goes on the stack.
1897 VisitForAccumulatorValue(expr->value());
Andrei Popescu402d9372010-02-26 13:31:12 +00001898
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001899 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1900 ? OVERWRITE_RIGHT
1901 : NO_OVERWRITE;
1902 SetSourcePosition(expr->position() + 1);
1903 if (ShouldInlineSmiCase(op)) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001904 EmitInlineSmiBinaryOp(expr->binary_operation(),
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001905 op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001906 mode,
1907 expr->target(),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001908 expr->value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001909 } else {
Ben Murdoch257744e2011-11-30 15:57:28 +00001910 EmitBinaryOp(expr->binary_operation(), op, mode);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001911 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001912
1913 // Deoptimization point in case the binary operation may have side effects.
1914 PrepareForBailout(expr->binary_operation(), TOS_REG);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001915 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001916 VisitForAccumulatorValue(expr->value());
Andrei Popescu402d9372010-02-26 13:31:12 +00001917 }
1918
1919 // Record source position before possible IC call.
1920 SetSourcePosition(expr->position());
1921
1922 // Store the value.
1923 switch (assign_type) {
1924 case VARIABLE:
1925 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001926 expr->op());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001927 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1928 context()->Plug(eax);
Andrei Popescu402d9372010-02-26 13:31:12 +00001929 break;
1930 case NAMED_PROPERTY:
1931 EmitNamedPropertyAssignment(expr);
1932 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001933 case NAMED_SUPER_PROPERTY:
1934 EmitNamedSuperPropertyStore(property);
1935 context()->Plug(result_register());
1936 break;
1937 case KEYED_SUPER_PROPERTY:
1938 EmitKeyedSuperPropertyStore(property);
1939 context()->Plug(result_register());
1940 break;
Andrei Popescu402d9372010-02-26 13:31:12 +00001941 case KEYED_PROPERTY:
1942 EmitKeyedPropertyAssignment(expr);
1943 break;
1944 }
1945}
1946
1947
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001948void FullCodeGenerator::VisitYield(Yield* expr) {
1949 Comment cmnt(masm_, "[ Yield");
1950 // Evaluate yielded value first; the initial iterator definition depends on
1951 // this. It stays on the stack while we update the iterator.
1952 VisitForStackValue(expr->expression());
1953
1954 switch (expr->yield_kind()) {
1955 case Yield::kSuspend:
1956 // Pop value from top-of-stack slot; box result into result register.
1957 EmitCreateIteratorResult(false);
1958 __ push(result_register());
1959 // Fall through.
1960 case Yield::kInitial: {
1961 Label suspend, continuation, post_runtime, resume;
1962
1963 __ jmp(&suspend);
1964
1965 __ bind(&continuation);
1966 __ jmp(&resume);
1967
1968 __ bind(&suspend);
1969 VisitForAccumulatorValue(expr->generator_object());
1970 DCHECK(continuation.pos() > 0 && Smi::IsValid(continuation.pos()));
1971 __ mov(FieldOperand(eax, JSGeneratorObject::kContinuationOffset),
1972 Immediate(Smi::FromInt(continuation.pos())));
1973 __ mov(FieldOperand(eax, JSGeneratorObject::kContextOffset), esi);
1974 __ mov(ecx, esi);
1975 __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx,
1976 kDontSaveFPRegs);
1977 __ lea(ebx, Operand(ebp, StandardFrameConstants::kExpressionsOffset));
1978 __ cmp(esp, ebx);
1979 __ j(equal, &post_runtime);
1980 __ push(eax); // generator object
1981 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
1982 __ mov(context_register(),
1983 Operand(ebp, StandardFrameConstants::kContextOffset));
1984 __ bind(&post_runtime);
1985 __ pop(result_register());
1986 EmitReturnSequence();
1987
1988 __ bind(&resume);
1989 context()->Plug(result_register());
1990 break;
1991 }
1992
1993 case Yield::kFinal: {
1994 VisitForAccumulatorValue(expr->generator_object());
1995 __ mov(FieldOperand(result_register(),
1996 JSGeneratorObject::kContinuationOffset),
1997 Immediate(Smi::FromInt(JSGeneratorObject::kGeneratorClosed)));
1998 // Pop value from top-of-stack slot, box result into result register.
1999 EmitCreateIteratorResult(true);
2000 EmitUnwindBeforeReturn();
2001 EmitReturnSequence();
2002 break;
2003 }
2004
2005 case Yield::kDelegating: {
2006 VisitForStackValue(expr->generator_object());
2007
2008 // Initial stack layout is as follows:
2009 // [sp + 1 * kPointerSize] iter
2010 // [sp + 0 * kPointerSize] g
2011
2012 Label l_catch, l_try, l_suspend, l_continuation, l_resume;
2013 Label l_next, l_call, l_loop;
2014 Register load_receiver = LoadDescriptor::ReceiverRegister();
2015 Register load_name = LoadDescriptor::NameRegister();
2016
2017 // Initial send value is undefined.
2018 __ mov(eax, isolate()->factory()->undefined_value());
2019 __ jmp(&l_next);
2020
2021 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; }
2022 __ bind(&l_catch);
2023 handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
2024 __ mov(load_name, isolate()->factory()->throw_string()); // "throw"
2025 __ push(load_name); // "throw"
2026 __ push(Operand(esp, 2 * kPointerSize)); // iter
2027 __ push(eax); // exception
2028 __ jmp(&l_call);
2029
2030 // try { received = %yield result }
2031 // Shuffle the received result above a try handler and yield it without
2032 // re-boxing.
2033 __ bind(&l_try);
2034 __ pop(eax); // result
2035 __ PushTryHandler(StackHandler::CATCH, expr->index());
2036 const int handler_size = StackHandlerConstants::kSize;
2037 __ push(eax); // result
2038 __ jmp(&l_suspend);
2039 __ bind(&l_continuation);
2040 __ jmp(&l_resume);
2041 __ bind(&l_suspend);
2042 const int generator_object_depth = kPointerSize + handler_size;
2043 __ mov(eax, Operand(esp, generator_object_depth));
2044 __ push(eax); // g
2045 DCHECK(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
2046 __ mov(FieldOperand(eax, JSGeneratorObject::kContinuationOffset),
2047 Immediate(Smi::FromInt(l_continuation.pos())));
2048 __ mov(FieldOperand(eax, JSGeneratorObject::kContextOffset), esi);
2049 __ mov(ecx, esi);
2050 __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx,
2051 kDontSaveFPRegs);
2052 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
2053 __ mov(context_register(),
2054 Operand(ebp, StandardFrameConstants::kContextOffset));
2055 __ pop(eax); // result
2056 EmitReturnSequence();
2057 __ bind(&l_resume); // received in eax
2058 __ PopTryHandler();
2059
2060 // receiver = iter; f = iter.next; arg = received;
2061 __ bind(&l_next);
2062
2063 __ mov(load_name, isolate()->factory()->next_string());
2064 __ push(load_name); // "next"
2065 __ push(Operand(esp, 2 * kPointerSize)); // iter
2066 __ push(eax); // received
2067
2068 // result = receiver[f](arg);
2069 __ bind(&l_call);
2070 __ mov(load_receiver, Operand(esp, kPointerSize));
2071 if (FLAG_vector_ics) {
2072 __ mov(VectorLoadICDescriptor::SlotRegister(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002073 Immediate(SmiFromSlot(expr->KeyedLoadFeedbackSlot())));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002074 }
2075 Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
2076 CallIC(ic, TypeFeedbackId::None());
2077 __ mov(edi, eax);
2078 __ mov(Operand(esp, 2 * kPointerSize), edi);
2079 CallFunctionStub stub(isolate(), 1, CALL_AS_METHOD);
2080 __ CallStub(&stub);
2081
2082 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2083 __ Drop(1); // The function is still on the stack; drop it.
2084
2085 // if (!result.done) goto l_try;
2086 __ bind(&l_loop);
2087 __ push(eax); // save result
2088 __ Move(load_receiver, eax); // result
2089 __ mov(load_name,
2090 isolate()->factory()->done_string()); // "done"
2091 if (FLAG_vector_ics) {
2092 __ mov(VectorLoadICDescriptor::SlotRegister(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002093 Immediate(SmiFromSlot(expr->DoneFeedbackSlot())));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002094 }
2095 CallLoadIC(NOT_CONTEXTUAL); // result.done in eax
2096 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
2097 CallIC(bool_ic);
2098 __ test(eax, eax);
2099 __ j(zero, &l_try);
2100
2101 // result.value
2102 __ pop(load_receiver); // result
2103 __ mov(load_name,
2104 isolate()->factory()->value_string()); // "value"
2105 if (FLAG_vector_ics) {
2106 __ mov(VectorLoadICDescriptor::SlotRegister(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002107 Immediate(SmiFromSlot(expr->ValueFeedbackSlot())));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002108 }
2109 CallLoadIC(NOT_CONTEXTUAL); // result.value in eax
2110 context()->DropAndPlug(2, eax); // drop iter and g
2111 break;
2112 }
2113 }
2114}
2115
2116
2117void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
2118 Expression *value,
2119 JSGeneratorObject::ResumeMode resume_mode) {
2120 // The value stays in eax, and is ultimately read by the resumed generator, as
2121 // if CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. Or it
2122 // is read to throw the value when the resumed generator is already closed.
2123 // ebx will hold the generator object until the activation has been resumed.
2124 VisitForStackValue(generator);
2125 VisitForAccumulatorValue(value);
2126 __ pop(ebx);
2127
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002128 // Load suspended function and context.
2129 __ mov(esi, FieldOperand(ebx, JSGeneratorObject::kContextOffset));
2130 __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset));
2131
2132 // Push receiver.
2133 __ push(FieldOperand(ebx, JSGeneratorObject::kReceiverOffset));
2134
2135 // Push holes for arguments to generator function.
2136 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2137 __ mov(edx,
2138 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
2139 __ mov(ecx, isolate()->factory()->the_hole_value());
2140 Label push_argument_holes, push_frame;
2141 __ bind(&push_argument_holes);
2142 __ sub(edx, Immediate(Smi::FromInt(1)));
2143 __ j(carry, &push_frame);
2144 __ push(ecx);
2145 __ jmp(&push_argument_holes);
2146
2147 // Enter a new JavaScript frame, and initialize its slots as they were when
2148 // the generator was suspended.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002149 Label resume_frame, done;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002150 __ bind(&push_frame);
2151 __ call(&resume_frame);
2152 __ jmp(&done);
2153 __ bind(&resume_frame);
2154 __ push(ebp); // Caller's frame pointer.
2155 __ mov(ebp, esp);
2156 __ push(esi); // Callee's context.
2157 __ push(edi); // Callee's JS Function.
2158
2159 // Load the operand stack size.
2160 __ mov(edx, FieldOperand(ebx, JSGeneratorObject::kOperandStackOffset));
2161 __ mov(edx, FieldOperand(edx, FixedArray::kLengthOffset));
2162 __ SmiUntag(edx);
2163
2164 // If we are sending a value and there is no operand stack, we can jump back
2165 // in directly.
2166 if (resume_mode == JSGeneratorObject::NEXT) {
2167 Label slow_resume;
2168 __ cmp(edx, Immediate(0));
2169 __ j(not_zero, &slow_resume);
2170 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2171 __ mov(ecx, FieldOperand(ebx, JSGeneratorObject::kContinuationOffset));
2172 __ SmiUntag(ecx);
2173 __ add(edx, ecx);
2174 __ mov(FieldOperand(ebx, JSGeneratorObject::kContinuationOffset),
2175 Immediate(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)));
2176 __ jmp(edx);
2177 __ bind(&slow_resume);
2178 }
2179
2180 // Otherwise, we push holes for the operand stack and call the runtime to fix
2181 // up the stack and the handlers.
2182 Label push_operand_holes, call_resume;
2183 __ bind(&push_operand_holes);
2184 __ sub(edx, Immediate(1));
2185 __ j(carry, &call_resume);
2186 __ push(ecx);
2187 __ jmp(&push_operand_holes);
2188 __ bind(&call_resume);
2189 __ push(ebx);
2190 __ push(result_register());
2191 __ Push(Smi::FromInt(resume_mode));
2192 __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3);
2193 // Not reached: the runtime call returns elsewhere.
2194 __ Abort(kGeneratorFailedToResume);
2195
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002196 __ bind(&done);
2197 context()->Plug(result_register());
2198}
2199
2200
2201void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
2202 Label gc_required;
2203 Label allocated;
2204
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002205 const int instance_size = 5 * kPointerSize;
2206 DCHECK_EQ(isolate()->native_context()->iterator_result_map()->instance_size(),
2207 instance_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002208
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002209 __ Allocate(instance_size, eax, ecx, edx, &gc_required, TAG_OBJECT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002210 __ jmp(&allocated);
2211
2212 __ bind(&gc_required);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002213 __ Push(Smi::FromInt(instance_size));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002214 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
2215 __ mov(context_register(),
2216 Operand(ebp, StandardFrameConstants::kContextOffset));
2217
2218 __ bind(&allocated);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002219 __ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
2220 __ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
2221 __ mov(ebx, ContextOperand(ebx, Context::ITERATOR_RESULT_MAP_INDEX));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002222 __ pop(ecx);
2223 __ mov(edx, isolate()->factory()->ToBoolean(done));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002224 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ebx);
2225 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
2226 isolate()->factory()->empty_fixed_array());
2227 __ mov(FieldOperand(eax, JSObject::kElementsOffset),
2228 isolate()->factory()->empty_fixed_array());
2229 __ mov(FieldOperand(eax, JSGeneratorObject::kResultValuePropertyOffset), ecx);
2230 __ mov(FieldOperand(eax, JSGeneratorObject::kResultDonePropertyOffset), edx);
2231
2232 // Only the value field needs a write barrier, as the other values are in the
2233 // root set.
2234 __ RecordWriteField(eax, JSGeneratorObject::kResultValuePropertyOffset,
2235 ecx, edx, kDontSaveFPRegs);
2236}
2237
2238
Leon Clarked91b9f72010-01-27 17:25:45 +00002239void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
Leon Clarkee46be812010-01-19 14:06:41 +00002240 SetSourcePosition(prop->position());
2241 Literal* key = prop->key()->AsLiteral();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002242 DCHECK(!key->value()->IsSmi());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002243 DCHECK(!prop->IsSuperAccess());
2244
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002245 __ mov(LoadDescriptor::NameRegister(), Immediate(key->value()));
2246 if (FLAG_vector_ics) {
2247 __ mov(VectorLoadICDescriptor::SlotRegister(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002248 Immediate(SmiFromSlot(prop->PropertyFeedbackSlot())));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002249 CallLoadIC(NOT_CONTEXTUAL);
2250 } else {
2251 CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId());
2252 }
2253}
2254
2255
2256void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002257 // Stack: receiver, home_object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002258 SetSourcePosition(prop->position());
2259 Literal* key = prop->key()->AsLiteral();
2260 DCHECK(!key->value()->IsSmi());
2261 DCHECK(prop->IsSuperAccess());
2262
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002263 __ push(Immediate(key->value()));
2264 __ CallRuntime(Runtime::kLoadFromSuper, 3);
Leon Clarkee46be812010-01-19 14:06:41 +00002265}
2266
2267
Leon Clarked91b9f72010-01-27 17:25:45 +00002268void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
Leon Clarkee46be812010-01-19 14:06:41 +00002269 SetSourcePosition(prop->position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002270 Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
2271 if (FLAG_vector_ics) {
2272 __ mov(VectorLoadICDescriptor::SlotRegister(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002273 Immediate(SmiFromSlot(prop->PropertyFeedbackSlot())));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002274 CallIC(ic);
2275 } else {
2276 CallIC(ic, prop->PropertyFeedbackId());
2277 }
Leon Clarkee46be812010-01-19 14:06:41 +00002278}
2279
2280
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002281void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
2282 // Stack: receiver, home_object, key.
2283 SetSourcePosition(prop->position());
2284
2285 __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
2286}
2287
2288
Ben Murdoch257744e2011-11-30 15:57:28 +00002289void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002290 Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002291 OverwriteMode mode,
2292 Expression* left,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002293 Expression* right) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002294 // Do combined smi check of the operands. Left operand is on the
2295 // stack. Right operand is in eax.
Ben Murdoch257744e2011-11-30 15:57:28 +00002296 Label smi_case, done, stub_call;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002297 __ pop(edx);
2298 __ mov(ecx, eax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002299 __ or_(eax, edx);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002300 JumpPatchSite patch_site(masm_);
Ben Murdoch257744e2011-11-30 15:57:28 +00002301 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002302
2303 __ bind(&stub_call);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002304 __ mov(eax, ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002305 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op, mode).code();
2306 CallIC(code, expr->BinaryOperationFeedbackId());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002307 patch_site.EmitPatchInfo();
Ben Murdoch257744e2011-11-30 15:57:28 +00002308 __ jmp(&done, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002309
Ben Murdochb0fe1622011-05-05 13:52:32 +01002310 // Smi case.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002311 __ bind(&smi_case);
2312 __ mov(eax, edx); // Copy left operand in case of a stub call.
2313
2314 switch (op) {
2315 case Token::SAR:
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002316 __ SmiUntag(ecx);
2317 __ sar_cl(eax); // No checks of result necessary
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002318 __ and_(eax, Immediate(~kSmiTagMask));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002319 break;
2320 case Token::SHL: {
2321 Label result_ok;
2322 __ SmiUntag(eax);
2323 __ SmiUntag(ecx);
2324 __ shl_cl(eax);
2325 // Check that the *signed* result fits in a smi.
2326 __ cmp(eax, 0xc0000000);
2327 __ j(positive, &result_ok);
2328 __ SmiTag(ecx);
2329 __ jmp(&stub_call);
2330 __ bind(&result_ok);
2331 __ SmiTag(eax);
2332 break;
2333 }
2334 case Token::SHR: {
2335 Label result_ok;
2336 __ SmiUntag(eax);
2337 __ SmiUntag(ecx);
2338 __ shr_cl(eax);
2339 __ test(eax, Immediate(0xc0000000));
2340 __ j(zero, &result_ok);
2341 __ SmiTag(ecx);
2342 __ jmp(&stub_call);
2343 __ bind(&result_ok);
2344 __ SmiTag(eax);
2345 break;
2346 }
2347 case Token::ADD:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002348 __ add(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002349 __ j(overflow, &stub_call);
2350 break;
2351 case Token::SUB:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002352 __ sub(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002353 __ j(overflow, &stub_call);
2354 break;
2355 case Token::MUL: {
2356 __ SmiUntag(eax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002357 __ imul(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002358 __ j(overflow, &stub_call);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002359 __ test(eax, eax);
Ben Murdoch257744e2011-11-30 15:57:28 +00002360 __ j(not_zero, &done, Label::kNear);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002361 __ mov(ebx, edx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002362 __ or_(ebx, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002363 __ j(negative, &stub_call);
2364 break;
2365 }
2366 case Token::BIT_OR:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002367 __ or_(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002368 break;
2369 case Token::BIT_AND:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002370 __ and_(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002371 break;
2372 case Token::BIT_XOR:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002373 __ xor_(eax, ecx);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002374 break;
2375 default:
2376 UNREACHABLE();
2377 }
2378
2379 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002380 context()->Plug(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002381}
2382
2383
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002384void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
2385 // Constructor is in eax.
2386 DCHECK(lit != NULL);
2387 __ push(eax);
2388
2389 // No access check is needed here since the constructor is created by the
2390 // class literal.
2391 Register scratch = ebx;
2392 __ mov(scratch, FieldOperand(eax, JSFunction::kPrototypeOrInitialMapOffset));
2393 __ Push(scratch);
2394
2395 for (int i = 0; i < lit->properties()->length(); i++) {
2396 ObjectLiteral::Property* property = lit->properties()->at(i);
2397 Literal* key = property->key()->AsLiteral();
2398 Expression* value = property->value();
2399 DCHECK(key != NULL);
2400
2401 if (property->is_static()) {
2402 __ push(Operand(esp, kPointerSize)); // constructor
2403 } else {
2404 __ push(Operand(esp, 0)); // prototype
2405 }
2406 VisitForStackValue(key);
2407 VisitForStackValue(value);
2408 EmitSetHomeObjectIfNeeded(value, 2);
2409
2410 switch (property->kind()) {
2411 case ObjectLiteral::Property::CONSTANT:
2412 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
2413 case ObjectLiteral::Property::COMPUTED:
2414 case ObjectLiteral::Property::PROTOTYPE:
2415 __ CallRuntime(Runtime::kDefineClassMethod, 3);
2416 break;
2417
2418 case ObjectLiteral::Property::GETTER:
2419 __ CallRuntime(Runtime::kDefineClassGetter, 3);
2420 break;
2421
2422 case ObjectLiteral::Property::SETTER:
2423 __ CallRuntime(Runtime::kDefineClassSetter, 3);
2424 break;
2425
2426 default:
2427 UNREACHABLE();
2428 }
2429 }
2430
2431 // prototype
2432 __ CallRuntime(Runtime::kToFastProperties, 1);
2433
2434 // constructor
2435 __ CallRuntime(Runtime::kToFastProperties, 1);
2436}
2437
2438
Ben Murdoch257744e2011-11-30 15:57:28 +00002439void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
2440 Token::Value op,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002441 OverwriteMode mode) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002442 __ pop(edx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002443 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op, mode).code();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002444 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002445 CallIC(code, expr->BinaryOperationFeedbackId());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002446 patch_site.EmitPatchInfo();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002447 context()->Plug(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00002448}
2449
2450
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002451void FullCodeGenerator::EmitAssignment(Expression* expr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002452 DCHECK(expr->IsValidReferenceExpression());
Leon Clarkef7060e22010-06-03 12:02:55 +01002453
Leon Clarkef7060e22010-06-03 12:02:55 +01002454 Property* prop = expr->AsProperty();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002455 LhsKind assign_type = GetAssignType(prop);
Leon Clarkef7060e22010-06-03 12:02:55 +01002456
2457 switch (assign_type) {
2458 case VARIABLE: {
2459 Variable* var = expr->AsVariableProxy()->var();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002460 EffectContext context(this);
2461 EmitVariableAssignment(var, Token::ASSIGN);
Leon Clarkef7060e22010-06-03 12:02:55 +01002462 break;
2463 }
2464 case NAMED_PROPERTY: {
2465 __ push(eax); // Preserve value.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002466 VisitForAccumulatorValue(prop->obj());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002467 __ Move(StoreDescriptor::ReceiverRegister(), eax);
2468 __ pop(StoreDescriptor::ValueRegister()); // Restore value.
2469 __ mov(StoreDescriptor::NameRegister(),
2470 prop->key()->AsLiteral()->value());
2471 CallStoreIC();
Leon Clarkef7060e22010-06-03 12:02:55 +01002472 break;
2473 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002474 case NAMED_SUPER_PROPERTY: {
2475 __ push(eax);
2476 VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
2477 EmitLoadHomeObject(prop->obj()->AsSuperReference());
2478 // stack: value, this; eax: home_object
2479 Register scratch = ecx;
2480 Register scratch2 = edx;
2481 __ mov(scratch, result_register()); // home_object
2482 __ mov(eax, MemOperand(esp, kPointerSize)); // value
2483 __ mov(scratch2, MemOperand(esp, 0)); // this
2484 __ mov(MemOperand(esp, kPointerSize), scratch2); // this
2485 __ mov(MemOperand(esp, 0), scratch); // home_object
2486 // stack: this, home_object. eax: value
2487 EmitNamedSuperPropertyStore(prop);
2488 break;
2489 }
2490 case KEYED_SUPER_PROPERTY: {
2491 __ push(eax);
2492 VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
2493 EmitLoadHomeObject(prop->obj()->AsSuperReference());
2494 __ push(result_register());
2495 VisitForAccumulatorValue(prop->key());
2496 Register scratch = ecx;
2497 Register scratch2 = edx;
2498 __ mov(scratch2, MemOperand(esp, 2 * kPointerSize)); // value
2499 // stack: value, this, home_object; eax: key, edx: value
2500 __ mov(scratch, MemOperand(esp, kPointerSize)); // this
2501 __ mov(MemOperand(esp, 2 * kPointerSize), scratch);
2502 __ mov(scratch, MemOperand(esp, 0)); // home_object
2503 __ mov(MemOperand(esp, kPointerSize), scratch);
2504 __ mov(MemOperand(esp, 0), eax);
2505 __ mov(eax, scratch2);
2506 // stack: this, home_object, key; eax: value.
2507 EmitKeyedSuperPropertyStore(prop);
2508 break;
2509 }
Leon Clarkef7060e22010-06-03 12:02:55 +01002510 case KEYED_PROPERTY: {
2511 __ push(eax); // Preserve value.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002512 VisitForStackValue(prop->obj());
2513 VisitForAccumulatorValue(prop->key());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002514 __ Move(StoreDescriptor::NameRegister(), eax);
2515 __ pop(StoreDescriptor::ReceiverRegister()); // Receiver.
2516 __ pop(StoreDescriptor::ValueRegister()); // Restore value.
2517 Handle<Code> ic =
2518 CodeFactory::KeyedStoreIC(isolate(), strict_mode()).code();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002519 CallIC(ic);
Leon Clarkef7060e22010-06-03 12:02:55 +01002520 break;
2521 }
2522 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002523 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01002524}
2525
2526
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002527void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
2528 Variable* var, MemOperand location) {
2529 __ mov(location, eax);
2530 if (var->IsContextSlot()) {
2531 __ mov(edx, eax);
2532 int offset = Context::SlotOffset(var->index());
2533 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
2534 }
2535}
2536
2537
Leon Clarked91b9f72010-01-27 17:25:45 +00002538void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002539 Token::Value op) {
Ben Murdoch589d6972011-11-30 16:04:58 +00002540 if (var->IsUnallocated()) {
2541 // Global var, const, or let.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002542 __ mov(StoreDescriptor::NameRegister(), var->name());
2543 __ mov(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
2544 CallStoreIC();
Steve Block3ce2e202009-11-05 08:53:23 +00002545
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002546 } else if (op == Token::INIT_CONST_LEGACY) {
Ben Murdoch589d6972011-11-30 16:04:58 +00002547 // Const initializers need a write barrier.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002548 DCHECK(!var->IsParameter()); // No const parameters.
2549 if (var->IsLookupSlot()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00002550 __ push(eax);
2551 __ push(esi);
2552 __ push(Immediate(var->name()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002553 __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
2554 } else {
2555 DCHECK(var->IsStackLocal() || var->IsContextSlot());
2556 Label skip;
2557 MemOperand location = VarOperand(var, ecx);
2558 __ mov(edx, location);
2559 __ cmp(edx, isolate()->factory()->the_hole_value());
2560 __ j(not_equal, &skip, Label::kNear);
2561 EmitStoreToStackLocalOrContextSlot(var, location);
2562 __ bind(&skip);
Steve Block1e0659c2011-05-24 12:43:12 +01002563 }
Steve Block1e0659c2011-05-24 12:43:12 +01002564
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002565 } else if (var->mode() == LET && op != Token::INIT_LET) {
Ben Murdoch589d6972011-11-30 16:04:58 +00002566 // Non-initializing assignment to let variable needs a write barrier.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002567 DCHECK(!var->IsLookupSlot());
2568 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2569 Label assign;
2570 MemOperand location = VarOperand(var, ecx);
2571 __ mov(edx, location);
2572 __ cmp(edx, isolate()->factory()->the_hole_value());
2573 __ j(not_equal, &assign, Label::kNear);
2574 __ push(Immediate(var->name()));
2575 __ CallRuntime(Runtime::kThrowReferenceError, 1);
2576 __ bind(&assign);
2577 EmitStoreToStackLocalOrContextSlot(var, location);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002578 } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
Ben Murdoch589d6972011-11-30 16:04:58 +00002579 if (var->IsLookupSlot()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002580 // Assignment to var.
Ben Murdoch589d6972011-11-30 16:04:58 +00002581 __ push(eax); // Value.
2582 __ push(esi); // Context.
2583 __ push(Immediate(var->name()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002584 __ push(Immediate(Smi::FromInt(strict_mode())));
2585 __ CallRuntime(Runtime::kStoreLookupSlot, 4);
Ben Murdoch589d6972011-11-30 16:04:58 +00002586 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002587 // Assignment to var or initializing assignment to let/const in harmony
2588 // mode.
2589 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
Ben Murdoch589d6972011-11-30 16:04:58 +00002590 MemOperand location = VarOperand(var, ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002591 if (generate_debug_code_ && op == Token::INIT_LET) {
Ben Murdoch589d6972011-11-30 16:04:58 +00002592 // Check for an uninitialized let binding.
2593 __ mov(edx, location);
2594 __ cmp(edx, isolate()->factory()->the_hole_value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002595 __ Check(equal, kLetBindingReInitialization);
Steve Block3ce2e202009-11-05 08:53:23 +00002596 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002597 EmitStoreToStackLocalOrContextSlot(var, location);
Steve Block3ce2e202009-11-05 08:53:23 +00002598 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002599 } else if (IsSignallingAssignmentToConst(var, op, strict_mode())) {
2600 __ CallRuntime(Runtime::kThrowConstAssignError, 0);
Steve Block3ce2e202009-11-05 08:53:23 +00002601 }
2602}
2603
2604
Leon Clarked91b9f72010-01-27 17:25:45 +00002605void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002606 // Assignment to a property, using a named store IC.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002607 // eax : value
2608 // esp[0] : receiver
Steve Block3ce2e202009-11-05 08:53:23 +00002609
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002610 Property* prop = expr->target()->AsProperty();
2611 DCHECK(prop != NULL);
2612 DCHECK(prop->key()->IsLiteral());
Steve Blockd0582a62009-12-15 09:54:21 +00002613
Leon Clarkee46be812010-01-19 14:06:41 +00002614 // Record source code position before IC call.
2615 SetSourcePosition(expr->position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002616 __ mov(StoreDescriptor::NameRegister(), prop->key()->AsLiteral()->value());
2617 __ pop(StoreDescriptor::ReceiverRegister());
2618 CallStoreIC(expr->AssignmentFeedbackId());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002619 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2620 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002621}
2622
2623
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002624void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
2625 // Assignment to named property of super.
2626 // eax : value
2627 // stack : receiver ('this'), home_object
2628 DCHECK(prop != NULL);
2629 Literal* key = prop->key()->AsLiteral();
2630 DCHECK(key != NULL);
2631
2632 __ push(Immediate(key->value()));
2633 __ push(eax);
2634 __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
2635 : Runtime::kStoreToSuper_Sloppy),
2636 4);
2637}
2638
2639
2640void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
2641 // Assignment to named property of super.
2642 // eax : value
2643 // stack : receiver ('this'), home_object, key
2644
2645 __ push(eax);
2646 __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreKeyedToSuper_Strict
2647 : Runtime::kStoreKeyedToSuper_Sloppy),
2648 4);
2649}
2650
2651
Leon Clarked91b9f72010-01-27 17:25:45 +00002652void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002653 // Assignment to a property, using a keyed store IC.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002654 // eax : value
2655 // esp[0] : key
2656 // esp[kPointerSize] : receiver
Steve Blockd0582a62009-12-15 09:54:21 +00002657
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002658 __ pop(StoreDescriptor::NameRegister()); // Key.
2659 __ pop(StoreDescriptor::ReceiverRegister());
2660 DCHECK(StoreDescriptor::ValueRegister().is(eax));
Leon Clarkee46be812010-01-19 14:06:41 +00002661 // Record source code position before IC call.
2662 SetSourcePosition(expr->position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002663 Handle<Code> ic = CodeFactory::KeyedStoreIC(isolate(), strict_mode()).code();
2664 CallIC(ic, expr->AssignmentFeedbackId());
Steve Blockd0582a62009-12-15 09:54:21 +00002665
Ben Murdochb0fe1622011-05-05 13:52:32 +01002666 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002667 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002668}
2669
2670
Leon Clarked91b9f72010-01-27 17:25:45 +00002671void FullCodeGenerator::VisitProperty(Property* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00002672 Comment cmnt(masm_, "[ Property");
2673 Expression* key = expr->key();
Steve Blockd0582a62009-12-15 09:54:21 +00002674
Leon Clarkee46be812010-01-19 14:06:41 +00002675 if (key->IsPropertyName()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002676 if (!expr->IsSuperAccess()) {
2677 VisitForAccumulatorValue(expr->obj());
2678 __ Move(LoadDescriptor::ReceiverRegister(), result_register());
2679 EmitNamedPropertyLoad(expr);
2680 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002681 VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
2682 EmitLoadHomeObject(expr->obj()->AsSuperReference());
2683 __ push(result_register());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002684 EmitNamedSuperPropertyLoad(expr);
2685 }
2686 PrepareForBailoutForId(expr->LoadId(), TOS_REG);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002687 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002688 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002689 if (!expr->IsSuperAccess()) {
2690 VisitForStackValue(expr->obj());
2691 VisitForAccumulatorValue(expr->key());
2692 __ pop(LoadDescriptor::ReceiverRegister()); // Object.
2693 __ Move(LoadDescriptor::NameRegister(), result_register()); // Key.
2694 EmitKeyedPropertyLoad(expr);
2695 } else {
2696 VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
2697 EmitLoadHomeObject(expr->obj()->AsSuperReference());
2698 __ push(result_register());
2699 VisitForStackValue(expr->key());
2700 EmitKeyedSuperPropertyLoad(expr);
2701 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002702 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002703 }
Steve Blockd0582a62009-12-15 09:54:21 +00002704}
2705
2706
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002707void FullCodeGenerator::CallIC(Handle<Code> code,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002708 TypeFeedbackId ast_id) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002709 ic_total_count_++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002710 __ call(code, RelocInfo::CODE_TARGET, ast_id);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002711}
2712
2713
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002714// Code common for calls using the IC.
2715void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
2716 Expression* callee = expr->expression();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002717
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002718 CallICState::CallType call_type =
2719 callee->IsVariableProxy() ? CallICState::FUNCTION : CallICState::METHOD;
2720 // Get the target function.
2721 if (call_type == CallICState::FUNCTION) {
2722 { StackValueContext context(this);
2723 EmitVariableLoad(callee->AsVariableProxy());
2724 PrepareForBailout(callee, NO_REGISTERS);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002725 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002726 // Push undefined as receiver. This is patched in the method prologue if it
2727 // is a sloppy mode method.
2728 __ push(Immediate(isolate()->factory()->undefined_value()));
2729 } else {
2730 // Load the function from the receiver.
2731 DCHECK(callee->IsProperty());
2732 DCHECK(!callee->AsProperty()->IsSuperAccess());
2733 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
2734 EmitNamedPropertyLoad(callee->AsProperty());
2735 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
2736 // Push the target function under the receiver.
2737 __ push(Operand(esp, 0));
2738 __ mov(Operand(esp, kPointerSize), eax);
Steve Block3ce2e202009-11-05 08:53:23 +00002739 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002740
2741 EmitCall(expr, call_type);
Steve Blockd0582a62009-12-15 09:54:21 +00002742}
2743
2744
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002745void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
2746 Expression* callee = expr->expression();
2747 DCHECK(callee->IsProperty());
2748 Property* prop = callee->AsProperty();
2749 DCHECK(prop->IsSuperAccess());
2750
2751 SetSourcePosition(prop->position());
2752 Literal* key = prop->key()->AsLiteral();
2753 DCHECK(!key->value()->IsSmi());
2754 // Load the function from the receiver.
2755 SuperReference* super_ref = callee->AsProperty()->obj()->AsSuperReference();
2756 EmitLoadHomeObject(super_ref);
2757 __ push(eax);
2758 VisitForAccumulatorValue(super_ref->this_var());
2759 __ push(eax);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002760 __ push(eax);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002761 __ push(Operand(esp, kPointerSize * 2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002762 __ push(Immediate(key->value()));
2763 // Stack here:
2764 // - home_object
2765 // - this (receiver)
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002766 // - this (receiver) <-- LoadFromSuper will pop here and below.
2767 // - home_object
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002768 // - key
2769 __ CallRuntime(Runtime::kLoadFromSuper, 3);
2770
2771 // Replace home_object with target function.
2772 __ mov(Operand(esp, kPointerSize), eax);
2773
2774 // Stack here:
2775 // - target function
2776 // - this (receiver)
2777 EmitCall(expr, CallICState::METHOD);
2778}
2779
2780
2781// Code common for calls using the IC.
2782void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
2783 Expression* key) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002784 // Load the key.
2785 VisitForAccumulatorValue(key);
2786
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002787 Expression* callee = expr->expression();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002788
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002789 // Load the function from the receiver.
2790 DCHECK(callee->IsProperty());
2791 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
2792 __ mov(LoadDescriptor::NameRegister(), eax);
2793 EmitKeyedPropertyLoad(callee->AsProperty());
2794 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
2795
2796 // Push the target function under the receiver.
2797 __ push(Operand(esp, 0));
2798 __ mov(Operand(esp, kPointerSize), eax);
2799
2800 EmitCall(expr, CallICState::METHOD);
2801}
2802
2803
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002804void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
2805 Expression* callee = expr->expression();
2806 DCHECK(callee->IsProperty());
2807 Property* prop = callee->AsProperty();
2808 DCHECK(prop->IsSuperAccess());
2809
2810 SetSourcePosition(prop->position());
2811 // Load the function from the receiver.
2812 SuperReference* super_ref = callee->AsProperty()->obj()->AsSuperReference();
2813 EmitLoadHomeObject(super_ref);
2814 __ push(eax);
2815 VisitForAccumulatorValue(super_ref->this_var());
2816 __ push(eax);
2817 __ push(eax);
2818 __ push(Operand(esp, kPointerSize * 2));
2819 VisitForStackValue(prop->key());
2820 // Stack here:
2821 // - home_object
2822 // - this (receiver)
2823 // - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
2824 // - home_object
2825 // - key
2826 __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
2827
2828 // Replace home_object with target function.
2829 __ mov(Operand(esp, kPointerSize), eax);
2830
2831 // Stack here:
2832 // - target function
2833 // - this (receiver)
2834 EmitCall(expr, CallICState::METHOD);
2835}
2836
2837
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002838void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002839 // Load the arguments.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002840 ZoneList<Expression*>* args = expr->arguments();
2841 int arg_count = args->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002842 { PreservePositionScope scope(masm()->positions_recorder());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002843 for (int i = 0; i < arg_count; i++) {
2844 VisitForStackValue(args->at(i));
2845 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002846 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002847
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002848 // Record source position of the IC call.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002849 SetSourcePosition(expr->position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002850 Handle<Code> ic = CallIC::initialize_stub(
2851 isolate(), arg_count, call_type);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002852 __ Move(edx, Immediate(SmiFromSlot(expr->CallFeedbackSlot())));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002853 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002854 // Don't assign a type feedback id to the IC, since type feedback is provided
2855 // by the vector above.
2856 CallIC(ic);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002857
Ben Murdochb0fe1622011-05-05 13:52:32 +01002858 RecordJSReturnSite(expr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002859
Steve Blockd0582a62009-12-15 09:54:21 +00002860 // Restore context register.
2861 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002862
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002863 context()->DropAndPlug(1, eax);
Steve Blockd0582a62009-12-15 09:54:21 +00002864}
2865
2866
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002867void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002868 // Push copy of the first argument or undefined if it doesn't exist.
2869 if (arg_count > 0) {
2870 __ push(Operand(esp, arg_count * kPointerSize));
2871 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01002872 __ push(Immediate(isolate()->factory()->undefined_value()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002873 }
2874
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002875 // Push the enclosing function.
2876 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002877 // Push the receiver of the enclosing function.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002878 __ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002879 // Push the language mode.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002880 __ push(Immediate(Smi::FromInt(strict_mode())));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002881
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002882 // Push the start position of the scope the calls resides in.
2883 __ push(Immediate(Smi::FromInt(scope()->start_position())));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002884
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002885 // Do the runtime call.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002886 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002887}
2888
2889
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002890void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) {
2891 DCHECK(super_ref != NULL);
2892 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
2893 __ CallRuntime(Runtime::kGetPrototype, 1);
2894}
2895
2896
Leon Clarked91b9f72010-01-27 17:25:45 +00002897void FullCodeGenerator::VisitCall(Call* expr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002898#ifdef DEBUG
2899 // We want to verify that RecordJSReturnSite gets called on all paths
2900 // through this function. Avoid early returns.
2901 expr->return_is_recorded_ = false;
2902#endif
2903
Steve Blockd0582a62009-12-15 09:54:21 +00002904 Comment cmnt(masm_, "[ Call");
Ben Murdoch589d6972011-11-30 16:04:58 +00002905 Expression* callee = expr->expression();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002906 Call::CallType call_type = expr->GetCallType(isolate());
Steve Blockd0582a62009-12-15 09:54:21 +00002907
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002908 if (call_type == Call::POSSIBLY_EVAL_CALL) {
2909 // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval
2910 // to resolve the function we need to call and the receiver of the call.
Ben Murdoch589d6972011-11-30 16:04:58 +00002911 // Then we call the resolved function using the given arguments.
Leon Clarkef7060e22010-06-03 12:02:55 +01002912 ZoneList<Expression*>* args = expr->arguments();
2913 int arg_count = args->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002914 { PreservePositionScope pos_scope(masm()->positions_recorder());
Ben Murdoch589d6972011-11-30 16:04:58 +00002915 VisitForStackValue(callee);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002916 // Reserved receiver slot.
Steve Block44f0eee2011-05-26 01:26:41 +01002917 __ push(Immediate(isolate()->factory()->undefined_value()));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002918 // Push the arguments.
2919 for (int i = 0; i < arg_count; i++) {
2920 VisitForStackValue(args->at(i));
2921 }
2922
Ben Murdoch589d6972011-11-30 16:04:58 +00002923 // Push a copy of the function (found below the arguments) and
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002924 // resolve eval.
2925 __ push(Operand(esp, (arg_count + 1) * kPointerSize));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002926 EmitResolvePossiblyDirectEval(arg_count);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002927
2928 // The runtime call returns a pair of values in eax (function) and
2929 // edx (receiver). Touch up the stack with the right values.
2930 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
2931 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002932
2933 PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
Leon Clarkef7060e22010-06-03 12:02:55 +01002934 }
Leon Clarkef7060e22010-06-03 12:02:55 +01002935 // Record source position for debugger.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002936 SetSourcePosition(expr->position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002937 CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002938 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
Leon Clarkef7060e22010-06-03 12:02:55 +01002939 __ CallStub(&stub);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002940 RecordJSReturnSite(expr);
Leon Clarkef7060e22010-06-03 12:02:55 +01002941 // Restore context register.
2942 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002943 context()->DropAndPlug(1, eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00002944
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002945 } else if (call_type == Call::GLOBAL_CALL) {
2946 EmitCallWithLoadIC(expr);
Ben Murdoch589d6972011-11-30 16:04:58 +00002947
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002948 } else if (call_type == Call::LOOKUP_SLOT_CALL) {
Steve Block59151502010-09-22 15:07:15 +01002949 // Call to a lookup slot (dynamically introduced variable).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002950 VariableProxy* proxy = callee->AsVariableProxy();
Steve Block59151502010-09-22 15:07:15 +01002951 Label slow, done;
Ben Murdochb0fe1622011-05-05 13:52:32 +01002952 { PreservePositionScope scope(masm()->positions_recorder());
Ben Murdoch589d6972011-11-30 16:04:58 +00002953 // Generate code for loading from variables potentially shadowed by
2954 // eval-introduced variables.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002955 EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002956 }
Steve Block59151502010-09-22 15:07:15 +01002957 __ bind(&slow);
Ben Murdoch589d6972011-11-30 16:04:58 +00002958 // Call the runtime to find the function to call (returned in eax) and
2959 // the object holding it (returned in edx).
Leon Clarkef7060e22010-06-03 12:02:55 +01002960 __ push(context_register());
Ben Murdoch589d6972011-11-30 16:04:58 +00002961 __ push(Immediate(proxy->name()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002962 __ CallRuntime(Runtime::kLoadLookupSlot, 2);
Leon Clarkef7060e22010-06-03 12:02:55 +01002963 __ push(eax); // Function.
2964 __ push(edx); // Receiver.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002965 PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
Steve Block59151502010-09-22 15:07:15 +01002966
Ben Murdoch589d6972011-11-30 16:04:58 +00002967 // If fast case code has been generated, emit code to push the function
2968 // and receiver and have the slow path jump around this code.
Steve Block59151502010-09-22 15:07:15 +01002969 if (done.is_linked()) {
2970 Label call;
Ben Murdoch589d6972011-11-30 16:04:58 +00002971 __ jmp(&call, Label::kNear);
Steve Block59151502010-09-22 15:07:15 +01002972 __ bind(&done);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002973 // Push function.
Steve Block59151502010-09-22 15:07:15 +01002974 __ push(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00002975 // The receiver is implicitly the global receiver. Indicate this by
2976 // passing the hole to the call function stub.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002977 __ push(Immediate(isolate()->factory()->undefined_value()));
Steve Block59151502010-09-22 15:07:15 +01002978 __ bind(&call);
2979 }
2980
Ben Murdoch589d6972011-11-30 16:04:58 +00002981 // The receiver is either the global receiver or an object found by
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002982 // LoadContextSlot.
2983 EmitCall(expr);
Ben Murdoch589d6972011-11-30 16:04:58 +00002984
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002985 } else if (call_type == Call::PROPERTY_CALL) {
2986 Property* property = callee->AsProperty();
2987 bool is_named_call = property->key()->IsPropertyName();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002988 if (property->IsSuperAccess()) {
2989 if (is_named_call) {
2990 EmitSuperCallWithLoadIC(expr);
2991 } else {
2992 EmitKeyedSuperCallWithLoadIC(expr);
2993 }
Ben Murdoch589d6972011-11-30 16:04:58 +00002994 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002995 {
2996 PreservePositionScope scope(masm()->positions_recorder());
2997 VisitForStackValue(property->obj());
2998 }
2999 if (is_named_call) {
3000 EmitCallWithLoadIC(expr);
3001 } else {
3002 EmitKeyedCallWithLoadIC(expr, property->key());
3003 }
Ben Murdoch589d6972011-11-30 16:04:58 +00003004 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003005 } else if (call_type == Call::SUPER_CALL) {
3006 SuperReference* super_ref = callee->AsSuperReference();
3007 EmitLoadSuperConstructor(super_ref);
3008 __ push(result_register());
3009 VisitForStackValue(super_ref->this_var());
3010 EmitCall(expr, CallICState::METHOD);
Ben Murdoch589d6972011-11-30 16:04:58 +00003011 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003012 DCHECK(call_type == Call::OTHER_CALL);
Ben Murdoch589d6972011-11-30 16:04:58 +00003013 // Call to an arbitrary expression not handled specially above.
3014 { PreservePositionScope scope(masm()->positions_recorder());
3015 VisitForStackValue(callee);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08003016 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003017 __ push(Immediate(isolate()->factory()->undefined_value()));
Steve Blockd0582a62009-12-15 09:54:21 +00003018 // Emit function call.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003019 EmitCall(expr);
Steve Blockd0582a62009-12-15 09:54:21 +00003020 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01003021
3022#ifdef DEBUG
3023 // RecordJSReturnSite should have been called.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003024 DCHECK(expr->return_is_recorded_);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003025#endif
Steve Blockd0582a62009-12-15 09:54:21 +00003026}
3027
3028
Leon Clarked91b9f72010-01-27 17:25:45 +00003029void FullCodeGenerator::VisitCallNew(CallNew* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00003030 Comment cmnt(masm_, "[ CallNew");
3031 // According to ECMA-262, section 11.2.2, page 44, the function
3032 // expression in new calls must be evaluated before the
3033 // arguments.
Steve Blockd0582a62009-12-15 09:54:21 +00003034
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003035 // Push constructor on the stack. If it's not a function it's used as
3036 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
3037 // ignored.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003038 if (expr->expression()->IsSuperReference()) {
3039 EmitLoadSuperConstructor(expr->expression()->AsSuperReference());
3040 __ push(result_register());
3041 } else {
3042 VisitForStackValue(expr->expression());
3043 }
Steve Blockd0582a62009-12-15 09:54:21 +00003044
3045 // Push the arguments ("left-to-right") on the stack.
3046 ZoneList<Expression*>* args = expr->arguments();
3047 int arg_count = args->length();
3048 for (int i = 0; i < arg_count; i++) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003049 VisitForStackValue(args->at(i));
Steve Blockd0582a62009-12-15 09:54:21 +00003050 }
3051
3052 // Call the construct call builtin that handles allocation and
3053 // constructor invocation.
3054 SetSourcePosition(expr->position());
3055
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003056 // Load function and argument count into edi and eax.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003057 __ Move(eax, Immediate(arg_count));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003058 __ mov(edi, Operand(esp, arg_count * kPointerSize));
Steve Blockd0582a62009-12-15 09:54:21 +00003059
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003060 // Record call targets in unoptimized code.
3061 if (FLAG_pretenuring_call_new) {
3062 EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003063 DCHECK(expr->AllocationSiteFeedbackSlot().ToInt() ==
3064 expr->CallNewFeedbackSlot().ToInt() + 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003065 }
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01003066
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003067 __ LoadHeapObject(ebx, FeedbackVector());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003068 __ mov(edx, Immediate(SmiFromSlot(expr->CallNewFeedbackSlot())));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003069
3070 CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003071 __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
3072 PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003073 context()->Plug(eax);
Steve Block3ce2e202009-11-05 08:53:23 +00003074}
3075
3076
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003077void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
3078 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003079 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003080
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003081 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003082
3083 Label materialize_true, materialize_false;
3084 Label* if_true = NULL;
3085 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003086 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003087 context()->PrepareTest(&materialize_true, &materialize_false,
3088 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003089
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003090 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003091 __ test(eax, Immediate(kSmiTagMask));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003092 Split(zero, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003093
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003094 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003095}
3096
3097
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003098void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
3099 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003100 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003101
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003102 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003103
3104 Label materialize_true, materialize_false;
3105 Label* if_true = NULL;
3106 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003107 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003108 context()->PrepareTest(&materialize_true, &materialize_false,
3109 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003110
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003111 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003112 __ test(eax, Immediate(kSmiTagMask | 0x80000000));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003113 Split(zero, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003114
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003115 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003116}
3117
3118
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003119void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
3120 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003121 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003122
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003123 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003124
3125 Label materialize_true, materialize_false;
3126 Label* if_true = NULL;
3127 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003128 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003129 context()->PrepareTest(&materialize_true, &materialize_false,
3130 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003131
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003132 __ JumpIfSmi(eax, if_false);
Steve Block44f0eee2011-05-26 01:26:41 +01003133 __ cmp(eax, isolate()->factory()->null_value());
Leon Clarkef7060e22010-06-03 12:02:55 +01003134 __ j(equal, if_true);
3135 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
3136 // Undetectable objects behave like undefined when tested with typeof.
3137 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset));
3138 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
3139 __ j(not_zero, if_false);
3140 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003141 __ cmp(ecx, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
Leon Clarkef7060e22010-06-03 12:02:55 +01003142 __ j(below, if_false);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003143 __ cmp(ecx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003144 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003145 Split(below_equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003146
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003147 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003148}
3149
3150
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003151void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
3152 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003153 DCHECK(args->length() == 1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003154
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003155 VisitForAccumulatorValue(args->at(0));
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003156
3157 Label materialize_true, materialize_false;
3158 Label* if_true = NULL;
3159 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003160 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003161 context()->PrepareTest(&materialize_true, &materialize_false,
3162 &if_true, &if_false, &fall_through);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003163
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003164 __ JumpIfSmi(eax, if_false);
3165 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ebx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003166 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003167 Split(above_equal, if_true, if_false, fall_through);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003168
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003169 context()->Plug(if_true, if_false);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003170}
3171
3172
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003173void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) {
3174 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003175 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003176
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003177 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003178
3179 Label materialize_true, materialize_false;
3180 Label* if_true = NULL;
3181 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003182 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003183 context()->PrepareTest(&materialize_true, &materialize_false,
3184 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003185
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003186 __ JumpIfSmi(eax, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003187 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
3188 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
3189 __ test(ebx, Immediate(1 << Map::kIsUndetectable));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003190 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003191 Split(not_zero, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003192
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003193 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003194}
3195
3196
Iain Merrick75681382010-08-19 15:07:18 +01003197void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003198 CallRuntime* expr) {
3199 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003200 DCHECK(args->length() == 1);
Iain Merrick75681382010-08-19 15:07:18 +01003201
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003202 VisitForAccumulatorValue(args->at(0));
Iain Merrick75681382010-08-19 15:07:18 +01003203
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003204 Label materialize_true, materialize_false, skip_lookup;
Iain Merrick75681382010-08-19 15:07:18 +01003205 Label* if_true = NULL;
3206 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003207 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003208 context()->PrepareTest(&materialize_true, &materialize_false,
3209 &if_true, &if_false, &fall_through);
Iain Merrick75681382010-08-19 15:07:18 +01003210
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003211 __ AssertNotSmi(eax);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003212
3213 // Check whether this map has already been checked to be safe for default
3214 // valueOf.
3215 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
3216 __ test_b(FieldOperand(ebx, Map::kBitField2Offset),
3217 1 << Map::kStringWrapperSafeForDefaultValueOf);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003218 __ j(not_zero, &skip_lookup);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003219
3220 // Check for fast case object. Return false for slow case objects.
3221 __ mov(ecx, FieldOperand(eax, JSObject::kPropertiesOffset));
3222 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003223 __ cmp(ecx, isolate()->factory()->hash_table_map());
Ben Murdoch8b112d22011-06-08 16:22:53 +01003224 __ j(equal, if_false);
3225
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003226 // Look for valueOf string in the descriptor array, and indicate false if
3227 // found. Since we omit an enumeration index check, if it is added via a
3228 // transition that shares its descriptor array, this is a false positive.
3229 Label entry, loop, done;
3230
3231 // Skip loop if no descriptors are valid.
3232 __ NumberOfOwnDescriptors(ecx, ebx);
3233 __ cmp(ecx, 0);
3234 __ j(equal, &done);
3235
Ben Murdoch257744e2011-11-30 15:57:28 +00003236 __ LoadInstanceDescriptors(ebx, ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003237 // ebx: descriptor array.
3238 // ecx: valid entries in the descriptor array.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003239 // Calculate the end of the descriptor array.
3240 STATIC_ASSERT(kSmiTag == 0);
3241 STATIC_ASSERT(kSmiTagSize == 1);
3242 STATIC_ASSERT(kPointerSize == 4);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003243 __ imul(ecx, ecx, DescriptorArray::kDescriptorSize);
3244 __ lea(ecx, Operand(ebx, ecx, times_4, DescriptorArray::kFirstOffset));
Ben Murdoch8b112d22011-06-08 16:22:53 +01003245 // Calculate location of the first key name.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003246 __ add(ebx, Immediate(DescriptorArray::kFirstOffset));
Ben Murdoch8b112d22011-06-08 16:22:53 +01003247 // Loop through all the keys in the descriptor array. If one of these is the
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003248 // internalized string "valueOf" the result is false.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003249 __ jmp(&entry);
3250 __ bind(&loop);
3251 __ mov(edx, FieldOperand(ebx, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003252 __ cmp(edx, isolate()->factory()->value_of_string());
Ben Murdoch8b112d22011-06-08 16:22:53 +01003253 __ j(equal, if_false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003254 __ add(ebx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
Ben Murdoch8b112d22011-06-08 16:22:53 +01003255 __ bind(&entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003256 __ cmp(ebx, ecx);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003257 __ j(not_equal, &loop);
3258
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003259 __ bind(&done);
3260
Ben Murdoch8b112d22011-06-08 16:22:53 +01003261 // Reload map as register ebx was used as temporary above.
3262 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
3263
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003264 // Set the bit in the map to indicate that there is no local valueOf field.
3265 __ or_(FieldOperand(ebx, Map::kBitField2Offset),
3266 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
3267
3268 __ bind(&skip_lookup);
3269
3270 // If a valueOf property is not found on the object check that its
Ben Murdoch8b112d22011-06-08 16:22:53 +01003271 // prototype is the un-modified String prototype. If not result is false.
3272 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003273 __ JumpIfSmi(ecx, if_false);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003274 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003275 __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
Ben Murdoch8b112d22011-06-08 16:22:53 +01003276 __ mov(edx,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003277 FieldOperand(edx, GlobalObject::kNativeContextOffset));
Ben Murdoch8b112d22011-06-08 16:22:53 +01003278 __ cmp(ecx,
3279 ContextOperand(edx,
3280 Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003281 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003282 Split(equal, if_true, if_false, fall_through);
3283
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003284 context()->Plug(if_true, if_false);
Iain Merrick75681382010-08-19 15:07:18 +01003285}
3286
3287
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003288void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
3289 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003290 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003291
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003292 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003293
3294 Label materialize_true, materialize_false;
3295 Label* if_true = NULL;
3296 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003297 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003298 context()->PrepareTest(&materialize_true, &materialize_false,
3299 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003300
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003301 __ JumpIfSmi(eax, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003302 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003303 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003304 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003305
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003306 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003307}
3308
3309
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003310void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) {
3311 ZoneList<Expression*>* args = expr->arguments();
3312 DCHECK(args->length() == 1);
3313
3314 VisitForAccumulatorValue(args->at(0));
3315
3316 Label materialize_true, materialize_false;
3317 Label* if_true = NULL;
3318 Label* if_false = NULL;
3319 Label* fall_through = NULL;
3320 context()->PrepareTest(&materialize_true, &materialize_false,
3321 &if_true, &if_false, &fall_through);
3322
3323 Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
3324 __ CheckMap(eax, map, if_false, DO_SMI_CHECK);
3325 // Check if the exponent half is 0x80000000. Comparing against 1 and
3326 // checking for overflow is the shortest possible encoding.
3327 __ cmp(FieldOperand(eax, HeapNumber::kExponentOffset), Immediate(0x1));
3328 __ j(no_overflow, if_false);
3329 __ cmp(FieldOperand(eax, HeapNumber::kMantissaOffset), Immediate(0x0));
3330 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3331 Split(equal, if_true, if_false, fall_through);
3332
3333 context()->Plug(if_true, if_false);
3334}
3335
3336
3337
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003338void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
3339 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003340 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003341
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003342 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003343
3344 Label materialize_true, materialize_false;
3345 Label* if_true = NULL;
3346 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003347 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003348 context()->PrepareTest(&materialize_true, &materialize_false,
3349 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003350
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003351 __ JumpIfSmi(eax, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003352 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003353 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003354 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003355
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003356 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003357}
3358
3359
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003360void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
3361 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003362 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003363
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003364 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003365
3366 Label materialize_true, materialize_false;
3367 Label* if_true = NULL;
3368 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003369 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003370 context()->PrepareTest(&materialize_true, &materialize_false,
3371 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003372
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003373 __ JumpIfSmi(eax, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003374 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003375 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003376 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003377
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003378 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003379}
3380
3381
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003382void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
3383 ZoneList<Expression*>* args = expr->arguments();
3384 DCHECK(args->length() == 1);
3385
3386 VisitForAccumulatorValue(args->at(0));
3387
3388 Label materialize_true, materialize_false;
3389 Label* if_true = NULL;
3390 Label* if_false = NULL;
3391 Label* fall_through = NULL;
3392 context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
3393 &if_false, &fall_through);
3394
3395 __ JumpIfSmi(eax, if_false);
3396 Register map = ebx;
3397 __ mov(map, FieldOperand(eax, HeapObject::kMapOffset));
3398 __ CmpInstanceType(map, FIRST_JS_PROXY_TYPE);
3399 __ j(less, if_false);
3400 __ CmpInstanceType(map, LAST_JS_PROXY_TYPE);
3401 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3402 Split(less_equal, if_true, if_false, fall_through);
3403
3404 context()->Plug(if_true, if_false);
3405}
3406
Leon Clarkef7060e22010-06-03 12:02:55 +01003407
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003408void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003409 DCHECK(expr->arguments()->length() == 0);
Leon Clarkef7060e22010-06-03 12:02:55 +01003410
3411 Label materialize_true, materialize_false;
3412 Label* if_true = NULL;
3413 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003414 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003415 context()->PrepareTest(&materialize_true, &materialize_false,
3416 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003417
3418 // Get the frame pointer for the calling frame.
3419 __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3420
3421 // Skip the arguments adaptor frame if it exists.
3422 Label check_frame_marker;
3423 __ cmp(Operand(eax, StandardFrameConstants::kContextOffset),
3424 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3425 __ j(not_equal, &check_frame_marker);
3426 __ mov(eax, Operand(eax, StandardFrameConstants::kCallerFPOffset));
3427
3428 // Check the marker in the calling frame.
3429 __ bind(&check_frame_marker);
3430 __ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
3431 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003432 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003433 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003434
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003435 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003436}
3437
3438
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003439void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
3440 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003441 DCHECK(args->length() == 2);
Leon Clarkef7060e22010-06-03 12:02:55 +01003442
3443 // Load the two objects into registers and perform the comparison.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003444 VisitForStackValue(args->at(0));
3445 VisitForAccumulatorValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003446
3447 Label materialize_true, materialize_false;
3448 Label* if_true = NULL;
3449 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003450 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003451 context()->PrepareTest(&materialize_true, &materialize_false,
3452 &if_true, &if_false, &fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003453
3454 __ pop(ebx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003455 __ cmp(eax, ebx);
3456 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003457 Split(equal, if_true, if_false, fall_through);
Leon Clarkef7060e22010-06-03 12:02:55 +01003458
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003459 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01003460}
3461
3462
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003463void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
3464 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003465 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003466
3467 // ArgumentsAccessStub expects the key in edx and the formal
3468 // parameter count in eax.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003469 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003470 __ mov(edx, eax);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003471 __ Move(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
3472 ArgumentsAccessStub stub(isolate(), ArgumentsAccessStub::READ_ELEMENT);
Leon Clarkef7060e22010-06-03 12:02:55 +01003473 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003474 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003475}
3476
3477
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003478void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003479 DCHECK(expr->arguments()->length() == 0);
Leon Clarkef7060e22010-06-03 12:02:55 +01003480
3481 Label exit;
3482 // Get the number of formal parameters.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003483 __ Move(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
Leon Clarkef7060e22010-06-03 12:02:55 +01003484
3485 // Check if the calling frame is an arguments adaptor frame.
3486 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3487 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
3488 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3489 __ j(not_equal, &exit);
3490
3491 // Arguments adaptor case: Read the arguments length from the
3492 // adaptor frame.
3493 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
3494
3495 __ bind(&exit);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003496 __ AssertSmi(eax);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003497 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003498}
3499
3500
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003501void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
3502 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003503 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003504 Label done, null, function, non_function_constructor;
3505
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003506 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003507
3508 // If the object is a smi, we return null.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003509 __ JumpIfSmi(eax, &null);
Leon Clarkef7060e22010-06-03 12:02:55 +01003510
3511 // Check that the object is a JS object but take special care of JS
3512 // functions to make sure they have 'Function' as their class.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003513 // Assume that there are only two callable types, and one of them is at
3514 // either end of the type range for JS object types. Saves extra comparisons.
3515 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003516 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, eax);
3517 // Map is now in eax.
Leon Clarkef7060e22010-06-03 12:02:55 +01003518 __ j(below, &null);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003519 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
3520 FIRST_SPEC_OBJECT_TYPE + 1);
3521 __ j(equal, &function);
Leon Clarkef7060e22010-06-03 12:02:55 +01003522
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003523 __ CmpInstanceType(eax, LAST_SPEC_OBJECT_TYPE);
3524 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
3525 LAST_SPEC_OBJECT_TYPE - 1);
3526 __ j(equal, &function);
3527 // Assume that there is no larger type.
3528 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003529
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003530 // Check if the constructor in the map is a JS function.
Leon Clarkef7060e22010-06-03 12:02:55 +01003531 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
3532 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
3533 __ j(not_equal, &non_function_constructor);
3534
3535 // eax now contains the constructor function. Grab the
3536 // instance class name from there.
3537 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
3538 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
3539 __ jmp(&done);
3540
3541 // Functions have class 'Function'.
3542 __ bind(&function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003543 __ mov(eax, isolate()->factory()->Function_string());
Leon Clarkef7060e22010-06-03 12:02:55 +01003544 __ jmp(&done);
3545
3546 // Objects with a non-function constructor have class 'Object'.
3547 __ bind(&non_function_constructor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003548 __ mov(eax, isolate()->factory()->Object_string());
Leon Clarkef7060e22010-06-03 12:02:55 +01003549 __ jmp(&done);
3550
3551 // Non-JS objects have class null.
3552 __ bind(&null);
Steve Block44f0eee2011-05-26 01:26:41 +01003553 __ mov(eax, isolate()->factory()->null_value());
Leon Clarkef7060e22010-06-03 12:02:55 +01003554
3555 // All done.
3556 __ bind(&done);
3557
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003558 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003559}
3560
3561
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003562void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003563 // Load the arguments on the stack and call the stub.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003564 SubStringStub stub(isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003565 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003566 DCHECK(args->length() == 3);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003567 VisitForStackValue(args->at(0));
3568 VisitForStackValue(args->at(1));
3569 VisitForStackValue(args->at(2));
Leon Clarkef7060e22010-06-03 12:02:55 +01003570 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003571 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003572}
3573
3574
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003575void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003576 // Load the arguments on the stack and call the stub.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003577 RegExpExecStub stub(isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003578 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003579 DCHECK(args->length() == 4);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003580 VisitForStackValue(args->at(0));
3581 VisitForStackValue(args->at(1));
3582 VisitForStackValue(args->at(2));
3583 VisitForStackValue(args->at(3));
Leon Clarkef7060e22010-06-03 12:02:55 +01003584 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003585 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003586}
3587
3588
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003589void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
3590 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003591 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003592
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003593 VisitForAccumulatorValue(args->at(0)); // Load the object.
Leon Clarkef7060e22010-06-03 12:02:55 +01003594
Ben Murdoch257744e2011-11-30 15:57:28 +00003595 Label done;
Leon Clarkef7060e22010-06-03 12:02:55 +01003596 // If the object is a smi return the object.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003597 __ JumpIfSmi(eax, &done, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01003598 // If the object is not a value type, return the object.
3599 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
Ben Murdoch257744e2011-11-30 15:57:28 +00003600 __ j(not_equal, &done, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01003601 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
3602
3603 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003604 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003605}
3606
3607
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003608void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
3609 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003610 DCHECK(args->length() == 2);
3611 DCHECK_NE(NULL, args->at(1)->AsLiteral());
3612 Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->value()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003613
3614 VisitForAccumulatorValue(args->at(0)); // Load the object.
3615
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003616 Label runtime, done, not_date_object;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003617 Register object = eax;
3618 Register result = eax;
3619 Register scratch = ecx;
3620
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003621 __ JumpIfSmi(object, &not_date_object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003622 __ CmpObjectType(object, JS_DATE_TYPE, scratch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003623 __ j(not_equal, &not_date_object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003624
3625 if (index->value() == 0) {
3626 __ mov(result, FieldOperand(object, JSDate::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003627 __ jmp(&done);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003628 } else {
3629 if (index->value() < JSDate::kFirstUncachedField) {
3630 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
3631 __ mov(scratch, Operand::StaticVariable(stamp));
3632 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
3633 __ j(not_equal, &runtime, Label::kNear);
3634 __ mov(result, FieldOperand(object, JSDate::kValueOffset +
3635 kPointerSize * index->value()));
3636 __ jmp(&done);
3637 }
3638 __ bind(&runtime);
3639 __ PrepareCallCFunction(2, scratch);
3640 __ mov(Operand(esp, 0), object);
3641 __ mov(Operand(esp, 1 * kPointerSize), Immediate(index));
3642 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003643 __ jmp(&done);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003644 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003645
3646 __ bind(&not_date_object);
3647 __ CallRuntime(Runtime::kThrowNotDateError, 0);
3648 __ bind(&done);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003649 context()->Plug(result);
3650}
3651
3652
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003653void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
3654 ZoneList<Expression*>* args = expr->arguments();
3655 DCHECK_EQ(3, args->length());
3656
3657 Register string = eax;
3658 Register index = ebx;
3659 Register value = ecx;
3660
3661 VisitForStackValue(args->at(0)); // index
3662 VisitForStackValue(args->at(1)); // value
3663 VisitForAccumulatorValue(args->at(2)); // string
3664
3665 __ pop(value);
3666 __ pop(index);
3667
3668 if (FLAG_debug_code) {
3669 __ test(value, Immediate(kSmiTagMask));
3670 __ Check(zero, kNonSmiValue);
3671 __ test(index, Immediate(kSmiTagMask));
3672 __ Check(zero, kNonSmiValue);
3673 }
3674
3675 __ SmiUntag(value);
3676 __ SmiUntag(index);
3677
3678 if (FLAG_debug_code) {
3679 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
3680 __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
3681 }
3682
3683 __ mov_b(FieldOperand(string, index, times_1, SeqOneByteString::kHeaderSize),
3684 value);
3685 context()->Plug(string);
3686}
3687
3688
3689void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) {
3690 ZoneList<Expression*>* args = expr->arguments();
3691 DCHECK_EQ(3, args->length());
3692
3693 Register string = eax;
3694 Register index = ebx;
3695 Register value = ecx;
3696
3697 VisitForStackValue(args->at(0)); // index
3698 VisitForStackValue(args->at(1)); // value
3699 VisitForAccumulatorValue(args->at(2)); // string
3700 __ pop(value);
3701 __ pop(index);
3702
3703 if (FLAG_debug_code) {
3704 __ test(value, Immediate(kSmiTagMask));
3705 __ Check(zero, kNonSmiValue);
3706 __ test(index, Immediate(kSmiTagMask));
3707 __ Check(zero, kNonSmiValue);
3708 __ SmiUntag(index);
3709 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
3710 __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
3711 __ SmiTag(index);
3712 }
3713
3714 __ SmiUntag(value);
3715 // No need to untag a smi for two-byte addressing.
3716 __ mov_w(FieldOperand(string, index, times_1, SeqTwoByteString::kHeaderSize),
3717 value);
3718 context()->Plug(string);
3719}
3720
3721
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003722void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003723 // Load the arguments on the stack and call the runtime function.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003724 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003725 DCHECK(args->length() == 2);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003726 VisitForStackValue(args->at(0));
3727 VisitForStackValue(args->at(1));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003728
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003729 MathPowStub stub(isolate(), MathPowStub::ON_STACK);
3730 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003731 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003732}
3733
3734
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003735void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
3736 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003737 DCHECK(args->length() == 2);
Leon Clarkef7060e22010-06-03 12:02:55 +01003738
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003739 VisitForStackValue(args->at(0)); // Load the object.
3740 VisitForAccumulatorValue(args->at(1)); // Load the value.
Leon Clarkef7060e22010-06-03 12:02:55 +01003741 __ pop(ebx); // eax = value. ebx = object.
3742
Ben Murdoch257744e2011-11-30 15:57:28 +00003743 Label done;
Leon Clarkef7060e22010-06-03 12:02:55 +01003744 // If the object is a smi, return the value.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003745 __ JumpIfSmi(ebx, &done, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01003746
3747 // If the object is not a value type, return the value.
3748 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx);
Ben Murdoch257744e2011-11-30 15:57:28 +00003749 __ j(not_equal, &done, Label::kNear);
Leon Clarkef7060e22010-06-03 12:02:55 +01003750
3751 // Store the value.
3752 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003753
Leon Clarkef7060e22010-06-03 12:02:55 +01003754 // Update the write barrier. Save the value as it will be
3755 // overwritten by the write barrier code and is needed afterward.
3756 __ mov(edx, eax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003757 __ RecordWriteField(ebx, JSValue::kValueOffset, edx, ecx, kDontSaveFPRegs);
Leon Clarkef7060e22010-06-03 12:02:55 +01003758
3759 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003760 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003761}
3762
3763
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003764void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
3765 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003766 DCHECK_EQ(args->length(), 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003767
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003768 // Load the argument into eax and call the stub.
3769 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003770
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003771 NumberToStringStub stub(isolate());
Leon Clarkef7060e22010-06-03 12:02:55 +01003772 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003773 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003774}
3775
3776
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003777void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
3778 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003779 DCHECK(args->length() == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003780
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003781 VisitForAccumulatorValue(args->at(0));
Leon Clarkef7060e22010-06-03 12:02:55 +01003782
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003783 Label done;
3784 StringCharFromCodeGenerator generator(eax, ebx);
3785 generator.GenerateFast(masm_);
Leon Clarkef7060e22010-06-03 12:02:55 +01003786 __ jmp(&done);
3787
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003788 NopRuntimeCallHelper call_helper;
3789 generator.GenerateSlow(masm_, call_helper);
Leon Clarkef7060e22010-06-03 12:02:55 +01003790
3791 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003792 context()->Plug(ebx);
Leon Clarkef7060e22010-06-03 12:02:55 +01003793}
3794
3795
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003796void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
3797 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003798 DCHECK(args->length() == 2);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003799
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003800 VisitForStackValue(args->at(0));
3801 VisitForAccumulatorValue(args->at(1));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003802
3803 Register object = ebx;
3804 Register index = eax;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003805 Register result = edx;
3806
3807 __ pop(object);
3808
3809 Label need_conversion;
3810 Label index_out_of_range;
3811 Label done;
3812 StringCharCodeAtGenerator generator(object,
3813 index,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003814 result,
3815 &need_conversion,
3816 &need_conversion,
3817 &index_out_of_range,
3818 STRING_INDEX_IS_NUMBER);
3819 generator.GenerateFast(masm_);
3820 __ jmp(&done);
3821
3822 __ bind(&index_out_of_range);
3823 // When the index is out of range, the spec requires us to return
3824 // NaN.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003825 __ Move(result, Immediate(isolate()->factory()->nan_value()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003826 __ jmp(&done);
3827
3828 __ bind(&need_conversion);
Leon Clarkef7060e22010-06-03 12:02:55 +01003829 // Move the undefined value into the result register, which will
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003830 // trigger conversion.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003831 __ Move(result, Immediate(isolate()->factory()->undefined_value()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003832 __ jmp(&done);
3833
3834 NopRuntimeCallHelper call_helper;
3835 generator.GenerateSlow(masm_, call_helper);
3836
3837 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003838 context()->Plug(result);
Leon Clarkef7060e22010-06-03 12:02:55 +01003839}
3840
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003841
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003842void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
3843 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003844 DCHECK(args->length() == 2);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003845
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003846 VisitForStackValue(args->at(0));
3847 VisitForAccumulatorValue(args->at(1));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003848
3849 Register object = ebx;
3850 Register index = eax;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003851 Register scratch = edx;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003852 Register result = eax;
3853
3854 __ pop(object);
3855
3856 Label need_conversion;
3857 Label index_out_of_range;
3858 Label done;
3859 StringCharAtGenerator generator(object,
3860 index,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003861 scratch,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003862 result,
3863 &need_conversion,
3864 &need_conversion,
3865 &index_out_of_range,
3866 STRING_INDEX_IS_NUMBER);
3867 generator.GenerateFast(masm_);
3868 __ jmp(&done);
3869
3870 __ bind(&index_out_of_range);
3871 // When the index is out of range, the spec requires us to return
3872 // the empty string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003873 __ Move(result, Immediate(isolate()->factory()->empty_string()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003874 __ jmp(&done);
3875
3876 __ bind(&need_conversion);
3877 // Move smi zero into the result register, which will trigger
3878 // conversion.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003879 __ Move(result, Immediate(Smi::FromInt(0)));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003880 __ jmp(&done);
3881
3882 NopRuntimeCallHelper call_helper;
3883 generator.GenerateSlow(masm_, call_helper);
3884
3885 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003886 context()->Plug(result);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003887}
3888
3889
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003890void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
3891 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003892 DCHECK_EQ(2, args->length());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003893 VisitForStackValue(args->at(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003894 VisitForAccumulatorValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003895
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003896 __ pop(edx);
3897 StringAddStub stub(isolate(), STRING_ADD_CHECK_BOTH, NOT_TENURED);
Leon Clarkef7060e22010-06-03 12:02:55 +01003898 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003899 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003900}
3901
3902
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003903void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
3904 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003905 DCHECK_EQ(2, args->length());
Leon Clarkef7060e22010-06-03 12:02:55 +01003906
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003907 VisitForStackValue(args->at(0));
3908 VisitForStackValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003909
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003910 StringCompareStub stub(isolate());
Leon Clarkef7060e22010-06-03 12:02:55 +01003911 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003912 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003913}
3914
3915
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003916void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
3917 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003918 DCHECK(args->length() >= 2);
Leon Clarkef7060e22010-06-03 12:02:55 +01003919
Ben Murdoch257744e2011-11-30 15:57:28 +00003920 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3921 for (int i = 0; i < arg_count + 1; ++i) {
3922 VisitForStackValue(args->at(i));
Leon Clarkef7060e22010-06-03 12:02:55 +01003923 }
Ben Murdoch257744e2011-11-30 15:57:28 +00003924 VisitForAccumulatorValue(args->last()); // Function.
Leon Clarkef7060e22010-06-03 12:02:55 +01003925
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003926 Label runtime, done;
3927 // Check for non-function argument (including proxy).
3928 __ JumpIfSmi(eax, &runtime);
3929 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
3930 __ j(not_equal, &runtime);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003931
Ben Murdoch257744e2011-11-30 15:57:28 +00003932 // InvokeFunction requires the function in edi. Move it in there.
3933 __ mov(edi, result_register());
Leon Clarkef7060e22010-06-03 12:02:55 +01003934 ParameterCount count(arg_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003935 __ InvokeFunction(edi, count, CALL_FUNCTION, NullCallWrapper());
Leon Clarkef7060e22010-06-03 12:02:55 +01003936 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003937 __ jmp(&done);
3938
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003939 __ bind(&runtime);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003940 __ push(eax);
3941 __ CallRuntime(Runtime::kCall, args->length());
3942 __ bind(&done);
3943
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003944 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003945}
3946
3947
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003948void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01003949 // Load the arguments on the stack and call the stub.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003950 RegExpConstructResultStub stub(isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003951 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003952 DCHECK(args->length() == 3);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003953 VisitForStackValue(args->at(0));
3954 VisitForStackValue(args->at(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003955 VisitForAccumulatorValue(args->at(2));
3956 __ pop(ebx);
3957 __ pop(ecx);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003958 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003959 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003960}
3961
3962
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003963void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
3964 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003965 DCHECK_EQ(2, args->length());
Leon Clarkef7060e22010-06-03 12:02:55 +01003966
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003967 DCHECK_NE(NULL, args->at(0)->AsLiteral());
3968 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003969
3970 Handle<FixedArray> jsfunction_result_caches(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003971 isolate()->native_context()->jsfunction_result_caches());
Leon Clarkef7060e22010-06-03 12:02:55 +01003972 if (jsfunction_result_caches->length() <= cache_id) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003973 __ Abort(kAttemptToUseUndefinedCache);
Steve Block44f0eee2011-05-26 01:26:41 +01003974 __ mov(eax, isolate()->factory()->undefined_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003975 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01003976 return;
3977 }
3978
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003979 VisitForAccumulatorValue(args->at(1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003980
3981 Register key = eax;
3982 Register cache = ebx;
3983 Register tmp = ecx;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003984 __ mov(cache, ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX));
Leon Clarkef7060e22010-06-03 12:02:55 +01003985 __ mov(cache,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003986 FieldOperand(cache, GlobalObject::kNativeContextOffset));
Steve Block59151502010-09-22 15:07:15 +01003987 __ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
Leon Clarkef7060e22010-06-03 12:02:55 +01003988 __ mov(cache,
3989 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3990
3991 Label done, not_found;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003992 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
Leon Clarkef7060e22010-06-03 12:02:55 +01003993 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003994 // tmp now holds finger offset as a smi.
3995 __ cmp(key, FixedArrayElementOperand(cache, tmp));
Leon Clarkef7060e22010-06-03 12:02:55 +01003996 __ j(not_equal, &not_found);
3997
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003998 __ mov(eax, FixedArrayElementOperand(cache, tmp, 1));
Leon Clarkef7060e22010-06-03 12:02:55 +01003999 __ jmp(&done);
4000
4001 __ bind(&not_found);
4002 // Call runtime to perform the lookup.
4003 __ push(cache);
4004 __ push(key);
4005 __ CallRuntime(Runtime::kGetFromCache, 2);
4006
4007 __ bind(&done);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004008 context()->Plug(eax);
Leon Clarkef7060e22010-06-03 12:02:55 +01004009}
4010
4011
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004012void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
4013 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004014 DCHECK(args->length() == 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004015
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004016 VisitForAccumulatorValue(args->at(0));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004017
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004018 __ AssertString(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004019
4020 Label materialize_true, materialize_false;
4021 Label* if_true = NULL;
4022 Label* if_false = NULL;
4023 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004024 context()->PrepareTest(&materialize_true, &materialize_false,
4025 &if_true, &if_false, &fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004026
4027 __ test(FieldOperand(eax, String::kHashFieldOffset),
4028 Immediate(String::kContainsCachedArrayIndexMask));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004029 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004030 Split(zero, if_true, if_false, fall_through);
4031
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004032 context()->Plug(if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004033}
4034
4035
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004036void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
4037 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004038 DCHECK(args->length() == 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004039 VisitForAccumulatorValue(args->at(0));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004040
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004041 __ AssertString(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004042
4043 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
4044 __ IndexFromHash(eax, eax);
4045
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004046 context()->Plug(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004047}
4048
4049
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004050void FullCodeGenerator::EmitFastOneByteArrayJoin(CallRuntime* expr) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01004051 Label bailout, done, one_char_separator, long_separator,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004052 non_trivial_array, not_size_one_array, loop,
Ben Murdochb8e0da22011-05-16 14:20:40 +01004053 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004054
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004055 ZoneList<Expression*>* args = expr->arguments();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004056 DCHECK(args->length() == 2);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004057 // We will leave the separator on the stack until the end of the function.
4058 VisitForStackValue(args->at(1));
4059 // Load this to eax (= array)
4060 VisitForAccumulatorValue(args->at(0));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004061 // All aliases of the same register have disjoint lifetimes.
4062 Register array = eax;
Ben Murdochb8e0da22011-05-16 14:20:40 +01004063 Register elements = no_reg; // Will be eax.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004064
Ben Murdochb8e0da22011-05-16 14:20:40 +01004065 Register index = edx;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004066
Ben Murdochb8e0da22011-05-16 14:20:40 +01004067 Register string_length = ecx;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004068
Ben Murdochb8e0da22011-05-16 14:20:40 +01004069 Register string = esi;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004070
4071 Register scratch = ebx;
4072
Ben Murdochb8e0da22011-05-16 14:20:40 +01004073 Register array_length = edi;
4074 Register result_pos = no_reg; // Will be edi.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004075
Ben Murdochb8e0da22011-05-16 14:20:40 +01004076 // Separator operand is already pushed.
4077 Operand separator_operand = Operand(esp, 2 * kPointerSize);
4078 Operand result_operand = Operand(esp, 1 * kPointerSize);
4079 Operand array_length_operand = Operand(esp, 0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004080 __ sub(esp, Immediate(2 * kPointerSize));
Ben Murdochb8e0da22011-05-16 14:20:40 +01004081 __ cld();
4082 // Check that the array is a JSArray
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004083 __ JumpIfSmi(array, &bailout);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004084 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
4085 __ j(not_equal, &bailout);
4086
4087 // Check that the array has fast elements.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004088 __ CheckFastElements(scratch, &bailout);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004089
Ben Murdochb8e0da22011-05-16 14:20:40 +01004090 // If the array has length zero, return the empty string.
4091 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004092 __ SmiUntag(array_length);
Ben Murdochb8e0da22011-05-16 14:20:40 +01004093 __ j(not_zero, &non_trivial_array);
Steve Block44f0eee2011-05-26 01:26:41 +01004094 __ mov(result_operand, isolate()->factory()->empty_string());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004095 __ jmp(&done);
4096
Ben Murdochb8e0da22011-05-16 14:20:40 +01004097 // Save the array length.
4098 __ bind(&non_trivial_array);
4099 __ mov(array_length_operand, array_length);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004100
Ben Murdochb8e0da22011-05-16 14:20:40 +01004101 // Save the FixedArray containing array's elements.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004102 // End of array's live range.
Ben Murdochb8e0da22011-05-16 14:20:40 +01004103 elements = array;
4104 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004105 array = no_reg;
4106
4107
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004108 // Check that all array elements are sequential one-byte strings, and
Ben Murdochb8e0da22011-05-16 14:20:40 +01004109 // accumulate the sum of their lengths, as a smi-encoded value.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004110 __ Move(index, Immediate(0));
4111 __ Move(string_length, Immediate(0));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004112 // Loop condition: while (index < length).
Ben Murdochb8e0da22011-05-16 14:20:40 +01004113 // Live loop registers: index, array_length, string,
4114 // scratch, string_length, elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004115 if (generate_debug_code_) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004116 __ cmp(index, array_length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004117 __ Assert(less, kNoEmptyArraysHereInEmitFastOneByteArrayJoin);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004118 }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004119 __ bind(&loop);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004120 __ mov(string, FieldOperand(elements,
4121 index,
4122 times_pointer_size,
4123 FixedArray::kHeaderSize));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004124 __ JumpIfSmi(string, &bailout);
Ben Murdochb8e0da22011-05-16 14:20:40 +01004125 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
4126 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
4127 __ and_(scratch, Immediate(
4128 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004129 __ cmp(scratch, kStringTag | kOneByteStringTag | kSeqStringTag);
Ben Murdochb8e0da22011-05-16 14:20:40 +01004130 __ j(not_equal, &bailout);
4131 __ add(string_length,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004132 FieldOperand(string, SeqOneByteString::kLengthOffset));
Ben Murdochb8e0da22011-05-16 14:20:40 +01004133 __ j(overflow, &bailout);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004134 __ add(index, Immediate(1));
4135 __ cmp(index, array_length);
Ben Murdochb8e0da22011-05-16 14:20:40 +01004136 __ j(less, &loop);
4137
4138 // If array_length is 1, return elements[0], a string.
4139 __ cmp(array_length, 1);
4140 __ j(not_equal, &not_size_one_array);
4141 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize));
4142 __ mov(result_operand, scratch);
4143 __ jmp(&done);
4144
4145 __ bind(&not_size_one_array);
4146
4147 // End of array_length live range.
4148 result_pos = array_length;
4149 array_length = no_reg;
4150
4151 // Live registers:
4152 // string_length: Sum of string lengths, as a smi.
4153 // elements: FixedArray of strings.
4154
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004155 // Check that the separator is a flat one-byte string.
Ben Murdochb8e0da22011-05-16 14:20:40 +01004156 __ mov(string, separator_operand);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004157 __ JumpIfSmi(string, &bailout);
Ben Murdochb8e0da22011-05-16 14:20:40 +01004158 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
4159 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004160 __ and_(scratch, Immediate(
4161 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004162 __ cmp(scratch, kStringTag | kOneByteStringTag | kSeqStringTag);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004163 __ j(not_equal, &bailout);
4164
Ben Murdochb8e0da22011-05-16 14:20:40 +01004165 // Add (separator length times array_length) - separator length
4166 // to string_length.
4167 __ mov(scratch, separator_operand);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004168 __ mov(scratch, FieldOperand(scratch, SeqOneByteString::kLengthOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004169 __ sub(string_length, scratch); // May be negative, temporarily.
Ben Murdochb8e0da22011-05-16 14:20:40 +01004170 __ imul(scratch, array_length_operand);
4171 __ j(overflow, &bailout);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004172 __ add(string_length, scratch);
Ben Murdochb8e0da22011-05-16 14:20:40 +01004173 __ j(overflow, &bailout);
4174
4175 __ shr(string_length, 1);
4176 // Live registers and stack values:
4177 // string_length
4178 // elements
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004179 __ AllocateOneByteString(result_pos, string_length, scratch, index, string,
4180 &bailout);
Ben Murdochb8e0da22011-05-16 14:20:40 +01004181 __ mov(result_operand, result_pos);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004182 __ lea(result_pos, FieldOperand(result_pos, SeqOneByteString::kHeaderSize));
Ben Murdochb8e0da22011-05-16 14:20:40 +01004183
4184
4185 __ mov(string, separator_operand);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004186 __ cmp(FieldOperand(string, SeqOneByteString::kLengthOffset),
Ben Murdochb8e0da22011-05-16 14:20:40 +01004187 Immediate(Smi::FromInt(1)));
4188 __ j(equal, &one_char_separator);
4189 __ j(greater, &long_separator);
4190
4191
4192 // Empty separator case
4193 __ mov(index, Immediate(0));
4194 __ jmp(&loop_1_condition);
4195 // Loop condition: while (index < length).
4196 __ bind(&loop_1);
4197 // Each iteration of the loop concatenates one string to the result.
4198 // Live values in registers:
4199 // index: which element of the elements array we are adding to the result.
4200 // result_pos: the position to which we are currently copying characters.
4201 // elements: the FixedArray of strings we are joining.
4202
4203 // Get string = array[index].
4204 __ mov(string, FieldOperand(elements, index,
4205 times_pointer_size,
4206 FixedArray::kHeaderSize));
4207 __ mov(string_length,
4208 FieldOperand(string, String::kLengthOffset));
4209 __ shr(string_length, 1);
4210 __ lea(string,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004211 FieldOperand(string, SeqOneByteString::kHeaderSize));
Ben Murdochb8e0da22011-05-16 14:20:40 +01004212 __ CopyBytes(string, result_pos, string_length, scratch);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004213 __ add(index, Immediate(1));
Ben Murdochb8e0da22011-05-16 14:20:40 +01004214 __ bind(&loop_1_condition);
4215 __ cmp(index, array_length_operand);
4216 __ j(less, &loop_1); // End while (index < length).
4217 __ jmp(&done);
4218
4219
4220
4221 // One-character separator case
4222 __ bind(&one_char_separator);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004223 // Replace separator with its one-byte character value.
4224 __ mov_b(scratch, FieldOperand(string, SeqOneByteString::kHeaderSize));
Ben Murdochb8e0da22011-05-16 14:20:40 +01004225 __ mov_b(separator_operand, scratch);
4226
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004227 __ Move(index, Immediate(0));
Ben Murdochb8e0da22011-05-16 14:20:40 +01004228 // Jump into the loop after the code that copies the separator, so the first
4229 // element is not preceded by a separator
4230 __ jmp(&loop_2_entry);
4231 // Loop condition: while (index < length).
4232 __ bind(&loop_2);
4233 // Each iteration of the loop concatenates one string to the result.
4234 // Live values in registers:
4235 // index: which element of the elements array we are adding to the result.
4236 // result_pos: the position to which we are currently copying characters.
4237
4238 // Copy the separator character to the result.
4239 __ mov_b(scratch, separator_operand);
4240 __ mov_b(Operand(result_pos, 0), scratch);
4241 __ inc(result_pos);
4242
4243 __ bind(&loop_2_entry);
4244 // Get string = array[index].
4245 __ mov(string, FieldOperand(elements, index,
4246 times_pointer_size,
4247 FixedArray::kHeaderSize));
4248 __ mov(string_length,
4249 FieldOperand(string, String::kLengthOffset));
4250 __ shr(string_length, 1);
4251 __ lea(string,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004252 FieldOperand(string, SeqOneByteString::kHeaderSize));
Ben Murdochb8e0da22011-05-16 14:20:40 +01004253 __ CopyBytes(string, result_pos, string_length, scratch);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004254 __ add(index, Immediate(1));
Ben Murdochb8e0da22011-05-16 14:20:40 +01004255
4256 __ cmp(index, array_length_operand);
4257 __ j(less, &loop_2); // End while (index < length).
4258 __ jmp(&done);
4259
4260
4261 // Long separator case (separator is more than one character).
4262 __ bind(&long_separator);
4263
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004264 __ Move(index, Immediate(0));
Ben Murdochb8e0da22011-05-16 14:20:40 +01004265 // Jump into the loop after the code that copies the separator, so the first
4266 // element is not preceded by a separator
4267 __ jmp(&loop_3_entry);
4268 // Loop condition: while (index < length).
4269 __ bind(&loop_3);
4270 // Each iteration of the loop concatenates one string to the result.
4271 // Live values in registers:
4272 // index: which element of the elements array we are adding to the result.
4273 // result_pos: the position to which we are currently copying characters.
4274
4275 // Copy the separator to the result.
4276 __ mov(string, separator_operand);
4277 __ mov(string_length,
4278 FieldOperand(string, String::kLengthOffset));
4279 __ shr(string_length, 1);
4280 __ lea(string,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004281 FieldOperand(string, SeqOneByteString::kHeaderSize));
Ben Murdochb8e0da22011-05-16 14:20:40 +01004282 __ CopyBytes(string, result_pos, string_length, scratch);
4283
4284 __ bind(&loop_3_entry);
4285 // Get string = array[index].
4286 __ mov(string, FieldOperand(elements, index,
4287 times_pointer_size,
4288 FixedArray::kHeaderSize));
4289 __ mov(string_length,
4290 FieldOperand(string, String::kLengthOffset));
4291 __ shr(string_length, 1);
4292 __ lea(string,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004293 FieldOperand(string, SeqOneByteString::kHeaderSize));
Ben Murdochb8e0da22011-05-16 14:20:40 +01004294 __ CopyBytes(string, result_pos, string_length, scratch);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004295 __ add(index, Immediate(1));
Ben Murdochb8e0da22011-05-16 14:20:40 +01004296
4297 __ cmp(index, array_length_operand);
4298 __ j(less, &loop_3); // End while (index < length).
4299 __ jmp(&done);
4300
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004301
4302 __ bind(&bailout);
Steve Block44f0eee2011-05-26 01:26:41 +01004303 __ mov(result_operand, isolate()->factory()->undefined_value());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004304 __ bind(&done);
Ben Murdochb8e0da22011-05-16 14:20:40 +01004305 __ mov(eax, result_operand);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004306 // Drop temp values from the stack, and restore context register.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004307 __ add(esp, Immediate(3 * kPointerSize));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004308
4309 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4310 context()->Plug(eax);
4311}
4312
4313
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004314void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
4315 DCHECK(expr->arguments()->length() == 0);
4316 ExternalReference debug_is_active =
4317 ExternalReference::debug_is_active_address(isolate());
4318 __ movzx_b(eax, Operand::StaticVariable(debug_is_active));
4319 __ SmiTag(eax);
4320 context()->Plug(eax);
4321}
4322
4323
Leon Clarked91b9f72010-01-27 17:25:45 +00004324void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004325 if (expr->function() != NULL &&
4326 expr->function()->intrinsic_type == Runtime::INLINE) {
Leon Clarkef7060e22010-06-03 12:02:55 +01004327 Comment cmnt(masm_, "[ InlineRuntimeCall");
4328 EmitInlineRuntimeCall(expr);
4329 return;
4330 }
4331
Steve Block3ce2e202009-11-05 08:53:23 +00004332 Comment cmnt(masm_, "[ CallRuntime");
4333 ZoneList<Expression*>* args = expr->arguments();
Steve Block3ce2e202009-11-05 08:53:23 +00004334
Steve Blockd0582a62009-12-15 09:54:21 +00004335 if (expr->is_jsruntime()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004336 // Push the builtins object as receiver.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08004337 __ mov(eax, GlobalObjectOperand());
Steve Blockd0582a62009-12-15 09:54:21 +00004338 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
Steve Block3ce2e202009-11-05 08:53:23 +00004339
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004340 // Load the function from the receiver.
4341 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
4342 __ mov(LoadDescriptor::NameRegister(), Immediate(expr->name()));
4343 if (FLAG_vector_ics) {
4344 __ mov(VectorLoadICDescriptor::SlotRegister(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004345 Immediate(SmiFromSlot(expr->CallRuntimeFeedbackSlot())));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004346 CallLoadIC(NOT_CONTEXTUAL);
4347 } else {
4348 CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
4349 }
Steve Block3ce2e202009-11-05 08:53:23 +00004350
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004351 // Push the target function under the receiver.
4352 __ push(Operand(esp, 0));
4353 __ mov(Operand(esp, kPointerSize), eax);
4354
4355 // Code common for calls using the IC.
4356 ZoneList<Expression*>* args = expr->arguments();
4357 int arg_count = args->length();
4358 for (int i = 0; i < arg_count; i++) {
4359 VisitForStackValue(args->at(i));
4360 }
4361
4362 // Record source position of the IC call.
4363 SetSourcePosition(expr->position());
4364 CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
4365 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
4366 __ CallStub(&stub);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004367 // Restore context register.
Steve Blockd0582a62009-12-15 09:54:21 +00004368 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004369 context()->DropAndPlug(1, eax);
4370
Steve Block3ce2e202009-11-05 08:53:23 +00004371 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004372 // Push the arguments ("left-to-right").
4373 int arg_count = args->length();
4374 for (int i = 0; i < arg_count; i++) {
4375 VisitForStackValue(args->at(i));
4376 }
4377
Steve Blockd0582a62009-12-15 09:54:21 +00004378 // Call the C runtime function.
4379 __ CallRuntime(expr->function(), arg_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004380
4381 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00004382 }
4383}
4384
4385
Leon Clarked91b9f72010-01-27 17:25:45 +00004386void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00004387 switch (expr->op()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01004388 case Token::DELETE: {
4389 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
Ben Murdoch589d6972011-11-30 16:04:58 +00004390 Property* property = expr->expression()->AsProperty();
4391 VariableProxy* proxy = expr->expression()->AsVariableProxy();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004392
Ben Murdoch589d6972011-11-30 16:04:58 +00004393 if (property != NULL) {
4394 VisitForStackValue(property->obj());
4395 VisitForStackValue(property->key());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004396 __ push(Immediate(Smi::FromInt(strict_mode())));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004397 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004398 context()->Plug(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00004399 } else if (proxy != NULL) {
4400 Variable* var = proxy->var();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004401 // Delete of an unqualified identifier is disallowed in strict mode
Ben Murdoch589d6972011-11-30 16:04:58 +00004402 // but "delete this" is allowed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004403 DCHECK(strict_mode() == SLOPPY || var->is_this());
Ben Murdoch589d6972011-11-30 16:04:58 +00004404 if (var->IsUnallocated()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004405 __ push(GlobalObjectOperand());
4406 __ push(Immediate(var->name()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004407 __ push(Immediate(Smi::FromInt(SLOPPY)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004408 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
4409 context()->Plug(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00004410 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
4411 // Result of deleting non-global variables is false. 'this' is
4412 // not really a variable, though we implement it as one. The
4413 // subexpression does not have side effects.
4414 context()->Plug(var->is_this());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004415 } else {
4416 // Non-global variable. Call the runtime to try to delete from the
4417 // context where the variable was introduced.
4418 __ push(context_register());
4419 __ push(Immediate(var->name()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004420 __ CallRuntime(Runtime::kDeleteLookupSlot, 2);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004421 context()->Plug(eax);
4422 }
Steve Block1e0659c2011-05-24 12:43:12 +01004423 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004424 // Result of deleting non-property, non-variable reference is true.
4425 // The subexpression may have side effects.
4426 VisitForEffect(expr->expression());
4427 context()->Plug(true);
Leon Clarkef7060e22010-06-03 12:02:55 +01004428 }
4429 break;
4430 }
4431
Steve Blockd0582a62009-12-15 09:54:21 +00004432 case Token::VOID: {
4433 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
Leon Clarkee46be812010-01-19 14:06:41 +00004434 VisitForEffect(expr->expression());
Steve Block44f0eee2011-05-26 01:26:41 +01004435 context()->Plug(isolate()->factory()->undefined_value());
Steve Blockd0582a62009-12-15 09:54:21 +00004436 break;
4437 }
4438
4439 case Token::NOT: {
4440 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004441 if (context()->IsEffect()) {
4442 // Unary NOT has no side effects so it's only necessary to visit the
4443 // subexpression. Match the optimizing compiler by not branching.
4444 VisitForEffect(expr->expression());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004445 } else if (context()->IsTest()) {
4446 const TestContext* test = TestContext::cast(context());
4447 // The labels are swapped for the recursive call.
4448 VisitForControl(expr->expression(),
4449 test->false_label(),
4450 test->true_label(),
4451 test->fall_through());
4452 context()->Plug(test->true_label(), test->false_label());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004453 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004454 // We handle value contexts explicitly rather than simply visiting
4455 // for control and plugging the control flow into the context,
4456 // because we need to prepare a pair of extra administrative AST ids
4457 // for the optimizing compiler.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004458 DCHECK(context()->IsAccumulatorValue() || context()->IsStackValue());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004459 Label materialize_true, materialize_false, done;
4460 VisitForControl(expr->expression(),
4461 &materialize_false,
4462 &materialize_true,
4463 &materialize_true);
4464 __ bind(&materialize_true);
4465 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
4466 if (context()->IsAccumulatorValue()) {
4467 __ mov(eax, isolate()->factory()->true_value());
4468 } else {
4469 __ Push(isolate()->factory()->true_value());
4470 }
4471 __ jmp(&done, Label::kNear);
4472 __ bind(&materialize_false);
4473 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
4474 if (context()->IsAccumulatorValue()) {
4475 __ mov(eax, isolate()->factory()->false_value());
4476 } else {
4477 __ Push(isolate()->factory()->false_value());
4478 }
4479 __ bind(&done);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004480 }
Steve Blockd0582a62009-12-15 09:54:21 +00004481 break;
4482 }
4483
4484 case Token::TYPEOF: {
4485 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004486 { StackValueContext context(this);
4487 VisitForTypeofValue(expr->expression());
4488 }
Steve Blockd0582a62009-12-15 09:54:21 +00004489 __ CallRuntime(Runtime::kTypeof, 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004490 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00004491 break;
4492 }
4493
4494 default:
4495 UNREACHABLE();
4496 }
4497}
4498
4499
Leon Clarked91b9f72010-01-27 17:25:45 +00004500void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004501 DCHECK(expr->expression()->IsValidReferenceExpression());
4502
Steve Blockd0582a62009-12-15 09:54:21 +00004503 Comment cmnt(masm_, "[ CountOperation");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004504 SetSourcePosition(expr->position());
4505
Leon Clarkee46be812010-01-19 14:06:41 +00004506 Property* prop = expr->expression()->AsProperty();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004507 LhsKind assign_type = GetAssignType(prop);
Leon Clarkee46be812010-01-19 14:06:41 +00004508
4509 // Evaluate expression and get value.
4510 if (assign_type == VARIABLE) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004511 DCHECK(expr->expression()->AsVariableProxy()->var() != NULL);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004512 AccumulatorValueContext context(this);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004513 EmitVariableLoad(expr->expression()->AsVariableProxy());
Leon Clarkef7060e22010-06-03 12:02:55 +01004514 } else {
Leon Clarkee46be812010-01-19 14:06:41 +00004515 // Reserve space for result of postfix operation.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004516 if (expr->is_postfix() && !context()->IsEffect()) {
Leon Clarkee46be812010-01-19 14:06:41 +00004517 __ push(Immediate(Smi::FromInt(0)));
4518 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004519 switch (assign_type) {
4520 case NAMED_PROPERTY: {
4521 // Put the object both on the stack and in the register.
4522 VisitForStackValue(prop->obj());
4523 __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
4524 EmitNamedPropertyLoad(prop);
4525 break;
4526 }
4527
4528 case NAMED_SUPER_PROPERTY: {
4529 VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
4530 EmitLoadHomeObject(prop->obj()->AsSuperReference());
4531 __ push(result_register());
4532 __ push(MemOperand(esp, kPointerSize));
4533 __ push(result_register());
4534 EmitNamedSuperPropertyLoad(prop);
4535 break;
4536 }
4537
4538 case KEYED_SUPER_PROPERTY: {
4539 VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
4540 EmitLoadHomeObject(prop->obj()->AsSuperReference());
4541 __ push(result_register());
4542 VisitForAccumulatorValue(prop->key());
4543 __ push(result_register());
4544 __ push(MemOperand(esp, 2 * kPointerSize));
4545 __ push(MemOperand(esp, 2 * kPointerSize));
4546 __ push(result_register());
4547 EmitKeyedSuperPropertyLoad(prop);
4548 break;
4549 }
4550
4551 case KEYED_PROPERTY: {
4552 VisitForStackValue(prop->obj());
4553 VisitForStackValue(prop->key());
4554 __ mov(LoadDescriptor::ReceiverRegister(),
4555 Operand(esp, kPointerSize)); // Object.
4556 __ mov(LoadDescriptor::NameRegister(), Operand(esp, 0)); // Key.
4557 EmitKeyedPropertyLoad(prop);
4558 break;
4559 }
4560
4561 case VARIABLE:
4562 UNREACHABLE();
Leon Clarkee46be812010-01-19 14:06:41 +00004563 }
Leon Clarkee46be812010-01-19 14:06:41 +00004564 }
4565
Ben Murdochb0fe1622011-05-05 13:52:32 +01004566 // We need a second deoptimization point after loading the value
4567 // in case evaluating the property load my have a side effect.
Ben Murdoch8b112d22011-06-08 16:22:53 +01004568 if (assign_type == VARIABLE) {
4569 PrepareForBailout(expr->expression(), TOS_REG);
4570 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004571 PrepareForBailoutForId(prop->LoadId(), TOS_REG);
Ben Murdoch8b112d22011-06-08 16:22:53 +01004572 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01004573
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004574 // Inline smi case if we are in a loop.
4575 Label done, stub_call;
4576 JumpPatchSite patch_site(masm_);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004577 if (ShouldInlineSmiCase(expr->op())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004578 Label slow;
4579 patch_site.EmitJumpIfNotSmi(eax, &slow, Label::kNear);
4580
4581 // Save result for postfix expressions.
4582 if (expr->is_postfix()) {
4583 if (!context()->IsEffect()) {
4584 // Save the result on the stack. If we have a named or keyed property
4585 // we store the result under the receiver that is currently on top
4586 // of the stack.
4587 switch (assign_type) {
4588 case VARIABLE:
4589 __ push(eax);
4590 break;
4591 case NAMED_PROPERTY:
4592 __ mov(Operand(esp, kPointerSize), eax);
4593 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004594 case NAMED_SUPER_PROPERTY:
4595 __ mov(Operand(esp, 2 * kPointerSize), eax);
4596 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004597 case KEYED_PROPERTY:
4598 __ mov(Operand(esp, 2 * kPointerSize), eax);
4599 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004600 case KEYED_SUPER_PROPERTY:
4601 __ mov(Operand(esp, 3 * kPointerSize), eax);
4602 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004603 }
4604 }
4605 }
4606
4607 if (expr->op() == Token::INC) {
4608 __ add(eax, Immediate(Smi::FromInt(1)));
4609 } else {
4610 __ sub(eax, Immediate(Smi::FromInt(1)));
4611 }
4612 __ j(no_overflow, &done, Label::kNear);
4613 // Call stub. Undo operation first.
4614 if (expr->op() == Token::INC) {
4615 __ sub(eax, Immediate(Smi::FromInt(1)));
4616 } else {
4617 __ add(eax, Immediate(Smi::FromInt(1)));
4618 }
4619 __ jmp(&stub_call, Label::kNear);
4620 __ bind(&slow);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004621 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004622 ToNumberStub convert_stub(isolate());
Steve Block1e0659c2011-05-24 12:43:12 +01004623 __ CallStub(&convert_stub);
Steve Blockd0582a62009-12-15 09:54:21 +00004624
Leon Clarkee46be812010-01-19 14:06:41 +00004625 // Save result for postfix expressions.
4626 if (expr->is_postfix()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004627 if (!context()->IsEffect()) {
4628 // Save the result on the stack. If we have a named or keyed property
4629 // we store the result under the receiver that is currently on top
4630 // of the stack.
4631 switch (assign_type) {
4632 case VARIABLE:
4633 __ push(eax);
4634 break;
4635 case NAMED_PROPERTY:
4636 __ mov(Operand(esp, kPointerSize), eax);
4637 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004638 case NAMED_SUPER_PROPERTY:
4639 __ mov(Operand(esp, 2 * kPointerSize), eax);
4640 break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004641 case KEYED_PROPERTY:
4642 __ mov(Operand(esp, 2 * kPointerSize), eax);
4643 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004644 case KEYED_SUPER_PROPERTY:
4645 __ mov(Operand(esp, 3 * kPointerSize), eax);
4646 break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004647 }
Leon Clarkee46be812010-01-19 14:06:41 +00004648 }
Steve Blockd0582a62009-12-15 09:54:21 +00004649 }
Leon Clarkee46be812010-01-19 14:06:41 +00004650
Ben Murdochb0fe1622011-05-05 13:52:32 +01004651 // Record position before stub call.
4652 SetSourcePosition(expr->position());
4653
Leon Clarkee46be812010-01-19 14:06:41 +00004654 // Call stub for +1/-1.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004655 __ bind(&stub_call);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004656 __ mov(edx, eax);
4657 __ mov(eax, Immediate(Smi::FromInt(1)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004658 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), expr->binary_op(),
4659 NO_OVERWRITE).code();
4660 CallIC(code, expr->CountBinOpFeedbackId());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004661 patch_site.EmitPatchInfo();
Leon Clarked91b9f72010-01-27 17:25:45 +00004662 __ bind(&done);
Steve Blockd0582a62009-12-15 09:54:21 +00004663
Leon Clarkee46be812010-01-19 14:06:41 +00004664 // Store the value returned in eax.
4665 switch (assign_type) {
4666 case VARIABLE:
4667 if (expr->is_postfix()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01004668 // Perform the assignment as if via '='.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004669 { EffectContext context(this);
4670 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4671 Token::ASSIGN);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004672 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4673 context.Plug(eax);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004674 }
4675 // For all contexts except EffectContext We have the result on
Leon Clarkee46be812010-01-19 14:06:41 +00004676 // top of the stack.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004677 if (!context()->IsEffect()) {
4678 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00004679 }
4680 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01004681 // Perform the assignment as if via '='.
Leon Clarkee46be812010-01-19 14:06:41 +00004682 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004683 Token::ASSIGN);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004684 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4685 context()->Plug(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00004686 }
Steve Blockd0582a62009-12-15 09:54:21 +00004687 break;
Leon Clarkee46be812010-01-19 14:06:41 +00004688 case NAMED_PROPERTY: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004689 __ mov(StoreDescriptor::NameRegister(),
4690 prop->key()->AsLiteral()->value());
4691 __ pop(StoreDescriptor::ReceiverRegister());
4692 CallStoreIC(expr->CountStoreFeedbackId());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004693 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Leon Clarkee46be812010-01-19 14:06:41 +00004694 if (expr->is_postfix()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004695 if (!context()->IsEffect()) {
4696 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00004697 }
4698 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004699 context()->Plug(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00004700 }
Steve Blockd0582a62009-12-15 09:54:21 +00004701 break;
4702 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004703 case NAMED_SUPER_PROPERTY: {
4704 EmitNamedSuperPropertyStore(prop);
4705 if (expr->is_postfix()) {
4706 if (!context()->IsEffect()) {
4707 context()->PlugTOS();
4708 }
4709 } else {
4710 context()->Plug(eax);
4711 }
4712 break;
4713 }
4714 case KEYED_SUPER_PROPERTY: {
4715 EmitKeyedSuperPropertyStore(prop);
4716 if (expr->is_postfix()) {
4717 if (!context()->IsEffect()) {
4718 context()->PlugTOS();
4719 }
4720 } else {
4721 context()->Plug(eax);
4722 }
4723 break;
4724 }
Leon Clarkee46be812010-01-19 14:06:41 +00004725 case KEYED_PROPERTY: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004726 __ pop(StoreDescriptor::NameRegister());
4727 __ pop(StoreDescriptor::ReceiverRegister());
4728 Handle<Code> ic =
4729 CodeFactory::KeyedStoreIC(isolate(), strict_mode()).code();
4730 CallIC(ic, expr->CountStoreFeedbackId());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004731 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
Leon Clarkee46be812010-01-19 14:06:41 +00004732 if (expr->is_postfix()) {
Steve Block6ded16b2010-05-10 14:33:55 +01004733 // Result is on the stack
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004734 if (!context()->IsEffect()) {
4735 context()->PlugTOS();
Leon Clarkee46be812010-01-19 14:06:41 +00004736 }
4737 } else {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004738 context()->Plug(eax);
Leon Clarkee46be812010-01-19 14:06:41 +00004739 }
Steve Blockd0582a62009-12-15 09:54:21 +00004740 break;
4741 }
Steve Block3ce2e202009-11-05 08:53:23 +00004742 }
4743}
4744
4745
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004746void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004747 VariableProxy* proxy = expr->AsVariableProxy();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004748 DCHECK(!context()->IsEffect());
4749 DCHECK(!context()->IsTest());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004750
Ben Murdoch589d6972011-11-30 16:04:58 +00004751 if (proxy != NULL && proxy->var()->IsUnallocated()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004752 Comment cmnt(masm_, "[ Global variable");
4753 __ mov(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
4754 __ mov(LoadDescriptor::NameRegister(), Immediate(proxy->name()));
4755 if (FLAG_vector_ics) {
4756 __ mov(VectorLoadICDescriptor::SlotRegister(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004757 Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004758 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004759 // Use a regular load, not a contextual load, to avoid a reference
4760 // error.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004761 CallLoadIC(NOT_CONTEXTUAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004762 PrepareForBailout(expr, TOS_REG);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004763 context()->Plug(eax);
Ben Murdoch589d6972011-11-30 16:04:58 +00004764 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004765 Comment cmnt(masm_, "[ Lookup slot");
Steve Block59151502010-09-22 15:07:15 +01004766 Label done, slow;
4767
4768 // Generate code for loading from variables potentially shadowed
4769 // by eval-introduced variables.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004770 EmitDynamicLookupFastCase(proxy, INSIDE_TYPEOF, &slow, &done);
Steve Block59151502010-09-22 15:07:15 +01004771
4772 __ bind(&slow);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004773 __ push(esi);
4774 __ push(Immediate(proxy->name()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004775 __ CallRuntime(Runtime::kLoadLookupSlotNoReferenceError, 2);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004776 PrepareForBailout(expr, TOS_REG);
Steve Block59151502010-09-22 15:07:15 +01004777 __ bind(&done);
4778
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004779 context()->Plug(eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004780 } else {
4781 // This expression cannot throw a reference error at the top level.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004782 VisitInDuplicateContext(expr);
Steve Block3ce2e202009-11-05 08:53:23 +00004783 }
Steve Block3ce2e202009-11-05 08:53:23 +00004784}
4785
4786
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004787void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004788 Expression* sub_expr,
4789 Handle<String> check) {
4790 Label materialize_true, materialize_false;
4791 Label* if_true = NULL;
4792 Label* if_false = NULL;
4793 Label* fall_through = NULL;
4794 context()->PrepareTest(&materialize_true, &materialize_false,
4795 &if_true, &if_false, &fall_through);
4796
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004797 { AccumulatorValueContext context(this);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004798 VisitForTypeofValue(sub_expr);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004799 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004800 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004801
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004802 Factory* factory = isolate()->factory();
4803 if (String::Equals(check, factory->number_string())) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004804 __ JumpIfSmi(eax, if_true);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004805 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
Steve Block44f0eee2011-05-26 01:26:41 +01004806 isolate()->factory()->heap_number_map());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004807 Split(equal, if_true, if_false, fall_through);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004808 } else if (String::Equals(check, factory->string_string())) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004809 __ JumpIfSmi(eax, if_false);
4810 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
4811 __ j(above_equal, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004812 // Check for undetectable objects => false.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004813 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
4814 1 << Map::kIsUndetectable);
4815 Split(zero, if_true, if_false, fall_through);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004816 } else if (String::Equals(check, factory->symbol_string())) {
4817 __ JumpIfSmi(eax, if_false);
4818 __ CmpObjectType(eax, SYMBOL_TYPE, edx);
4819 Split(equal, if_true, if_false, fall_through);
4820 } else if (String::Equals(check, factory->boolean_string())) {
Steve Block44f0eee2011-05-26 01:26:41 +01004821 __ cmp(eax, isolate()->factory()->true_value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004822 __ j(equal, if_true);
Steve Block44f0eee2011-05-26 01:26:41 +01004823 __ cmp(eax, isolate()->factory()->false_value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004824 Split(equal, if_true, if_false, fall_through);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004825 } else if (String::Equals(check, factory->undefined_string())) {
Steve Block44f0eee2011-05-26 01:26:41 +01004826 __ cmp(eax, isolate()->factory()->undefined_value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004827 __ j(equal, if_true);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004828 __ JumpIfSmi(eax, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004829 // Check for undetectable objects => true.
4830 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4831 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
4832 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
4833 Split(not_zero, if_true, if_false, fall_through);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004834 } else if (String::Equals(check, factory->function_string())) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004835 __ JumpIfSmi(eax, if_false);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004836 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
4837 __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx);
4838 __ j(equal, if_true);
4839 __ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE);
4840 Split(equal, if_true, if_false, fall_through);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004841 } else if (String::Equals(check, factory->object_string())) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004842 __ JumpIfSmi(eax, if_false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004843 __ cmp(eax, isolate()->factory()->null_value());
4844 __ j(equal, if_true);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004845 __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004846 __ j(below, if_false);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004847 __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4848 __ j(above, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004849 // Check for undetectable objects => false.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004850 __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
4851 1 << Map::kIsUndetectable);
4852 Split(zero, if_true, if_false, fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004853 } else {
4854 if (if_false != fall_through) __ jmp(if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01004855 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004856 context()->Plug(if_true, if_false);
Leon Clarkef7060e22010-06-03 12:02:55 +01004857}
4858
4859
Leon Clarked91b9f72010-01-27 17:25:45 +00004860void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00004861 Comment cmnt(masm_, "[ CompareOperation");
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004862 SetSourcePosition(expr->position());
Steve Blockd0582a62009-12-15 09:54:21 +00004863
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004864 // First we try a fast inlined version of the compare when one of
4865 // the operands is a literal.
4866 if (TryLiteralCompare(expr)) return;
4867
Leon Clarkee46be812010-01-19 14:06:41 +00004868 // Always perform the comparison for its control flow. Pack the result
4869 // into the expression's context after the comparison is performed.
Leon Clarkef7060e22010-06-03 12:02:55 +01004870 Label materialize_true, materialize_false;
4871 Label* if_true = NULL;
4872 Label* if_false = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004873 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004874 context()->PrepareTest(&materialize_true, &materialize_false,
4875 &if_true, &if_false, &fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004876
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004877 Token::Value op = expr->op();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004878 VisitForStackValue(expr->left());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004879 switch (op) {
Leon Clarkee46be812010-01-19 14:06:41 +00004880 case Token::IN:
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004881 VisitForStackValue(expr->right());
Steve Blockd0582a62009-12-15 09:54:21 +00004882 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004883 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
Steve Block44f0eee2011-05-26 01:26:41 +01004884 __ cmp(eax, isolate()->factory()->true_value());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004885 Split(equal, if_true, if_false, fall_through);
Steve Blockd0582a62009-12-15 09:54:21 +00004886 break;
Steve Blockd0582a62009-12-15 09:54:21 +00004887
4888 case Token::INSTANCEOF: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004889 VisitForStackValue(expr->right());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004890 InstanceofStub stub(isolate(), InstanceofStub::kNoFlags);
Steve Blockd0582a62009-12-15 09:54:21 +00004891 __ CallStub(&stub);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004892 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4893 __ test(eax, eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004894 // The stub returns 0 for true.
4895 Split(zero, if_true, if_false, fall_through);
Steve Blockd0582a62009-12-15 09:54:21 +00004896 break;
4897 }
4898
4899 default: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004900 VisitForAccumulatorValue(expr->right());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004901 Condition cc = CompareIC::ComputeCondition(op);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004902 __ pop(edx);
Steve Blockd0582a62009-12-15 09:54:21 +00004903
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004904 bool inline_smi_code = ShouldInlineSmiCase(op);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004905 JumpPatchSite patch_site(masm_);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004906 if (inline_smi_code) {
Ben Murdoch257744e2011-11-30 15:57:28 +00004907 Label slow_case;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004908 __ mov(ecx, edx);
4909 __ or_(ecx, eax);
Ben Murdoch257744e2011-11-30 15:57:28 +00004910 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004911 __ cmp(edx, eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004912 Split(cc, if_true, if_false, NULL);
4913 __ bind(&slow_case);
4914 }
Steve Blockd0582a62009-12-15 09:54:21 +00004915
Ben Murdochb0fe1622011-05-05 13:52:32 +01004916 // Record position and call the compare IC.
4917 SetSourcePosition(expr->position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004918 Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
4919 CallIC(ic, expr->CompareOperationFeedbackId());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004920 patch_site.EmitPatchInfo();
Ben Murdochb0fe1622011-05-05 13:52:32 +01004921
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004922 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4923 __ test(eax, eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004924 Split(cc, if_true, if_false, fall_through);
Steve Blockd0582a62009-12-15 09:54:21 +00004925 }
4926 }
4927
Leon Clarkee46be812010-01-19 14:06:41 +00004928 // Convert the result of the comparison into one expected for this
4929 // expression's context.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004930 context()->Plug(if_true, if_false);
Steve Blockd0582a62009-12-15 09:54:21 +00004931}
4932
4933
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004934void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
4935 Expression* sub_expr,
4936 NilValue nil) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004937 Label materialize_true, materialize_false;
4938 Label* if_true = NULL;
4939 Label* if_false = NULL;
4940 Label* fall_through = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004941 context()->PrepareTest(&materialize_true, &materialize_false,
4942 &if_true, &if_false, &fall_through);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004943
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004944 VisitForAccumulatorValue(sub_expr);
4945 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004946
4947 Handle<Object> nil_value = nil == kNullValue
4948 ? isolate()->factory()->null_value()
4949 : isolate()->factory()->undefined_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004950 if (expr->op() == Token::EQ_STRICT) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004951 __ cmp(eax, nil_value);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004952 Split(equal, if_true, if_false, fall_through);
4953 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004954 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil);
4955 CallIC(ic, expr->CompareOperationFeedbackId());
4956 __ test(eax, eax);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004957 Split(not_zero, if_true, if_false, fall_through);
4958 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004959 context()->Plug(if_true, if_false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004960}
4961
4962
Leon Clarked91b9f72010-01-27 17:25:45 +00004963void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
Steve Blockd0582a62009-12-15 09:54:21 +00004964 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004965 context()->Plug(eax);
Steve Blockd0582a62009-12-15 09:54:21 +00004966}
4967
Steve Blockd0582a62009-12-15 09:54:21 +00004968
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004969Register FullCodeGenerator::result_register() {
4970 return eax;
4971}
Leon Clarkee46be812010-01-19 14:06:41 +00004972
4973
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004974Register FullCodeGenerator::context_register() {
4975 return esi;
4976}
4977
4978
Leon Clarked91b9f72010-01-27 17:25:45 +00004979void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004980 DCHECK_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
Leon Clarkee46be812010-01-19 14:06:41 +00004981 __ mov(Operand(ebp, frame_offset), value);
4982}
4983
4984
Leon Clarked91b9f72010-01-27 17:25:45 +00004985void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
Steve Block59151502010-09-22 15:07:15 +01004986 __ mov(dst, ContextOperand(esi, context_index));
Leon Clarkee46be812010-01-19 14:06:41 +00004987}
4988
4989
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004990void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
4991 Scope* declaration_scope = scope()->DeclarationScope();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004992 if (declaration_scope->is_script_scope() ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004993 declaration_scope->is_module_scope()) {
4994 // Contexts nested in the native context have a canonical empty function
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004995 // as their closure, not the anonymous closure containing the global
4996 // code. Pass a smi sentinel and let the runtime look up the empty
4997 // function.
4998 __ push(Immediate(Smi::FromInt(0)));
4999 } else if (declaration_scope->is_eval_scope()) {
5000 // Contexts nested inside eval code have the same closure as the context
5001 // calling eval, not the anonymous closure containing the eval code.
5002 // Fetch it from the context.
5003 __ push(ContextOperand(esi, Context::CLOSURE_INDEX));
5004 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005005 DCHECK(declaration_scope->is_function_scope());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005006 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
5007 }
5008}
5009
5010
Leon Clarkee46be812010-01-19 14:06:41 +00005011// ----------------------------------------------------------------------------
5012// Non-local control flow support.
5013
Leon Clarked91b9f72010-01-27 17:25:45 +00005014void FullCodeGenerator::EnterFinallyBlock() {
Leon Clarkee46be812010-01-19 14:06:41 +00005015 // Cook return address on top of stack (smi encoded Code* delta)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005016 DCHECK(!result_register().is(edx));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005017 __ pop(edx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005018 __ sub(edx, Immediate(masm_->CodeObject()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005019 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
5020 STATIC_ASSERT(kSmiTag == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005021 __ SmiTag(edx);
5022 __ push(edx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005023
Leon Clarkee46be812010-01-19 14:06:41 +00005024 // Store result register while executing finally block.
5025 __ push(result_register());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005026
5027 // Store pending message while executing finally block.
5028 ExternalReference pending_message_obj =
5029 ExternalReference::address_of_pending_message_obj(isolate());
5030 __ mov(edx, Operand::StaticVariable(pending_message_obj));
5031 __ push(edx);
5032
5033 ExternalReference has_pending_message =
5034 ExternalReference::address_of_has_pending_message(isolate());
5035 __ mov(edx, Operand::StaticVariable(has_pending_message));
5036 __ SmiTag(edx);
5037 __ push(edx);
5038
5039 ExternalReference pending_message_script =
5040 ExternalReference::address_of_pending_message_script(isolate());
5041 __ mov(edx, Operand::StaticVariable(pending_message_script));
5042 __ push(edx);
Leon Clarkee46be812010-01-19 14:06:41 +00005043}
5044
5045
Leon Clarked91b9f72010-01-27 17:25:45 +00005046void FullCodeGenerator::ExitFinallyBlock() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005047 DCHECK(!result_register().is(edx));
5048 // Restore pending message from stack.
5049 __ pop(edx);
5050 ExternalReference pending_message_script =
5051 ExternalReference::address_of_pending_message_script(isolate());
5052 __ mov(Operand::StaticVariable(pending_message_script), edx);
5053
5054 __ pop(edx);
5055 __ SmiUntag(edx);
5056 ExternalReference has_pending_message =
5057 ExternalReference::address_of_has_pending_message(isolate());
5058 __ mov(Operand::StaticVariable(has_pending_message), edx);
5059
5060 __ pop(edx);
5061 ExternalReference pending_message_obj =
5062 ExternalReference::address_of_pending_message_obj(isolate());
5063 __ mov(Operand::StaticVariable(pending_message_obj), edx);
5064
5065 // Restore result register from stack.
Leon Clarkee46be812010-01-19 14:06:41 +00005066 __ pop(result_register());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005067
Leon Clarkee46be812010-01-19 14:06:41 +00005068 // Uncook return address.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005069 __ pop(edx);
5070 __ SmiUntag(edx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005071 __ add(edx, Immediate(masm_->CodeObject()));
5072 __ jmp(edx);
Leon Clarkee46be812010-01-19 14:06:41 +00005073}
5074
5075
5076#undef __
Steve Blockd0582a62009-12-15 09:54:21 +00005077
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005078#define __ ACCESS_MASM(masm())
5079
5080FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
5081 int* stack_depth,
5082 int* context_length) {
5083 // The macros used here must preserve the result register.
5084
5085 // Because the handler block contains the context of the finally
5086 // code, we can restore it directly from there for the finally code
5087 // rather than iteratively unwinding contexts via their previous
5088 // links.
5089 __ Drop(*stack_depth); // Down to the handler block.
5090 if (*context_length > 0) {
5091 // Restore the context to its dedicated register and the stack.
5092 __ mov(esi, Operand(esp, StackHandlerConstants::kContextOffset));
5093 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
5094 }
5095 __ PopTryHandler();
5096 __ call(finally_entry_);
5097
5098 *stack_depth = 0;
5099 *context_length = 0;
5100 return previous_;
5101}
5102
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005103#undef __
5104
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005105
5106static const byte kJnsInstruction = 0x79;
5107static const byte kJnsOffset = 0x11;
5108static const byte kNopByteOne = 0x66;
5109static const byte kNopByteTwo = 0x90;
5110#ifdef DEBUG
5111static const byte kCallInstruction = 0xe8;
5112#endif
5113
5114
5115void BackEdgeTable::PatchAt(Code* unoptimized_code,
5116 Address pc,
5117 BackEdgeState target_state,
5118 Code* replacement_code) {
5119 Address call_target_address = pc - kIntSize;
5120 Address jns_instr_address = call_target_address - 3;
5121 Address jns_offset_address = call_target_address - 2;
5122
5123 switch (target_state) {
5124 case INTERRUPT:
5125 // sub <profiling_counter>, <delta> ;; Not changed
5126 // jns ok
5127 // call <interrupt stub>
5128 // ok:
5129 *jns_instr_address = kJnsInstruction;
5130 *jns_offset_address = kJnsOffset;
5131 break;
5132 case ON_STACK_REPLACEMENT:
5133 case OSR_AFTER_STACK_CHECK:
5134 // sub <profiling_counter>, <delta> ;; Not changed
5135 // nop
5136 // nop
5137 // call <on-stack replacment>
5138 // ok:
5139 *jns_instr_address = kNopByteOne;
5140 *jns_offset_address = kNopByteTwo;
5141 break;
5142 }
5143
5144 Assembler::set_target_address_at(call_target_address,
5145 unoptimized_code,
5146 replacement_code->entry());
5147 unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
5148 unoptimized_code, call_target_address, replacement_code);
5149}
5150
5151
5152BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
5153 Isolate* isolate,
5154 Code* unoptimized_code,
5155 Address pc) {
5156 Address call_target_address = pc - kIntSize;
5157 Address jns_instr_address = call_target_address - 3;
5158 DCHECK_EQ(kCallInstruction, *(call_target_address - 1));
5159
5160 if (*jns_instr_address == kJnsInstruction) {
5161 DCHECK_EQ(kJnsOffset, *(call_target_address - 2));
5162 DCHECK_EQ(isolate->builtins()->InterruptCheck()->entry(),
5163 Assembler::target_address_at(call_target_address,
5164 unoptimized_code));
5165 return INTERRUPT;
5166 }
5167
5168 DCHECK_EQ(kNopByteOne, *jns_instr_address);
5169 DCHECK_EQ(kNopByteTwo, *(call_target_address - 2));
5170
5171 if (Assembler::target_address_at(call_target_address, unoptimized_code) ==
5172 isolate->builtins()->OnStackReplacement()->entry()) {
5173 return ON_STACK_REPLACEMENT;
5174 }
5175
5176 DCHECK_EQ(isolate->builtins()->OsrAfterStackCheck()->entry(),
5177 Assembler::target_address_at(call_target_address,
5178 unoptimized_code));
5179 return OSR_AFTER_STACK_CHECK;
5180}
5181
5182
Steve Block3ce2e202009-11-05 08:53:23 +00005183} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01005184
5185#endif // V8_TARGET_ARCH_IA32