blob: dfced7c221335f060f7c333e02c0ec38bb7516d8 [file] [log] [blame]
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001// Copyright 2012 the V8 project authors. All rights reserved.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000028#include "v8.h"
29
30#if defined(V8_TARGET_ARCH_IA32)
31
kasperl@chromium.orga5551262010-12-07 12:49:48 +000032#include "ia32/lithium-codegen-ia32.h"
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000033#include "ic.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000034#include "code-stubs.h"
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000035#include "deoptimizer.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "stub-cache.h"
erikcorry0ad885c2011-11-21 13:51:57 +000037#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000038
39namespace v8 {
40namespace internal {
41
42
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000043// When invoking builtins, we need to record the safepoint in the middle of
44// the invoke instruction sequence generated by the macro assembler.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000045class SafepointGenerator : public CallWrapper {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000046 public:
47 SafepointGenerator(LCodeGen* codegen,
48 LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +000049 Safepoint::DeoptMode mode)
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050 : codegen_(codegen),
51 pointers_(pointers),
ricow@chromium.org27bf2882011-11-17 08:34:43 +000052 deopt_mode_(mode) {}
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053 virtual ~SafepointGenerator() { }
54
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000055 virtual void BeforeCall(int call_size) const {}
56
57 virtual void AfterCall() const {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000058 codegen_->RecordSafepoint(pointers_, deopt_mode_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000059 }
60
61 private:
62 LCodeGen* codegen_;
63 LPointerMap* pointers_;
ricow@chromium.org27bf2882011-11-17 08:34:43 +000064 Safepoint::DeoptMode deopt_mode_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000065};
66
67
68#define __ masm()->
69
70bool LCodeGen::GenerateCode() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000071 HPhase phase("Z_Code generation", chunk());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000072 ASSERT(is_unused());
73 status_ = GENERATING;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000074
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000075 // Open a frame scope to indicate that there is a frame on the stack. The
76 // MANUAL indicates that the scope shouldn't actually generate code to set up
77 // the frame (that is done in GeneratePrologue).
78 FrameScope frame_scope(masm_, StackFrame::MANUAL);
79
danno@chromium.org94b0d6f2013-02-04 13:33:20 +000080 support_aligned_spilled_doubles_ = info()->IsOptimizing();
81
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000082 dynamic_frame_alignment_ = info()->IsOptimizing() &&
83 ((chunk()->num_double_slots() > 2 &&
84 !chunk()->graph()->is_recursive()) ||
85 !info()->osr_ast_id().IsNone());
mmassi@chromium.org7028c052012-06-13 11:51:58 +000086
kasperl@chromium.orga5551262010-12-07 12:49:48 +000087 return GeneratePrologue() &&
88 GenerateBody() &&
89 GenerateDeferredCode() &&
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000090 GenerateJumpTable() &&
kasperl@chromium.orga5551262010-12-07 12:49:48 +000091 GenerateSafepointTable();
92}
93
94
95void LCodeGen::FinishCode(Handle<Code> code) {
96 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +000097 code->set_stack_slots(GetStackSlotCount());
ricow@chromium.org83aa5492011-02-07 12:42:56 +000098 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000099 PopulateDeoptimizationData(code);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000100 if (!info()->IsStub()) {
101 Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
102 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000103}
104
105
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000106void LCodeGen::Abort(const char* reason) {
107 info()->set_bailout_reason(reason);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000108 status_ = ABORTED;
109}
110
111
112void LCodeGen::Comment(const char* format, ...) {
113 if (!FLAG_code_comments) return;
114 char buffer[4 * KB];
115 StringBuilder builder(buffer, ARRAY_SIZE(buffer));
116 va_list arguments;
117 va_start(arguments, format);
118 builder.AddFormattedList(format, arguments);
119 va_end(arguments);
120
121 // Copy the string before recording it in the assembler to avoid
122 // issues when the stack allocated buffer goes out of scope.
123 size_t length = builder.position();
124 Vector<char> copy = Vector<char>::New(length + 1);
125 memcpy(copy.start(), builder.Finalize(), copy.length());
126 masm()->RecordComment(copy.start());
127}
128
129
130bool LCodeGen::GeneratePrologue() {
131 ASSERT(is_generating());
132
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000133 if (info()->IsOptimizing()) {
134 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000135
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000136#ifdef DEBUG
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000137 if (strlen(FLAG_stop_at) > 0 &&
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000138 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000139 __ int3();
140 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000141#endif
142
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000143 // Strict mode functions and builtins need to replace the receiver
144 // with undefined when called as functions (without an explicit
145 // receiver object). ecx is zero for method calls and non-zero for
146 // function calls.
147 if (!info_->is_classic_mode() || info_->is_native()) {
148 Label ok;
149 __ test(ecx, Operand(ecx));
150 __ j(zero, &ok, Label::kNear);
151 // +1 for return address.
152 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
153 __ mov(Operand(esp, receiver_offset),
154 Immediate(isolate()->factory()->undefined_value()));
155 __ bind(&ok);
156 }
danno@chromium.org40cb8782011-05-25 07:58:50 +0000157
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000158 if (support_aligned_spilled_doubles_ && dynamic_frame_alignment_) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000159 // Move state of dynamic frame alignment into edx.
160 __ mov(edx, Immediate(kNoAlignmentPadding));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000161
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000162 Label do_not_pad, align_loop;
163 STATIC_ASSERT(kDoubleSize == 2 * kPointerSize);
164 // Align esp + 4 to a multiple of 2 * kPointerSize.
165 __ test(esp, Immediate(kPointerSize));
166 __ j(not_zero, &do_not_pad, Label::kNear);
167 __ push(Immediate(0));
168 __ mov(ebx, esp);
169 __ mov(edx, Immediate(kAlignmentPaddingPushed));
170 // Copy arguments, receiver, and return address.
171 __ mov(ecx, Immediate(scope()->num_parameters() + 2));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000172
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000173 __ bind(&align_loop);
174 __ mov(eax, Operand(ebx, 1 * kPointerSize));
175 __ mov(Operand(ebx, 0), eax);
176 __ add(Operand(ebx), Immediate(kPointerSize));
177 __ dec(ecx);
178 __ j(not_zero, &align_loop, Label::kNear);
179 __ mov(Operand(ebx, 0), Immediate(kAlignmentZapValue));
180 __ bind(&do_not_pad);
181 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000182 }
183
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000184 info()->set_prologue_offset(masm_->pc_offset());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000185 if (NeedsEagerFrame()) {
186 ASSERT(!frame_is_built_);
187 frame_is_built_ = true;
188 __ push(ebp); // Caller's frame pointer.
189 __ mov(ebp, esp);
190 __ push(esi); // Callee's context.
191 if (info()->IsStub()) {
192 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
193 } else {
194 __ push(edi); // Callee's JS function.
195 }
196 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000197
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000198 if (info()->IsOptimizing() &&
199 dynamic_frame_alignment_ &&
200 FLAG_debug_code) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000201 __ test(esp, Immediate(kPointerSize));
202 __ Assert(zero, "frame is expected to be aligned");
203 }
204
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000205 // Reserve space for the stack slots needed by the code.
danno@chromium.org160a7b02011-04-18 15:51:38 +0000206 int slots = GetStackSlotCount();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000207 ASSERT(slots != 0 || !info()->IsOptimizing());
208 if (slots > 0) {
209 if (slots == 1) {
210 if (dynamic_frame_alignment_) {
211 __ push(edx);
212 } else {
213 __ push(Immediate(kNoAlignmentPadding));
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +0000214 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000215 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000216 if (FLAG_debug_code) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000217 __ sub(Operand(esp), Immediate(slots * kPointerSize));
218 __ push(eax);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000219 __ mov(Operand(eax), Immediate(slots));
220 Label loop;
221 __ bind(&loop);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000222 __ mov(MemOperand(esp, eax, times_4, 0),
223 Immediate(kSlotsZapValue));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000224 __ dec(eax);
225 __ j(not_zero, &loop);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000226 __ pop(eax);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000227 } else {
228 __ sub(Operand(esp), Immediate(slots * kPointerSize));
229#ifdef _MSC_VER
230 // On windows, you may not access the stack more than one page below
231 // the most recently mapped page. To make the allocated area randomly
232 // accessible, we write to each page in turn (the value is irrelevant).
233 const int kPageSize = 4 * KB;
234 for (int offset = slots * kPointerSize - kPageSize;
235 offset > 0;
236 offset -= kPageSize) {
237 __ mov(Operand(esp, offset), eax);
238 }
239#endif
240 }
241
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000242 if (support_aligned_spilled_doubles_) {
243 Comment(";;; Store dynamic frame alignment tag for spilled doubles");
244 // Store dynamic frame alignment state in the first local.
245 int offset = JavaScriptFrameConstants::kDynamicAlignmentStateOffset;
246 if (dynamic_frame_alignment_) {
247 __ mov(Operand(ebp, offset), edx);
248 } else {
249 __ mov(Operand(ebp, offset), Immediate(kNoAlignmentPadding));
250 }
251 }
252 }
253
254 if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(SSE2)) {
255 Comment(";;; Save clobbered callee double registers");
256 CpuFeatures::Scope scope(SSE2);
257 int count = 0;
258 BitVector* doubles = chunk()->allocated_double_registers();
259 BitVector::Iterator save_iterator(doubles);
260 while (!save_iterator.Done()) {
261 __ movdbl(MemOperand(esp, count * kDoubleSize),
262 XMMRegister::FromAllocationIndex(save_iterator.Current()));
263 save_iterator.Advance();
264 count++;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000265 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000266 }
267 }
268
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000269 // Possibly allocate a local context.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000270 int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000271 if (heap_slots > 0) {
272 Comment(";;; Allocate local context");
273 // Argument to NewContext is the function, which is still in edi.
274 __ push(edi);
275 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
276 FastNewContextStub stub(heap_slots);
277 __ CallStub(&stub);
278 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000279 __ CallRuntime(Runtime::kNewFunctionContext, 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000280 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000281 RecordSafepoint(Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000282 // Context is returned in both eax and esi. It replaces the context
283 // passed to us. It's saved in the stack and kept live in esi.
284 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
285
286 // Copy parameters into context if necessary.
287 int num_parameters = scope()->num_parameters();
288 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000289 Variable* var = scope()->parameter(i);
290 if (var->IsContextSlot()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000291 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
292 (num_parameters - 1 - i) * kPointerSize;
293 // Load parameter from stack.
294 __ mov(eax, Operand(ebp, parameter_offset));
295 // Store it in the context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000296 int context_offset = Context::SlotOffset(var->index());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000297 __ mov(Operand(esi, context_offset), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000298 // Update the write barrier. This clobbers eax and ebx.
299 __ RecordWriteContextSlot(esi,
300 context_offset,
301 eax,
302 ebx,
303 kDontSaveFPRegs);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000304 }
305 }
306 Comment(";;; End allocate local context");
307 }
308
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000309 // Trace the call.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000310 if (FLAG_trace && info()->IsOptimizing()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000311 // We have not executed any compiled code yet, so esi still holds the
312 // incoming context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000313 __ CallRuntime(Runtime::kTraceEnter, 0);
314 }
315 return !is_aborted();
316}
317
318
319bool LCodeGen::GenerateBody() {
320 ASSERT(is_generating());
321 bool emit_instructions = true;
322 for (current_instruction_ = 0;
323 !is_aborted() && current_instruction_ < instructions_->length();
324 current_instruction_++) {
325 LInstruction* instr = instructions_->at(current_instruction_);
326 if (instr->IsLabel()) {
327 LLabel* label = LLabel::cast(instr);
328 emit_instructions = !label->HasReplacement();
329 }
330
331 if (emit_instructions) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000332 if (FLAG_code_comments) {
333 HValue* hydrogen = instr->hydrogen_value();
334 if (hydrogen != NULL) {
335 if (hydrogen->IsChange()) {
336 HValue* changed_value = HChange::cast(hydrogen)->value();
337 int use_id = 0;
338 const char* use_mnemo = "dead";
339 if (hydrogen->UseCount() >= 1) {
340 HValue* use_value = hydrogen->uses().value();
341 use_id = use_value->id();
342 use_mnemo = use_value->Mnemonic();
343 }
344 Comment(";;; @%d: %s. <of #%d %s for #%d %s>",
345 current_instruction_, instr->Mnemonic(),
346 changed_value->id(), changed_value->Mnemonic(),
347 use_id, use_mnemo);
348 } else {
349 Comment(";;; @%d: %s. <#%d>", current_instruction_,
350 instr->Mnemonic(), hydrogen->id());
351 }
352 } else {
353 Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
354 }
355 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000356 instr->CompileToNative(this);
357 }
358 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000359 EnsureSpaceForLazyDeopt();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000360 return !is_aborted();
361}
362
363
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000364bool LCodeGen::GenerateJumpTable() {
365 Label needs_frame_not_call;
366 Label needs_frame_is_call;
367 for (int i = 0; i < jump_table_.length(); i++) {
368 __ bind(&jump_table_[i].label);
369 Address entry = jump_table_[i].address;
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000370 bool is_lazy_deopt = jump_table_[i].is_lazy_deopt;
371 Deoptimizer::BailoutType type =
372 is_lazy_deopt ? Deoptimizer::LAZY : Deoptimizer::EAGER;
373 int id = Deoptimizer::GetDeoptimizationId(entry, type);
374 if (id == Deoptimizer::kNotDeoptimizationEntry) {
375 Comment(";;; jump table entry %d.", i);
376 } else {
377 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id);
378 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000379 if (jump_table_[i].needs_frame) {
380 __ push(Immediate(ExternalReference::ForDeoptEntry(entry)));
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000381 if (is_lazy_deopt) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000382 if (needs_frame_is_call.is_bound()) {
383 __ jmp(&needs_frame_is_call);
384 } else {
385 __ bind(&needs_frame_is_call);
386 __ push(MemOperand(ebp, StandardFrameConstants::kContextOffset));
387 // This variant of deopt can only be used with stubs. Since we don't
388 // have a function pointer to install in the stack frame that we're
389 // building, install a special marker there instead.
390 ASSERT(info()->IsStub());
391 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
392 // Push a PC inside the function so that the deopt code can find where
393 // the deopt comes from. It doesn't have to be the precise return
394 // address of a "calling" LAZY deopt, it only has to be somewhere
395 // inside the code body.
396 Label push_approx_pc;
397 __ call(&push_approx_pc);
398 __ bind(&push_approx_pc);
399 // Push the continuation which was stashed were the ebp should
400 // be. Replace it with the saved ebp.
401 __ push(MemOperand(esp, 3 * kPointerSize));
402 __ mov(MemOperand(esp, 4 * kPointerSize), ebp);
403 __ lea(ebp, MemOperand(esp, 4 * kPointerSize));
404 __ ret(0); // Call the continuation without clobbering registers.
405 }
406 } else {
407 if (needs_frame_not_call.is_bound()) {
408 __ jmp(&needs_frame_not_call);
409 } else {
410 __ bind(&needs_frame_not_call);
411 __ push(MemOperand(ebp, StandardFrameConstants::kContextOffset));
412 // This variant of deopt can only be used with stubs. Since we don't
413 // have a function pointer to install in the stack frame that we're
414 // building, install a special marker there instead.
415 ASSERT(info()->IsStub());
416 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
417 // Push the continuation which was stashed were the ebp should
418 // be. Replace it with the saved ebp.
419 __ push(MemOperand(esp, 2 * kPointerSize));
420 __ mov(MemOperand(esp, 3 * kPointerSize), ebp);
421 __ lea(ebp, MemOperand(esp, 3 * kPointerSize));
422 __ ret(0); // Call the continuation without clobbering registers.
423 }
424 }
425 } else {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000426 if (is_lazy_deopt) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000427 __ call(entry, RelocInfo::RUNTIME_ENTRY);
428 } else {
429 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
430 }
431 }
432 }
433 return !is_aborted();
434}
435
436
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000437bool LCodeGen::GenerateDeferredCode() {
438 ASSERT(is_generating());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000439 if (deferred_.length() > 0) {
440 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
441 LDeferredCode* code = deferred_[i];
442 __ bind(code->entry());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000443 if (NeedsDeferredFrame()) {
444 Comment(";;; Deferred build frame",
445 code->instruction_index(),
446 code->instr()->Mnemonic());
447 ASSERT(!frame_is_built_);
448 ASSERT(info()->IsStub());
449 frame_is_built_ = true;
450 // Build the frame in such a way that esi isn't trashed.
451 __ push(ebp); // Caller's frame pointer.
452 __ push(Operand(ebp, StandardFrameConstants::kContextOffset));
453 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
454 __ lea(ebp, Operand(esp, 2 * kPointerSize));
455 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000456 Comment(";;; Deferred code @%d: %s.",
457 code->instruction_index(),
458 code->instr()->Mnemonic());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000459 code->Generate();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000460 if (NeedsDeferredFrame()) {
461 Comment(";;; Deferred destroy frame",
462 code->instruction_index(),
463 code->instr()->Mnemonic());
464 ASSERT(frame_is_built_);
465 frame_is_built_ = false;
466 __ mov(esp, ebp);
467 __ pop(ebp);
468 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000469 __ jmp(code->exit());
470 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000471 }
472
473 // Deferred code is the last part of the instruction sequence. Mark
474 // the generated code as done unless we bailed out.
475 if (!is_aborted()) status_ = DONE;
476 return !is_aborted();
477}
478
479
480bool LCodeGen::GenerateSafepointTable() {
481 ASSERT(is_done());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000482 if (!info()->IsStub()) {
483 // For lazy deoptimization we need space to patch a call after every call.
484 // Ensure there is always space for such patching, even if the code ends
485 // in a call.
486 int target_offset = masm()->pc_offset() + Deoptimizer::patch_size();
487 while (masm()->pc_offset() < target_offset) {
488 masm()->nop();
489 }
490 }
danno@chromium.org160a7b02011-04-18 15:51:38 +0000491 safepoints_.Emit(masm(), GetStackSlotCount());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000492 return !is_aborted();
493}
494
495
496Register LCodeGen::ToRegister(int index) const {
497 return Register::FromAllocationIndex(index);
498}
499
500
501XMMRegister LCodeGen::ToDoubleRegister(int index) const {
502 return XMMRegister::FromAllocationIndex(index);
503}
504
505
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000506bool LCodeGen::IsX87TopOfStack(LOperand* op) const {
507 return op->IsDoubleRegister();
508}
509
510
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000511Register LCodeGen::ToRegister(LOperand* op) const {
512 ASSERT(op->IsRegister());
513 return ToRegister(op->index());
514}
515
516
517XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
518 ASSERT(op->IsDoubleRegister());
519 return ToDoubleRegister(op->index());
520}
521
522
523int LCodeGen::ToInteger32(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000524 HConstant* constant = chunk_->LookupConstant(op);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000525 return constant->Integer32Value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000526}
527
528
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000529Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000530 HConstant* constant = chunk_->LookupConstant(op);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000531 ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000532 return constant->handle();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000533}
534
535
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000536double LCodeGen::ToDouble(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000537 HConstant* constant = chunk_->LookupConstant(op);
538 ASSERT(constant->HasDoubleValue());
539 return constant->DoubleValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000540}
541
542
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000543bool LCodeGen::IsInteger32(LConstantOperand* op) const {
544 return chunk_->LookupLiteralRepresentation(op).IsInteger32();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000545}
546
547
548Operand LCodeGen::ToOperand(LOperand* op) const {
549 if (op->IsRegister()) return Operand(ToRegister(op));
550 if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
551 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
552 int index = op->index();
553 if (index >= 0) {
554 // Local or spill slot. Skip the frame pointer, function, and
555 // context in the fixed part of the frame.
556 return Operand(ebp, -(index + 3) * kPointerSize);
557 } else {
558 // Incoming parameter. Skip the return address.
559 return Operand(ebp, -(index - 1) * kPointerSize);
560 }
561}
562
563
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000564Operand LCodeGen::HighOperand(LOperand* op) {
565 ASSERT(op->IsDoubleStackSlot());
566 int index = op->index();
567 int offset = (index >= 0) ? index + 3 : index - 1;
568 return Operand(ebp, -offset * kPointerSize);
569}
570
571
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000572void LCodeGen::WriteTranslation(LEnvironment* environment,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000573 Translation* translation,
574 int* arguments_index,
575 int* arguments_count) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000576 if (environment == NULL) return;
577
578 // The translation includes one command per value in the environment.
579 int translation_size = environment->values()->length();
580 // The output frame height does not include the parameters.
581 int height = translation_size - environment->parameter_count();
582
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000583 // Function parameters are arguments to the outermost environment. The
584 // arguments index points to the first element of a sequence of tagged
585 // values on the stack that represent the arguments. This needs to be
586 // kept in sync with the LArgumentsElements implementation.
587 *arguments_index = -environment->parameter_count();
588 *arguments_count = environment->parameter_count();
589
590 WriteTranslation(environment->outer(),
591 translation,
592 arguments_index,
593 arguments_count);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000594 bool has_closure_id = !info()->closure().is_null() &&
595 *info()->closure() != *environment->closure();
596 int closure_id = has_closure_id
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000597 ? DefineDeoptimizationLiteral(environment->closure())
598 : Translation::kSelfLiteralId;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000599 switch (environment->frame_type()) {
600 case JS_FUNCTION:
601 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
602 break;
603 case JS_CONSTRUCT:
604 translation->BeginConstructStubFrame(closure_id, translation_size);
605 break;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000606 case JS_GETTER:
607 ASSERT(translation_size == 1);
608 ASSERT(height == 0);
609 translation->BeginGetterStubFrame(closure_id);
610 break;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000611 case JS_SETTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000612 ASSERT(translation_size == 2);
613 ASSERT(height == 0);
614 translation->BeginSetterStubFrame(closure_id);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000615 break;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000616 case ARGUMENTS_ADAPTOR:
617 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
618 break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000619 case STUB:
620 translation->BeginCompiledStubFrame();
621 break;
622 default:
623 UNREACHABLE();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000624 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000625
626 // Inlined frames which push their arguments cause the index to be
627 // bumped and another stack area to be used for materialization.
628 if (environment->entry() != NULL &&
629 environment->entry()->arguments_pushed()) {
630 *arguments_index = *arguments_index < 0
631 ? GetStackSlotCount()
632 : *arguments_index + *arguments_count;
633 *arguments_count = environment->entry()->arguments_count() + 1;
634 }
635
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000636 for (int i = 0; i < translation_size; ++i) {
637 LOperand* value = environment->values()->at(i);
638 // spilled_registers_ and spilled_double_registers_ are either
639 // both NULL or both set.
640 if (environment->spilled_registers() != NULL && value != NULL) {
641 if (value->IsRegister() &&
642 environment->spilled_registers()[value->index()] != NULL) {
643 translation->MarkDuplicate();
644 AddToTranslation(translation,
645 environment->spilled_registers()[value->index()],
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000646 environment->HasTaggedValueAt(i),
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000647 environment->HasUint32ValueAt(i),
648 *arguments_index,
649 *arguments_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000650 } else if (
651 value->IsDoubleRegister() &&
652 environment->spilled_double_registers()[value->index()] != NULL) {
653 translation->MarkDuplicate();
654 AddToTranslation(
655 translation,
656 environment->spilled_double_registers()[value->index()],
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000657 false,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000658 false,
659 *arguments_index,
660 *arguments_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000661 }
662 }
663
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000664 AddToTranslation(translation,
665 value,
666 environment->HasTaggedValueAt(i),
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000667 environment->HasUint32ValueAt(i),
668 *arguments_index,
669 *arguments_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000670 }
671}
672
673
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000674void LCodeGen::AddToTranslation(Translation* translation,
675 LOperand* op,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000676 bool is_tagged,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000677 bool is_uint32,
678 int arguments_index,
679 int arguments_count) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000680 if (op == NULL) {
681 // TODO(twuerthinger): Introduce marker operands to indicate that this value
682 // is not present and must be reconstructed from the deoptimizer. Currently
683 // this is only used for the arguments object.
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000684 translation->StoreArgumentsObject(arguments_index, arguments_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000685 } else if (op->IsStackSlot()) {
686 if (is_tagged) {
687 translation->StoreStackSlot(op->index());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000688 } else if (is_uint32) {
689 translation->StoreUint32StackSlot(op->index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000690 } else {
691 translation->StoreInt32StackSlot(op->index());
692 }
693 } else if (op->IsDoubleStackSlot()) {
694 translation->StoreDoubleStackSlot(op->index());
695 } else if (op->IsArgument()) {
696 ASSERT(is_tagged);
danno@chromium.org160a7b02011-04-18 15:51:38 +0000697 int src_index = GetStackSlotCount() + op->index();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000698 translation->StoreStackSlot(src_index);
699 } else if (op->IsRegister()) {
700 Register reg = ToRegister(op);
701 if (is_tagged) {
702 translation->StoreRegister(reg);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000703 } else if (is_uint32) {
704 translation->StoreUint32Register(reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000705 } else {
706 translation->StoreInt32Register(reg);
707 }
708 } else if (op->IsDoubleRegister()) {
709 XMMRegister reg = ToDoubleRegister(op);
710 translation->StoreDoubleRegister(reg);
711 } else if (op->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000712 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
713 int src_index = DefineDeoptimizationLiteral(constant->handle());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000714 translation->StoreLiteral(src_index);
715 } else {
716 UNREACHABLE();
717 }
718}
719
720
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000721void LCodeGen::CallCodeGeneric(Handle<Code> code,
722 RelocInfo::Mode mode,
723 LInstruction* instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000724 SafepointMode safepoint_mode) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000725 ASSERT(instr != NULL);
726 LPointerMap* pointers = instr->pointer_map();
727 RecordPosition(pointers->position());
728 __ call(code, mode);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000729 RecordSafepointWithLazyDeopt(instr, safepoint_mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000730
731 // Signal that we don't inline smi code before these stubs in the
732 // optimizing code generator.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000733 if (code->kind() == Code::BINARY_OP_IC ||
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000734 code->kind() == Code::COMPARE_IC) {
735 __ nop();
736 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000737}
738
739
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000740void LCodeGen::CallCode(Handle<Code> code,
741 RelocInfo::Mode mode,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000742 LInstruction* instr) {
743 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000744}
745
746
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000747void LCodeGen::CallRuntime(const Runtime::Function* fun,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000748 int argc,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000749 LInstruction* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000750 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000751 ASSERT(instr->HasPointerMap());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000752 LPointerMap* pointers = instr->pointer_map();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000753 RecordPosition(pointers->position());
754
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000755 __ CallRuntime(fun, argc);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000756
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000757 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000758
759 ASSERT(info()->is_calling());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000760}
761
762
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000763void LCodeGen::LoadContextFromDeferred(LOperand* context) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000764 if (context->IsRegister()) {
765 if (!ToRegister(context).is(esi)) {
766 __ mov(esi, ToRegister(context));
767 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000768 } else if (context->IsStackSlot()) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000769 __ mov(esi, ToOperand(context));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000770 } else if (context->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000771 HConstant* constant =
772 chunk_->LookupConstant(LConstantOperand::cast(context));
773 __ LoadHeapObject(esi, Handle<Context>::cast(constant->handle()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000774 } else {
775 UNREACHABLE();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000776 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000777}
778
779void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
780 int argc,
781 LInstruction* instr,
782 LOperand* context) {
783 LoadContextFromDeferred(context);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000784
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000785 __ CallRuntimeSaveDoubles(id);
786 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000787 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000788
789 ASSERT(info()->is_calling());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000790}
791
792
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000793void LCodeGen::RegisterEnvironmentForDeoptimization(
794 LEnvironment* environment, Safepoint::DeoptMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000795 if (!environment->HasBeenRegistered()) {
796 // Physical stack frame layout:
797 // -x ............. -4 0 ..................................... y
798 // [incoming arguments] [spill slots] [pushed outgoing arguments]
799
800 // Layout of the environment:
801 // 0 ..................................................... size-1
802 // [parameters] [locals] [expression stack including arguments]
803
804 // Layout of the translation:
805 // 0 ........................................................ size - 1 + 4
806 // [expression stack including arguments] [locals] [4 words] [parameters]
807 // |>------------ translation_size ------------<|
808
809 int frame_count = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000810 int jsframe_count = 0;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000811 int args_index = 0;
812 int args_count = 0;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000813 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
814 ++frame_count;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000815 if (e->frame_type() == JS_FUNCTION) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000816 ++jsframe_count;
817 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000818 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000819 Translation translation(&translations_, frame_count, jsframe_count, zone());
820 WriteTranslation(environment, &translation, &args_index, &args_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000821 int deoptimization_index = deoptimizations_.length();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000822 int pc_offset = masm()->pc_offset();
823 environment->Register(deoptimization_index,
824 translation.index(),
825 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000826 deoptimizations_.Add(environment, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000827 }
828}
829
830
831void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000832 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000833 ASSERT(environment->HasBeenRegistered());
834 int id = environment->deoptimization_index();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000835 ASSERT(info()->IsOptimizing() || info()->IsStub());
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000836 Deoptimizer::BailoutType bailout_type = info()->IsStub()
837 ? Deoptimizer::LAZY
838 : Deoptimizer::EAGER;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000839 Address entry = Deoptimizer::GetDeoptimizationEntry(id, bailout_type);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000840 if (entry == NULL) {
841 Abort("bailout was not prepared");
842 return;
843 }
844
845 if (FLAG_deopt_every_n_times != 0) {
846 Handle<SharedFunctionInfo> shared(info_->shared_info());
847 Label no_deopt;
848 __ pushfd();
849 __ push(eax);
850 __ push(ebx);
851 __ mov(ebx, shared);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000852 __ mov(eax,
853 FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000854 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000855 __ j(not_zero, &no_deopt, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000856 if (FLAG_trap_on_deopt) __ int3();
857 __ mov(eax, Immediate(Smi::FromInt(FLAG_deopt_every_n_times)));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000858 __ mov(FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset),
859 eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000860 __ pop(ebx);
861 __ pop(eax);
862 __ popfd();
863 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
864
865 __ bind(&no_deopt);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000866 __ mov(FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset),
867 eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000868 __ pop(ebx);
869 __ pop(eax);
870 __ popfd();
871 }
872
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000873 ASSERT(info()->IsStub() || frame_is_built_);
874 bool lazy_deopt_needed = info()->IsStub();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000875 if (cc == no_condition) {
876 if (FLAG_trap_on_deopt) __ int3();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000877 if (lazy_deopt_needed) {
878 __ call(entry, RelocInfo::RUNTIME_ENTRY);
879 } else {
880 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
881 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000882 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000883 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000884 if (FLAG_trap_on_deopt) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000885 __ j(NegateCondition(cc), &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000886 __ int3();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +0000887 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000888 if (!lazy_deopt_needed && frame_is_built_) {
889 if (FLAG_trap_on_deopt) {
890 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
891 } else {
892 __ j(cc, entry, RelocInfo::RUNTIME_ENTRY);
893 }
894 } else {
895 // We often have several deopts to the same entry, reuse the last
896 // jump entry if this is the case.
897 if (jump_table_.is_empty() ||
898 jump_table_.last().address != entry ||
899 jump_table_.last().needs_frame != !frame_is_built_ ||
900 jump_table_.last().is_lazy_deopt != lazy_deopt_needed) {
901 JumpTableEntry table_entry(entry, !frame_is_built_, lazy_deopt_needed);
902 jump_table_.Add(table_entry, zone());
903 }
904 if (FLAG_trap_on_deopt) {
905 __ jmp(&jump_table_.last().label);
906 } else {
907 __ j(cc, &jump_table_.last().label);
908 }
909 }
910 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000911 }
912}
913
914
915void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
916 int length = deoptimizations_.length();
917 if (length == 0) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000918 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000919 factory()->NewDeoptimizationInputData(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000920
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000921 Handle<ByteArray> translations = translations_.CreateByteArray();
922 data->SetTranslationByteArray(*translations);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000923 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
924
925 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000926 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000927 for (int i = 0; i < deoptimization_literals_.length(); i++) {
928 literals->set(i, *deoptimization_literals_[i]);
929 }
930 data->SetLiteralArray(*literals);
931
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000932 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000933 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
934
935 // Populate the deoptimization entries.
936 for (int i = 0; i < length; i++) {
937 LEnvironment* env = deoptimizations_[i];
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000938 data->SetAstId(i, env->ast_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000939 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
940 data->SetArgumentsStackHeight(i,
941 Smi::FromInt(env->arguments_stack_height()));
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000942 data->SetPc(i, Smi::FromInt(env->pc_offset()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000943 }
944 code->set_deoptimization_data(*data);
945}
946
947
948int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
949 int result = deoptimization_literals_.length();
950 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
951 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
952 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000953 deoptimization_literals_.Add(literal, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000954 return result;
955}
956
957
958void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
959 ASSERT(deoptimization_literals_.length() == 0);
960
961 const ZoneList<Handle<JSFunction> >* inlined_closures =
962 chunk()->inlined_closures();
963
964 for (int i = 0, length = inlined_closures->length();
965 i < length;
966 i++) {
967 DefineDeoptimizationLiteral(inlined_closures->at(i));
968 }
969
970 inlined_function_count_ = deoptimization_literals_.length();
971}
972
973
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000974void LCodeGen::RecordSafepointWithLazyDeopt(
975 LInstruction* instr, SafepointMode safepoint_mode) {
976 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
977 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
978 } else {
979 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
980 RecordSafepointWithRegisters(
981 instr->pointer_map(), 0, Safepoint::kLazyDeopt);
982 }
983}
984
985
ager@chromium.org378b34e2011-01-28 08:04:38 +0000986void LCodeGen::RecordSafepoint(
987 LPointerMap* pointers,
988 Safepoint::Kind kind,
989 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000990 Safepoint::DeoptMode deopt_mode) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000991 ASSERT(kind == expected_safepoint_kind_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000992 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000993 Safepoint safepoint =
994 safepoints_.DefineSafepoint(masm(), kind, arguments, deopt_mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000995 for (int i = 0; i < operands->length(); i++) {
996 LOperand* pointer = operands->at(i);
997 if (pointer->IsStackSlot()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000998 safepoint.DefinePointerSlot(pointer->index(), zone());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000999 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001000 safepoint.DefinePointerRegister(ToRegister(pointer), zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001001 }
1002 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00001003}
1004
1005
1006void LCodeGen::RecordSafepoint(LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001007 Safepoint::DeoptMode mode) {
1008 RecordSafepoint(pointers, Safepoint::kSimple, 0, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001009}
1010
1011
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001012void LCodeGen::RecordSafepoint(Safepoint::DeoptMode mode) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001013 LPointerMap empty_pointers(RelocInfo::kNoPosition, zone());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001014 RecordSafepoint(&empty_pointers, mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001015}
1016
1017
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001018void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
1019 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001020 Safepoint::DeoptMode mode) {
1021 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001022}
1023
1024
1025void LCodeGen::RecordPosition(int position) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001026 if (position == RelocInfo::kNoPosition) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001027 masm()->positions_recorder()->RecordPosition(position);
1028}
1029
1030
1031void LCodeGen::DoLabel(LLabel* label) {
1032 if (label->is_loop_header()) {
1033 Comment(";;; B%d - LOOP entry", label->block_id());
1034 } else {
1035 Comment(";;; B%d", label->block_id());
1036 }
1037 __ bind(label->label());
1038 current_block_ = label->block_id();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001039 DoGap(label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001040}
1041
1042
1043void LCodeGen::DoParallelMove(LParallelMove* move) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001044 resolver_.Resolve(move);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001045}
1046
1047
1048void LCodeGen::DoGap(LGap* gap) {
1049 for (int i = LGap::FIRST_INNER_POSITION;
1050 i <= LGap::LAST_INNER_POSITION;
1051 i++) {
1052 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
1053 LParallelMove* move = gap->GetParallelMove(inner_pos);
1054 if (move != NULL) DoParallelMove(move);
1055 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001056}
1057
1058
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001059void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
1060 DoGap(instr);
1061}
1062
1063
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001064void LCodeGen::DoParameter(LParameter* instr) {
1065 // Nothing to do.
1066}
1067
1068
1069void LCodeGen::DoCallStub(LCallStub* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001070 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001071 ASSERT(ToRegister(instr->result()).is(eax));
1072 switch (instr->hydrogen()->major_key()) {
1073 case CodeStub::RegExpConstructResult: {
1074 RegExpConstructResultStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001075 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001076 break;
1077 }
1078 case CodeStub::RegExpExec: {
1079 RegExpExecStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001080 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001081 break;
1082 }
1083 case CodeStub::SubString: {
1084 SubStringStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001085 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001086 break;
1087 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001088 case CodeStub::NumberToString: {
1089 NumberToStringStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001090 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001091 break;
1092 }
1093 case CodeStub::StringAdd: {
1094 StringAddStub stub(NO_STRING_ADD_FLAGS);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001095 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001096 break;
1097 }
1098 case CodeStub::StringCompare: {
1099 StringCompareStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001100 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001101 break;
1102 }
1103 case CodeStub::TranscendentalCache: {
whesse@chromium.org023421e2010-12-21 12:19:12 +00001104 TranscendentalCacheStub stub(instr->transcendental_type(),
1105 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001106 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001107 break;
1108 }
1109 default:
1110 UNREACHABLE();
1111 }
1112}
1113
1114
1115void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
1116 // Nothing to do.
1117}
1118
1119
1120void LCodeGen::DoModI(LModI* instr) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001121 if (instr->hydrogen()->HasPowerOf2Divisor()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001122 Register dividend = ToRegister(instr->left());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001123
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001124 int32_t divisor =
1125 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001126
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001127 if (divisor < 0) divisor = -divisor;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001128
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001129 Label positive_dividend, done;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001130 __ test(dividend, Operand(dividend));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001131 __ j(not_sign, &positive_dividend, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001132 __ neg(dividend);
1133 __ and_(dividend, divisor - 1);
1134 __ neg(dividend);
1135 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001136 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001137 DeoptimizeIf(no_condition, instr->environment());
whesse@chromium.org7b260152011-06-20 15:33:18 +00001138 } else {
1139 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001140 }
1141 __ bind(&positive_dividend);
1142 __ and_(dividend, divisor - 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001143 __ bind(&done);
1144 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001145 Label done, remainder_eq_dividend, slow, do_subtraction, both_positive;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001146 Register left_reg = ToRegister(instr->left());
1147 Register right_reg = ToRegister(instr->right());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001148 Register result_reg = ToRegister(instr->result());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001149
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001150 ASSERT(left_reg.is(eax));
1151 ASSERT(result_reg.is(edx));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001152 ASSERT(!right_reg.is(eax));
1153 ASSERT(!right_reg.is(edx));
1154
1155 // Check for x % 0.
1156 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001157 __ test(right_reg, Operand(right_reg));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001158 DeoptimizeIf(zero, instr->environment());
1159 }
1160
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001161 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001162 __ j(zero, &remainder_eq_dividend, Label::kNear);
1163 __ j(sign, &slow, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001164
1165 __ test(right_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001166 __ j(not_sign, &both_positive, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001167 // The sign of the divisor doesn't matter.
1168 __ neg(right_reg);
1169
1170 __ bind(&both_positive);
1171 // If the dividend is smaller than the nonnegative
1172 // divisor, the dividend is the result.
1173 __ cmp(left_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001174 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001175
1176 // Check if the divisor is a PowerOfTwo integer.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001177 Register scratch = ToRegister(instr->temp());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001178 __ mov(scratch, right_reg);
1179 __ sub(Operand(scratch), Immediate(1));
1180 __ test(scratch, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001181 __ j(not_zero, &do_subtraction, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001182 __ and_(left_reg, Operand(scratch));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001183 __ jmp(&remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001184
1185 __ bind(&do_subtraction);
1186 const int kUnfolds = 3;
1187 // Try a few subtractions of the dividend.
1188 __ mov(scratch, left_reg);
1189 for (int i = 0; i < kUnfolds; i++) {
1190 // Reduce the dividend by the divisor.
1191 __ sub(left_reg, Operand(right_reg));
1192 // Check if the dividend is less than the divisor.
1193 __ cmp(left_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001194 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001195 }
1196 __ mov(left_reg, scratch);
1197
1198 // Slow case, using idiv instruction.
1199 __ bind(&slow);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001200
1201 // Check for (kMinInt % -1).
1202 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1203 Label left_not_min_int;
1204 __ cmp(left_reg, kMinInt);
1205 __ j(not_zero, &left_not_min_int, Label::kNear);
1206 __ cmp(right_reg, -1);
1207 DeoptimizeIf(zero, instr->environment());
1208 __ bind(&left_not_min_int);
1209 }
1210
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001211 // Sign extend to edx.
1212 __ cdq();
1213
1214 // Check for (0 % -x) that will produce negative zero.
1215 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001216 Label positive_left;
1217 Label done;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001218 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001219 __ j(not_sign, &positive_left, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001220 __ idiv(right_reg);
1221
1222 // Test the remainder for 0, because then the result would be -0.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001223 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001224 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001225
1226 DeoptimizeIf(no_condition, instr->environment());
1227 __ bind(&positive_left);
1228 __ idiv(right_reg);
1229 __ bind(&done);
1230 } else {
1231 __ idiv(right_reg);
1232 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001233 __ jmp(&done, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001234
1235 __ bind(&remainder_eq_dividend);
1236 __ mov(result_reg, left_reg);
1237
1238 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001239 }
1240}
1241
1242
1243void LCodeGen::DoDivI(LDivI* instr) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001244 if (!instr->is_flooring() && instr->hydrogen()->HasPowerOf2Divisor()) {
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001245 Register dividend = ToRegister(instr->left());
1246 int32_t divisor =
1247 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
1248 int32_t test_value = 0;
1249 int32_t power = 0;
1250
1251 if (divisor > 0) {
1252 test_value = divisor - 1;
1253 power = WhichPowerOf2(divisor);
1254 } else {
1255 // Check for (0 / -x) that will produce negative zero.
1256 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1257 __ test(dividend, Operand(dividend));
1258 DeoptimizeIf(zero, instr->environment());
1259 }
1260 // Check for (kMinInt / -1).
1261 if (divisor == -1 && instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1262 __ cmp(dividend, kMinInt);
1263 DeoptimizeIf(zero, instr->environment());
1264 }
1265 test_value = - divisor - 1;
1266 power = WhichPowerOf2(-divisor);
1267 }
1268
1269 if (test_value != 0) {
1270 // Deoptimize if remainder is not 0.
1271 __ test(dividend, Immediate(test_value));
1272 DeoptimizeIf(not_zero, instr->environment());
1273 __ sar(dividend, power);
1274 }
1275
1276 if (divisor < 0) __ neg(dividend);
1277
1278 return;
1279 }
1280
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001281 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001282 ASSERT(ToRegister(instr->result()).is(eax));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001283 ASSERT(ToRegister(instr->left()).is(eax));
1284 ASSERT(!ToRegister(instr->right()).is(eax));
1285 ASSERT(!ToRegister(instr->right()).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001286
1287 Register left_reg = eax;
1288
1289 // Check for x / 0.
1290 Register right_reg = ToRegister(right);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001291 if (instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001292 __ test(right_reg, ToOperand(right));
1293 DeoptimizeIf(zero, instr->environment());
1294 }
1295
1296 // Check for (0 / -x) that will produce negative zero.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001297 if (instr->hydrogen_value()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001298 Label left_not_zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001299 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001300 __ j(not_zero, &left_not_zero, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001301 __ test(right_reg, ToOperand(right));
1302 DeoptimizeIf(sign, instr->environment());
1303 __ bind(&left_not_zero);
1304 }
1305
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001306 // Check for (kMinInt / -1).
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001307 if (instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001308 Label left_not_min_int;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001309 __ cmp(left_reg, kMinInt);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001310 __ j(not_zero, &left_not_min_int, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001311 __ cmp(right_reg, -1);
1312 DeoptimizeIf(zero, instr->environment());
1313 __ bind(&left_not_min_int);
1314 }
1315
1316 // Sign extend to edx.
1317 __ cdq();
1318 __ idiv(right_reg);
1319
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001320 if (!instr->is_flooring()) {
1321 // Deoptimize if remainder is not 0.
1322 __ test(edx, Operand(edx));
1323 DeoptimizeIf(not_zero, instr->environment());
1324 } else {
1325 Label done;
1326 __ test(edx, edx);
1327 __ j(zero, &done, Label::kNear);
1328 __ xor_(edx, right_reg);
1329 __ sar(edx, 31);
1330 __ add(eax, edx);
1331 __ bind(&done);
1332 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001333}
1334
1335
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001336void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001337 ASSERT(instr->right()->IsConstantOperand());
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001338
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001339 Register dividend = ToRegister(instr->left());
1340 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001341 Register result = ToRegister(instr->result());
1342
1343 switch (divisor) {
1344 case 0:
1345 DeoptimizeIf(no_condition, instr->environment());
1346 return;
1347
1348 case 1:
1349 __ Move(result, dividend);
1350 return;
1351
1352 case -1:
1353 __ Move(result, dividend);
1354 __ neg(result);
1355 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1356 DeoptimizeIf(zero, instr->environment());
1357 }
1358 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1359 DeoptimizeIf(overflow, instr->environment());
1360 }
1361 return;
1362 }
1363
1364 uint32_t divisor_abs = abs(divisor);
1365 if (IsPowerOf2(divisor_abs)) {
1366 int32_t power = WhichPowerOf2(divisor_abs);
1367 if (divisor < 0) {
1368 // Input[dividend] is clobbered.
1369 // The sequence is tedious because neg(dividend) might overflow.
1370 __ mov(result, dividend);
1371 __ sar(dividend, 31);
1372 __ neg(result);
1373 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1374 DeoptimizeIf(zero, instr->environment());
1375 }
1376 __ shl(dividend, 32 - power);
1377 __ sar(result, power);
1378 __ not_(dividend);
1379 // Clear result.sign if dividend.sign is set.
1380 __ and_(result, dividend);
1381 } else {
1382 __ Move(result, dividend);
1383 __ sar(result, power);
1384 }
1385 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001386 ASSERT(ToRegister(instr->left()).is(eax));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001387 ASSERT(ToRegister(instr->result()).is(edx));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001388 Register scratch = ToRegister(instr->temp());
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001389
1390 // Find b which: 2^b < divisor_abs < 2^(b+1).
1391 unsigned b = 31 - CompilerIntrinsics::CountLeadingZeros(divisor_abs);
1392 unsigned shift = 32 + b; // Precision +1bit (effectively).
1393 double multiplier_f =
1394 static_cast<double>(static_cast<uint64_t>(1) << shift) / divisor_abs;
1395 int64_t multiplier;
1396 if (multiplier_f - floor(multiplier_f) < 0.5) {
1397 multiplier = static_cast<int64_t>(floor(multiplier_f));
1398 } else {
1399 multiplier = static_cast<int64_t>(floor(multiplier_f)) + 1;
1400 }
1401 // The multiplier is a uint32.
1402 ASSERT(multiplier > 0 &&
1403 multiplier < (static_cast<int64_t>(1) << 32));
1404 __ mov(scratch, dividend);
1405 if (divisor < 0 &&
1406 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1407 __ test(dividend, dividend);
1408 DeoptimizeIf(zero, instr->environment());
1409 }
1410 __ mov(edx, static_cast<int32_t>(multiplier));
1411 __ imul(edx);
1412 if (static_cast<int32_t>(multiplier) < 0) {
1413 __ add(edx, scratch);
1414 }
1415 Register reg_lo = eax;
1416 Register reg_byte_scratch = scratch;
1417 if (!reg_byte_scratch.is_byte_register()) {
1418 __ xchg(reg_lo, reg_byte_scratch);
1419 reg_lo = scratch;
1420 reg_byte_scratch = eax;
1421 }
1422 if (divisor < 0) {
1423 __ xor_(reg_byte_scratch, reg_byte_scratch);
1424 __ cmp(reg_lo, 0x40000000);
1425 __ setcc(above, reg_byte_scratch);
1426 __ neg(edx);
1427 __ sub(edx, reg_byte_scratch);
1428 } else {
1429 __ xor_(reg_byte_scratch, reg_byte_scratch);
1430 __ cmp(reg_lo, 0xC0000000);
1431 __ setcc(above_equal, reg_byte_scratch);
1432 __ add(edx, reg_byte_scratch);
1433 }
1434 __ sar(edx, shift - 32);
1435 }
1436}
1437
1438
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001439void LCodeGen::DoMulI(LMulI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001440 Register left = ToRegister(instr->left());
1441 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001442
1443 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001444 __ mov(ToRegister(instr->temp()), left);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001445 }
1446
1447 if (right->IsConstantOperand()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001448 // Try strength reductions on the multiplication.
1449 // All replacement instructions are at most as long as the imul
1450 // and have better latency.
1451 int constant = ToInteger32(LConstantOperand::cast(right));
1452 if (constant == -1) {
1453 __ neg(left);
1454 } else if (constant == 0) {
1455 __ xor_(left, Operand(left));
1456 } else if (constant == 2) {
1457 __ add(left, Operand(left));
1458 } else if (!instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1459 // If we know that the multiplication can't overflow, it's safe to
1460 // use instructions that don't set the overflow flag for the
1461 // multiplication.
1462 switch (constant) {
1463 case 1:
1464 // Do nothing.
1465 break;
1466 case 3:
1467 __ lea(left, Operand(left, left, times_2, 0));
1468 break;
1469 case 4:
1470 __ shl(left, 2);
1471 break;
1472 case 5:
1473 __ lea(left, Operand(left, left, times_4, 0));
1474 break;
1475 case 8:
1476 __ shl(left, 3);
1477 break;
1478 case 9:
1479 __ lea(left, Operand(left, left, times_8, 0));
1480 break;
1481 case 16:
1482 __ shl(left, 4);
1483 break;
1484 default:
1485 __ imul(left, left, constant);
1486 break;
1487 }
1488 } else {
1489 __ imul(left, left, constant);
1490 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001491 } else {
1492 __ imul(left, ToOperand(right));
1493 }
1494
1495 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1496 DeoptimizeIf(overflow, instr->environment());
1497 }
1498
1499 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1500 // Bail out if the result is supposed to be negative zero.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001501 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001502 __ test(left, Operand(left));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001503 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001504 if (right->IsConstantOperand()) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001505 if (ToInteger32(LConstantOperand::cast(right)) < 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001506 DeoptimizeIf(no_condition, instr->environment());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001507 } else if (ToInteger32(LConstantOperand::cast(right)) == 0) {
1508 __ cmp(ToRegister(instr->temp()), Immediate(0));
1509 DeoptimizeIf(less, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001510 }
1511 } else {
1512 // Test the non-zero operand for negative sign.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001513 __ or_(ToRegister(instr->temp()), ToOperand(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001514 DeoptimizeIf(sign, instr->environment());
1515 }
1516 __ bind(&done);
1517 }
1518}
1519
1520
1521void LCodeGen::DoBitI(LBitI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001522 LOperand* left = instr->left();
1523 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001524 ASSERT(left->Equals(instr->result()));
1525 ASSERT(left->IsRegister());
1526
1527 if (right->IsConstantOperand()) {
1528 int right_operand = ToInteger32(LConstantOperand::cast(right));
1529 switch (instr->op()) {
1530 case Token::BIT_AND:
1531 __ and_(ToRegister(left), right_operand);
1532 break;
1533 case Token::BIT_OR:
1534 __ or_(ToRegister(left), right_operand);
1535 break;
1536 case Token::BIT_XOR:
1537 __ xor_(ToRegister(left), right_operand);
1538 break;
1539 default:
1540 UNREACHABLE();
1541 break;
1542 }
1543 } else {
1544 switch (instr->op()) {
1545 case Token::BIT_AND:
1546 __ and_(ToRegister(left), ToOperand(right));
1547 break;
1548 case Token::BIT_OR:
1549 __ or_(ToRegister(left), ToOperand(right));
1550 break;
1551 case Token::BIT_XOR:
1552 __ xor_(ToRegister(left), ToOperand(right));
1553 break;
1554 default:
1555 UNREACHABLE();
1556 break;
1557 }
1558 }
1559}
1560
1561
1562void LCodeGen::DoShiftI(LShiftI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001563 LOperand* left = instr->left();
1564 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001565 ASSERT(left->Equals(instr->result()));
1566 ASSERT(left->IsRegister());
1567 if (right->IsRegister()) {
1568 ASSERT(ToRegister(right).is(ecx));
1569
1570 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001571 case Token::ROR:
1572 __ ror_cl(ToRegister(left));
1573 if (instr->can_deopt()) {
1574 __ test(ToRegister(left), Immediate(0x80000000));
1575 DeoptimizeIf(not_zero, instr->environment());
1576 }
1577 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001578 case Token::SAR:
1579 __ sar_cl(ToRegister(left));
1580 break;
1581 case Token::SHR:
1582 __ shr_cl(ToRegister(left));
1583 if (instr->can_deopt()) {
1584 __ test(ToRegister(left), Immediate(0x80000000));
1585 DeoptimizeIf(not_zero, instr->environment());
1586 }
1587 break;
1588 case Token::SHL:
1589 __ shl_cl(ToRegister(left));
1590 break;
1591 default:
1592 UNREACHABLE();
1593 break;
1594 }
1595 } else {
1596 int value = ToInteger32(LConstantOperand::cast(right));
1597 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1598 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001599 case Token::ROR:
1600 if (shift_count == 0 && instr->can_deopt()) {
1601 __ test(ToRegister(left), Immediate(0x80000000));
1602 DeoptimizeIf(not_zero, instr->environment());
1603 } else {
1604 __ ror(ToRegister(left), shift_count);
1605 }
1606 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001607 case Token::SAR:
1608 if (shift_count != 0) {
1609 __ sar(ToRegister(left), shift_count);
1610 }
1611 break;
1612 case Token::SHR:
1613 if (shift_count == 0 && instr->can_deopt()) {
1614 __ test(ToRegister(left), Immediate(0x80000000));
1615 DeoptimizeIf(not_zero, instr->environment());
1616 } else {
1617 __ shr(ToRegister(left), shift_count);
1618 }
1619 break;
1620 case Token::SHL:
1621 if (shift_count != 0) {
1622 __ shl(ToRegister(left), shift_count);
1623 }
1624 break;
1625 default:
1626 UNREACHABLE();
1627 break;
1628 }
1629 }
1630}
1631
1632
1633void LCodeGen::DoSubI(LSubI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001634 LOperand* left = instr->left();
1635 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001636 ASSERT(left->Equals(instr->result()));
1637
1638 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001639 __ sub(ToOperand(left), ToInteger32Immediate(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001640 } else {
1641 __ sub(ToRegister(left), ToOperand(right));
1642 }
1643 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1644 DeoptimizeIf(overflow, instr->environment());
1645 }
1646}
1647
1648
1649void LCodeGen::DoConstantI(LConstantI* instr) {
1650 ASSERT(instr->result()->IsRegister());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001651 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001652}
1653
1654
1655void LCodeGen::DoConstantD(LConstantD* instr) {
1656 ASSERT(instr->result()->IsDoubleRegister());
1657 XMMRegister res = ToDoubleRegister(instr->result());
1658 double v = instr->value();
1659 // Use xor to produce +0.0 in a fast and compact way, but avoid to
1660 // do so if the constant is -0.0.
1661 if (BitCast<uint64_t, double>(v) == 0) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001662 __ xorps(res, res);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001663 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001664 Register temp = ToRegister(instr->temp());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001665 uint64_t int_val = BitCast<uint64_t, double>(v);
1666 int32_t lower = static_cast<int32_t>(int_val);
1667 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001668 if (CpuFeatures::IsSupported(SSE4_1)) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001669 CpuFeatures::Scope scope1(SSE2);
1670 CpuFeatures::Scope scope2(SSE4_1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001671 if (lower != 0) {
1672 __ Set(temp, Immediate(lower));
1673 __ movd(res, Operand(temp));
1674 __ Set(temp, Immediate(upper));
1675 __ pinsrd(res, Operand(temp), 1);
1676 } else {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001677 __ xorps(res, res);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001678 __ Set(temp, Immediate(upper));
1679 __ pinsrd(res, Operand(temp), 1);
1680 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001681 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001682 CpuFeatures::Scope scope(SSE2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001683 __ Set(temp, Immediate(upper));
1684 __ movd(res, Operand(temp));
1685 __ psllq(res, 32);
1686 if (lower != 0) {
1687 __ Set(temp, Immediate(lower));
1688 __ movd(xmm0, Operand(temp));
1689 __ por(res, xmm0);
1690 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001691 }
1692 }
1693}
1694
1695
1696void LCodeGen::DoConstantT(LConstantT* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001697 Register reg = ToRegister(instr->result());
1698 Handle<Object> handle = instr->value();
1699 if (handle->IsHeapObject()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001700 __ LoadHeapObject(reg, Handle<HeapObject>::cast(handle));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001701 } else {
1702 __ Set(reg, Immediate(handle));
1703 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001704}
1705
1706
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001707void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001708 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001709 Register array = ToRegister(instr->value());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001710 __ mov(result, FieldOperand(array, JSArray::kLengthOffset));
1711}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001712
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001713
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001714void LCodeGen::DoFixedArrayBaseLength(
1715 LFixedArrayBaseLength* instr) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001716 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001717 Register array = ToRegister(instr->value());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001718 __ mov(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001719}
1720
1721
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001722void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
1723 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001724 Register map = ToRegister(instr->value());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001725 __ EnumLength(result, map);
1726}
1727
1728
whesse@chromium.org7b260152011-06-20 15:33:18 +00001729void LCodeGen::DoElementsKind(LElementsKind* instr) {
1730 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001731 Register input = ToRegister(instr->value());
whesse@chromium.org7b260152011-06-20 15:33:18 +00001732
1733 // Load map into |result|.
1734 __ mov(result, FieldOperand(input, HeapObject::kMapOffset));
1735 // Load the map's "bit field 2" into |result|. We only need the first byte,
1736 // but the following masking takes care of that anyway.
1737 __ mov(result, FieldOperand(result, Map::kBitField2Offset));
1738 // Retrieve elements_kind from bit field 2.
1739 __ and_(result, Map::kElementsKindMask);
1740 __ shr(result, Map::kElementsKindShift);
1741}
1742
1743
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001744void LCodeGen::DoValueOf(LValueOf* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001745 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001746 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001747 Register map = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001748 ASSERT(input.is(result));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001749
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001750 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001751 // If the object is a smi return the object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001752 __ JumpIfSmi(input, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001753
1754 // If the object is not a value type, return the object.
1755 __ CmpObjectType(input, JS_VALUE_TYPE, map);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001756 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001757 __ mov(result, FieldOperand(input, JSValue::kValueOffset));
1758
1759 __ bind(&done);
1760}
1761
1762
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001763void LCodeGen::DoDateField(LDateField* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001764 Register object = ToRegister(instr->date());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001765 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001766 Register scratch = ToRegister(instr->temp());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001767 Smi* index = instr->index();
1768 Label runtime, done;
1769 ASSERT(object.is(result));
1770 ASSERT(object.is(eax));
1771
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001772 __ test(object, Immediate(kSmiTagMask));
1773 DeoptimizeIf(zero, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001774 __ CmpObjectType(object, JS_DATE_TYPE, scratch);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001775 DeoptimizeIf(not_equal, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001776
1777 if (index->value() == 0) {
1778 __ mov(result, FieldOperand(object, JSDate::kValueOffset));
1779 } else {
1780 if (index->value() < JSDate::kFirstUncachedField) {
1781 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
1782 __ mov(scratch, Operand::StaticVariable(stamp));
1783 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
1784 __ j(not_equal, &runtime, Label::kNear);
1785 __ mov(result, FieldOperand(object, JSDate::kValueOffset +
1786 kPointerSize * index->value()));
1787 __ jmp(&done);
1788 }
1789 __ bind(&runtime);
1790 __ PrepareCallCFunction(2, scratch);
1791 __ mov(Operand(esp, 0), object);
1792 __ mov(Operand(esp, 1 * kPointerSize), Immediate(index));
1793 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
1794 __ bind(&done);
1795 }
1796}
1797
1798
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00001799void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
1800 SeqStringSetCharGenerator::Generate(masm(),
1801 instr->encoding(),
1802 ToRegister(instr->string()),
1803 ToRegister(instr->index()),
1804 ToRegister(instr->value()));
1805}
1806
1807
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001808void LCodeGen::DoBitNotI(LBitNotI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001809 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001810 ASSERT(input->Equals(instr->result()));
1811 __ not_(ToRegister(input));
1812}
1813
1814
1815void LCodeGen::DoThrow(LThrow* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001816 __ push(ToOperand(instr->value()));
1817 ASSERT(ToRegister(instr->context()).is(esi));
1818 CallRuntime(Runtime::kThrow, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001819
1820 if (FLAG_debug_code) {
1821 Comment("Unreachable code.");
1822 __ int3();
1823 }
1824}
1825
1826
1827void LCodeGen::DoAddI(LAddI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001828 LOperand* left = instr->left();
1829 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001830 ASSERT(left->Equals(instr->result()));
1831
1832 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001833 __ add(ToOperand(left), ToInteger32Immediate(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001834 } else {
1835 __ add(ToRegister(left), ToOperand(right));
1836 }
1837
1838 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1839 DeoptimizeIf(overflow, instr->environment());
1840 }
1841}
1842
1843
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001844void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001845 CpuFeatures::Scope scope(SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001846 LOperand* left = instr->left();
1847 LOperand* right = instr->right();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001848 ASSERT(left->Equals(instr->result()));
1849 HMathMinMax::Operation operation = instr->hydrogen()->operation();
1850 if (instr->hydrogen()->representation().IsInteger32()) {
1851 Label return_left;
1852 Condition condition = (operation == HMathMinMax::kMathMin)
1853 ? less_equal
1854 : greater_equal;
1855 if (right->IsConstantOperand()) {
1856 Operand left_op = ToOperand(left);
1857 Immediate right_imm = ToInteger32Immediate(right);
1858 __ cmp(left_op, right_imm);
1859 __ j(condition, &return_left, Label::kNear);
1860 __ mov(left_op, right_imm);
1861 } else {
1862 Register left_reg = ToRegister(left);
1863 Operand right_op = ToOperand(right);
1864 __ cmp(left_reg, right_op);
1865 __ j(condition, &return_left, Label::kNear);
1866 __ mov(left_reg, right_op);
1867 }
1868 __ bind(&return_left);
1869 } else {
1870 ASSERT(instr->hydrogen()->representation().IsDouble());
1871 Label check_nan_left, check_zero, return_left, return_right;
1872 Condition condition = (operation == HMathMinMax::kMathMin) ? below : above;
1873 XMMRegister left_reg = ToDoubleRegister(left);
1874 XMMRegister right_reg = ToDoubleRegister(right);
1875 __ ucomisd(left_reg, right_reg);
1876 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN.
1877 __ j(equal, &check_zero, Label::kNear); // left == right.
1878 __ j(condition, &return_left, Label::kNear);
1879 __ jmp(&return_right, Label::kNear);
1880
1881 __ bind(&check_zero);
1882 XMMRegister xmm_scratch = xmm0;
1883 __ xorps(xmm_scratch, xmm_scratch);
1884 __ ucomisd(left_reg, xmm_scratch);
1885 __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
1886 // At this point, both left and right are either 0 or -0.
1887 if (operation == HMathMinMax::kMathMin) {
1888 __ orpd(left_reg, right_reg);
1889 } else {
1890 // Since we operate on +0 and/or -0, addsd and andsd have the same effect.
1891 __ addsd(left_reg, right_reg);
1892 }
1893 __ jmp(&return_left, Label::kNear);
1894
1895 __ bind(&check_nan_left);
1896 __ ucomisd(left_reg, left_reg); // NaN check.
1897 __ j(parity_even, &return_left, Label::kNear); // left == NaN.
1898 __ bind(&return_right);
1899 __ movsd(left_reg, right_reg);
1900
1901 __ bind(&return_left);
1902 }
1903}
1904
1905
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001906void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001907 CpuFeatures::Scope scope(SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001908 XMMRegister left = ToDoubleRegister(instr->left());
1909 XMMRegister right = ToDoubleRegister(instr->right());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001910 XMMRegister result = ToDoubleRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001911 // Modulo uses a fixed result register.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001912 ASSERT(instr->op() == Token::MOD || left.is(result));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001913 switch (instr->op()) {
1914 case Token::ADD:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001915 __ addsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001916 break;
1917 case Token::SUB:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001918 __ subsd(left, right);
1919 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001920 case Token::MUL:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001921 __ mulsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001922 break;
1923 case Token::DIV:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001924 __ divsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001925 break;
1926 case Token::MOD: {
1927 // Pass two doubles as arguments on the stack.
1928 __ PrepareCallCFunction(4, eax);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001929 __ movdbl(Operand(esp, 0 * kDoubleSize), left);
1930 __ movdbl(Operand(esp, 1 * kDoubleSize), right);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001931 __ CallCFunction(
1932 ExternalReference::double_fp_operation(Token::MOD, isolate()),
1933 4);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001934
1935 // Return value is in st(0) on ia32.
1936 // Store it into the (fixed) result register.
1937 __ sub(Operand(esp), Immediate(kDoubleSize));
1938 __ fstp_d(Operand(esp, 0));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001939 __ movdbl(result, Operand(esp, 0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001940 __ add(Operand(esp), Immediate(kDoubleSize));
1941 break;
1942 }
1943 default:
1944 UNREACHABLE();
1945 break;
1946 }
1947}
1948
1949
1950void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001951 ASSERT(ToRegister(instr->context()).is(esi));
1952 ASSERT(ToRegister(instr->left()).is(edx));
1953 ASSERT(ToRegister(instr->right()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001954 ASSERT(ToRegister(instr->result()).is(eax));
1955
danno@chromium.org40cb8782011-05-25 07:58:50 +00001956 BinaryOpStub stub(instr->op(), NO_OVERWRITE);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001957 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001958 __ nop(); // Signals no inlined code.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001959}
1960
1961
1962int LCodeGen::GetNextEmittedBlock(int block) {
1963 for (int i = block + 1; i < graph()->blocks()->length(); ++i) {
1964 LLabel* label = chunk_->GetLabel(i);
1965 if (!label->HasReplacement()) return i;
1966 }
1967 return -1;
1968}
1969
1970
1971void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
1972 int next_block = GetNextEmittedBlock(current_block_);
1973 right_block = chunk_->LookupDestination(right_block);
1974 left_block = chunk_->LookupDestination(left_block);
1975
1976 if (right_block == left_block) {
1977 EmitGoto(left_block);
1978 } else if (left_block == next_block) {
1979 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
1980 } else if (right_block == next_block) {
1981 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1982 } else {
1983 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1984 __ jmp(chunk_->GetAssemblyLabel(right_block));
1985 }
1986}
1987
1988
1989void LCodeGen::DoBranch(LBranch* instr) {
1990 int true_block = chunk_->LookupDestination(instr->true_block_id());
1991 int false_block = chunk_->LookupDestination(instr->false_block_id());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001992 CpuFeatures::Scope scope(SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001993
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001994 Representation r = instr->hydrogen()->value()->representation();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001995 if (r.IsInteger32()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001996 Register reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001997 __ test(reg, Operand(reg));
1998 EmitBranch(true_block, false_block, not_zero);
1999 } else if (r.IsDouble()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002000 XMMRegister reg = ToDoubleRegister(instr->value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00002001 __ xorps(xmm0, xmm0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002002 __ ucomisd(reg, xmm0);
2003 EmitBranch(true_block, false_block, not_equal);
2004 } else {
2005 ASSERT(r.IsTagged());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002006 Register reg = ToRegister(instr->value());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002007 HType type = instr->hydrogen()->value()->type();
2008 if (type.IsBoolean()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002009 __ cmp(reg, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002010 EmitBranch(true_block, false_block, equal);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002011 } else if (type.IsSmi()) {
2012 __ test(reg, Operand(reg));
2013 EmitBranch(true_block, false_block, not_equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002014 } else {
2015 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2016 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2017
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002018 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
2019 // Avoid deopts in the case where we've never executed this path before.
2020 if (expected.IsEmpty()) expected = ToBooleanStub::all_types();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002021
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002022 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
2023 // undefined -> false.
2024 __ cmp(reg, factory()->undefined_value());
2025 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002026 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002027 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
2028 // true -> true.
2029 __ cmp(reg, factory()->true_value());
2030 __ j(equal, true_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002031 // false -> false.
2032 __ cmp(reg, factory()->false_value());
2033 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002034 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002035 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
2036 // 'null' -> false.
2037 __ cmp(reg, factory()->null_value());
2038 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002039 }
2040
2041 if (expected.Contains(ToBooleanStub::SMI)) {
2042 // Smis: 0 -> false, all other -> true.
2043 __ test(reg, Operand(reg));
2044 __ j(equal, false_label);
2045 __ JumpIfSmi(reg, true_label);
2046 } else if (expected.NeedsMap()) {
2047 // If we need a map later and have a Smi -> deopt.
2048 __ test(reg, Immediate(kSmiTagMask));
2049 DeoptimizeIf(zero, instr->environment());
2050 }
2051
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002052 Register map = no_reg; // Keep the compiler happy.
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002053 if (expected.NeedsMap()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002054 map = ToRegister(instr->temp());
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002055 ASSERT(!map.is(reg));
2056 __ mov(map, FieldOperand(reg, HeapObject::kMapOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002057
2058 if (expected.CanBeUndetectable()) {
2059 // Undetectable -> false.
2060 __ test_b(FieldOperand(map, Map::kBitFieldOffset),
2061 1 << Map::kIsUndetectable);
2062 __ j(not_zero, false_label);
2063 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002064 }
2065
2066 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
2067 // spec object -> true.
2068 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
2069 __ j(above_equal, true_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002070 }
2071
2072 if (expected.Contains(ToBooleanStub::STRING)) {
2073 // String value -> false iff empty.
2074 Label not_string;
2075 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
2076 __ j(above_equal, &not_string, Label::kNear);
2077 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
2078 __ j(not_zero, true_label);
2079 __ jmp(false_label);
2080 __ bind(&not_string);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002081 }
2082
2083 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
2084 // heap number -> false iff +0, -0, or NaN.
2085 Label not_heap_number;
2086 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
2087 factory()->heap_number_map());
2088 __ j(not_equal, &not_heap_number, Label::kNear);
2089 __ fldz();
2090 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset));
2091 __ FCmp();
2092 __ j(zero, false_label);
2093 __ jmp(true_label);
2094 __ bind(&not_heap_number);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002095 }
2096
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002097 // We've seen something for the first time -> deopt.
2098 DeoptimizeIf(no_condition, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002099 }
2100 }
2101}
2102
2103
ager@chromium.org04921a82011-06-27 13:21:41 +00002104void LCodeGen::EmitGoto(int block) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002105 block = chunk_->LookupDestination(block);
2106 int next_block = GetNextEmittedBlock(current_block_);
2107 if (block != next_block) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002108 __ jmp(chunk_->GetAssemblyLabel(block));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002109 }
2110}
2111
2112
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002113void LCodeGen::DoGoto(LGoto* instr) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002114 EmitGoto(instr->block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002115}
2116
2117
2118Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
2119 Condition cond = no_condition;
2120 switch (op) {
2121 case Token::EQ:
2122 case Token::EQ_STRICT:
2123 cond = equal;
2124 break;
2125 case Token::LT:
2126 cond = is_unsigned ? below : less;
2127 break;
2128 case Token::GT:
2129 cond = is_unsigned ? above : greater;
2130 break;
2131 case Token::LTE:
2132 cond = is_unsigned ? below_equal : less_equal;
2133 break;
2134 case Token::GTE:
2135 cond = is_unsigned ? above_equal : greater_equal;
2136 break;
2137 case Token::IN:
2138 case Token::INSTANCEOF:
2139 default:
2140 UNREACHABLE();
2141 }
2142 return cond;
2143}
2144
2145
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002146void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002147 LOperand* left = instr->left();
2148 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002149 int false_block = chunk_->LookupDestination(instr->false_block_id());
2150 int true_block = chunk_->LookupDestination(instr->true_block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002151 Condition cc = TokenToCondition(instr->op(), instr->is_double());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002152 CpuFeatures::Scope scope(SSE2);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002153
2154 if (left->IsConstantOperand() && right->IsConstantOperand()) {
2155 // We can statically evaluate the comparison.
2156 double left_val = ToDouble(LConstantOperand::cast(left));
2157 double right_val = ToDouble(LConstantOperand::cast(right));
2158 int next_block =
2159 EvalComparison(instr->op(), left_val, right_val) ? true_block
2160 : false_block;
2161 EmitGoto(next_block);
2162 } else {
2163 if (instr->is_double()) {
2164 // Don't base result on EFLAGS when a NaN is involved. Instead
2165 // jump to the false block.
2166 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
2167 __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
2168 } else {
2169 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00002170 __ cmp(ToRegister(left), ToInteger32Immediate(right));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002171 } else if (left->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00002172 __ cmp(ToOperand(right), ToInteger32Immediate(left));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002173 // We transposed the operands. Reverse the condition.
2174 cc = ReverseCondition(cc);
2175 } else {
2176 __ cmp(ToRegister(left), ToOperand(right));
2177 }
2178 }
2179 EmitBranch(true_block, false_block, cc);
2180 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002181}
2182
2183
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002184void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002185 Register left = ToRegister(instr->left());
2186 Operand right = ToOperand(instr->right());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002187 int false_block = chunk_->LookupDestination(instr->false_block_id());
2188 int true_block = chunk_->LookupDestination(instr->true_block_id());
2189
2190 __ cmp(left, Operand(right));
2191 EmitBranch(true_block, false_block, equal);
2192}
2193
2194
whesse@chromium.org7b260152011-06-20 15:33:18 +00002195void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002196 Register left = ToRegister(instr->left());
whesse@chromium.org7b260152011-06-20 15:33:18 +00002197 int true_block = chunk_->LookupDestination(instr->true_block_id());
2198 int false_block = chunk_->LookupDestination(instr->false_block_id());
2199
2200 __ cmp(left, instr->hydrogen()->right());
2201 EmitBranch(true_block, false_block, equal);
2202}
2203
2204
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002205void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002206 Register reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002207 int false_block = chunk_->LookupDestination(instr->false_block_id());
2208
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002209 // If the expression is known to be untagged or a smi, then it's definitely
2210 // not null, and it can't be a an undetectable object.
2211 if (instr->hydrogen()->representation().IsSpecialization() ||
2212 instr->hydrogen()->type().IsSmi()) {
2213 EmitGoto(false_block);
2214 return;
2215 }
2216
2217 int true_block = chunk_->LookupDestination(instr->true_block_id());
2218 Handle<Object> nil_value = instr->nil() == kNullValue ?
2219 factory()->null_value() :
2220 factory()->undefined_value();
2221 __ cmp(reg, nil_value);
2222 if (instr->kind() == kStrictEquality) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002223 EmitBranch(true_block, false_block, equal);
2224 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002225 Handle<Object> other_nil_value = instr->nil() == kNullValue ?
2226 factory()->undefined_value() :
2227 factory()->null_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002228 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2229 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2230 __ j(equal, true_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002231 __ cmp(reg, other_nil_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002232 __ j(equal, true_label);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002233 __ JumpIfSmi(reg, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002234 // Check for undetectable objects by looking in the bit field in
2235 // the map. The object has already been smi checked.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002236 Register scratch = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002237 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
2238 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
2239 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
2240 EmitBranch(true_block, false_block, not_zero);
2241 }
2242}
2243
2244
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002245Condition LCodeGen::EmitIsObject(Register input,
2246 Register temp1,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002247 Label* is_not_object,
2248 Label* is_object) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002249 __ JumpIfSmi(input, is_not_object);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002250
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002251 __ cmp(input, isolate()->factory()->null_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002252 __ j(equal, is_object);
2253
2254 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
2255 // Undetectable objects behave like undefined.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002256 __ test_b(FieldOperand(temp1, Map::kBitFieldOffset),
2257 1 << Map::kIsUndetectable);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002258 __ j(not_zero, is_not_object);
2259
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002260 __ movzx_b(temp1, FieldOperand(temp1, Map::kInstanceTypeOffset));
2261 __ cmp(temp1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002262 __ j(below, is_not_object);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002263 __ cmp(temp1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002264 return below_equal;
2265}
2266
2267
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002268void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002269 Register reg = ToRegister(instr->value());
2270 Register temp = ToRegister(instr->temp());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002271
2272 int true_block = chunk_->LookupDestination(instr->true_block_id());
2273 int false_block = chunk_->LookupDestination(instr->false_block_id());
2274 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2275 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2276
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002277 Condition true_cond = EmitIsObject(reg, temp, false_label, true_label);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002278
2279 EmitBranch(true_block, false_block, true_cond);
2280}
2281
2282
erikcorry0ad885c2011-11-21 13:51:57 +00002283Condition LCodeGen::EmitIsString(Register input,
2284 Register temp1,
2285 Label* is_not_string) {
2286 __ JumpIfSmi(input, is_not_string);
2287
2288 Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
2289
2290 return cond;
2291}
2292
2293
2294void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002295 Register reg = ToRegister(instr->value());
2296 Register temp = ToRegister(instr->temp());
erikcorry0ad885c2011-11-21 13:51:57 +00002297
2298 int true_block = chunk_->LookupDestination(instr->true_block_id());
2299 int false_block = chunk_->LookupDestination(instr->false_block_id());
2300 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2301
2302 Condition true_cond = EmitIsString(reg, temp, false_label);
2303
2304 EmitBranch(true_block, false_block, true_cond);
2305}
2306
2307
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002308void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002309 Operand input = ToOperand(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002310
2311 int true_block = chunk_->LookupDestination(instr->true_block_id());
2312 int false_block = chunk_->LookupDestination(instr->false_block_id());
2313
2314 __ test(input, Immediate(kSmiTagMask));
2315 EmitBranch(true_block, false_block, zero);
2316}
2317
2318
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002319void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002320 Register input = ToRegister(instr->value());
2321 Register temp = ToRegister(instr->temp());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002322
2323 int true_block = chunk_->LookupDestination(instr->true_block_id());
2324 int false_block = chunk_->LookupDestination(instr->false_block_id());
2325
2326 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002327 __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002328 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
2329 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
2330 1 << Map::kIsUndetectable);
2331 EmitBranch(true_block, false_block, not_zero);
2332}
2333
2334
erikcorry0ad885c2011-11-21 13:51:57 +00002335static Condition ComputeCompareCondition(Token::Value op) {
2336 switch (op) {
2337 case Token::EQ_STRICT:
2338 case Token::EQ:
2339 return equal;
2340 case Token::LT:
2341 return less;
2342 case Token::GT:
2343 return greater;
2344 case Token::LTE:
2345 return less_equal;
2346 case Token::GTE:
2347 return greater_equal;
2348 default:
2349 UNREACHABLE();
2350 return no_condition;
2351 }
2352}
2353
2354
2355void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
2356 Token::Value op = instr->op();
2357 int true_block = chunk_->LookupDestination(instr->true_block_id());
2358 int false_block = chunk_->LookupDestination(instr->false_block_id());
2359
2360 Handle<Code> ic = CompareIC::GetUninitialized(op);
2361 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2362
2363 Condition condition = ComputeCompareCondition(op);
2364 __ test(eax, Operand(eax));
2365
2366 EmitBranch(true_block, false_block, condition);
2367}
2368
2369
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002370static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002371 InstanceType from = instr->from();
2372 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002373 if (from == FIRST_TYPE) return to;
2374 ASSERT(from == to || to == LAST_TYPE);
2375 return from;
2376}
2377
2378
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002379static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002380 InstanceType from = instr->from();
2381 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002382 if (from == to) return equal;
2383 if (to == LAST_TYPE) return above_equal;
2384 if (from == FIRST_TYPE) return below_equal;
2385 UNREACHABLE();
2386 return equal;
2387}
2388
2389
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002390void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002391 Register input = ToRegister(instr->value());
2392 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002393
2394 int true_block = chunk_->LookupDestination(instr->true_block_id());
2395 int false_block = chunk_->LookupDestination(instr->false_block_id());
2396
2397 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2398
whesse@chromium.org7b260152011-06-20 15:33:18 +00002399 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002400
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002401 __ CmpObjectType(input, TestType(instr->hydrogen()), temp);
2402 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002403}
2404
2405
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002406void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002407 Register input = ToRegister(instr->value());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002408 Register result = ToRegister(instr->result());
2409
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002410 __ AssertString(input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002411
2412 __ mov(result, FieldOperand(input, String::kHashFieldOffset));
2413 __ IndexFromHash(result, result);
2414}
2415
2416
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002417void LCodeGen::DoHasCachedArrayIndexAndBranch(
2418 LHasCachedArrayIndexAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002419 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002420
2421 int true_block = chunk_->LookupDestination(instr->true_block_id());
2422 int false_block = chunk_->LookupDestination(instr->false_block_id());
2423
2424 __ test(FieldOperand(input, String::kHashFieldOffset),
2425 Immediate(String::kContainsCachedArrayIndexMask));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002426 EmitBranch(true_block, false_block, equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002427}
2428
2429
2430// Branches to a label or falls through with the answer in the z flag. Trashes
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002431// the temp registers, but not the input.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002432void LCodeGen::EmitClassOfTest(Label* is_true,
2433 Label* is_false,
2434 Handle<String>class_name,
2435 Register input,
2436 Register temp,
2437 Register temp2) {
2438 ASSERT(!input.is(temp));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002439 ASSERT(!input.is(temp2));
2440 ASSERT(!temp.is(temp2));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002441 __ JumpIfSmi(input, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002442
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002443 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Function"))) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002444 // Assuming the following assertions, we can use the same compares to test
2445 // for both being a function type and being in the object type range.
2446 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2447 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2448 FIRST_SPEC_OBJECT_TYPE + 1);
2449 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2450 LAST_SPEC_OBJECT_TYPE - 1);
2451 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
2452 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
2453 __ j(below, is_false);
2454 __ j(equal, is_true);
2455 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
2456 __ j(equal, is_true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002457 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002458 // Faster code path to avoid two compares: subtract lower bound from the
2459 // actual type and do a signed compare with the width of the type range.
2460 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002461 __ movzx_b(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002462 __ sub(Operand(temp2), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002463 __ cmp(Operand(temp2), Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
2464 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002465 __ j(above, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002466 }
2467
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002468 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002469 // Check if the constructor in the map is a function.
2470 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002471 // Objects with a non-function constructor have class 'Object'.
2472 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002473 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002474 __ j(not_equal, is_true);
2475 } else {
2476 __ j(not_equal, is_false);
2477 }
2478
2479 // temp now contains the constructor function. Grab the
2480 // instance class name from there.
2481 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
2482 __ mov(temp, FieldOperand(temp,
2483 SharedFunctionInfo::kInstanceClassNameOffset));
2484 // The class name we are testing against is a symbol because it's a literal.
2485 // The name in the constructor is a symbol because of the way the context is
2486 // booted. This routine isn't expected to work for random API-created
2487 // classes and it doesn't have to because you can't access it with natives
2488 // syntax. Since both sides are symbols it is sufficient to use an identity
2489 // comparison.
2490 __ cmp(temp, class_name);
2491 // End with the answer in the z flag.
2492}
2493
2494
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002495void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002496 Register input = ToRegister(instr->value());
2497 Register temp = ToRegister(instr->temp());
2498 Register temp2 = ToRegister(instr->temp2());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002499
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002500 Handle<String> class_name = instr->hydrogen()->class_name();
2501
2502 int true_block = chunk_->LookupDestination(instr->true_block_id());
2503 int false_block = chunk_->LookupDestination(instr->false_block_id());
2504
2505 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2506 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2507
2508 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2);
2509
2510 EmitBranch(true_block, false_block, equal);
2511}
2512
2513
2514void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002515 Register reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002516 int true_block = instr->true_block_id();
2517 int false_block = instr->false_block_id();
2518
2519 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
2520 EmitBranch(true_block, false_block, equal);
2521}
2522
2523
2524void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002525 // Object and function are in fixed registers defined by the stub.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002526 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002527 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002528 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002529
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002530 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002531 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002532 __ j(zero, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002533 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002534 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002535 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002536 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002537 __ bind(&done);
2538}
2539
2540
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002541void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
2542 class DeferredInstanceOfKnownGlobal: public LDeferredCode {
2543 public:
2544 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
2545 LInstanceOfKnownGlobal* instr)
2546 : LDeferredCode(codegen), instr_(instr) { }
2547 virtual void Generate() {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002548 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002549 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002550 virtual LInstruction* instr() { return instr_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002551 Label* map_check() { return &map_check_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002552 private:
2553 LInstanceOfKnownGlobal* instr_;
2554 Label map_check_;
2555 };
2556
2557 DeferredInstanceOfKnownGlobal* deferred;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002558 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002559
2560 Label done, false_result;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002561 Register object = ToRegister(instr->value());
2562 Register temp = ToRegister(instr->temp());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002563
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002564 // A Smi is not an instance of anything.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002565 __ JumpIfSmi(object, &false_result);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002566
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002567 // This is the inlined call site instanceof cache. The two occurences of the
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002568 // hole value will be patched to the last map/result pair generated by the
2569 // instanceof stub.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002570 Label cache_miss;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002571 Register map = ToRegister(instr->temp());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002572 __ mov(map, FieldOperand(object, HeapObject::kMapOffset));
2573 __ bind(deferred->map_check()); // Label for calculating code patching.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002574 Handle<JSGlobalPropertyCell> cache_cell =
2575 factory()->NewJSGlobalPropertyCell(factory()->the_hole_value());
2576 __ cmp(map, Operand::Cell(cache_cell)); // Patched to cached map.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002577 __ j(not_equal, &cache_miss, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002578 __ mov(eax, factory()->the_hole_value()); // Patched to either true or false.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002579 __ jmp(&done);
2580
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002581 // The inlined call site cache did not match. Check for null and string
2582 // before calling the deferred code.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002583 __ bind(&cache_miss);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002584 // Null is not an instance of anything.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002585 __ cmp(object, factory()->null_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002586 __ j(equal, &false_result);
2587
2588 // String values are not instances of anything.
2589 Condition is_string = masm_->IsObjectStringType(object, temp, temp);
2590 __ j(is_string, &false_result);
2591
2592 // Go to the deferred code.
2593 __ jmp(deferred->entry());
2594
2595 __ bind(&false_result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002596 __ mov(ToRegister(instr->result()), factory()->false_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002597
2598 // Here result has either true or false. Deferred code also produces true or
2599 // false object.
2600 __ bind(deferred->exit());
2601 __ bind(&done);
2602}
2603
2604
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002605void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2606 Label* map_check) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002607 PushSafepointRegistersScope scope(this);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002608
2609 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
2610 flags = static_cast<InstanceofStub::Flags>(
2611 flags | InstanceofStub::kArgsInRegisters);
2612 flags = static_cast<InstanceofStub::Flags>(
2613 flags | InstanceofStub::kCallSiteInlineCheck);
2614 flags = static_cast<InstanceofStub::Flags>(
2615 flags | InstanceofStub::kReturnTrueFalseObject);
2616 InstanceofStub stub(flags);
2617
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002618 // Get the temp register reserved by the instruction. This needs to be a
2619 // register which is pushed last by PushSafepointRegisters as top of the
2620 // stack is used to pass the offset to the location of the map check to
2621 // the stub.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002622 Register temp = ToRegister(instr->temp());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002623 ASSERT(MacroAssembler::SafepointRegisterStackIndex(temp) == 0);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002624 __ LoadHeapObject(InstanceofStub::right(), instr->function());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002625 static const int kAdditionalDelta = 13;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002626 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002627 __ mov(temp, Immediate(delta));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002628 __ StoreToSafepointRegisterSlot(temp, temp);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002629 CallCodeGeneric(stub.GetCode(),
2630 RelocInfo::CODE_TARGET,
2631 instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002632 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002633 // Get the deoptimization index of the LLazyBailout-environment that
2634 // corresponds to this instruction.
2635 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002636 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
2637
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002638 // Put the result value into the eax slot and restore all registers.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002639 __ StoreToSafepointRegisterSlot(eax, eax);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002640}
2641
2642
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002643void LCodeGen::DoCmpT(LCmpT* instr) {
2644 Token::Value op = instr->op();
2645
2646 Handle<Code> ic = CompareIC::GetUninitialized(op);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002647 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002648
2649 Condition condition = ComputeCompareCondition(op);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002650 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002651 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002652 __ j(condition, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002653 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002654 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002655 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002656 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002657 __ bind(&done);
2658}
2659
2660
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002661void LCodeGen::DoReturn(LReturn* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002662 if (FLAG_trace && info()->IsOptimizing()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002663 // Preserve the return value on the stack and rely on the runtime call
2664 // to return the value in the same register. We're leaving the code
2665 // managed by the register allocator and tearing down the frame, it's
2666 // safe to write to the context register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002667 __ push(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002668 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002669 __ CallRuntime(Runtime::kTraceExit, 1);
2670 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002671 if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(SSE2)) {
2672 ASSERT(NeedsEagerFrame());
2673 CpuFeatures::Scope scope(SSE2);
2674 BitVector* doubles = chunk()->allocated_double_registers();
2675 BitVector::Iterator save_iterator(doubles);
2676 int count = 0;
2677 while (!save_iterator.Done()) {
2678 __ movdbl(XMMRegister::FromAllocationIndex(save_iterator.Current()),
2679 MemOperand(esp, count * kDoubleSize));
2680 save_iterator.Advance();
2681 count++;
2682 }
2683 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002684 if (dynamic_frame_alignment_) {
2685 // Fetch the state of the dynamic frame alignment.
2686 __ mov(edx, Operand(ebp,
2687 JavaScriptFrameConstants::kDynamicAlignmentStateOffset));
2688 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002689 if (NeedsEagerFrame()) {
2690 __ mov(esp, ebp);
2691 __ pop(ebp);
2692 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002693 if (dynamic_frame_alignment_) {
2694 Label no_padding;
2695 __ cmp(edx, Immediate(kNoAlignmentPadding));
2696 __ j(equal, &no_padding);
2697 if (FLAG_debug_code) {
2698 __ cmp(Operand(esp, (GetParameterCount() + 2) * kPointerSize),
2699 Immediate(kAlignmentZapValue));
2700 __ Assert(equal, "expected alignment marker");
2701 }
2702 __ Ret((GetParameterCount() + 2) * kPointerSize, ecx);
2703 __ bind(&no_padding);
2704 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002705 if (info()->IsStub()) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002706 __ Ret();
2707 } else {
2708 __ Ret((GetParameterCount() + 1) * kPointerSize, ecx);
2709 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002710}
2711
2712
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002713void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002714 Register result = ToRegister(instr->result());
2715 __ mov(result, Operand::Cell(instr->hydrogen()->cell()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002716 if (instr->hydrogen()->RequiresHoleCheck()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002717 __ cmp(result, factory()->the_hole_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002718 DeoptimizeIf(equal, instr->environment());
2719 }
2720}
2721
2722
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002723void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2724 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002725 ASSERT(ToRegister(instr->global_object()).is(edx));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002726 ASSERT(ToRegister(instr->result()).is(eax));
2727
2728 __ mov(ecx, instr->name());
2729 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
2730 RelocInfo::CODE_TARGET_CONTEXT;
2731 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002732 CallCode(ic, mode, instr);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002733}
2734
2735
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002736void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002737 Register value = ToRegister(instr->value());
2738 Handle<JSGlobalPropertyCell> cell_handle = instr->hydrogen()->cell();
ager@chromium.org378b34e2011-01-28 08:04:38 +00002739
2740 // If the cell we are storing to contains the hole it could have
2741 // been deleted from the property dictionary. In that case, we need
2742 // to update the property details in the property dictionary to mark
2743 // it as no longer deleted. We deoptimize in that case.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002744 if (instr->hydrogen()->RequiresHoleCheck()) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002745 __ cmp(Operand::Cell(cell_handle), factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00002746 DeoptimizeIf(equal, instr->environment());
2747 }
2748
2749 // Store the value.
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002750 __ mov(Operand::Cell(cell_handle), value);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002751 // Cells are always rescanned, so no write barrier here.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002752}
2753
2754
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002755void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
2756 ASSERT(ToRegister(instr->context()).is(esi));
2757 ASSERT(ToRegister(instr->global_object()).is(edx));
2758 ASSERT(ToRegister(instr->value()).is(eax));
2759
2760 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002761 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002762 ? isolate()->builtins()->StoreIC_Initialize_Strict()
2763 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002764 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002765}
2766
2767
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002768void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002769 Register context = ToRegister(instr->context());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002770 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002771 __ mov(result, ContextOperand(context, instr->slot_index()));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002772
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002773 if (instr->hydrogen()->RequiresHoleCheck()) {
2774 __ cmp(result, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002775 if (instr->hydrogen()->DeoptimizesOnHole()) {
2776 DeoptimizeIf(equal, instr->environment());
2777 } else {
2778 Label is_not_hole;
2779 __ j(not_equal, &is_not_hole, Label::kNear);
2780 __ mov(result, factory()->undefined_value());
2781 __ bind(&is_not_hole);
2782 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002783 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002784}
2785
2786
2787void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2788 Register context = ToRegister(instr->context());
2789 Register value = ToRegister(instr->value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002790
2791 Label skip_assignment;
2792
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002793 Operand target = ContextOperand(context, instr->slot_index());
2794 if (instr->hydrogen()->RequiresHoleCheck()) {
2795 __ cmp(target, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002796 if (instr->hydrogen()->DeoptimizesOnHole()) {
2797 DeoptimizeIf(equal, instr->environment());
2798 } else {
2799 __ j(not_equal, &skip_assignment, Label::kNear);
2800 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002801 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002802
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002803 __ mov(target, value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002804 if (instr->hydrogen()->NeedsWriteBarrier()) {
2805 HType type = instr->hydrogen()->value()->type();
2806 SmiCheck check_needed =
2807 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002808 Register temp = ToRegister(instr->temp());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002809 int offset = Context::SlotOffset(instr->slot_index());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002810 __ RecordWriteContextSlot(context,
2811 offset,
2812 value,
2813 temp,
2814 kSaveFPRegs,
2815 EMIT_REMEMBERED_SET,
2816 check_needed);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002817 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002818
2819 __ bind(&skip_assignment);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002820}
2821
2822
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002823void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002824 Register object = ToRegister(instr->object());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002825 Register result = ToRegister(instr->result());
2826 if (instr->hydrogen()->is_in_object()) {
2827 __ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
2828 } else {
2829 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2830 __ mov(result, FieldOperand(result, instr->hydrogen()->offset()));
2831 }
2832}
2833
2834
lrn@chromium.org1c092762011-05-09 09:42:16 +00002835void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
2836 Register object,
2837 Handle<Map> type,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002838 Handle<String> name,
2839 LEnvironment* env) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002840 LookupResult lookup(isolate());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002841 type->LookupDescriptor(NULL, *name, &lookup);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002842 ASSERT(lookup.IsFound() || lookup.IsCacheable());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002843 if (lookup.IsField()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002844 int index = lookup.GetLocalFieldIndexFromMap(*type);
2845 int offset = index * kPointerSize;
2846 if (index < 0) {
2847 // Negative property indices are in-object properties, indexed
2848 // from the end of the fixed part of the object.
2849 __ mov(result, FieldOperand(object, offset + type->instance_size()));
2850 } else {
2851 // Non-negative property indices are in the properties array.
2852 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2853 __ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
2854 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002855 } else if (lookup.IsConstantFunction()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002856 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002857 __ LoadHeapObject(result, function);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002858 } else {
2859 // Negative lookup.
2860 // Check prototypes.
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002861 Handle<HeapObject> current(HeapObject::cast((*type)->prototype()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002862 Heap* heap = type->GetHeap();
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002863 while (*current != heap->null_value()) {
2864 __ LoadHeapObject(result, current);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002865 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002866 Handle<Map>(current->map()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002867 DeoptimizeIf(not_equal, env);
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002868 current =
2869 Handle<HeapObject>(HeapObject::cast(current->map()->prototype()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002870 }
2871 __ mov(result, factory()->undefined_value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002872 }
2873}
2874
2875
2876void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
2877 ASSERT(!operand->IsDoubleRegister());
2878 if (operand->IsConstantOperand()) {
2879 Handle<Object> object = ToHandle(LConstantOperand::cast(operand));
2880 if (object->IsSmi()) {
2881 __ Push(Handle<Smi>::cast(object));
2882 } else {
2883 __ PushHeapObject(Handle<HeapObject>::cast(object));
2884 }
2885 } else if (operand->IsRegister()) {
2886 __ push(ToRegister(operand));
2887 } else {
2888 __ push(ToOperand(operand));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002889 }
2890}
2891
2892
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002893// Check for cases where EmitLoadFieldOrConstantFunction needs to walk the
2894// prototype chain, which causes unbounded code generation.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002895static bool CompactEmit(SmallMapList* list,
2896 Handle<String> name,
2897 int i,
2898 Isolate* isolate) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002899 Handle<Map> map = list->at(i);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002900 // If the map has ElementsKind transitions, we will generate map checks
2901 // for each kind in __ CompareMap(..., ALLOW_ELEMENTS_TRANSITION_MAPS).
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002902 if (map->HasElementsTransition()) return false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002903 LookupResult lookup(isolate);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002904 map->LookupDescriptor(NULL, *name, &lookup);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002905 return lookup.IsField() || lookup.IsConstantFunction();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002906}
2907
2908
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002909void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
2910 Register object = ToRegister(instr->object());
2911 Register result = ToRegister(instr->result());
2912
2913 int map_count = instr->hydrogen()->types()->length();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002914 bool need_generic = instr->hydrogen()->need_generic();
2915
2916 if (map_count == 0 && !need_generic) {
2917 DeoptimizeIf(no_condition, instr->environment());
2918 return;
2919 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002920 Handle<String> name = instr->hydrogen()->name();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002921 Label done;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002922 bool all_are_compact = true;
2923 for (int i = 0; i < map_count; ++i) {
2924 if (!CompactEmit(instr->hydrogen()->types(), name, i, isolate())) {
2925 all_are_compact = false;
2926 break;
2927 }
2928 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002929 for (int i = 0; i < map_count; ++i) {
2930 bool last = (i == map_count - 1);
2931 Handle<Map> map = instr->hydrogen()->types()->at(i);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002932 Label check_passed;
2933 __ CompareMap(object, map, &check_passed, ALLOW_ELEMENT_TRANSITION_MAPS);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002934 if (last && !need_generic) {
2935 DeoptimizeIf(not_equal, instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002936 __ bind(&check_passed);
2937 EmitLoadFieldOrConstantFunction(
2938 result, object, map, name, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002939 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002940 Label next;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002941 bool compact = all_are_compact ? true :
2942 CompactEmit(instr->hydrogen()->types(), name, i, isolate());
2943 __ j(not_equal, &next, compact ? Label::kNear : Label::kFar);
2944 __ bind(&check_passed);
2945 EmitLoadFieldOrConstantFunction(
2946 result, object, map, name, instr->environment());
2947 __ jmp(&done, all_are_compact ? Label::kNear : Label::kFar);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002948 __ bind(&next);
2949 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002950 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002951 if (need_generic) {
2952 __ mov(ecx, name);
2953 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2954 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2955 }
2956 __ bind(&done);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002957}
2958
2959
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002960void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002961 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002962 ASSERT(ToRegister(instr->object()).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002963 ASSERT(ToRegister(instr->result()).is(eax));
2964
2965 __ mov(ecx, instr->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002966 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002967 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002968}
2969
2970
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002971void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
2972 Register function = ToRegister(instr->function());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002973 Register temp = ToRegister(instr->temp());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002974 Register result = ToRegister(instr->result());
2975
2976 // Check that the function really is a function.
2977 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
2978 DeoptimizeIf(not_equal, instr->environment());
2979
2980 // Check whether the function has an instance prototype.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002981 Label non_instance;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002982 __ test_b(FieldOperand(result, Map::kBitFieldOffset),
2983 1 << Map::kHasNonInstancePrototype);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002984 __ j(not_zero, &non_instance, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002985
2986 // Get the prototype or initial map from the function.
2987 __ mov(result,
2988 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2989
2990 // Check that the function has a prototype or an initial map.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002991 __ cmp(Operand(result), Immediate(factory()->the_hole_value()));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002992 DeoptimizeIf(equal, instr->environment());
2993
2994 // If the function does not have an initial map, we're done.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002995 Label done;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002996 __ CmpObjectType(result, MAP_TYPE, temp);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002997 __ j(not_equal, &done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002998
2999 // Get the prototype from the initial map.
3000 __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003001 __ jmp(&done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003002
3003 // Non-instance prototype: Fetch prototype from constructor field
3004 // in the function's map.
3005 __ bind(&non_instance);
3006 __ mov(result, FieldOperand(result, Map::kConstructorOffset));
3007
3008 // All done.
3009 __ bind(&done);
3010}
3011
3012
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003013void LCodeGen::DoLoadElements(LLoadElements* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003014 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003015 Register input = ToRegister(instr->object());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003016 __ mov(result, FieldOperand(input, JSObject::kElementsOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003017 if (FLAG_debug_code) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003018 Label done, ok, fail;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003019 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003020 Immediate(factory()->fixed_array_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003021 __ j(equal, &done, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003022 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003023 Immediate(factory()->fixed_cow_array_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003024 __ j(equal, &done, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003025 Register temp((result.is(eax)) ? ebx : eax);
3026 __ push(temp);
3027 __ mov(temp, FieldOperand(result, HeapObject::kMapOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00003028 __ movzx_b(temp, FieldOperand(temp, Map::kBitField2Offset));
3029 __ and_(temp, Map::kElementsKindMask);
3030 __ shr(temp, Map::kElementsKindShift);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003031 __ cmp(temp, GetInitialFastElementsKind());
3032 __ j(less, &fail, Label::kNear);
3033 __ cmp(temp, TERMINAL_FAST_ELEMENTS_KIND);
3034 __ j(less_equal, &ok, Label::kNear);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003035 __ cmp(temp, FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003036 __ j(less, &fail, Label::kNear);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003037 __ cmp(temp, LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003038 __ j(less_equal, &ok, Label::kNear);
3039 __ bind(&fail);
3040 __ Abort("Check for fast or external elements failed.");
3041 __ bind(&ok);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003042 __ pop(temp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003043 __ bind(&done);
3044 }
3045}
3046
3047
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003048void LCodeGen::DoLoadExternalArrayPointer(
3049 LLoadExternalArrayPointer* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003050 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003051 Register input = ToRegister(instr->object());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003052 __ mov(result, FieldOperand(input,
3053 ExternalArray::kExternalPointerOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003054}
3055
3056
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003057void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
3058 Register arguments = ToRegister(instr->arguments());
3059 Register length = ToRegister(instr->length());
3060 Operand index = ToOperand(instr->index());
3061 Register result = ToRegister(instr->result());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003062 // There are two words between the frame pointer and the last argument.
3063 // Subtracting from length accounts for one of them add one more.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003064 __ sub(length, index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003065 __ mov(result, Operand(arguments, length, times_4, kPointerSize));
3066}
3067
3068
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003069void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003070 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003071 LOperand* key = instr->key();
3072 if (!key->IsConstantOperand() &&
3073 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
3074 elements_kind)) {
3075 __ SmiUntag(ToRegister(key));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003076 }
3077 Operand operand(BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003078 instr->elements(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003079 key,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003080 instr->hydrogen()->key()->representation(),
3081 elements_kind,
3082 0,
3083 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003084 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003085 if (CpuFeatures::IsSupported(SSE2)) {
3086 CpuFeatures::Scope scope(SSE2);
3087 XMMRegister result(ToDoubleRegister(instr->result()));
3088 __ movss(result, operand);
3089 __ cvtss2sd(result, result);
3090 } else {
3091 __ fld_s(operand);
3092 HandleX87FPReturnValue(instr);
3093 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003094 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003095 if (CpuFeatures::IsSupported(SSE2)) {
3096 CpuFeatures::Scope scope(SSE2);
3097 __ movdbl(ToDoubleRegister(instr->result()), operand);
3098 } else {
3099 __ fld_d(operand);
3100 HandleX87FPReturnValue(instr);
3101 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003102 } else {
3103 Register result(ToRegister(instr->result()));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003104 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003105 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003106 __ movsx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003107 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003108 case EXTERNAL_PIXEL_ELEMENTS:
3109 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003110 __ movzx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003111 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003112 case EXTERNAL_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003113 __ movsx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003114 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003115 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003116 __ movzx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003117 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003118 case EXTERNAL_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003119 __ mov(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003120 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003121 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003122 __ mov(result, operand);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003123 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
3124 __ test(result, Operand(result));
3125 DeoptimizeIf(negative, instr->environment());
3126 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003127 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003128 case EXTERNAL_FLOAT_ELEMENTS:
3129 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003130 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003131 case FAST_ELEMENTS:
3132 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003133 case FAST_HOLEY_SMI_ELEMENTS:
3134 case FAST_HOLEY_ELEMENTS:
3135 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003136 case DICTIONARY_ELEMENTS:
3137 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003138 UNREACHABLE();
3139 break;
3140 }
3141 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003142}
3143
3144
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003145void LCodeGen::HandleX87FPReturnValue(LInstruction* instr) {
3146 if (IsX87TopOfStack(instr->result())) {
3147 // Return value is already on stack. If the value has no uses, then
3148 // pop it off the FP stack. Otherwise, make sure that there are enough
3149 // copies of the value on the stack to feed all of the usages, e.g.
3150 // when the following instruction uses the return value in multiple
3151 // inputs.
3152 int count = instr->hydrogen_value()->UseCount();
3153 if (count == 0) {
3154 __ fstp(0);
3155 } else {
3156 count--;
3157 ASSERT(count <= 7);
3158 while (count-- > 0) {
3159 __ fld(0);
3160 }
3161 }
3162 } else {
3163 __ fstp_d(ToOperand(instr->result()));
3164 }
3165}
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00003166
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003167
3168void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003169 if (instr->hydrogen()->RequiresHoleCheck()) {
3170 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
3171 sizeof(kHoleNanLower32);
3172 Operand hole_check_operand = BuildFastArrayOperand(
3173 instr->elements(), instr->key(),
3174 instr->hydrogen()->key()->representation(),
3175 FAST_DOUBLE_ELEMENTS,
3176 offset,
3177 instr->additional_index());
3178 __ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
3179 DeoptimizeIf(equal, instr->environment());
3180 }
3181
3182 Operand double_load_operand = BuildFastArrayOperand(
3183 instr->elements(),
3184 instr->key(),
3185 instr->hydrogen()->key()->representation(),
3186 FAST_DOUBLE_ELEMENTS,
3187 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
3188 instr->additional_index());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003189 if (CpuFeatures::IsSupported(SSE2)) {
3190 CpuFeatures::Scope scope(SSE2);
3191 XMMRegister result = ToDoubleRegister(instr->result());
3192 __ movdbl(result, double_load_operand);
3193 } else {
3194 __ fld_d(double_load_operand);
3195 HandleX87FPReturnValue(instr);
3196 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003197}
3198
3199
3200void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
3201 Register result = ToRegister(instr->result());
3202
3203 // Load the result.
3204 __ mov(result,
3205 BuildFastArrayOperand(instr->elements(),
3206 instr->key(),
3207 instr->hydrogen()->key()->representation(),
3208 FAST_ELEMENTS,
3209 FixedArray::kHeaderSize - kHeapObjectTag,
3210 instr->additional_index()));
3211
3212 // Check for the hole value.
3213 if (instr->hydrogen()->RequiresHoleCheck()) {
3214 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
3215 __ test(result, Immediate(kSmiTagMask));
3216 DeoptimizeIf(not_equal, instr->environment());
3217 } else {
3218 __ cmp(result, factory()->the_hole_value());
3219 DeoptimizeIf(equal, instr->environment());
3220 }
3221 }
3222}
3223
3224
3225void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
3226 if (instr->is_external()) {
3227 DoLoadKeyedExternalArray(instr);
3228 } else if (instr->hydrogen()->representation().IsDouble()) {
3229 DoLoadKeyedFixedDoubleArray(instr);
3230 } else {
3231 DoLoadKeyedFixedArray(instr);
3232 }
3233}
3234
3235
3236Operand LCodeGen::BuildFastArrayOperand(
3237 LOperand* elements_pointer,
3238 LOperand* key,
3239 Representation key_representation,
3240 ElementsKind elements_kind,
3241 uint32_t offset,
3242 uint32_t additional_index) {
3243 Register elements_pointer_reg = ToRegister(elements_pointer);
3244 int shift_size = ElementsKindToShiftSize(elements_kind);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003245 if (key->IsConstantOperand()) {
3246 int constant_value = ToInteger32(LConstantOperand::cast(key));
3247 if (constant_value & 0xF0000000) {
3248 Abort("array index constant value too big");
3249 }
3250 return Operand(elements_pointer_reg,
3251 ((constant_value + additional_index) << shift_size)
3252 + offset);
3253 } else {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00003254 // Take the tag bit into account while computing the shift size.
3255 if (key_representation.IsTagged() && (shift_size >= 1)) {
3256 shift_size -= kSmiTagSize;
3257 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003258 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
3259 return Operand(elements_pointer_reg,
3260 ToRegister(key),
3261 scale_factor,
3262 offset + (additional_index << shift_size));
3263 }
3264}
3265
3266
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003267void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003268 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003269 ASSERT(ToRegister(instr->object()).is(edx));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003270 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003271
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003272 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003273 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003274}
3275
3276
3277void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
3278 Register result = ToRegister(instr->result());
3279
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003280 if (instr->hydrogen()->from_inlined()) {
3281 __ lea(result, Operand(esp, -2 * kPointerSize));
3282 } else {
3283 // Check for arguments adapter frame.
3284 Label done, adapted;
3285 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3286 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
3287 __ cmp(Operand(result),
3288 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3289 __ j(equal, &adapted, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003290
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003291 // No arguments adaptor frame.
3292 __ mov(result, Operand(ebp));
3293 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003294
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003295 // Arguments adaptor frame present.
3296 __ bind(&adapted);
3297 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003298
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003299 // Result is the frame pointer for the frame if not adapted and for the real
3300 // frame below the adaptor frame if adapted.
3301 __ bind(&done);
3302 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003303}
3304
3305
3306void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003307 Operand elem = ToOperand(instr->elements());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003308 Register result = ToRegister(instr->result());
3309
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003310 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003311
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003312 // If no arguments adaptor frame the number of arguments is fixed.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003313 __ cmp(ebp, elem);
3314 __ mov(result, Immediate(scope()->num_parameters()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003315 __ j(equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003316
3317 // Arguments adaptor frame present. Get argument length from there.
3318 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3319 __ mov(result, Operand(result,
3320 ArgumentsAdaptorFrameConstants::kLengthOffset));
3321 __ SmiUntag(result);
3322
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003323 // Argument length is in result register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003324 __ bind(&done);
3325}
3326
3327
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003328void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003329 Register receiver = ToRegister(instr->receiver());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003330 Register function = ToRegister(instr->function());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003331 Register scratch = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003332
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003333 // If the receiver is null or undefined, we have to pass the global
3334 // object as a receiver to normal functions. Values have to be
3335 // passed unchanged to builtins and strict-mode functions.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003336 Label global_object, receiver_ok;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003337
3338 // Do not transform the receiver to object for strict mode
3339 // functions.
3340 __ mov(scratch,
3341 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
3342 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset),
3343 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
danno@chromium.org412fa512012-09-14 13:28:26 +00003344 __ j(not_equal, &receiver_ok); // A near jump is not sufficient here!
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003345
3346 // Do not transform the receiver to object for builtins.
3347 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset),
3348 1 << SharedFunctionInfo::kNativeBitWithinByte);
danno@chromium.org412fa512012-09-14 13:28:26 +00003349 __ j(not_equal, &receiver_ok);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003350
3351 // Normal function. Replace undefined or null with global receiver.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003352 __ cmp(receiver, factory()->null_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003353 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003354 __ cmp(receiver, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003355 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003356
3357 // The receiver should be a JS object.
3358 __ test(receiver, Immediate(kSmiTagMask));
3359 DeoptimizeIf(equal, instr->environment());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003360 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, scratch);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003361 DeoptimizeIf(below, instr->environment());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003362 __ jmp(&receiver_ok, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003363
3364 __ bind(&global_object);
3365 // TODO(kmillikin): We have a hydrogen value for the global object. See
3366 // if it's better to use it than to explicitly fetch it from the context
3367 // here.
3368 __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003369 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_OBJECT_INDEX));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003370 __ mov(receiver,
3371 FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003372 __ bind(&receiver_ok);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003373}
3374
3375
3376void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
3377 Register receiver = ToRegister(instr->receiver());
3378 Register function = ToRegister(instr->function());
3379 Register length = ToRegister(instr->length());
3380 Register elements = ToRegister(instr->elements());
3381 ASSERT(receiver.is(eax)); // Used for parameter count.
3382 ASSERT(function.is(edi)); // Required by InvokeFunction.
3383 ASSERT(ToRegister(instr->result()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003384
3385 // Copy the arguments to this function possibly from the
3386 // adaptor frame below it.
3387 const uint32_t kArgumentsLimit = 1 * KB;
3388 __ cmp(length, kArgumentsLimit);
3389 DeoptimizeIf(above, instr->environment());
3390
3391 __ push(receiver);
3392 __ mov(receiver, length);
3393
3394 // Loop through the arguments pushing them onto the execution
3395 // stack.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003396 Label invoke, loop;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003397 // length is a small non-negative integer, due to the test above.
3398 __ test(length, Operand(length));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003399 __ j(zero, &invoke, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003400 __ bind(&loop);
3401 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
3402 __ dec(length);
3403 __ j(not_zero, &loop);
3404
3405 // Invoke the function.
3406 __ bind(&invoke);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003407 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003408 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003409 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003410 SafepointGenerator safepoint_generator(
3411 this, pointers, Safepoint::kLazyDeopt);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003412 ParameterCount actual(eax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003413 __ InvokeFunction(function, actual, CALL_FUNCTION,
3414 safepoint_generator, CALL_AS_METHOD);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003415}
3416
3417
3418void LCodeGen::DoPushArgument(LPushArgument* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003419 LOperand* argument = instr->value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003420 EmitPushTaggedOperand(argument);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003421}
3422
3423
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003424void LCodeGen::DoDrop(LDrop* instr) {
3425 __ Drop(instr->count());
3426}
3427
3428
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003429void LCodeGen::DoThisFunction(LThisFunction* instr) {
3430 Register result = ToRegister(instr->result());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003431 __ mov(result, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003432}
3433
3434
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003435void LCodeGen::DoContext(LContext* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003436 Register result = ToRegister(instr->result());
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00003437 if (info()->IsOptimizing()) {
3438 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
3439 } else {
3440 // If there is no frame, the context must be in esi.
3441 ASSERT(result.is(esi));
3442 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003443}
3444
3445
3446void LCodeGen::DoOuterContext(LOuterContext* instr) {
3447 Register context = ToRegister(instr->context());
3448 Register result = ToRegister(instr->result());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003449 __ mov(result,
3450 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003451}
3452
3453
yangguo@chromium.org56454712012-02-16 15:33:53 +00003454void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003455 ASSERT(ToRegister(instr->context()).is(esi));
yangguo@chromium.org56454712012-02-16 15:33:53 +00003456 __ push(esi); // The context is the first argument.
3457 __ push(Immediate(instr->hydrogen()->pairs()));
3458 __ push(Immediate(Smi::FromInt(instr->hydrogen()->flags())));
3459 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
3460}
3461
3462
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003463void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
3464 Register context = ToRegister(instr->context());
3465 Register result = ToRegister(instr->result());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003466 __ mov(result,
3467 Operand(context, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003468}
3469
3470
3471void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003472 Register global = ToRegister(instr->global());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003473 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003474 __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003475}
3476
3477
3478void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
3479 int arity,
danno@chromium.org40cb8782011-05-25 07:58:50 +00003480 LInstruction* instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003481 CallKind call_kind,
3482 EDIState edi_state) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003483 bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
3484 function->shared()->formal_parameter_count() == arity;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003485
3486 LPointerMap* pointers = instr->pointer_map();
3487 RecordPosition(pointers->position());
3488
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003489 if (can_invoke_directly) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003490 if (edi_state == EDI_UNINITIALIZED) {
3491 __ LoadHeapObject(edi, function);
3492 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003493
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00003494 // Change context.
3495 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003496
3497 // Set eax to arguments count if adaption is not needed. Assumes that eax
3498 // is available to write to at this point.
3499 if (!function->NeedsArgumentsAdaption()) {
3500 __ mov(eax, arity);
3501 }
3502
3503 // Invoke function directly.
3504 __ SetCallKind(ecx, call_kind);
3505 if (*function == *info()->closure()) {
3506 __ CallSelf();
3507 } else {
3508 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
3509 }
3510 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
3511 } else {
3512 // We need to adapt arguments.
3513 SafepointGenerator generator(
3514 this, pointers, Safepoint::kLazyDeopt);
3515 ParameterCount count(arity);
3516 __ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind);
3517 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003518}
3519
3520
3521void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
3522 ASSERT(ToRegister(instr->result()).is(eax));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003523 CallKnownFunction(instr->function(),
3524 instr->arity(),
3525 instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003526 CALL_AS_METHOD,
3527 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003528}
3529
3530
3531void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003532 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003533 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003534 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003535 DeoptimizeIf(not_equal, instr->environment());
3536
3537 Label done;
3538 Register tmp = input_reg.is(eax) ? ecx : eax;
3539 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx;
3540
3541 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003542 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003543
3544 Label negative;
3545 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003546 // Check the sign of the argument. If the argument is positive, just
3547 // return it. We do not need to patch the stack since |input| and
3548 // |result| are the same register and |input| will be restored
3549 // unchanged by popping safepoint registers.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003550 __ test(tmp, Immediate(HeapNumber::kSignMask));
3551 __ j(not_zero, &negative);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003552 __ jmp(&done);
3553
3554 __ bind(&negative);
3555
3556 Label allocated, slow;
3557 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow);
3558 __ jmp(&allocated);
3559
3560 // Slow case: Call the runtime system to do the number allocation.
3561 __ bind(&slow);
3562
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003563 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0,
3564 instr, instr->context());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003565
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003566 // Set the pointer to the new heap number in tmp.
3567 if (!tmp.is(eax)) __ mov(tmp, eax);
3568
3569 // Restore input_reg after call to runtime.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003570 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003571
3572 __ bind(&allocated);
3573 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3574 __ and_(tmp2, ~HeapNumber::kSignMask);
3575 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
3576 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
3577 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003578 __ StoreToSafepointRegisterSlot(input_reg, tmp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003579
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003580 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003581}
3582
3583
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003584void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003585 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003586 __ test(input_reg, Operand(input_reg));
3587 Label is_positive;
3588 __ j(not_sign, &is_positive);
3589 __ neg(input_reg);
3590 __ test(input_reg, Operand(input_reg));
3591 DeoptimizeIf(negative, instr->environment());
3592 __ bind(&is_positive);
3593}
3594
3595
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003596void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
3597 // Class for deferred case.
3598 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
3599 public:
3600 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
3601 LUnaryMathOperation* instr)
3602 : LDeferredCode(codegen), instr_(instr) { }
3603 virtual void Generate() {
3604 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3605 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003606 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003607 private:
3608 LUnaryMathOperation* instr_;
3609 };
3610
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003611 ASSERT(instr->value()->Equals(instr->result()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003612 Representation r = instr->hydrogen()->value()->representation();
3613
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003614 CpuFeatures::Scope scope(SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003615 if (r.IsDouble()) {
3616 XMMRegister scratch = xmm0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003617 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003618 __ xorps(scratch, scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003619 __ subsd(scratch, input_reg);
3620 __ pand(input_reg, scratch);
3621 } else if (r.IsInteger32()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003622 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003623 } else { // Tagged case.
3624 DeferredMathAbsTaggedHeapNumber* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003625 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003626 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003627 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003628 __ JumpIfNotSmi(input_reg, deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003629 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003630 __ bind(deferred->exit());
3631 }
3632}
3633
3634
3635void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003636 CpuFeatures::Scope scope(SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003637 XMMRegister xmm_scratch = xmm0;
3638 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003639 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003640
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003641 if (CpuFeatures::IsSupported(SSE4_1)) {
3642 CpuFeatures::Scope scope(SSE4_1);
3643 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3644 // Deoptimize on negative zero.
3645 Label non_zero;
3646 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3647 __ ucomisd(input_reg, xmm_scratch);
3648 __ j(not_equal, &non_zero, Label::kNear);
3649 __ movmskpd(output_reg, input_reg);
3650 __ test(output_reg, Immediate(1));
3651 DeoptimizeIf(not_zero, instr->environment());
3652 __ bind(&non_zero);
3653 }
3654 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
3655 __ cvttsd2si(output_reg, Operand(xmm_scratch));
3656 // Overflow is signalled with minint.
3657 __ cmp(output_reg, 0x80000000u);
3658 DeoptimizeIf(equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003659 } else {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003660 Label negative_sign, done;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003661 // Deoptimize on unordered.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003662 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3663 __ ucomisd(input_reg, xmm_scratch);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003664 DeoptimizeIf(parity_even, instr->environment());
3665 __ j(below, &negative_sign, Label::kNear);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003666
3667 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3668 // Check for negative zero.
3669 Label positive_sign;
3670 __ j(above, &positive_sign, Label::kNear);
3671 __ movmskpd(output_reg, input_reg);
3672 __ test(output_reg, Immediate(1));
3673 DeoptimizeIf(not_zero, instr->environment());
3674 __ Set(output_reg, Immediate(0));
3675 __ jmp(&done, Label::kNear);
3676 __ bind(&positive_sign);
3677 }
3678
3679 // Use truncating instruction (OK because input is positive).
3680 __ cvttsd2si(output_reg, Operand(input_reg));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003681 // Overflow is signalled with minint.
3682 __ cmp(output_reg, 0x80000000u);
3683 DeoptimizeIf(equal, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003684 __ jmp(&done, Label::kNear);
3685
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003686 // Non-zero negative reaches here.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003687 __ bind(&negative_sign);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003688 // Truncate, then compare and compensate.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003689 __ cvttsd2si(output_reg, Operand(input_reg));
3690 __ cvtsi2sd(xmm_scratch, output_reg);
3691 __ ucomisd(input_reg, xmm_scratch);
3692 __ j(equal, &done, Label::kNear);
3693 __ sub(output_reg, Immediate(1));
3694 DeoptimizeIf(overflow, instr->environment());
3695
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003696 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003697 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003698}
3699
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003700void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003701 CpuFeatures::Scope scope(SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003702 XMMRegister xmm_scratch = xmm0;
3703 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003704 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003705
danno@chromium.org160a7b02011-04-18 15:51:38 +00003706 Label below_half, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003707 // xmm_scratch = 0.5
3708 ExternalReference one_half = ExternalReference::address_of_one_half();
3709 __ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
danno@chromium.org160a7b02011-04-18 15:51:38 +00003710 __ ucomisd(xmm_scratch, input_reg);
3711 __ j(above, &below_half);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003712 // xmm_scratch = input + 0.5
3713 __ addsd(xmm_scratch, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003714
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003715 // Compute Math.floor(value + 0.5).
3716 // Use truncating instruction (OK because input is positive).
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003717 __ cvttsd2si(output_reg, Operand(xmm_scratch));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003718
3719 // Overflow is signalled with minint.
3720 __ cmp(output_reg, 0x80000000u);
3721 DeoptimizeIf(equal, instr->environment());
danno@chromium.org160a7b02011-04-18 15:51:38 +00003722 __ jmp(&done);
3723
3724 __ bind(&below_half);
3725
3726 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
3727 // we can ignore the difference between a result of -0 and +0.
3728 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3729 // If the sign is positive, we return +0.
3730 __ movmskpd(output_reg, input_reg);
3731 __ test(output_reg, Immediate(1));
3732 DeoptimizeIf(not_zero, instr->environment());
3733 } else {
3734 // If the input is >= -0.5, we return +0.
3735 __ mov(output_reg, Immediate(0xBF000000));
3736 __ movd(xmm_scratch, Operand(output_reg));
3737 __ cvtss2sd(xmm_scratch, xmm_scratch);
3738 __ ucomisd(input_reg, xmm_scratch);
3739 DeoptimizeIf(below, instr->environment());
3740 }
3741 __ Set(output_reg, Immediate(0));
3742 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003743}
3744
3745
3746void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003747 CpuFeatures::Scope scope(SSE2);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003748 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003749 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
3750 __ sqrtsd(input_reg, input_reg);
3751}
3752
3753
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003754void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003755 CpuFeatures::Scope scope(SSE2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003756 XMMRegister xmm_scratch = xmm0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003757 XMMRegister input_reg = ToDoubleRegister(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003758 Register scratch = ToRegister(instr->temp());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003759 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003760
3761 // Note that according to ECMA-262 15.8.2.13:
3762 // Math.pow(-Infinity, 0.5) == Infinity
3763 // Math.sqrt(-Infinity) == NaN
3764 Label done, sqrt;
3765 // Check base for -Infinity. According to IEEE-754, single-precision
3766 // -Infinity has the highest 9 bits set and the lowest 23 bits cleared.
3767 __ mov(scratch, 0xFF800000);
3768 __ movd(xmm_scratch, scratch);
3769 __ cvtss2sd(xmm_scratch, xmm_scratch);
3770 __ ucomisd(input_reg, xmm_scratch);
3771 // Comparing -Infinity with NaN results in "unordered", which sets the
3772 // zero flag as if both were equal. However, it also sets the carry flag.
3773 __ j(not_equal, &sqrt, Label::kNear);
3774 __ j(carry, &sqrt, Label::kNear);
3775 // If input is -Infinity, return Infinity.
3776 __ xorps(input_reg, input_reg);
3777 __ subsd(input_reg, xmm_scratch);
3778 __ jmp(&done, Label::kNear);
3779
3780 // Square root.
3781 __ bind(&sqrt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003782 __ xorps(xmm_scratch, xmm_scratch);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003783 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003784 __ sqrtsd(input_reg, input_reg);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003785 __ bind(&done);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003786}
3787
3788
3789void LCodeGen::DoPower(LPower* instr) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003790 Representation exponent_type = instr->hydrogen()->right()->representation();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003791 // Having marked this as a call, we can use any registers.
3792 // Just make sure that the input/output registers are the expected ones.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003793 ASSERT(!instr->right()->IsDoubleRegister() ||
3794 ToDoubleRegister(instr->right()).is(xmm1));
3795 ASSERT(!instr->right()->IsRegister() ||
3796 ToRegister(instr->right()).is(eax));
3797 ASSERT(ToDoubleRegister(instr->left()).is(xmm2));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003798 ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003799
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003800 if (exponent_type.IsTagged()) {
3801 Label no_deopt;
3802 __ JumpIfSmi(eax, &no_deopt);
3803 __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003804 DeoptimizeIf(not_equal, instr->environment());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003805 __ bind(&no_deopt);
3806 MathPowStub stub(MathPowStub::TAGGED);
3807 __ CallStub(&stub);
3808 } else if (exponent_type.IsInteger32()) {
3809 MathPowStub stub(MathPowStub::INTEGER);
3810 __ CallStub(&stub);
3811 } else {
3812 ASSERT(exponent_type.IsDouble());
3813 MathPowStub stub(MathPowStub::DOUBLE);
3814 __ CallStub(&stub);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003815 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003816}
3817
3818
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003819void LCodeGen::DoRandom(LRandom* instr) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003820 class DeferredDoRandom: public LDeferredCode {
3821 public:
3822 DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
3823 : LDeferredCode(codegen), instr_(instr) { }
3824 virtual void Generate() { codegen()->DoDeferredRandom(instr_); }
3825 virtual LInstruction* instr() { return instr_; }
3826 private:
3827 LRandom* instr_;
3828 };
3829
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003830 DeferredDoRandom* deferred = new(zone()) DeferredDoRandom(this, instr);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003831
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003832 CpuFeatures::Scope scope(SSE2);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003833 // Having marked this instruction as a call we can use any
3834 // registers.
3835 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003836 ASSERT(ToRegister(instr->global_object()).is(eax));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003837 // Assert that the register size is indeed the size of each seed.
3838 static const int kSeedSize = sizeof(uint32_t);
3839 STATIC_ASSERT(kPointerSize == kSeedSize);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003840
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003841 __ mov(eax, FieldOperand(eax, GlobalObject::kNativeContextOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003842 static const int kRandomSeedOffset =
3843 FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
3844 __ mov(ebx, FieldOperand(eax, kRandomSeedOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003845 // ebx: FixedArray of the native context's random seeds
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003846
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003847 // Load state[0].
3848 __ mov(ecx, FieldOperand(ebx, ByteArray::kHeaderSize));
3849 // If state[0] == 0, call runtime to initialize seeds.
3850 __ test(ecx, ecx);
3851 __ j(zero, deferred->entry());
3852 // Load state[1].
3853 __ mov(eax, FieldOperand(ebx, ByteArray::kHeaderSize + kSeedSize));
3854 // ecx: state[0]
3855 // eax: state[1]
3856
3857 // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
3858 __ movzx_w(edx, ecx);
3859 __ imul(edx, edx, 18273);
3860 __ shr(ecx, 16);
3861 __ add(ecx, edx);
3862 // Save state[0].
3863 __ mov(FieldOperand(ebx, ByteArray::kHeaderSize), ecx);
3864
3865 // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
3866 __ movzx_w(edx, eax);
3867 __ imul(edx, edx, 36969);
3868 __ shr(eax, 16);
3869 __ add(eax, edx);
3870 // Save state[1].
3871 __ mov(FieldOperand(ebx, ByteArray::kHeaderSize + kSeedSize), eax);
3872
3873 // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
3874 __ shl(ecx, 14);
3875 __ and_(eax, Immediate(0x3FFFF));
3876 __ add(eax, ecx);
3877
3878 __ bind(deferred->exit());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003879 // Convert 32 random bits in eax to 0.(32 random bits) in a double
3880 // by computing:
3881 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
3882 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
3883 __ movd(xmm2, ebx);
3884 __ movd(xmm1, eax);
3885 __ cvtss2sd(xmm2, xmm2);
3886 __ xorps(xmm1, xmm2);
3887 __ subsd(xmm1, xmm2);
3888}
3889
3890
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003891void LCodeGen::DoDeferredRandom(LRandom* instr) {
3892 __ PrepareCallCFunction(1, ebx);
3893 __ mov(Operand(esp, 0), eax);
3894 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
3895 // Return value is in eax.
3896}
3897
3898
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003899void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003900 CpuFeatures::Scope scope(SSE2);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003901 ASSERT(instr->value()->Equals(instr->result()));
3902 XMMRegister input_reg = ToDoubleRegister(instr->value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003903 Label positive, done, zero;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003904 __ xorps(xmm0, xmm0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003905 __ ucomisd(input_reg, xmm0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003906 __ j(above, &positive, Label::kNear);
3907 __ j(equal, &zero, Label::kNear);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003908 ExternalReference nan =
3909 ExternalReference::address_of_canonical_non_hole_nan();
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003910 __ movdbl(input_reg, Operand::StaticVariable(nan));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003911 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003912 __ bind(&zero);
3913 __ push(Immediate(0xFFF00000));
3914 __ push(Immediate(0));
3915 __ movdbl(input_reg, Operand(esp, 0));
3916 __ add(Operand(esp), Immediate(kDoubleSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003917 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003918 __ bind(&positive);
3919 __ fldln2();
3920 __ sub(Operand(esp), Immediate(kDoubleSize));
3921 __ movdbl(Operand(esp, 0), input_reg);
3922 __ fld_d(Operand(esp, 0));
3923 __ fyl2x();
3924 __ fstp_d(Operand(esp, 0));
3925 __ movdbl(input_reg, Operand(esp, 0));
3926 __ add(Operand(esp), Immediate(kDoubleSize));
3927 __ bind(&done);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003928}
3929
3930
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003931void LCodeGen::DoMathExp(LMathExp* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003932 CpuFeatures::Scope scope(SSE2);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003933 XMMRegister input = ToDoubleRegister(instr->value());
3934 XMMRegister result = ToDoubleRegister(instr->result());
3935 Register temp1 = ToRegister(instr->temp1());
3936 Register temp2 = ToRegister(instr->temp2());
3937
3938 MathExpGenerator::EmitMathExp(masm(), input, result, xmm0, temp1, temp2);
3939}
3940
3941
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003942void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
3943 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3944 TranscendentalCacheStub stub(TranscendentalCache::TAN,
3945 TranscendentalCacheStub::UNTAGGED);
3946 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
3947}
3948
3949
whesse@chromium.org023421e2010-12-21 12:19:12 +00003950void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
3951 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3952 TranscendentalCacheStub stub(TranscendentalCache::COS,
3953 TranscendentalCacheStub::UNTAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003954 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003955}
3956
3957
3958void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
3959 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3960 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3961 TranscendentalCacheStub::UNTAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003962 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003963}
3964
3965
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003966void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
3967 switch (instr->op()) {
3968 case kMathAbs:
3969 DoMathAbs(instr);
3970 break;
3971 case kMathFloor:
3972 DoMathFloor(instr);
3973 break;
3974 case kMathRound:
3975 DoMathRound(instr);
3976 break;
3977 case kMathSqrt:
3978 DoMathSqrt(instr);
3979 break;
whesse@chromium.org023421e2010-12-21 12:19:12 +00003980 case kMathCos:
3981 DoMathCos(instr);
3982 break;
3983 case kMathSin:
3984 DoMathSin(instr);
3985 break;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003986 case kMathTan:
3987 DoMathTan(instr);
3988 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003989 case kMathLog:
3990 DoMathLog(instr);
3991 break;
3992
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003993 default:
3994 UNREACHABLE();
3995 }
3996}
3997
3998
danno@chromium.org160a7b02011-04-18 15:51:38 +00003999void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
4000 ASSERT(ToRegister(instr->context()).is(esi));
4001 ASSERT(ToRegister(instr->function()).is(edi));
4002 ASSERT(instr->HasPointerMap());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004003
4004 if (instr->known_function().is_null()) {
4005 LPointerMap* pointers = instr->pointer_map();
4006 RecordPosition(pointers->position());
4007 SafepointGenerator generator(
4008 this, pointers, Safepoint::kLazyDeopt);
4009 ParameterCount count(instr->arity());
4010 __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
4011 } else {
4012 CallKnownFunction(instr->known_function(),
4013 instr->arity(),
4014 instr,
4015 CALL_AS_METHOD,
4016 EDI_CONTAINS_TARGET);
4017 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00004018}
4019
4020
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004021void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004022 ASSERT(ToRegister(instr->context()).is(esi));
4023 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004024 ASSERT(ToRegister(instr->result()).is(eax));
4025
4026 int arity = instr->arity();
lrn@chromium.org34e60782011-09-15 07:25:40 +00004027 Handle<Code> ic =
4028 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004029 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004030}
4031
4032
4033void LCodeGen::DoCallNamed(LCallNamed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004034 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004035 ASSERT(ToRegister(instr->result()).is(eax));
4036
4037 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00004038 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
4039 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00004040 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004041 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004042 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004043}
4044
4045
4046void LCodeGen::DoCallFunction(LCallFunction* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004047 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.orgc612e022011-11-10 11:38:15 +00004048 ASSERT(ToRegister(instr->function()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004049 ASSERT(ToRegister(instr->result()).is(eax));
4050
4051 int arity = instr->arity();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004052 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004053 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004054}
4055
4056
4057void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004058 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004059 ASSERT(ToRegister(instr->result()).is(eax));
4060
4061 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00004062 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
4063 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00004064 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004065 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004066 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004067}
4068
4069
4070void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
4071 ASSERT(ToRegister(instr->result()).is(eax));
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004072 CallKnownFunction(instr->target(),
4073 instr->arity(),
4074 instr,
4075 CALL_AS_FUNCTION,
4076 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004077}
4078
4079
4080void LCodeGen::DoCallNew(LCallNew* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004081 ASSERT(ToRegister(instr->context()).is(esi));
4082 ASSERT(ToRegister(instr->constructor()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004083 ASSERT(ToRegister(instr->result()).is(eax));
4084
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004085 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004086 __ Set(eax, Immediate(instr->arity()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004087 CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004088}
4089
4090
4091void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004092 CallRuntime(instr->function(), instr->arity(), instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004093}
4094
4095
4096void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
4097 Register object = ToRegister(instr->object());
4098 Register value = ToRegister(instr->value());
4099 int offset = instr->offset();
4100
4101 if (!instr->transition().is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +00004102 if (!instr->hydrogen()->NeedsWriteBarrierForMap()) {
4103 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition());
4104 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004105 Register temp = ToRegister(instr->temp());
4106 Register temp_map = ToRegister(instr->temp_map());
verwaest@chromium.org37141392012-05-31 13:27:02 +00004107 __ mov(temp_map, instr->transition());
4108 __ mov(FieldOperand(object, HeapObject::kMapOffset), temp_map);
4109 // Update the write barrier for the map field.
4110 __ RecordWriteField(object,
4111 HeapObject::kMapOffset,
4112 temp_map,
4113 temp,
4114 kSaveFPRegs,
4115 OMIT_REMEMBERED_SET,
4116 OMIT_SMI_CHECK);
4117 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004118 }
4119
4120 // Do the store.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004121 HType type = instr->hydrogen()->value()->type();
4122 SmiCheck check_needed =
4123 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004124 if (instr->is_in_object()) {
4125 __ mov(FieldOperand(object, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004126 if (instr->hydrogen()->NeedsWriteBarrier()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004127 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004128 // Update the write barrier for the object for in-object properties.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004129 __ RecordWriteField(object,
4130 offset,
4131 value,
4132 temp,
4133 kSaveFPRegs,
4134 EMIT_REMEMBERED_SET,
4135 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004136 }
4137 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004138 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004139 __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset));
4140 __ mov(FieldOperand(temp, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004141 if (instr->hydrogen()->NeedsWriteBarrier()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004142 // Update the write barrier for the properties array.
4143 // object is used as a scratch register.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004144 __ RecordWriteField(temp,
4145 offset,
4146 value,
4147 object,
4148 kSaveFPRegs,
4149 EMIT_REMEMBERED_SET,
4150 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004151 }
4152 }
4153}
4154
4155
4156void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004157 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004158 ASSERT(ToRegister(instr->object()).is(edx));
4159 ASSERT(ToRegister(instr->value()).is(eax));
4160
4161 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004162 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004163 ? isolate()->builtins()->StoreIC_Initialize_Strict()
4164 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004165 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004166}
4167
4168
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004169void LCodeGen::DeoptIfTaggedButNotSmi(LEnvironment* environment,
4170 HValue* value,
4171 LOperand* operand) {
4172 if (value->representation().IsTagged() && !value->type().IsSmi()) {
4173 if (operand->IsRegister()) {
4174 __ test(ToRegister(operand), Immediate(kSmiTagMask));
4175 } else {
4176 __ test(ToOperand(operand), Immediate(kSmiTagMask));
4177 }
4178 DeoptimizeIf(not_zero, environment);
4179 }
4180}
4181
4182
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004183void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004184 DeoptIfTaggedButNotSmi(instr->environment(),
4185 instr->hydrogen()->length(),
4186 instr->length());
4187 DeoptIfTaggedButNotSmi(instr->environment(),
4188 instr->hydrogen()->index(),
4189 instr->index());
danno@chromium.orgb6451162011-08-17 14:33:23 +00004190 if (instr->index()->IsConstantOperand()) {
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004191 int constant_index =
4192 ToInteger32(LConstantOperand::cast(instr->index()));
4193 if (instr->hydrogen()->length()->representation().IsTagged()) {
4194 __ cmp(ToOperand(instr->length()),
4195 Immediate(Smi::FromInt(constant_index)));
4196 } else {
4197 __ cmp(ToOperand(instr->length()), Immediate(constant_index));
4198 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00004199 DeoptimizeIf(below_equal, instr->environment());
4200 } else {
4201 __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
4202 DeoptimizeIf(above_equal, instr->environment());
4203 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004204}
4205
4206
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004207void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004208 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004209 LOperand* key = instr->key();
4210 if (!key->IsConstantOperand() &&
4211 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
4212 elements_kind)) {
4213 __ SmiUntag(ToRegister(key));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004214 }
4215 Operand operand(BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004216 instr->elements(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004217 key,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004218 instr->hydrogen()->key()->representation(),
4219 elements_kind,
4220 0,
4221 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004222 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004223 CpuFeatures::Scope scope(SSE2);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004224 __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004225 __ movss(operand, xmm0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004226 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004227 CpuFeatures::Scope scope(SSE2);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004228 __ movdbl(operand, ToDoubleRegister(instr->value()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004229 } else {
4230 Register value = ToRegister(instr->value());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004231 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004232 case EXTERNAL_PIXEL_ELEMENTS:
4233 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4234 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004235 __ mov_b(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004236 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004237 case EXTERNAL_SHORT_ELEMENTS:
4238 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004239 __ mov_w(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004240 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004241 case EXTERNAL_INT_ELEMENTS:
4242 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004243 __ mov(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004244 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004245 case EXTERNAL_FLOAT_ELEMENTS:
4246 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004247 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004248 case FAST_ELEMENTS:
4249 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004250 case FAST_HOLEY_SMI_ELEMENTS:
4251 case FAST_HOLEY_ELEMENTS:
4252 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004253 case DICTIONARY_ELEMENTS:
4254 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004255 UNREACHABLE();
4256 break;
4257 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004258 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004259}
4260
4261
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004262void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004263 CpuFeatures::Scope scope(SSE2);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004264 XMMRegister value = ToDoubleRegister(instr->value());
4265
4266 if (instr->NeedsCanonicalization()) {
4267 Label have_value;
4268
4269 __ ucomisd(value, value);
4270 __ j(parity_odd, &have_value); // NaN.
4271
4272 ExternalReference canonical_nan_reference =
4273 ExternalReference::address_of_canonical_non_hole_nan();
4274 __ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
4275 __ bind(&have_value);
4276 }
4277
4278 Operand double_store_operand = BuildFastArrayOperand(
4279 instr->elements(),
4280 instr->key(),
4281 instr->hydrogen()->key()->representation(),
4282 FAST_DOUBLE_ELEMENTS,
4283 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
4284 instr->additional_index());
4285 __ movdbl(double_store_operand, value);
4286}
4287
4288
4289void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004290 Register value = ToRegister(instr->value());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004291 Register elements = ToRegister(instr->elements());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004292 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
4293
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004294 Operand operand = BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004295 instr->elements(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004296 instr->key(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004297 instr->hydrogen()->key()->representation(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004298 FAST_ELEMENTS,
4299 FixedArray::kHeaderSize - kHeapObjectTag,
4300 instr->additional_index());
4301 __ mov(operand, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004302
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004303 if (instr->hydrogen()->NeedsWriteBarrier()) {
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004304 ASSERT(!instr->key()->IsConstantOperand());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004305 HType type = instr->hydrogen()->value()->type();
4306 SmiCheck check_needed =
4307 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004308 // Compute address of modified element and store it into key register.
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004309 __ lea(key, operand);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004310 __ RecordWrite(elements,
4311 key,
4312 value,
4313 kSaveFPRegs,
4314 EMIT_REMEMBERED_SET,
4315 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004316 }
4317}
4318
4319
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004320void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
4321 // By cases...external, fast-double, fast
4322 if (instr->is_external()) {
4323 DoStoreKeyedExternalArray(instr);
4324 } else if (instr->hydrogen()->value()->representation().IsDouble()) {
4325 DoStoreKeyedFixedDoubleArray(instr);
4326 } else {
4327 DoStoreKeyedFixedArray(instr);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004328 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004329}
4330
4331
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004332void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004333 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004334 ASSERT(ToRegister(instr->object()).is(edx));
4335 ASSERT(ToRegister(instr->key()).is(ecx));
4336 ASSERT(ToRegister(instr->value()).is(eax));
4337
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004338 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004339 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
4340 : isolate()->builtins()->KeyedStoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004341 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004342}
4343
4344
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004345void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
4346 Register object = ToRegister(instr->object());
4347 Register temp = ToRegister(instr->temp());
4348 __ TestJSArrayForAllocationSiteInfo(object, temp);
4349 DeoptimizeIf(equal, instr->environment());
4350}
4351
4352
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004353void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
4354 Register object_reg = ToRegister(instr->object());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004355
4356 Handle<Map> from_map = instr->original_map();
4357 Handle<Map> to_map = instr->transitioned_map();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00004358 ElementsKind from_kind = instr->from_kind();
4359 ElementsKind to_kind = instr->to_kind();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004360
4361 Label not_applicable;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004362 bool is_simple_map_transition =
4363 IsSimpleMapChangeTransition(from_kind, to_kind);
4364 Label::Distance branch_distance =
4365 is_simple_map_transition ? Label::kNear : Label::kFar;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004366 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004367 __ j(not_equal, &not_applicable, branch_distance);
4368 if (is_simple_map_transition) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004369 Register new_map_reg = ToRegister(instr->new_map_temp());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004370 Handle<Map> map = instr->hydrogen()->transitioned_map();
4371 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset),
4372 Immediate(map));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004373 // Write barrier.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004374 ASSERT_NE(instr->temp(), NULL);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004375 __ RecordWriteForMap(object_reg, to_map, new_map_reg,
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004376 ToRegister(instr->temp()),
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004377 kDontSaveFPRegs);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004378 } else if (FLAG_compiled_transitions) {
4379 PushSafepointRegistersScope scope(this);
4380 if (!object_reg.is(eax)) {
4381 __ push(object_reg);
4382 }
4383 LoadContextFromDeferred(instr->context());
4384 if (!object_reg.is(eax)) {
4385 __ pop(eax);
4386 }
4387 __ mov(ebx, to_map);
4388 TransitionElementsKindStub stub(from_kind, to_kind);
4389 __ CallStub(&stub);
4390 RecordSafepointWithRegisters(
4391 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004392 } else if (IsFastSmiElementsKind(from_kind) &&
4393 IsFastDoubleElementsKind(to_kind)) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004394 Register new_map_reg = ToRegister(instr->new_map_temp());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004395 __ mov(new_map_reg, to_map);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004396 Register fixed_object_reg = ToRegister(instr->temp());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004397 ASSERT(fixed_object_reg.is(edx));
4398 ASSERT(new_map_reg.is(ebx));
4399 __ mov(fixed_object_reg, object_reg);
4400 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
4401 RelocInfo::CODE_TARGET, instr);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004402 } else if (IsFastDoubleElementsKind(from_kind) &&
4403 IsFastObjectElementsKind(to_kind)) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004404 Register new_map_reg = ToRegister(instr->new_map_temp());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004405 __ mov(new_map_reg, to_map);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004406 Register fixed_object_reg = ToRegister(instr->temp());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004407 ASSERT(fixed_object_reg.is(edx));
4408 ASSERT(new_map_reg.is(ebx));
4409 __ mov(fixed_object_reg, object_reg);
4410 CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
4411 RelocInfo::CODE_TARGET, instr);
4412 } else {
4413 UNREACHABLE();
4414 }
4415 __ bind(&not_applicable);
4416}
4417
4418
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004419void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
4420 class DeferredStringCharCodeAt: public LDeferredCode {
4421 public:
4422 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
4423 : LDeferredCode(codegen), instr_(instr) { }
4424 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004425 virtual LInstruction* instr() { return instr_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004426 private:
4427 LStringCharCodeAt* instr_;
4428 };
4429
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004430 DeferredStringCharCodeAt* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004431 new(zone()) DeferredStringCharCodeAt(this, instr);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004432
erikcorry0ad885c2011-11-21 13:51:57 +00004433 StringCharLoadGenerator::Generate(masm(),
4434 factory(),
4435 ToRegister(instr->string()),
4436 ToRegister(instr->index()),
4437 ToRegister(instr->result()),
4438 deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004439 __ bind(deferred->exit());
4440}
4441
4442
4443void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
4444 Register string = ToRegister(instr->string());
4445 Register result = ToRegister(instr->result());
4446
4447 // TODO(3095996): Get rid of this. For now, we need to make the
4448 // result register contain a valid pointer because it is already
4449 // contained in the register pointer map.
4450 __ Set(result, Immediate(0));
4451
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004452 PushSafepointRegistersScope scope(this);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004453 __ push(string);
4454 // Push the index as a smi. This is safe because of the checks in
4455 // DoStringCharCodeAt above.
4456 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
4457 if (instr->index()->IsConstantOperand()) {
4458 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
4459 __ push(Immediate(Smi::FromInt(const_index)));
4460 } else {
4461 Register index = ToRegister(instr->index());
4462 __ SmiTag(index);
4463 __ push(index);
4464 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004465 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2,
4466 instr, instr->context());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004467 __ AssertSmi(eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004468 __ SmiUntag(eax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004469 __ StoreToSafepointRegisterSlot(result, eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004470}
4471
4472
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004473void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
4474 class DeferredStringCharFromCode: public LDeferredCode {
4475 public:
4476 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
4477 : LDeferredCode(codegen), instr_(instr) { }
4478 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004479 virtual LInstruction* instr() { return instr_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004480 private:
4481 LStringCharFromCode* instr_;
4482 };
4483
4484 DeferredStringCharFromCode* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004485 new(zone()) DeferredStringCharFromCode(this, instr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004486
4487 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
4488 Register char_code = ToRegister(instr->char_code());
4489 Register result = ToRegister(instr->result());
4490 ASSERT(!char_code.is(result));
4491
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004492 __ cmp(char_code, String::kMaxOneByteCharCode);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004493 __ j(above, deferred->entry());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004494 __ Set(result, Immediate(factory()->single_character_string_cache()));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004495 __ mov(result, FieldOperand(result,
4496 char_code, times_pointer_size,
4497 FixedArray::kHeaderSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004498 __ cmp(result, factory()->undefined_value());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004499 __ j(equal, deferred->entry());
4500 __ bind(deferred->exit());
4501}
4502
4503
4504void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4505 Register char_code = ToRegister(instr->char_code());
4506 Register result = ToRegister(instr->result());
4507
4508 // TODO(3095996): Get rid of this. For now, we need to make the
4509 // result register contain a valid pointer because it is already
4510 // contained in the register pointer map.
4511 __ Set(result, Immediate(0));
4512
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004513 PushSafepointRegistersScope scope(this);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004514 __ SmiTag(char_code);
4515 __ push(char_code);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004516 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004517 __ StoreToSafepointRegisterSlot(result, eax);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004518}
4519
4520
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004521void LCodeGen::DoStringLength(LStringLength* instr) {
4522 Register string = ToRegister(instr->string());
4523 Register result = ToRegister(instr->result());
4524 __ mov(result, FieldOperand(string, String::kLengthOffset));
4525}
4526
4527
danno@chromium.org160a7b02011-04-18 15:51:38 +00004528void LCodeGen::DoStringAdd(LStringAdd* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004529 EmitPushTaggedOperand(instr->left());
4530 EmitPushTaggedOperand(instr->right());
danno@chromium.org160a7b02011-04-18 15:51:38 +00004531 StringAddStub stub(NO_STRING_CHECK_IN_STUB);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004532 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
danno@chromium.org160a7b02011-04-18 15:51:38 +00004533}
4534
4535
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004536void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004537 if (CpuFeatures::IsSupported(SSE2)) {
4538 CpuFeatures::Scope scope(SSE2);
4539 LOperand* input = instr->value();
4540 ASSERT(input->IsRegister() || input->IsStackSlot());
4541 LOperand* output = instr->result();
4542 ASSERT(output->IsDoubleRegister());
4543 __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
4544 } else {
4545 UNREACHABLE();
4546 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004547}
4548
4549
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004550void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004551 CpuFeatures::Scope scope(SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004552 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004553 LOperand* output = instr->result();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004554 LOperand* temp = instr->temp();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004555
4556 __ LoadUint32(ToDoubleRegister(output),
4557 ToRegister(input),
4558 ToDoubleRegister(temp));
4559}
4560
4561
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004562void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
4563 class DeferredNumberTagI: public LDeferredCode {
4564 public:
4565 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
4566 : LDeferredCode(codegen), instr_(instr) { }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004567 virtual void Generate() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004568 codegen()->DoDeferredNumberTagI(instr_, instr_->value(), SIGNED_INT32);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004569 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004570 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004571 private:
4572 LNumberTagI* instr_;
4573 };
4574
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004575 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004576 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4577 Register reg = ToRegister(input);
4578
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004579 DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004580 __ SmiTag(reg);
4581 __ j(overflow, deferred->entry());
4582 __ bind(deferred->exit());
4583}
4584
4585
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004586void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
4587 class DeferredNumberTagU: public LDeferredCode {
4588 public:
4589 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
4590 : LDeferredCode(codegen), instr_(instr) { }
4591 virtual void Generate() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004592 codegen()->DoDeferredNumberTagI(instr_, instr_->value(), UNSIGNED_INT32);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004593 }
4594 virtual LInstruction* instr() { return instr_; }
4595 private:
4596 LNumberTagU* instr_;
4597 };
4598
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004599 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004600 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4601 Register reg = ToRegister(input);
4602
4603 DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
4604 __ cmp(reg, Immediate(Smi::kMaxValue));
4605 __ j(above, deferred->entry());
4606 __ SmiTag(reg);
4607 __ bind(deferred->exit());
4608}
4609
4610
4611void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
4612 LOperand* value,
4613 IntegerSignedness signedness) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004614 Label slow;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004615 Register reg = ToRegister(value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004616 Register tmp = reg.is(eax) ? ecx : eax;
4617
4618 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004619 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004620
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004621 Label done;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004622
4623 if (signedness == SIGNED_INT32) {
4624 // There was overflow, so bits 30 and 31 of the original integer
4625 // disagree. Try to allocate a heap number in new space and store
4626 // the value in there. If that fails, call the runtime system.
4627 __ SmiUntag(reg);
4628 __ xor_(reg, 0x80000000);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004629 if (CpuFeatures::IsSupported(SSE2)) {
4630 CpuFeatures::Scope feature_scope(SSE2);
4631 __ cvtsi2sd(xmm0, Operand(reg));
4632 } else {
4633 __ push(reg);
4634 __ fild_s(Operand(esp, 0));
4635 __ pop(reg);
4636 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004637 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004638 if (CpuFeatures::IsSupported(SSE2)) {
4639 CpuFeatures::Scope feature_scope(SSE2);
4640 __ LoadUint32(xmm0, reg, xmm1);
4641 } else {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00004642 // There's no fild variant for unsigned values, so zero-extend to a 64-bit
4643 // int manually.
4644 __ push(Immediate(0));
4645 __ push(reg);
4646 __ fild_d(Operand(esp, 0));
4647 __ pop(reg);
4648 __ pop(reg);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004649 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004650 }
4651
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004652 if (FLAG_inline_new) {
4653 __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004654 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004655 }
4656
4657 // Slow case: Call the runtime system to do the number allocation.
4658 __ bind(&slow);
4659
4660 // TODO(3095996): Put a valid pointer value in the stack slot where the result
4661 // register is stored, as this register is in the pointer map, but contains an
4662 // integer value.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004663 __ StoreToSafepointRegisterSlot(reg, Immediate(0));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004664 // NumberTagI and NumberTagD use the context from the frame, rather than
4665 // the environment's HContext or HInlinedContext value.
4666 // They only call Runtime::kAllocateHeapNumber.
4667 // The corresponding HChange instructions are added in a phase that does
4668 // not have easy access to the local context.
4669 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4670 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4671 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004672 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004673 if (!reg.is(eax)) __ mov(reg, eax);
4674
4675 // Done. Put the value in xmm0 into the value of the allocated heap
4676 // number.
4677 __ bind(&done);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004678 if (CpuFeatures::IsSupported(SSE2)) {
4679 CpuFeatures::Scope feature_scope(SSE2);
4680 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0);
4681 } else {
4682 __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
4683 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004684 __ StoreToSafepointRegisterSlot(reg, reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004685}
4686
4687
4688void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
4689 class DeferredNumberTagD: public LDeferredCode {
4690 public:
4691 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
4692 : LDeferredCode(codegen), instr_(instr) { }
4693 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004694 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004695 private:
4696 LNumberTagD* instr_;
4697 };
4698
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004699 Register reg = ToRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004700
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004701 bool convert_hole = false;
4702 HValue* change_input = instr->hydrogen()->value();
4703 if (change_input->IsLoadKeyed()) {
4704 HLoadKeyed* load = HLoadKeyed::cast(change_input);
4705 convert_hole = load->UsesMustHandleHole();
4706 }
4707
4708 Label no_special_nan_handling;
4709 Label done;
4710 if (convert_hole) {
4711 bool use_sse2 = CpuFeatures::IsSupported(SSE2);
4712 if (use_sse2) {
4713 CpuFeatures::Scope scope(SSE2);
4714 XMMRegister input_reg = ToDoubleRegister(instr->value());
4715 __ ucomisd(input_reg, input_reg);
4716 } else {
4717 if (!IsX87TopOfStack(instr->value())) {
4718 __ fld_d(ToOperand(instr->value()));
4719 }
4720 __ fld(0);
4721 __ fld(0);
4722 __ FCmp();
4723 }
4724
4725 __ j(parity_odd, &no_special_nan_handling);
4726 __ sub(esp, Immediate(kDoubleSize));
4727 if (use_sse2) {
4728 CpuFeatures::Scope scope(SSE2);
4729 XMMRegister input_reg = ToDoubleRegister(instr->value());
4730 __ movdbl(MemOperand(esp, 0), input_reg);
4731 } else {
4732 __ fld(0);
4733 __ fstp_d(MemOperand(esp, 0));
4734 }
4735 __ cmp(MemOperand(esp, sizeof(kHoleNanLower32)),
4736 Immediate(kHoleNanUpper32));
4737 Label canonicalize;
4738 __ j(not_equal, &canonicalize);
4739 __ add(esp, Immediate(kDoubleSize));
4740 __ mov(reg, factory()->the_hole_value());
4741 __ jmp(&done);
4742 __ bind(&canonicalize);
4743 __ add(esp, Immediate(kDoubleSize));
4744 ExternalReference nan =
4745 ExternalReference::address_of_canonical_non_hole_nan();
4746 if (use_sse2) {
4747 CpuFeatures::Scope scope(SSE2);
4748 XMMRegister input_reg = ToDoubleRegister(instr->value());
4749 __ movdbl(input_reg, Operand::StaticVariable(nan));
4750 } else {
4751 __ fstp(0);
4752 __ fld_d(Operand::StaticVariable(nan));
4753 }
4754 }
4755
4756 __ bind(&no_special_nan_handling);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004757 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004758 if (FLAG_inline_new) {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00004759 Register tmp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004760 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
4761 } else {
4762 __ jmp(deferred->entry());
4763 }
4764 __ bind(deferred->exit());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004765 if (CpuFeatures::IsSupported(SSE2)) {
4766 CpuFeatures::Scope scope(SSE2);
4767 XMMRegister input_reg = ToDoubleRegister(instr->value());
4768 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
4769 } else {
4770 if (!IsX87TopOfStack(instr->value())) {
4771 __ fld_d(ToOperand(instr->value()));
4772 }
4773 __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
4774 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004775 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004776}
4777
4778
4779void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
4780 // TODO(3095996): Get rid of this. For now, we need to make the
4781 // result register contain a valid pointer because it is already
4782 // contained in the register pointer map.
4783 Register reg = ToRegister(instr->result());
4784 __ Set(reg, Immediate(0));
4785
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004786 PushSafepointRegistersScope scope(this);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004787 // NumberTagI and NumberTagD use the context from the frame, rather than
4788 // the environment's HContext or HInlinedContext value.
4789 // They only call Runtime::kAllocateHeapNumber.
4790 // The corresponding HChange instructions are added in a phase that does
4791 // not have easy access to the local context.
4792 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4793 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004794 RecordSafepointWithRegisters(
4795 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004796 __ StoreToSafepointRegisterSlot(reg, eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004797}
4798
4799
4800void LCodeGen::DoSmiTag(LSmiTag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004801 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004802 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4803 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
4804 __ SmiTag(ToRegister(input));
4805}
4806
4807
4808void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004809 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004810 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4811 if (instr->needs_check()) {
4812 __ test(ToRegister(input), Immediate(kSmiTagMask));
4813 DeoptimizeIf(not_zero, instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004814 } else {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004815 __ AssertSmi(ToRegister(input));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004816 }
4817 __ SmiUntag(ToRegister(input));
4818}
4819
4820
4821void LCodeGen::EmitNumberUntagD(Register input_reg,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004822 Register temp_reg,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004823 XMMRegister result_reg,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004824 bool deoptimize_on_undefined,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004825 bool deoptimize_on_minus_zero,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004826 LEnvironment* env,
4827 NumberUntagDMode mode) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004828 Label load_smi, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004829
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004830 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
4831 // Smi check.
4832 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004833
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004834 // Heap number map check.
4835 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
4836 factory()->heap_number_map());
4837 if (deoptimize_on_undefined) {
4838 DeoptimizeIf(not_equal, env);
4839 } else {
4840 Label heap_number;
4841 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004842
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004843 __ cmp(input_reg, factory()->undefined_value());
4844 DeoptimizeIf(not_equal, env);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004845
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004846 // Convert undefined to NaN.
4847 ExternalReference nan =
4848 ExternalReference::address_of_canonical_non_hole_nan();
4849 __ movdbl(result_reg, Operand::StaticVariable(nan));
4850 __ jmp(&done, Label::kNear);
4851
4852 __ bind(&heap_number);
4853 }
4854 // Heap number to XMM conversion.
4855 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
4856 if (deoptimize_on_minus_zero) {
4857 XMMRegister xmm_scratch = xmm0;
4858 __ xorps(xmm_scratch, xmm_scratch);
4859 __ ucomisd(result_reg, xmm_scratch);
4860 __ j(not_zero, &done, Label::kNear);
4861 __ movmskpd(temp_reg, result_reg);
4862 __ test_b(temp_reg, 1);
4863 DeoptimizeIf(not_zero, env);
4864 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004865 __ jmp(&done, Label::kNear);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004866 } else if (mode == NUMBER_CANDIDATE_IS_SMI_OR_HOLE) {
4867 __ test(input_reg, Immediate(kSmiTagMask));
4868 DeoptimizeIf(not_equal, env);
4869 } else if (mode == NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE) {
4870 __ test(input_reg, Immediate(kSmiTagMask));
4871 __ j(zero, &load_smi);
4872 ExternalReference hole_nan_reference =
4873 ExternalReference::address_of_the_hole_nan();
4874 __ movdbl(result_reg, Operand::StaticVariable(hole_nan_reference));
4875 __ jmp(&done, Label::kNear);
4876 } else {
4877 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004878 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004879
4880 // Smi to XMM conversion
4881 __ bind(&load_smi);
4882 __ SmiUntag(input_reg); // Untag smi before converting to float.
4883 __ cvtsi2sd(result_reg, Operand(input_reg));
4884 __ SmiTag(input_reg); // Retag smi.
4885 __ bind(&done);
4886}
4887
4888
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004889void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004890 Label done, heap_number;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004891 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004892
4893 // Heap number map check.
4894 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004895 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004896
4897 if (instr->truncating()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004898 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004899 // Check for undefined. Undefined is converted to zero for truncating
4900 // conversions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004901 __ cmp(input_reg, factory()->undefined_value());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004902 __ RecordComment("Deferred TaggedToI: cannot truncate");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004903 DeoptimizeIf(not_equal, instr->environment());
4904 __ mov(input_reg, 0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004905 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004906
4907 __ bind(&heap_number);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004908 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004909 CpuFeatures::Scope scope(SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004910 Label convert;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004911 // Use more powerful conversion when sse3 is available.
4912 // Load x87 register with heap number.
4913 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
4914 // Get exponent alone and check for too-big exponent.
4915 __ mov(input_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
4916 __ and_(input_reg, HeapNumber::kExponentMask);
4917 const uint32_t kTooBigExponent =
4918 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
4919 __ cmp(Operand(input_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004920 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004921 // Pop FPU stack before deoptimizing.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004922 __ fstp(0);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004923 __ RecordComment("Deferred TaggedToI: exponent too big");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004924 DeoptimizeIf(no_condition, instr->environment());
4925
4926 // Reserve space for 64 bit answer.
4927 __ bind(&convert);
4928 __ sub(Operand(esp), Immediate(kDoubleSize));
4929 // Do conversion, which cannot fail because we checked the exponent.
4930 __ fisttp_d(Operand(esp, 0));
4931 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result.
4932 __ add(Operand(esp), Immediate(kDoubleSize));
4933 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004934 CpuFeatures::Scope scope(SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004935 XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004936 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
4937 __ cvttsd2si(input_reg, Operand(xmm0));
4938 __ cmp(input_reg, 0x80000000u);
4939 __ j(not_equal, &done);
4940 // Check if the input was 0x8000000 (kMinInt).
4941 // If no, then we got an overflow and we deoptimize.
4942 ExternalReference min_int = ExternalReference::address_of_min_int();
4943 __ movdbl(xmm_temp, Operand::StaticVariable(min_int));
4944 __ ucomisd(xmm_temp, xmm0);
4945 DeoptimizeIf(not_equal, instr->environment());
4946 DeoptimizeIf(parity_even, instr->environment()); // NaN.
4947 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004948 } else if (CpuFeatures::IsSupported(SSE2)) {
4949 CpuFeatures::Scope scope(SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004950 // Deoptimize if we don't have a heap number.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004951 __ RecordComment("Deferred TaggedToI: not a heap number");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004952 DeoptimizeIf(not_equal, instr->environment());
4953
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004954 XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004955 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
4956 __ cvttsd2si(input_reg, Operand(xmm0));
4957 __ cvtsi2sd(xmm_temp, Operand(input_reg));
4958 __ ucomisd(xmm0, xmm_temp);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004959 __ RecordComment("Deferred TaggedToI: lost precision");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004960 DeoptimizeIf(not_equal, instr->environment());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004961 __ RecordComment("Deferred TaggedToI: NaN");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004962 DeoptimizeIf(parity_even, instr->environment()); // NaN.
4963 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4964 __ test(input_reg, Operand(input_reg));
4965 __ j(not_zero, &done);
4966 __ movmskpd(input_reg, xmm0);
4967 __ and_(input_reg, 1);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004968 __ RecordComment("Deferred TaggedToI: minus zero");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004969 DeoptimizeIf(not_zero, instr->environment());
4970 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004971 } else {
4972 UNREACHABLE();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004973 }
4974 __ bind(&done);
4975}
4976
4977
4978void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004979 class DeferredTaggedToI: public LDeferredCode {
4980 public:
4981 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
4982 : LDeferredCode(codegen), instr_(instr) { }
4983 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
4984 virtual LInstruction* instr() { return instr_; }
4985 private:
4986 LTaggedToI* instr_;
4987 };
4988
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004989 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004990 ASSERT(input->IsRegister());
4991 ASSERT(input->Equals(instr->result()));
4992
4993 Register input_reg = ToRegister(input);
4994
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004995 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004996
4997 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00004998 __ JumpIfNotSmi(input_reg, deferred->entry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004999
5000 // Smi to int32 conversion
5001 __ SmiUntag(input_reg); // Untag smi.
5002
5003 __ bind(deferred->exit());
5004}
5005
5006
5007void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005008 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005009 ASSERT(input->IsRegister());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005010 LOperand* temp = instr->temp();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005011 ASSERT(temp == NULL || temp->IsRegister());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005012 LOperand* result = instr->result();
5013 ASSERT(result->IsDoubleRegister());
5014
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005015 if (CpuFeatures::IsSupported(SSE2)) {
5016 CpuFeatures::Scope scope(SSE2);
5017 Register input_reg = ToRegister(input);
5018 XMMRegister result_reg = ToDoubleRegister(result);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005019
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005020 bool deoptimize_on_minus_zero =
5021 instr->hydrogen()->deoptimize_on_minus_zero();
5022 Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005023
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005024 NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED;
5025 HValue* value = instr->hydrogen()->value();
5026 if (value->type().IsSmi()) {
5027 if (value->IsLoadKeyed()) {
5028 HLoadKeyed* load = HLoadKeyed::cast(value);
5029 if (load->UsesMustHandleHole()) {
5030 if (load->hole_mode() == ALLOW_RETURN_HOLE) {
5031 mode = NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE;
5032 } else {
5033 mode = NUMBER_CANDIDATE_IS_SMI_OR_HOLE;
5034 }
5035 } else {
5036 mode = NUMBER_CANDIDATE_IS_SMI;
5037 }
5038 }
5039 }
5040
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005041 EmitNumberUntagD(input_reg,
5042 temp_reg,
5043 result_reg,
5044 instr->hydrogen()->deoptimize_on_undefined(),
5045 deoptimize_on_minus_zero,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005046 instr->environment(),
5047 mode);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005048 } else {
5049 UNIMPLEMENTED();
5050 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005051}
5052
5053
5054void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005055 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005056 ASSERT(input->IsDoubleRegister());
5057 LOperand* result = instr->result();
5058 ASSERT(result->IsRegister());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005059 CpuFeatures::Scope scope(SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005060
5061 XMMRegister input_reg = ToDoubleRegister(input);
5062 Register result_reg = ToRegister(result);
5063
5064 if (instr->truncating()) {
5065 // Performs a truncating conversion of a floating point number as used by
5066 // the JS bitwise operations.
5067 __ cvttsd2si(result_reg, Operand(input_reg));
5068 __ cmp(result_reg, 0x80000000u);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005069 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005070 // This will deoptimize if the exponent of the input in out of range.
5071 CpuFeatures::Scope scope(SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005072 Label convert, done;
5073 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005074 __ sub(Operand(esp), Immediate(kDoubleSize));
5075 __ movdbl(Operand(esp, 0), input_reg);
5076 // Get exponent alone and check for too-big exponent.
5077 __ mov(result_reg, Operand(esp, sizeof(int32_t)));
5078 __ and_(result_reg, HeapNumber::kExponentMask);
5079 const uint32_t kTooBigExponent =
5080 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
5081 __ cmp(Operand(result_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005082 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005083 __ add(Operand(esp), Immediate(kDoubleSize));
5084 DeoptimizeIf(no_condition, instr->environment());
5085 __ bind(&convert);
5086 // Do conversion, which cannot fail because we checked the exponent.
5087 __ fld_d(Operand(esp, 0));
5088 __ fisttp_d(Operand(esp, 0));
5089 __ mov(result_reg, Operand(esp, 0)); // Low word of answer is the result.
5090 __ add(Operand(esp), Immediate(kDoubleSize));
5091 __ bind(&done);
5092 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005093 Label done;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005094 Register temp_reg = ToRegister(instr->temp());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005095 XMMRegister xmm_scratch = xmm0;
5096
5097 // If cvttsd2si succeeded, we're done. Otherwise, we attempt
5098 // manual conversion.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005099 __ j(not_equal, &done, Label::kNear);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005100
5101 // Get high 32 bits of the input in result_reg and temp_reg.
5102 __ pshufd(xmm_scratch, input_reg, 1);
5103 __ movd(Operand(temp_reg), xmm_scratch);
5104 __ mov(result_reg, temp_reg);
5105
5106 // Prepare negation mask in temp_reg.
5107 __ sar(temp_reg, kBitsPerInt - 1);
5108
5109 // Extract the exponent from result_reg and subtract adjusted
5110 // bias from it. The adjustment is selected in a way such that
5111 // when the difference is zero, the answer is in the low 32 bits
5112 // of the input, otherwise a shift has to be performed.
5113 __ shr(result_reg, HeapNumber::kExponentShift);
5114 __ and_(result_reg,
5115 HeapNumber::kExponentMask >> HeapNumber::kExponentShift);
5116 __ sub(Operand(result_reg),
5117 Immediate(HeapNumber::kExponentBias +
5118 HeapNumber::kExponentBits +
5119 HeapNumber::kMantissaBits));
5120 // Don't handle big (> kMantissaBits + kExponentBits == 63) or
5121 // special exponents.
5122 DeoptimizeIf(greater, instr->environment());
5123
5124 // Zero out the sign and the exponent in the input (by shifting
5125 // it to the left) and restore the implicit mantissa bit,
5126 // i.e. convert the input to unsigned int64 shifted left by
5127 // kExponentBits.
5128 ExternalReference minus_zero = ExternalReference::address_of_minus_zero();
5129 // Minus zero has the most significant bit set and the other
5130 // bits cleared.
5131 __ movdbl(xmm_scratch, Operand::StaticVariable(minus_zero));
5132 __ psllq(input_reg, HeapNumber::kExponentBits);
5133 __ por(input_reg, xmm_scratch);
5134
5135 // Get the amount to shift the input right in xmm_scratch.
5136 __ neg(result_reg);
5137 __ movd(xmm_scratch, Operand(result_reg));
5138
5139 // Shift the input right and extract low 32 bits.
5140 __ psrlq(input_reg, xmm_scratch);
5141 __ movd(Operand(result_reg), input_reg);
5142
5143 // Use the prepared mask in temp_reg to negate the result if necessary.
5144 __ xor_(result_reg, Operand(temp_reg));
5145 __ sub(result_reg, Operand(temp_reg));
5146 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005147 }
5148 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005149 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005150 __ cvttsd2si(result_reg, Operand(input_reg));
5151 __ cvtsi2sd(xmm0, Operand(result_reg));
5152 __ ucomisd(xmm0, input_reg);
5153 DeoptimizeIf(not_equal, instr->environment());
5154 DeoptimizeIf(parity_even, instr->environment()); // NaN.
5155 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
5156 // The integer converted back is equal to the original. We
5157 // only have to test if we got -0 as an input.
5158 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005159 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005160 __ movmskpd(result_reg, input_reg);
5161 // Bit 0 contains the sign of the double in input_reg.
5162 // If input was positive, we are ok and return 0, otherwise
5163 // deoptimize.
5164 __ and_(result_reg, 1);
5165 DeoptimizeIf(not_zero, instr->environment());
5166 }
5167 __ bind(&done);
5168 }
5169}
5170
5171
5172void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005173 LOperand* input = instr->value();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005174 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005175 DeoptimizeIf(not_zero, instr->environment());
5176}
5177
5178
5179void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005180 LOperand* input = instr->value();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005181 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005182 DeoptimizeIf(zero, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005183}
5184
5185
5186void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005187 Register input = ToRegister(instr->value());
5188 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005189
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005190 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005191
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005192 if (instr->hydrogen()->is_interval_check()) {
5193 InstanceType first;
5194 InstanceType last;
5195 instr->hydrogen()->GetCheckInterval(&first, &last);
5196
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005197 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
5198 static_cast<int8_t>(first));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005199
5200 // If there is only one type in the interval check for equality.
5201 if (first == last) {
5202 DeoptimizeIf(not_equal, instr->environment());
5203 } else {
5204 DeoptimizeIf(below, instr->environment());
5205 // Omit check for the last type.
5206 if (last != LAST_TYPE) {
5207 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
5208 static_cast<int8_t>(last));
5209 DeoptimizeIf(above, instr->environment());
5210 }
5211 }
5212 } else {
5213 uint8_t mask;
5214 uint8_t tag;
5215 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
5216
5217 if (IsPowerOf2(mask)) {
5218 ASSERT(tag == 0 || IsPowerOf2(tag));
5219 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), mask);
5220 DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
5221 } else {
5222 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
5223 __ and_(temp, mask);
yangguo@chromium.org56454712012-02-16 15:33:53 +00005224 __ cmp(temp, tag);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005225 DeoptimizeIf(not_equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005226 }
5227 }
5228}
5229
5230
5231void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005232 Handle<JSFunction> target = instr->hydrogen()->target();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00005233 if (instr->hydrogen()->target_in_new_space()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005234 Register reg = ToRegister(instr->value());
5235 Handle<JSGlobalPropertyCell> cell =
5236 isolate()->factory()->NewJSGlobalPropertyCell(target);
5237 __ cmp(reg, Operand::Cell(cell));
5238 } else {
5239 Operand operand = ToOperand(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005240 __ cmp(operand, target);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005241 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005242 DeoptimizeIf(not_equal, instr->environment());
5243}
5244
5245
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005246void LCodeGen::DoCheckMapCommon(Register reg,
5247 Handle<Map> map,
5248 CompareMapMode mode,
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005249 LInstruction* instr) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005250 Label success;
5251 __ CompareMap(reg, map, &success, mode);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005252 DeoptimizeIf(not_equal, instr->environment());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005253 __ bind(&success);
5254}
5255
5256
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005257void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005258 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005259 ASSERT(input->IsRegister());
5260 Register reg = ToRegister(input);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005261
5262 Label success;
5263 SmallMapList* map_set = instr->hydrogen()->map_set();
5264 for (int i = 0; i < map_set->length() - 1; i++) {
5265 Handle<Map> map = map_set->at(i);
5266 __ CompareMap(reg, map, &success, REQUIRE_EXACT_MAP);
5267 __ j(equal, &success);
5268 }
5269 Handle<Map> map = map_set->last();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005270 DoCheckMapCommon(reg, map, REQUIRE_EXACT_MAP, instr);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005271 __ bind(&success);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005272}
5273
5274
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005275void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005276 CpuFeatures::Scope scope(SSE2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005277 XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
5278 Register result_reg = ToRegister(instr->result());
5279 __ ClampDoubleToUint8(value_reg, xmm0, result_reg);
5280}
5281
5282
5283void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
5284 ASSERT(instr->unclamped()->Equals(instr->result()));
5285 Register value_reg = ToRegister(instr->result());
5286 __ ClampUint8(value_reg);
5287}
5288
5289
5290void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005291 CpuFeatures::Scope scope(SSE2);
5292
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005293 ASSERT(instr->unclamped()->Equals(instr->result()));
5294 Register input_reg = ToRegister(instr->unclamped());
5295 Label is_smi, done, heap_number;
5296
5297 __ JumpIfSmi(input_reg, &is_smi);
5298
5299 // Check for heap number
5300 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5301 factory()->heap_number_map());
5302 __ j(equal, &heap_number, Label::kNear);
5303
5304 // Check for undefined. Undefined is converted to zero for clamping
5305 // conversions.
5306 __ cmp(input_reg, factory()->undefined_value());
5307 DeoptimizeIf(not_equal, instr->environment());
5308 __ mov(input_reg, 0);
5309 __ jmp(&done, Label::kNear);
5310
5311 // Heap number
5312 __ bind(&heap_number);
5313 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
5314 __ ClampDoubleToUint8(xmm0, xmm1, input_reg);
5315 __ jmp(&done, Label::kNear);
5316
5317 // smi
5318 __ bind(&is_smi);
5319 __ SmiUntag(input_reg);
5320 __ ClampUint8(input_reg);
5321
5322 __ bind(&done);
5323}
5324
5325
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005326void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00005327 ASSERT(instr->temp()->Equals(instr->result()));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005328 Register reg = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005329
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00005330 ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
5331 ZoneList<Handle<Map> >* maps = instr->maps();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005332
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00005333 ASSERT(prototypes->length() == maps->length());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005334
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00005335 for (int i = 0; i < prototypes->length(); i++) {
5336 __ LoadHeapObject(reg, prototypes->at(i));
5337 DoCheckMapCommon(reg, maps->at(i), ALLOW_ELEMENT_TRANSITION_MAPS, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005338 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005339}
5340
5341
ulan@chromium.org967e2702012-02-28 09:49:15 +00005342void LCodeGen::DoAllocateObject(LAllocateObject* instr) {
5343 class DeferredAllocateObject: public LDeferredCode {
5344 public:
5345 DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr)
5346 : LDeferredCode(codegen), instr_(instr) { }
5347 virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); }
5348 virtual LInstruction* instr() { return instr_; }
5349 private:
5350 LAllocateObject* instr_;
5351 };
5352
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005353 DeferredAllocateObject* deferred =
5354 new(zone()) DeferredAllocateObject(this, instr);
ulan@chromium.org967e2702012-02-28 09:49:15 +00005355
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005356 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005357 Register scratch = ToRegister(instr->temp());
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005358 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
5359 Handle<Map> initial_map(constructor->initial_map());
5360 int instance_size = initial_map->instance_size();
5361 ASSERT(initial_map->pre_allocated_property_fields() +
5362 initial_map->unused_property_fields() -
5363 initial_map->inobject_properties() == 0);
5364
5365 // Allocate memory for the object. The initial map might change when
5366 // the constructor's prototype changes, but instance size and property
5367 // counts remain unchanged (if slack tracking finished).
5368 ASSERT(!constructor->shared()->IsInobjectSlackTrackingInProgress());
5369 __ AllocateInNewSpace(instance_size,
5370 result,
5371 no_reg,
5372 scratch,
5373 deferred->entry(),
5374 TAG_OBJECT);
5375
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005376 __ bind(deferred->exit());
5377 if (FLAG_debug_code) {
5378 Label is_in_new_space;
5379 __ JumpIfInNewSpace(result, scratch, &is_in_new_space);
5380 __ Abort("Allocated object is not in new-space");
5381 __ bind(&is_in_new_space);
5382 }
5383
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005384 // Load the initial map.
5385 Register map = scratch;
5386 __ LoadHeapObject(scratch, constructor);
5387 __ mov(map, FieldOperand(scratch, JSFunction::kPrototypeOrInitialMapOffset));
5388
5389 if (FLAG_debug_code) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005390 __ AssertNotSmi(map);
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005391 __ cmpb(FieldOperand(map, Map::kInstanceSizeOffset),
5392 instance_size >> kPointerSizeLog2);
5393 __ Assert(equal, "Unexpected instance size");
5394 __ cmpb(FieldOperand(map, Map::kPreAllocatedPropertyFieldsOffset),
5395 initial_map->pre_allocated_property_fields());
5396 __ Assert(equal, "Unexpected pre-allocated property fields count");
5397 __ cmpb(FieldOperand(map, Map::kUnusedPropertyFieldsOffset),
5398 initial_map->unused_property_fields());
5399 __ Assert(equal, "Unexpected unused property fields count");
5400 __ cmpb(FieldOperand(map, Map::kInObjectPropertiesOffset),
5401 initial_map->inobject_properties());
5402 __ Assert(equal, "Unexpected in-object property fields count");
5403 }
5404
5405 // Initialize map and fields of the newly allocated object.
5406 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE);
5407 __ mov(FieldOperand(result, JSObject::kMapOffset), map);
5408 __ mov(scratch, factory()->empty_fixed_array());
5409 __ mov(FieldOperand(result, JSObject::kElementsOffset), scratch);
5410 __ mov(FieldOperand(result, JSObject::kPropertiesOffset), scratch);
5411 if (initial_map->inobject_properties() != 0) {
5412 __ mov(scratch, factory()->undefined_value());
5413 for (int i = 0; i < initial_map->inobject_properties(); i++) {
5414 int property_offset = JSObject::kHeaderSize + i * kPointerSize;
5415 __ mov(FieldOperand(result, property_offset), scratch);
5416 }
5417 }
ulan@chromium.org967e2702012-02-28 09:49:15 +00005418}
5419
5420
5421void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) {
5422 Register result = ToRegister(instr->result());
5423 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005424 Handle<Map> initial_map(constructor->initial_map());
5425 int instance_size = initial_map->instance_size();
ulan@chromium.org967e2702012-02-28 09:49:15 +00005426
5427 // TODO(3095996): Get rid of this. For now, we need to make the
5428 // result register contain a valid pointer because it is already
5429 // contained in the register pointer map.
5430 __ Set(result, Immediate(0));
5431
5432 PushSafepointRegistersScope scope(this);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005433 __ push(Immediate(Smi::FromInt(instance_size)));
5434 CallRuntimeFromDeferred(
5435 Runtime::kAllocateInNewSpace, 1, instr, instr->context());
ulan@chromium.org967e2702012-02-28 09:49:15 +00005436 __ StoreToSafepointRegisterSlot(result, eax);
5437}
5438
5439
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005440void LCodeGen::DoAllocate(LAllocate* instr) {
5441 class DeferredAllocate: public LDeferredCode {
5442 public:
5443 DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
5444 : LDeferredCode(codegen), instr_(instr) { }
5445 virtual void Generate() { codegen()->DoDeferredAllocate(instr_); }
5446 virtual LInstruction* instr() { return instr_; }
5447 private:
5448 LAllocate* instr_;
5449 };
5450
5451 DeferredAllocate* deferred =
5452 new(zone()) DeferredAllocate(this, instr);
5453
5454 Register size = ToRegister(instr->size());
5455 Register result = ToRegister(instr->result());
5456 Register temp = ToRegister(instr->temp());
5457
5458 HAllocate* original_instr = instr->hydrogen();
5459 if (original_instr->size()->IsConstant()) {
5460 UNREACHABLE();
5461 } else {
5462 // Allocate memory for the object.
5463 AllocationFlags flags = TAG_OBJECT;
5464 if (original_instr->MustAllocateDoubleAligned()) {
5465 flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
5466 }
5467 __ AllocateInNewSpace(size, result, temp, no_reg,
5468 deferred->entry(), flags);
5469 }
5470
5471 __ bind(deferred->exit());
5472}
5473
5474
5475void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
5476 Register size = ToRegister(instr->size());
5477 Register result = ToRegister(instr->result());
5478
5479 __ SmiTag(size);
5480 PushSafepointRegistersScope scope(this);
5481 // TODO(3095996): Get rid of this. For now, we need to make the
5482 // result register contain a valid pointer because it is already
5483 // contained in the register pointer map.
5484 if (!size.is(result)) {
5485 __ StoreToSafepointRegisterSlot(result, size);
5486 }
5487 __ push(size);
5488 CallRuntimeFromDeferred(
5489 Runtime::kAllocateInNewSpace, 1, instr, instr->context());
5490 __ StoreToSafepointRegisterSlot(result, eax);
5491}
5492
5493
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005494void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005495 ASSERT(ToRegister(instr->context()).is(esi));
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005496 Handle<FixedArray> literals(instr->environment()->closure()->literals());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005497 ElementsKind boilerplate_elements_kind =
5498 instr->hydrogen()->boilerplate_elements_kind();
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005499 AllocationSiteMode allocation_site_mode =
5500 instr->hydrogen()->allocation_site_mode();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005501
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005502 // Deopt if the array literal boilerplate ElementsKind is of a type different
5503 // than the expected one. The check isn't necessary if the boilerplate has
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005504 // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
5505 if (CanTransitionToMoreGeneralFastElementsKind(
5506 boilerplate_elements_kind, true)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005507 __ LoadHeapObject(eax, instr->hydrogen()->boilerplate_object());
5508 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
5509 // Load the map's "bit field 2". We only need the first byte,
5510 // but the following masking takes care of that anyway.
5511 __ mov(ebx, FieldOperand(ebx, Map::kBitField2Offset));
5512 // Retrieve elements_kind from bit field 2.
5513 __ and_(ebx, Map::kElementsKindMask);
5514 __ cmp(ebx, boilerplate_elements_kind << Map::kElementsKindShift);
5515 DeoptimizeIf(not_equal, instr->environment());
5516 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005517
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005518 // Set up the parameters to the stub/runtime call.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005519 __ PushHeapObject(literals);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005520 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005521 // Boilerplate already exists, constant elements are never accessed.
5522 // Pass an empty fixed array.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005523 __ push(Immediate(isolate()->factory()->empty_fixed_array()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005524
5525 // Pick the right runtime function or stub to call.
5526 int length = instr->hydrogen()->length();
5527 if (instr->hydrogen()->IsCopyOnWrite()) {
5528 ASSERT(instr->hydrogen()->depth() == 1);
5529 FastCloneShallowArrayStub::Mode mode =
5530 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005531 FastCloneShallowArrayStub stub(mode, DONT_TRACK_ALLOCATION_SITE, length);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005532 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005533 } else if (instr->hydrogen()->depth() > 1) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005534 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005535 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005536 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005537 } else {
5538 FastCloneShallowArrayStub::Mode mode =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005539 boilerplate_elements_kind == FAST_DOUBLE_ELEMENTS
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005540 ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
5541 : FastCloneShallowArrayStub::CLONE_ELEMENTS;
5542 FastCloneShallowArrayStub stub(mode, allocation_site_mode, length);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005543 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005544 }
5545}
5546
5547
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005548void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
5549 Register result,
5550 Register source,
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005551 int* offset,
5552 AllocationSiteMode mode) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005553 ASSERT(!source.is(ecx));
5554 ASSERT(!result.is(ecx));
5555
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005556 bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
5557 object->map()->CanTrackAllocationSite();
5558
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005559 if (FLAG_debug_code) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005560 __ LoadHeapObject(ecx, object);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005561 __ cmp(source, ecx);
5562 __ Assert(equal, "Unexpected object literal boilerplate");
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005563 __ mov(ecx, FieldOperand(source, HeapObject::kMapOffset));
5564 __ cmp(ecx, Handle<Map>(object->map()));
5565 __ Assert(equal, "Unexpected boilerplate map");
5566 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
5567 __ and_(ecx, Map::kElementsKindMask);
5568 __ cmp(ecx, object->GetElementsKind() << Map::kElementsKindShift);
5569 __ Assert(equal, "Unexpected boilerplate elements kind");
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005570 }
5571
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005572 // Only elements backing stores for non-COW arrays need to be copied.
5573 Handle<FixedArrayBase> elements(object->elements());
5574 bool has_elements = elements->length() > 0 &&
5575 elements->map() != isolate()->heap()->fixed_cow_array_map();
5576
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005577 // Increase the offset so that subsequent objects end up right after
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005578 // this object and its backing store.
5579 int object_offset = *offset;
5580 int object_size = object->map()->instance_size();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005581 int elements_size = has_elements ? elements->Size() : 0;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005582 int elements_offset = *offset + object_size;
5583 if (create_allocation_site_info) {
5584 elements_offset += AllocationSiteInfo::kSize;
5585 *offset += AllocationSiteInfo::kSize;
5586 }
5587
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005588 *offset += object_size + elements_size;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005589
5590 // Copy object header.
5591 ASSERT(object->properties()->length() == 0);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005592 int inobject_properties = object->map()->inobject_properties();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005593 int header_size = object_size - inobject_properties * kPointerSize;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005594 for (int i = 0; i < header_size; i += kPointerSize) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005595 if (has_elements && i == JSObject::kElementsOffset) {
5596 __ lea(ecx, Operand(result, elements_offset));
5597 } else {
5598 __ mov(ecx, FieldOperand(source, i));
5599 }
5600 __ mov(FieldOperand(result, object_offset + i), ecx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005601 }
5602
5603 // Copy in-object properties.
5604 for (int i = 0; i < inobject_properties; i++) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005605 int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005606 Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i));
5607 if (value->IsJSObject()) {
5608 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5609 __ lea(ecx, Operand(result, *offset));
5610 __ mov(FieldOperand(result, total_offset), ecx);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005611 __ LoadHeapObject(source, value_object);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005612 EmitDeepCopy(value_object, result, source, offset,
5613 DONT_TRACK_ALLOCATION_SITE);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005614 } else if (value->IsHeapObject()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005615 __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005616 __ mov(FieldOperand(result, total_offset), ecx);
5617 } else {
5618 __ mov(FieldOperand(result, total_offset), Immediate(value));
5619 }
5620 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005621
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005622 // Build Allocation Site Info if desired
5623 if (create_allocation_site_info) {
5624 __ mov(FieldOperand(result, object_size),
5625 Immediate(Handle<Map>(isolate()->heap()->
5626 allocation_site_info_map())));
5627 __ mov(FieldOperand(result, object_size + kPointerSize), source);
5628 }
5629
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005630 if (has_elements) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005631 // Copy elements backing store header.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005632 __ LoadHeapObject(source, elements);
5633 for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
5634 __ mov(ecx, FieldOperand(source, i));
5635 __ mov(FieldOperand(result, elements_offset + i), ecx);
5636 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005637
danno@chromium.org88aa0582012-03-23 15:11:57 +00005638 // Copy elements backing store content.
5639 int elements_length = elements->length();
5640 if (elements->IsFixedDoubleArray()) {
5641 Handle<FixedDoubleArray> double_array =
5642 Handle<FixedDoubleArray>::cast(elements);
5643 for (int i = 0; i < elements_length; i++) {
5644 int64_t value = double_array->get_representation(i);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00005645 int32_t value_low = static_cast<int32_t>(value & 0xFFFFFFFF);
5646 int32_t value_high = static_cast<int32_t>(value >> 32);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005647 int total_offset =
5648 elements_offset + FixedDoubleArray::OffsetOfElementAt(i);
5649 __ mov(FieldOperand(result, total_offset), Immediate(value_low));
5650 __ mov(FieldOperand(result, total_offset + 4), Immediate(value_high));
5651 }
5652 } else if (elements->IsFixedArray()) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005653 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005654 for (int i = 0; i < elements_length; i++) {
5655 int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005656 Handle<Object> value(fast_elements->get(i));
danno@chromium.org88aa0582012-03-23 15:11:57 +00005657 if (value->IsJSObject()) {
5658 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5659 __ lea(ecx, Operand(result, *offset));
5660 __ mov(FieldOperand(result, total_offset), ecx);
5661 __ LoadHeapObject(source, value_object);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005662 EmitDeepCopy(value_object, result, source, offset,
5663 DONT_TRACK_ALLOCATION_SITE);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005664 } else if (value->IsHeapObject()) {
5665 __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
5666 __ mov(FieldOperand(result, total_offset), ecx);
5667 } else {
5668 __ mov(FieldOperand(result, total_offset), Immediate(value));
5669 }
5670 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005671 } else {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005672 UNREACHABLE();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005673 }
5674 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005675}
5676
5677
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005678void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005679 ASSERT(ToRegister(instr->context()).is(esi));
5680 int size = instr->hydrogen()->total_size();
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005681 ElementsKind boilerplate_elements_kind =
5682 instr->hydrogen()->boilerplate()->GetElementsKind();
5683
5684 // Deopt if the literal boilerplate ElementsKind is of a type different than
5685 // the expected one. The check isn't necessary if the boilerplate has already
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005686 // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
5687 if (CanTransitionToMoreGeneralFastElementsKind(
5688 boilerplate_elements_kind, true)) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005689 __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
5690 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
5691 // Load the map's "bit field 2". We only need the first byte,
5692 // but the following masking takes care of that anyway.
5693 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
5694 // Retrieve elements_kind from bit field 2.
5695 __ and_(ecx, Map::kElementsKindMask);
5696 __ cmp(ecx, boilerplate_elements_kind << Map::kElementsKindShift);
5697 DeoptimizeIf(not_equal, instr->environment());
5698 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005699
5700 // Allocate all objects that are part of the literal in one big
5701 // allocation. This avoids multiple limit checks.
5702 Label allocated, runtime_allocate;
5703 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
5704 __ jmp(&allocated);
5705
5706 __ bind(&runtime_allocate);
5707 __ push(Immediate(Smi::FromInt(size)));
5708 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
5709
5710 __ bind(&allocated);
5711 int offset = 0;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005712 __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005713 EmitDeepCopy(instr->hydrogen()->boilerplate(), eax, ebx, &offset,
5714 instr->hydrogen()->allocation_site_mode());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005715 ASSERT_EQ(size, offset);
5716}
5717
5718
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005719void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005720 ASSERT(ToRegister(instr->context()).is(esi));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005721 Handle<FixedArray> literals(instr->environment()->closure()->literals());
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005722 Handle<FixedArray> constant_properties =
5723 instr->hydrogen()->constant_properties();
5724
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005725 // Set up the parameters to the stub/runtime call.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005726 __ PushHeapObject(literals);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005727 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005728 __ push(Immediate(constant_properties));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005729 int flags = instr->hydrogen()->fast_elements()
5730 ? ObjectLiteral::kFastElements
5731 : ObjectLiteral::kNoFlags;
5732 flags |= instr->hydrogen()->has_function()
5733 ? ObjectLiteral::kHasFunction
5734 : ObjectLiteral::kNoFlags;
5735 __ push(Immediate(Smi::FromInt(flags)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005736
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005737 // Pick the right runtime function or stub to call.
5738 int properties_count = constant_properties->length() / 2;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005739 if (instr->hydrogen()->depth() > 1) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005740 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005741 } else if (flags != ObjectLiteral::kFastElements ||
5742 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005743 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005744 } else {
5745 FastCloneShallowObjectStub stub(properties_count);
5746 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005747 }
5748}
5749
5750
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005751void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005752 ASSERT(ToRegister(instr->value()).is(eax));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005753 __ push(eax);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005754 CallRuntime(Runtime::kToFastProperties, 1, instr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005755}
5756
5757
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005758void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005759 ASSERT(ToRegister(instr->context()).is(esi));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005760 Label materialized;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005761 // Registers will be used as follows:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005762 // ecx = literals array.
5763 // ebx = regexp literal.
5764 // eax = regexp literal clone.
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005765 // esi = context.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005766 int literal_offset =
5767 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
5768 __ LoadHeapObject(ecx, instr->hydrogen()->literals());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005769 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005770 __ cmp(ebx, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005771 __ j(not_equal, &materialized, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005772
5773 // Create regexp literal using runtime function
5774 // Result will be in eax.
5775 __ push(ecx);
5776 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
5777 __ push(Immediate(instr->hydrogen()->pattern()));
5778 __ push(Immediate(instr->hydrogen()->flags()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005779 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005780 __ mov(ebx, eax);
5781
5782 __ bind(&materialized);
5783 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
5784 Label allocated, runtime_allocate;
5785 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
5786 __ jmp(&allocated);
5787
5788 __ bind(&runtime_allocate);
5789 __ push(ebx);
5790 __ push(Immediate(Smi::FromInt(size)));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005791 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005792 __ pop(ebx);
5793
5794 __ bind(&allocated);
5795 // Copy the content into the newly allocated memory.
5796 // (Unroll copy loop once for better throughput).
5797 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
5798 __ mov(edx, FieldOperand(ebx, i));
5799 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
5800 __ mov(FieldOperand(eax, i), edx);
5801 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
5802 }
5803 if ((size % (2 * kPointerSize)) != 0) {
5804 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
5805 __ mov(FieldOperand(eax, size - kPointerSize), edx);
5806 }
5807}
5808
5809
5810void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005811 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005812 // Use the fast case closure allocation code that allocates in new
5813 // space for nested functions that don't need literals cloning.
5814 Handle<SharedFunctionInfo> shared_info = instr->shared_info();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005815 bool pretenure = instr->hydrogen()->pretenure();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005816 if (!pretenure && shared_info->num_literals() == 0) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005817 FastNewClosureStub stub(shared_info->language_mode());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005818 __ push(Immediate(shared_info));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005819 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005820 } else {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005821 __ push(esi);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005822 __ push(Immediate(shared_info));
5823 __ push(Immediate(pretenure
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005824 ? factory()->true_value()
5825 : factory()->false_value()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005826 CallRuntime(Runtime::kNewClosure, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005827 }
5828}
5829
5830
5831void LCodeGen::DoTypeof(LTypeof* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005832 LOperand* input = instr->value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005833 EmitPushTaggedOperand(input);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005834 CallRuntime(Runtime::kTypeof, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005835}
5836
5837
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005838void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005839 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005840 int true_block = chunk_->LookupDestination(instr->true_block_id());
5841 int false_block = chunk_->LookupDestination(instr->false_block_id());
5842 Label* true_label = chunk_->GetAssemblyLabel(true_block);
5843 Label* false_label = chunk_->GetAssemblyLabel(false_block);
5844
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005845 Condition final_branch_condition =
5846 EmitTypeofIs(true_label, false_label, input, instr->type_literal());
5847 if (final_branch_condition != no_condition) {
5848 EmitBranch(true_block, false_block, final_branch_condition);
5849 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005850}
5851
5852
5853Condition LCodeGen::EmitTypeofIs(Label* true_label,
5854 Label* false_label,
5855 Register input,
5856 Handle<String> type_name) {
5857 Condition final_branch_condition = no_condition;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005858 if (type_name->Equals(heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005859 __ JumpIfSmi(input, true_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005860 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005861 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005862 final_branch_condition = equal;
5863
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005864 } else if (type_name->Equals(heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005865 __ JumpIfSmi(input, false_label);
5866 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
5867 __ j(above_equal, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005868 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5869 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005870 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005871
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005872 } else if (type_name->Equals(heap()->boolean_symbol())) {
5873 __ cmp(input, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005874 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005875 __ cmp(input, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005876 final_branch_condition = equal;
5877
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005878 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_symbol())) {
5879 __ cmp(input, factory()->null_value());
5880 final_branch_condition = equal;
5881
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005882 } else if (type_name->Equals(heap()->undefined_symbol())) {
5883 __ cmp(input, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005884 __ j(equal, true_label);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005885 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005886 // Check for undetectable objects => true.
5887 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
5888 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5889 1 << Map::kIsUndetectable);
5890 final_branch_condition = not_zero;
5891
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005892 } else if (type_name->Equals(heap()->function_symbol())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005893 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005894 __ JumpIfSmi(input, false_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005895 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
5896 __ j(equal, true_label);
5897 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
5898 final_branch_condition = equal;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005899
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005900 } else if (type_name->Equals(heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005901 __ JumpIfSmi(input, false_label);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005902 if (!FLAG_harmony_typeof) {
5903 __ cmp(input, factory()->null_value());
5904 __ j(equal, true_label);
5905 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005906 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005907 __ j(below, false_label);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005908 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
5909 __ j(above, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005910 // Check for undetectable objects => false.
5911 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5912 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005913 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005914
5915 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005916 __ jmp(false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005917 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005918 return final_branch_condition;
5919}
5920
5921
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005922void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005923 Register temp = ToRegister(instr->temp());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005924 int true_block = chunk_->LookupDestination(instr->true_block_id());
5925 int false_block = chunk_->LookupDestination(instr->false_block_id());
5926
5927 EmitIsConstructCall(temp);
5928 EmitBranch(true_block, false_block, equal);
5929}
5930
5931
5932void LCodeGen::EmitIsConstructCall(Register temp) {
5933 // Get the frame pointer for the calling frame.
5934 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
5935
5936 // Skip the arguments adaptor frame if it exists.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005937 Label check_frame_marker;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005938 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
5939 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005940 __ j(not_equal, &check_frame_marker, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005941 __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
5942
5943 // Check the marker in the calling frame.
5944 __ bind(&check_frame_marker);
5945 __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
5946 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
5947}
5948
5949
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005950void LCodeGen::EnsureSpaceForLazyDeopt() {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005951 if (!info()->IsStub()) {
5952 // Ensure that we have enough space after the previous lazy-bailout
5953 // instruction for patching the code here.
5954 int current_pc = masm()->pc_offset();
5955 int patch_size = Deoptimizer::patch_size();
5956 if (current_pc < last_lazy_deopt_pc_ + patch_size) {
5957 int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc;
5958 __ Nop(padding_size);
5959 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005960 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005961 last_lazy_deopt_pc_ = masm()->pc_offset();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005962}
5963
5964
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005965void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005966 EnsureSpaceForLazyDeopt();
5967 ASSERT(instr->HasEnvironment());
5968 LEnvironment* env = instr->environment();
5969 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5970 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005971}
5972
5973
5974void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
5975 DeoptimizeIf(no_condition, instr->environment());
5976}
5977
5978
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005979void LCodeGen::DoDummyUse(LDummyUse* instr) {
5980 // Nothing to see here, move on!
5981}
5982
5983
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005984void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
5985 LOperand* obj = instr->object();
5986 LOperand* key = instr->key();
5987 __ push(ToOperand(obj));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005988 EmitPushTaggedOperand(key);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00005989 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00005990 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00005991 RecordPosition(pointers->position());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005992 // Create safepoint generator that will also ensure enough space in the
5993 // reloc info for patching in deoptimization (since this is invoking a
5994 // builtin)
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005995 SafepointGenerator safepoint_generator(
5996 this, pointers, Safepoint::kLazyDeopt);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005997 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00005998 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005999}
6000
6001
ager@chromium.org04921a82011-06-27 13:21:41 +00006002void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006003 PushSafepointRegistersScope scope(this);
6004 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
6005 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
6006 RecordSafepointWithLazyDeopt(
6007 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
6008 ASSERT(instr->HasEnvironment());
6009 LEnvironment* env = instr->environment();
6010 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00006011}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006012
ager@chromium.org04921a82011-06-27 13:21:41 +00006013
6014void LCodeGen::DoStackCheck(LStackCheck* instr) {
6015 class DeferredStackCheck: public LDeferredCode {
6016 public:
6017 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
6018 : LDeferredCode(codegen), instr_(instr) { }
6019 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006020 virtual LInstruction* instr() { return instr_; }
ager@chromium.org04921a82011-06-27 13:21:41 +00006021 private:
6022 LStackCheck* instr_;
6023 };
6024
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006025 ASSERT(instr->HasEnvironment());
6026 LEnvironment* env = instr->environment();
6027 // There is no LLazyBailout instruction for stack-checks. We have to
6028 // prepare for lazy deoptimization explicitly here.
ager@chromium.org04921a82011-06-27 13:21:41 +00006029 if (instr->hydrogen()->is_function_entry()) {
6030 // Perform stack overflow check.
6031 Label done;
6032 ExternalReference stack_limit =
6033 ExternalReference::address_of_stack_limit(isolate());
6034 __ cmp(esp, Operand::StaticVariable(stack_limit));
6035 __ j(above_equal, &done, Label::kNear);
6036
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006037 ASSERT(instr->context()->IsRegister());
6038 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org04921a82011-06-27 13:21:41 +00006039 StackCheckStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006040 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006041 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00006042 __ bind(&done);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006043 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
6044 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00006045 } else {
6046 ASSERT(instr->hydrogen()->is_backwards_branch());
6047 // Perform stack overflow check if this goto needs it before jumping.
6048 DeferredStackCheck* deferred_stack_check =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00006049 new(zone()) DeferredStackCheck(this, instr);
ager@chromium.org04921a82011-06-27 13:21:41 +00006050 ExternalReference stack_limit =
6051 ExternalReference::address_of_stack_limit(isolate());
6052 __ cmp(esp, Operand::StaticVariable(stack_limit));
6053 __ j(below, deferred_stack_check->entry());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006054 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00006055 __ bind(instr->done_label());
6056 deferred_stack_check->SetExit(instr->done_label());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006057 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
6058 // Don't record a deoptimization index for the safepoint here.
6059 // This will be done explicitly when emitting call and the safepoint in
6060 // the deferred code.
ager@chromium.org04921a82011-06-27 13:21:41 +00006061 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006062}
6063
6064
6065void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
6066 // This is a pseudo-instruction that ensures that the environment here is
6067 // properly registered for deoptimization and records the assembler's PC
6068 // offset.
6069 LEnvironment* environment = instr->environment();
6070 environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
6071 instr->SpilledDoubleRegisterArray());
6072
6073 // If the environment were already registered, we would have no way of
6074 // backpatching it with the spill slot operands.
6075 ASSERT(!environment->HasBeenRegistered());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006076 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006077 ASSERT(osr_pc_offset_ == -1);
6078 osr_pc_offset_ = masm()->pc_offset();
6079}
6080
6081
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006082void LCodeGen::DoIn(LIn* instr) {
6083 LOperand* obj = instr->object();
6084 LOperand* key = instr->key();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006085 EmitPushTaggedOperand(key);
6086 EmitPushTaggedOperand(obj);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00006087 ASSERT(instr->HasPointerMap());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006088 LPointerMap* pointers = instr->pointer_map();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006089 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006090 SafepointGenerator safepoint_generator(
6091 this, pointers, Safepoint::kLazyDeopt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00006092 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006093}
6094
6095
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006096void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
6097 __ cmp(eax, isolate()->factory()->undefined_value());
6098 DeoptimizeIf(equal, instr->environment());
6099
6100 __ cmp(eax, isolate()->factory()->null_value());
6101 DeoptimizeIf(equal, instr->environment());
6102
6103 __ test(eax, Immediate(kSmiTagMask));
6104 DeoptimizeIf(zero, instr->environment());
6105
6106 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
6107 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
6108 DeoptimizeIf(below_equal, instr->environment());
6109
6110 Label use_cache, call_runtime;
6111 __ CheckEnumCache(&call_runtime);
6112
6113 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
6114 __ jmp(&use_cache, Label::kNear);
6115
6116 // Get the set of properties to enumerate.
6117 __ bind(&call_runtime);
6118 __ push(eax);
6119 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
6120
6121 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
6122 isolate()->factory()->meta_map());
6123 DeoptimizeIf(not_equal, instr->environment());
6124 __ bind(&use_cache);
6125}
6126
6127
6128void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
6129 Register map = ToRegister(instr->map());
6130 Register result = ToRegister(instr->result());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00006131 Label load_cache, done;
6132 __ EnumLength(result, map);
6133 __ cmp(result, Immediate(Smi::FromInt(0)));
6134 __ j(not_equal, &load_cache);
6135 __ mov(result, isolate()->factory()->empty_fixed_array());
6136 __ jmp(&done);
6137
6138 __ bind(&load_cache);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006139 __ LoadInstanceDescriptors(map, result);
6140 __ mov(result,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006141 FieldOperand(result, DescriptorArray::kEnumCacheOffset));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006142 __ mov(result,
6143 FieldOperand(result, FixedArray::SizeFor(instr->idx())));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00006144 __ bind(&done);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006145 __ test(result, result);
6146 DeoptimizeIf(equal, instr->environment());
6147}
6148
6149
6150void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
6151 Register object = ToRegister(instr->value());
6152 __ cmp(ToRegister(instr->map()),
6153 FieldOperand(object, HeapObject::kMapOffset));
6154 DeoptimizeIf(not_equal, instr->environment());
6155}
6156
6157
6158void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
6159 Register object = ToRegister(instr->object());
6160 Register index = ToRegister(instr->index());
6161
6162 Label out_of_object, done;
6163 __ cmp(index, Immediate(0));
6164 __ j(less, &out_of_object);
6165 __ mov(object, FieldOperand(object,
6166 index,
6167 times_half_pointer_size,
6168 JSObject::kHeaderSize));
6169 __ jmp(&done, Label::kNear);
6170
6171 __ bind(&out_of_object);
6172 __ mov(object, FieldOperand(object, JSObject::kPropertiesOffset));
6173 __ neg(index);
6174 // Index is now equal to out of object property index plus 1.
6175 __ mov(object, FieldOperand(object,
6176 index,
6177 times_half_pointer_size,
6178 FixedArray::kHeaderSize - kPointerSize));
6179 __ bind(&done);
6180}
6181
6182
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006183#undef __
6184
6185} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006186
6187#endif // V8_TARGET_ARCH_IA32