blob: 4ae660380ab620e33ce1f20b572227e0ba705ca5 [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
ulan@chromium.org750145a2013-03-07 15:14:13 +000043static SaveFPRegsMode GetSaveFPRegsMode() {
44 // We don't need to save floating point regs when generating the snapshot
45 return CpuFeatures::IsSafeForSnapshot(SSE2) ? kSaveFPRegs : kDontSaveFPRegs;
46}
47
48
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000049// When invoking builtins, we need to record the safepoint in the middle of
50// the invoke instruction sequence generated by the macro assembler.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000051class SafepointGenerator : public CallWrapper {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000052 public:
53 SafepointGenerator(LCodeGen* codegen,
54 LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +000055 Safepoint::DeoptMode mode)
kasperl@chromium.orga5551262010-12-07 12:49:48 +000056 : codegen_(codegen),
57 pointers_(pointers),
ricow@chromium.org27bf2882011-11-17 08:34:43 +000058 deopt_mode_(mode) {}
kasperl@chromium.orga5551262010-12-07 12:49:48 +000059 virtual ~SafepointGenerator() { }
60
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000061 virtual void BeforeCall(int call_size) const {}
62
63 virtual void AfterCall() const {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000064 codegen_->RecordSafepoint(pointers_, deopt_mode_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000065 }
66
67 private:
68 LCodeGen* codegen_;
69 LPointerMap* pointers_;
ricow@chromium.org27bf2882011-11-17 08:34:43 +000070 Safepoint::DeoptMode deopt_mode_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000071};
72
73
74#define __ masm()->
75
76bool LCodeGen::GenerateCode() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000077 HPhase phase("Z_Code generation", chunk());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000078 ASSERT(is_unused());
79 status_ = GENERATING;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000080
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000081 // Open a frame scope to indicate that there is a frame on the stack. The
82 // MANUAL indicates that the scope shouldn't actually generate code to set up
83 // the frame (that is done in GeneratePrologue).
84 FrameScope frame_scope(masm_, StackFrame::MANUAL);
85
danno@chromium.org94b0d6f2013-02-04 13:33:20 +000086 support_aligned_spilled_doubles_ = info()->IsOptimizing();
87
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000088 dynamic_frame_alignment_ = info()->IsOptimizing() &&
89 ((chunk()->num_double_slots() > 2 &&
90 !chunk()->graph()->is_recursive()) ||
91 !info()->osr_ast_id().IsNone());
mmassi@chromium.org7028c052012-06-13 11:51:58 +000092
kasperl@chromium.orga5551262010-12-07 12:49:48 +000093 return GeneratePrologue() &&
94 GenerateBody() &&
95 GenerateDeferredCode() &&
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000096 GenerateJumpTable() &&
kasperl@chromium.orga5551262010-12-07 12:49:48 +000097 GenerateSafepointTable();
98}
99
100
101void LCodeGen::FinishCode(Handle<Code> code) {
102 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +0000103 code->set_stack_slots(GetStackSlotCount());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000104 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +0000105 if (FLAG_weak_embedded_maps_in_optimized_code) {
106 RegisterDependentCodeForEmbeddedMaps(code);
107 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000108 PopulateDeoptimizationData(code);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000109 if (!info()->IsStub()) {
110 Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
111 }
ulan@chromium.org2e04b582013-02-21 14:06:02 +0000112 for (int i = 0 ; i < prototype_maps_.length(); i++) {
113 prototype_maps_.at(i)->AddDependentCode(
114 DependentCode::kPrototypeCheckGroup, code);
115 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000116}
117
118
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000119void LCodeGen::Abort(const char* reason) {
120 info()->set_bailout_reason(reason);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000121 status_ = ABORTED;
122}
123
124
125void LCodeGen::Comment(const char* format, ...) {
126 if (!FLAG_code_comments) return;
127 char buffer[4 * KB];
128 StringBuilder builder(buffer, ARRAY_SIZE(buffer));
129 va_list arguments;
130 va_start(arguments, format);
131 builder.AddFormattedList(format, arguments);
132 va_end(arguments);
133
134 // Copy the string before recording it in the assembler to avoid
135 // issues when the stack allocated buffer goes out of scope.
136 size_t length = builder.position();
137 Vector<char> copy = Vector<char>::New(length + 1);
138 memcpy(copy.start(), builder.Finalize(), copy.length());
139 masm()->RecordComment(copy.start());
140}
141
142
143bool LCodeGen::GeneratePrologue() {
144 ASSERT(is_generating());
145
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000146 if (info()->IsOptimizing()) {
147 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000148
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000149#ifdef DEBUG
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000150 if (strlen(FLAG_stop_at) > 0 &&
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000151 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000152 __ int3();
153 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000154#endif
155
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000156 // Strict mode functions and builtins need to replace the receiver
157 // with undefined when called as functions (without an explicit
158 // receiver object). ecx is zero for method calls and non-zero for
159 // function calls.
160 if (!info_->is_classic_mode() || info_->is_native()) {
161 Label ok;
162 __ test(ecx, Operand(ecx));
163 __ j(zero, &ok, Label::kNear);
164 // +1 for return address.
165 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
166 __ mov(Operand(esp, receiver_offset),
167 Immediate(isolate()->factory()->undefined_value()));
168 __ bind(&ok);
169 }
danno@chromium.org40cb8782011-05-25 07:58:50 +0000170
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000171 if (support_aligned_spilled_doubles_ && dynamic_frame_alignment_) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000172 // Move state of dynamic frame alignment into edx.
173 __ mov(edx, Immediate(kNoAlignmentPadding));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000174
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000175 Label do_not_pad, align_loop;
176 STATIC_ASSERT(kDoubleSize == 2 * kPointerSize);
177 // Align esp + 4 to a multiple of 2 * kPointerSize.
178 __ test(esp, Immediate(kPointerSize));
179 __ j(not_zero, &do_not_pad, Label::kNear);
180 __ push(Immediate(0));
181 __ mov(ebx, esp);
182 __ mov(edx, Immediate(kAlignmentPaddingPushed));
183 // Copy arguments, receiver, and return address.
184 __ mov(ecx, Immediate(scope()->num_parameters() + 2));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000185
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000186 __ bind(&align_loop);
187 __ mov(eax, Operand(ebx, 1 * kPointerSize));
188 __ mov(Operand(ebx, 0), eax);
189 __ add(Operand(ebx), Immediate(kPointerSize));
190 __ dec(ecx);
191 __ j(not_zero, &align_loop, Label::kNear);
192 __ mov(Operand(ebx, 0), Immediate(kAlignmentZapValue));
193 __ bind(&do_not_pad);
194 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000195 }
196
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000197 info()->set_prologue_offset(masm_->pc_offset());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000198 if (NeedsEagerFrame()) {
199 ASSERT(!frame_is_built_);
200 frame_is_built_ = true;
201 __ push(ebp); // Caller's frame pointer.
202 __ mov(ebp, esp);
203 __ push(esi); // Callee's context.
204 if (info()->IsStub()) {
205 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
206 } else {
207 __ push(edi); // Callee's JS function.
208 }
209 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000210
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000211 if (info()->IsOptimizing() &&
212 dynamic_frame_alignment_ &&
213 FLAG_debug_code) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000214 __ test(esp, Immediate(kPointerSize));
215 __ Assert(zero, "frame is expected to be aligned");
216 }
217
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000218 // Reserve space for the stack slots needed by the code.
danno@chromium.org160a7b02011-04-18 15:51:38 +0000219 int slots = GetStackSlotCount();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000220 ASSERT(slots != 0 || !info()->IsOptimizing());
221 if (slots > 0) {
222 if (slots == 1) {
223 if (dynamic_frame_alignment_) {
224 __ push(edx);
225 } else {
226 __ push(Immediate(kNoAlignmentPadding));
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +0000227 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000228 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000229 if (FLAG_debug_code) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000230 __ sub(Operand(esp), Immediate(slots * kPointerSize));
231 __ push(eax);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000232 __ mov(Operand(eax), Immediate(slots));
233 Label loop;
234 __ bind(&loop);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000235 __ mov(MemOperand(esp, eax, times_4, 0),
236 Immediate(kSlotsZapValue));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000237 __ dec(eax);
238 __ j(not_zero, &loop);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000239 __ pop(eax);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000240 } else {
241 __ sub(Operand(esp), Immediate(slots * kPointerSize));
242#ifdef _MSC_VER
243 // On windows, you may not access the stack more than one page below
244 // the most recently mapped page. To make the allocated area randomly
245 // accessible, we write to each page in turn (the value is irrelevant).
246 const int kPageSize = 4 * KB;
247 for (int offset = slots * kPointerSize - kPageSize;
248 offset > 0;
249 offset -= kPageSize) {
250 __ mov(Operand(esp, offset), eax);
251 }
252#endif
253 }
254
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000255 if (support_aligned_spilled_doubles_) {
256 Comment(";;; Store dynamic frame alignment tag for spilled doubles");
257 // Store dynamic frame alignment state in the first local.
258 int offset = JavaScriptFrameConstants::kDynamicAlignmentStateOffset;
259 if (dynamic_frame_alignment_) {
260 __ mov(Operand(ebp, offset), edx);
261 } else {
262 __ mov(Operand(ebp, offset), Immediate(kNoAlignmentPadding));
263 }
264 }
265 }
266
267 if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(SSE2)) {
268 Comment(";;; Save clobbered callee double registers");
ulan@chromium.org750145a2013-03-07 15:14:13 +0000269 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000270 int count = 0;
271 BitVector* doubles = chunk()->allocated_double_registers();
272 BitVector::Iterator save_iterator(doubles);
273 while (!save_iterator.Done()) {
274 __ movdbl(MemOperand(esp, count * kDoubleSize),
275 XMMRegister::FromAllocationIndex(save_iterator.Current()));
276 save_iterator.Advance();
277 count++;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000278 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000279 }
280 }
281
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000282 // Possibly allocate a local context.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000283 int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000284 if (heap_slots > 0) {
285 Comment(";;; Allocate local context");
286 // Argument to NewContext is the function, which is still in edi.
287 __ push(edi);
288 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
289 FastNewContextStub stub(heap_slots);
290 __ CallStub(&stub);
291 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000292 __ CallRuntime(Runtime::kNewFunctionContext, 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000293 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000294 RecordSafepoint(Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000295 // Context is returned in both eax and esi. It replaces the context
296 // passed to us. It's saved in the stack and kept live in esi.
297 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
298
299 // Copy parameters into context if necessary.
300 int num_parameters = scope()->num_parameters();
301 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000302 Variable* var = scope()->parameter(i);
303 if (var->IsContextSlot()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000304 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
305 (num_parameters - 1 - i) * kPointerSize;
306 // Load parameter from stack.
307 __ mov(eax, Operand(ebp, parameter_offset));
308 // Store it in the context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000309 int context_offset = Context::SlotOffset(var->index());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000310 __ mov(Operand(esi, context_offset), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000311 // Update the write barrier. This clobbers eax and ebx.
312 __ RecordWriteContextSlot(esi,
313 context_offset,
314 eax,
315 ebx,
316 kDontSaveFPRegs);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000317 }
318 }
319 Comment(";;; End allocate local context");
320 }
321
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000322 // Trace the call.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000323 if (FLAG_trace && info()->IsOptimizing()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000324 // We have not executed any compiled code yet, so esi still holds the
325 // incoming context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000326 __ CallRuntime(Runtime::kTraceEnter, 0);
327 }
328 return !is_aborted();
329}
330
331
332bool LCodeGen::GenerateBody() {
333 ASSERT(is_generating());
334 bool emit_instructions = true;
335 for (current_instruction_ = 0;
336 !is_aborted() && current_instruction_ < instructions_->length();
337 current_instruction_++) {
338 LInstruction* instr = instructions_->at(current_instruction_);
339 if (instr->IsLabel()) {
340 LLabel* label = LLabel::cast(instr);
341 emit_instructions = !label->HasReplacement();
342 }
343
344 if (emit_instructions) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000345 if (FLAG_code_comments) {
346 HValue* hydrogen = instr->hydrogen_value();
347 if (hydrogen != NULL) {
348 if (hydrogen->IsChange()) {
349 HValue* changed_value = HChange::cast(hydrogen)->value();
350 int use_id = 0;
351 const char* use_mnemo = "dead";
352 if (hydrogen->UseCount() >= 1) {
353 HValue* use_value = hydrogen->uses().value();
354 use_id = use_value->id();
355 use_mnemo = use_value->Mnemonic();
356 }
357 Comment(";;; @%d: %s. <of #%d %s for #%d %s>",
358 current_instruction_, instr->Mnemonic(),
359 changed_value->id(), changed_value->Mnemonic(),
360 use_id, use_mnemo);
361 } else {
362 Comment(";;; @%d: %s. <#%d>", current_instruction_,
363 instr->Mnemonic(), hydrogen->id());
364 }
365 } else {
366 Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
367 }
368 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000369 instr->CompileToNative(this);
370 }
371 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000372 EnsureSpaceForLazyDeopt();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000373 return !is_aborted();
374}
375
376
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000377bool LCodeGen::GenerateJumpTable() {
378 Label needs_frame_not_call;
379 Label needs_frame_is_call;
380 for (int i = 0; i < jump_table_.length(); i++) {
381 __ bind(&jump_table_[i].label);
382 Address entry = jump_table_[i].address;
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000383 bool is_lazy_deopt = jump_table_[i].is_lazy_deopt;
384 Deoptimizer::BailoutType type =
385 is_lazy_deopt ? Deoptimizer::LAZY : Deoptimizer::EAGER;
386 int id = Deoptimizer::GetDeoptimizationId(entry, type);
387 if (id == Deoptimizer::kNotDeoptimizationEntry) {
388 Comment(";;; jump table entry %d.", i);
389 } else {
390 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id);
391 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000392 if (jump_table_[i].needs_frame) {
393 __ push(Immediate(ExternalReference::ForDeoptEntry(entry)));
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000394 if (is_lazy_deopt) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000395 if (needs_frame_is_call.is_bound()) {
396 __ jmp(&needs_frame_is_call);
397 } else {
398 __ bind(&needs_frame_is_call);
399 __ push(MemOperand(ebp, StandardFrameConstants::kContextOffset));
400 // This variant of deopt can only be used with stubs. Since we don't
401 // have a function pointer to install in the stack frame that we're
402 // building, install a special marker there instead.
403 ASSERT(info()->IsStub());
404 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
405 // Push a PC inside the function so that the deopt code can find where
406 // the deopt comes from. It doesn't have to be the precise return
407 // address of a "calling" LAZY deopt, it only has to be somewhere
408 // inside the code body.
409 Label push_approx_pc;
410 __ call(&push_approx_pc);
411 __ bind(&push_approx_pc);
412 // Push the continuation which was stashed were the ebp should
413 // be. Replace it with the saved ebp.
414 __ push(MemOperand(esp, 3 * kPointerSize));
415 __ mov(MemOperand(esp, 4 * kPointerSize), ebp);
416 __ lea(ebp, MemOperand(esp, 4 * kPointerSize));
417 __ ret(0); // Call the continuation without clobbering registers.
418 }
419 } else {
420 if (needs_frame_not_call.is_bound()) {
421 __ jmp(&needs_frame_not_call);
422 } else {
423 __ bind(&needs_frame_not_call);
424 __ push(MemOperand(ebp, StandardFrameConstants::kContextOffset));
425 // This variant of deopt can only be used with stubs. Since we don't
426 // have a function pointer to install in the stack frame that we're
427 // building, install a special marker there instead.
428 ASSERT(info()->IsStub());
429 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
430 // Push the continuation which was stashed were the ebp should
431 // be. Replace it with the saved ebp.
432 __ push(MemOperand(esp, 2 * kPointerSize));
433 __ mov(MemOperand(esp, 3 * kPointerSize), ebp);
434 __ lea(ebp, MemOperand(esp, 3 * kPointerSize));
435 __ ret(0); // Call the continuation without clobbering registers.
436 }
437 }
438 } else {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000439 if (is_lazy_deopt) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000440 __ call(entry, RelocInfo::RUNTIME_ENTRY);
441 } else {
442 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
443 }
444 }
445 }
446 return !is_aborted();
447}
448
449
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000450bool LCodeGen::GenerateDeferredCode() {
451 ASSERT(is_generating());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000452 if (deferred_.length() > 0) {
453 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
454 LDeferredCode* code = deferred_[i];
455 __ bind(code->entry());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000456 if (NeedsDeferredFrame()) {
457 Comment(";;; Deferred build frame",
458 code->instruction_index(),
459 code->instr()->Mnemonic());
460 ASSERT(!frame_is_built_);
461 ASSERT(info()->IsStub());
462 frame_is_built_ = true;
463 // Build the frame in such a way that esi isn't trashed.
464 __ push(ebp); // Caller's frame pointer.
465 __ push(Operand(ebp, StandardFrameConstants::kContextOffset));
466 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
467 __ lea(ebp, Operand(esp, 2 * kPointerSize));
468 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000469 Comment(";;; Deferred code @%d: %s.",
470 code->instruction_index(),
471 code->instr()->Mnemonic());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000472 code->Generate();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000473 if (NeedsDeferredFrame()) {
474 Comment(";;; Deferred destroy frame",
475 code->instruction_index(),
476 code->instr()->Mnemonic());
477 ASSERT(frame_is_built_);
478 frame_is_built_ = false;
479 __ mov(esp, ebp);
480 __ pop(ebp);
481 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000482 __ jmp(code->exit());
483 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000484 }
485
486 // Deferred code is the last part of the instruction sequence. Mark
487 // the generated code as done unless we bailed out.
488 if (!is_aborted()) status_ = DONE;
489 return !is_aborted();
490}
491
492
493bool LCodeGen::GenerateSafepointTable() {
494 ASSERT(is_done());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000495 if (!info()->IsStub()) {
496 // For lazy deoptimization we need space to patch a call after every call.
497 // Ensure there is always space for such patching, even if the code ends
498 // in a call.
499 int target_offset = masm()->pc_offset() + Deoptimizer::patch_size();
500 while (masm()->pc_offset() < target_offset) {
501 masm()->nop();
502 }
503 }
danno@chromium.org160a7b02011-04-18 15:51:38 +0000504 safepoints_.Emit(masm(), GetStackSlotCount());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000505 return !is_aborted();
506}
507
508
509Register LCodeGen::ToRegister(int index) const {
510 return Register::FromAllocationIndex(index);
511}
512
513
514XMMRegister LCodeGen::ToDoubleRegister(int index) const {
515 return XMMRegister::FromAllocationIndex(index);
516}
517
518
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000519bool LCodeGen::IsX87TopOfStack(LOperand* op) const {
520 return op->IsDoubleRegister();
521}
522
523
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000524Register LCodeGen::ToRegister(LOperand* op) const {
525 ASSERT(op->IsRegister());
526 return ToRegister(op->index());
527}
528
529
530XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
531 ASSERT(op->IsDoubleRegister());
532 return ToDoubleRegister(op->index());
533}
534
535
536int LCodeGen::ToInteger32(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000537 HConstant* constant = chunk_->LookupConstant(op);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000538 return constant->Integer32Value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000539}
540
541
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000542Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000543 HConstant* constant = chunk_->LookupConstant(op);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000544 ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000545 return constant->handle();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000546}
547
548
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000549double LCodeGen::ToDouble(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000550 HConstant* constant = chunk_->LookupConstant(op);
551 ASSERT(constant->HasDoubleValue());
552 return constant->DoubleValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000553}
554
555
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000556bool LCodeGen::IsInteger32(LConstantOperand* op) const {
557 return chunk_->LookupLiteralRepresentation(op).IsInteger32();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000558}
559
560
561Operand LCodeGen::ToOperand(LOperand* op) const {
562 if (op->IsRegister()) return Operand(ToRegister(op));
563 if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
564 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
jkummerow@chromium.orgac360712013-02-11 09:00:07 +0000565 return Operand(ebp, StackSlotOffset(op->index()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000566}
567
568
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000569Operand LCodeGen::HighOperand(LOperand* op) {
570 ASSERT(op->IsDoubleStackSlot());
jkummerow@chromium.orgac360712013-02-11 09:00:07 +0000571 return Operand(ebp, StackSlotOffset(op->index()) + kPointerSize);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000572}
573
574
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000575void LCodeGen::WriteTranslation(LEnvironment* environment,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000576 Translation* translation,
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000577 int* pushed_arguments_index,
578 int* pushed_arguments_count) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000579 if (environment == NULL) return;
580
581 // The translation includes one command per value in the environment.
582 int translation_size = environment->values()->length();
583 // The output frame height does not include the parameters.
584 int height = translation_size - environment->parameter_count();
585
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000586 // Function parameters are arguments to the outermost environment. The
587 // arguments index points to the first element of a sequence of tagged
588 // values on the stack that represent the arguments. This needs to be
589 // kept in sync with the LArgumentsElements implementation.
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000590 *pushed_arguments_index = -environment->parameter_count();
591 *pushed_arguments_count = environment->parameter_count();
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000592
593 WriteTranslation(environment->outer(),
594 translation,
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000595 pushed_arguments_index,
596 pushed_arguments_count);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000597 bool has_closure_id = !info()->closure().is_null() &&
598 *info()->closure() != *environment->closure();
599 int closure_id = has_closure_id
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000600 ? DefineDeoptimizationLiteral(environment->closure())
601 : Translation::kSelfLiteralId;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000602 switch (environment->frame_type()) {
603 case JS_FUNCTION:
604 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
605 break;
606 case JS_CONSTRUCT:
607 translation->BeginConstructStubFrame(closure_id, translation_size);
608 break;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000609 case JS_GETTER:
610 ASSERT(translation_size == 1);
611 ASSERT(height == 0);
612 translation->BeginGetterStubFrame(closure_id);
613 break;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000614 case JS_SETTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000615 ASSERT(translation_size == 2);
616 ASSERT(height == 0);
617 translation->BeginSetterStubFrame(closure_id);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000618 break;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000619 case ARGUMENTS_ADAPTOR:
620 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
621 break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000622 case STUB:
623 translation->BeginCompiledStubFrame();
624 break;
625 default:
626 UNREACHABLE();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000627 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000628
629 // Inlined frames which push their arguments cause the index to be
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000630 // bumped and another stack area to be used for materialization,
631 // otherwise actual argument values are unknown for inlined frames.
632 bool arguments_known = true;
633 int arguments_index = *pushed_arguments_index;
634 int arguments_count = *pushed_arguments_count;
635 if (environment->entry() != NULL) {
636 arguments_known = environment->entry()->arguments_pushed();
637 arguments_index = arguments_index < 0
638 ? GetStackSlotCount() : arguments_index + arguments_count;
639 arguments_count = environment->entry()->arguments_count() + 1;
640 if (environment->entry()->arguments_pushed()) {
641 *pushed_arguments_index = arguments_index;
642 *pushed_arguments_count = arguments_count;
643 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000644 }
645
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000646 for (int i = 0; i < translation_size; ++i) {
647 LOperand* value = environment->values()->at(i);
648 // spilled_registers_ and spilled_double_registers_ are either
649 // both NULL or both set.
650 if (environment->spilled_registers() != NULL && value != NULL) {
651 if (value->IsRegister() &&
652 environment->spilled_registers()[value->index()] != NULL) {
653 translation->MarkDuplicate();
654 AddToTranslation(translation,
655 environment->spilled_registers()[value->index()],
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000656 environment->HasTaggedValueAt(i),
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000657 environment->HasUint32ValueAt(i),
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000658 arguments_known,
659 arguments_index,
660 arguments_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000661 } else if (
662 value->IsDoubleRegister() &&
663 environment->spilled_double_registers()[value->index()] != NULL) {
664 translation->MarkDuplicate();
665 AddToTranslation(
666 translation,
667 environment->spilled_double_registers()[value->index()],
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000668 false,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000669 false,
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000670 arguments_known,
671 arguments_index,
672 arguments_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000673 }
674 }
675
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000676 AddToTranslation(translation,
677 value,
678 environment->HasTaggedValueAt(i),
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000679 environment->HasUint32ValueAt(i),
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000680 arguments_known,
681 arguments_index,
682 arguments_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000683 }
684}
685
686
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000687void LCodeGen::AddToTranslation(Translation* translation,
688 LOperand* op,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000689 bool is_tagged,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000690 bool is_uint32,
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000691 bool arguments_known,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000692 int arguments_index,
693 int arguments_count) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000694 if (op == NULL) {
695 // TODO(twuerthinger): Introduce marker operands to indicate that this value
696 // is not present and must be reconstructed from the deoptimizer. Currently
697 // this is only used for the arguments object.
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000698 translation->StoreArgumentsObject(
699 arguments_known, arguments_index, arguments_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000700 } else if (op->IsStackSlot()) {
701 if (is_tagged) {
702 translation->StoreStackSlot(op->index());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000703 } else if (is_uint32) {
704 translation->StoreUint32StackSlot(op->index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000705 } else {
706 translation->StoreInt32StackSlot(op->index());
707 }
708 } else if (op->IsDoubleStackSlot()) {
709 translation->StoreDoubleStackSlot(op->index());
710 } else if (op->IsArgument()) {
711 ASSERT(is_tagged);
danno@chromium.org160a7b02011-04-18 15:51:38 +0000712 int src_index = GetStackSlotCount() + op->index();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000713 translation->StoreStackSlot(src_index);
714 } else if (op->IsRegister()) {
715 Register reg = ToRegister(op);
716 if (is_tagged) {
717 translation->StoreRegister(reg);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000718 } else if (is_uint32) {
719 translation->StoreUint32Register(reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000720 } else {
721 translation->StoreInt32Register(reg);
722 }
723 } else if (op->IsDoubleRegister()) {
724 XMMRegister reg = ToDoubleRegister(op);
725 translation->StoreDoubleRegister(reg);
726 } else if (op->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000727 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
728 int src_index = DefineDeoptimizationLiteral(constant->handle());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000729 translation->StoreLiteral(src_index);
730 } else {
731 UNREACHABLE();
732 }
733}
734
735
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000736void LCodeGen::CallCodeGeneric(Handle<Code> code,
737 RelocInfo::Mode mode,
738 LInstruction* instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000739 SafepointMode safepoint_mode) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000740 ASSERT(instr != NULL);
741 LPointerMap* pointers = instr->pointer_map();
742 RecordPosition(pointers->position());
743 __ call(code, mode);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000744 RecordSafepointWithLazyDeopt(instr, safepoint_mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000745
746 // Signal that we don't inline smi code before these stubs in the
747 // optimizing code generator.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000748 if (code->kind() == Code::BINARY_OP_IC ||
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000749 code->kind() == Code::COMPARE_IC) {
750 __ nop();
751 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000752}
753
754
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000755void LCodeGen::CallCode(Handle<Code> code,
756 RelocInfo::Mode mode,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000757 LInstruction* instr) {
758 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000759}
760
761
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000762void LCodeGen::CallRuntime(const Runtime::Function* fun,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000763 int argc,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000764 LInstruction* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000765 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000766 ASSERT(instr->HasPointerMap());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000767 LPointerMap* pointers = instr->pointer_map();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000768 RecordPosition(pointers->position());
769
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000770 __ CallRuntime(fun, argc);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000771
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000772 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000773
774 ASSERT(info()->is_calling());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000775}
776
777
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000778void LCodeGen::LoadContextFromDeferred(LOperand* context) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000779 if (context->IsRegister()) {
780 if (!ToRegister(context).is(esi)) {
781 __ mov(esi, ToRegister(context));
782 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000783 } else if (context->IsStackSlot()) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000784 __ mov(esi, ToOperand(context));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000785 } else if (context->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000786 HConstant* constant =
787 chunk_->LookupConstant(LConstantOperand::cast(context));
788 __ LoadHeapObject(esi, Handle<Context>::cast(constant->handle()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000789 } else {
790 UNREACHABLE();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000791 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000792}
793
794void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
795 int argc,
796 LInstruction* instr,
797 LOperand* context) {
798 LoadContextFromDeferred(context);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000799
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000800 __ CallRuntimeSaveDoubles(id);
801 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000802 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000803
804 ASSERT(info()->is_calling());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000805}
806
807
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000808void LCodeGen::RegisterEnvironmentForDeoptimization(
809 LEnvironment* environment, Safepoint::DeoptMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000810 if (!environment->HasBeenRegistered()) {
811 // Physical stack frame layout:
812 // -x ............. -4 0 ..................................... y
813 // [incoming arguments] [spill slots] [pushed outgoing arguments]
814
815 // Layout of the environment:
816 // 0 ..................................................... size-1
817 // [parameters] [locals] [expression stack including arguments]
818
819 // Layout of the translation:
820 // 0 ........................................................ size - 1 + 4
821 // [expression stack including arguments] [locals] [4 words] [parameters]
822 // |>------------ translation_size ------------<|
823
824 int frame_count = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000825 int jsframe_count = 0;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000826 int args_index = 0;
827 int args_count = 0;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000828 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
829 ++frame_count;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000830 if (e->frame_type() == JS_FUNCTION) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000831 ++jsframe_count;
832 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000833 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000834 Translation translation(&translations_, frame_count, jsframe_count, zone());
835 WriteTranslation(environment, &translation, &args_index, &args_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000836 int deoptimization_index = deoptimizations_.length();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000837 int pc_offset = masm()->pc_offset();
838 environment->Register(deoptimization_index,
839 translation.index(),
840 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000841 deoptimizations_.Add(environment, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000842 }
843}
844
845
846void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000847 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000848 ASSERT(environment->HasBeenRegistered());
849 int id = environment->deoptimization_index();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000850 ASSERT(info()->IsOptimizing() || info()->IsStub());
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000851 Deoptimizer::BailoutType bailout_type = info()->IsStub()
852 ? Deoptimizer::LAZY
853 : Deoptimizer::EAGER;
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000854 Address entry =
855 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000856 if (entry == NULL) {
857 Abort("bailout was not prepared");
858 return;
859 }
860
861 if (FLAG_deopt_every_n_times != 0) {
862 Handle<SharedFunctionInfo> shared(info_->shared_info());
863 Label no_deopt;
864 __ pushfd();
865 __ push(eax);
866 __ push(ebx);
867 __ mov(ebx, shared);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000868 __ mov(eax,
869 FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000870 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000871 __ j(not_zero, &no_deopt, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000872 if (FLAG_trap_on_deopt) __ int3();
873 __ mov(eax, Immediate(Smi::FromInt(FLAG_deopt_every_n_times)));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000874 __ mov(FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset),
875 eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000876 __ pop(ebx);
877 __ pop(eax);
878 __ popfd();
879 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
880
881 __ bind(&no_deopt);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000882 __ mov(FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset),
883 eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000884 __ pop(ebx);
885 __ pop(eax);
886 __ popfd();
887 }
888
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000889 if (FLAG_trap_on_deopt) {
890 Label done;
891 if (cc != no_condition) {
892 __ j(NegateCondition(cc), &done, Label::kNear);
893 }
894 __ int3();
895 __ bind(&done);
896 }
897
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000898 ASSERT(info()->IsStub() || frame_is_built_);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000899 bool needs_lazy_deopt = info()->IsStub();
900 if (cc == no_condition && frame_is_built_) {
901 if (needs_lazy_deopt) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000902 __ call(entry, RelocInfo::RUNTIME_ENTRY);
903 } else {
904 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
905 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000906 } else {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000907 // We often have several deopts to the same entry, reuse the last
908 // jump entry if this is the case.
909 if (jump_table_.is_empty() ||
910 jump_table_.last().address != entry ||
911 jump_table_.last().needs_frame != !frame_is_built_ ||
912 jump_table_.last().is_lazy_deopt != needs_lazy_deopt) {
913 JumpTableEntry table_entry(entry, !frame_is_built_, needs_lazy_deopt);
914 jump_table_.Add(table_entry, zone());
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +0000915 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000916 if (cc == no_condition) {
917 __ jmp(&jump_table_.last().label);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000918 } else {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000919 __ j(cc, &jump_table_.last().label);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000920 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000921 }
922}
923
924
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +0000925void LCodeGen::RegisterDependentCodeForEmbeddedMaps(Handle<Code> code) {
926 ZoneList<Handle<Map> > maps(1, zone());
927 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
928 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) {
929 RelocInfo::Mode mode = it.rinfo()->rmode();
930 if (mode == RelocInfo::EMBEDDED_OBJECT &&
931 it.rinfo()->target_object()->IsMap()) {
932 Handle<Map> map(Map::cast(it.rinfo()->target_object()));
933 if (map->CanTransition()) {
934 maps.Add(map, zone());
935 }
936 }
937 }
938#ifdef VERIFY_HEAP
939 // This disables verification of weak embedded maps after full GC.
940 // AddDependentCode can cause a GC, which would observe the state where
941 // this code is not yet in the depended code lists of the embedded maps.
942 NoWeakEmbeddedMapsVerificationScope disable_verification_of_embedded_maps;
943#endif
944 for (int i = 0; i < maps.length(); i++) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +0000945 maps.at(i)->AddDependentCode(DependentCode::kWeaklyEmbeddedGroup, code);
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +0000946 }
947}
948
949
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000950void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
951 int length = deoptimizations_.length();
952 if (length == 0) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000953 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000954 factory()->NewDeoptimizationInputData(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000955
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000956 Handle<ByteArray> translations = translations_.CreateByteArray();
957 data->SetTranslationByteArray(*translations);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000958 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
959
960 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000961 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000962 for (int i = 0; i < deoptimization_literals_.length(); i++) {
963 literals->set(i, *deoptimization_literals_[i]);
964 }
965 data->SetLiteralArray(*literals);
966
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000967 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000968 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
969
970 // Populate the deoptimization entries.
971 for (int i = 0; i < length; i++) {
972 LEnvironment* env = deoptimizations_[i];
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000973 data->SetAstId(i, env->ast_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000974 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
975 data->SetArgumentsStackHeight(i,
976 Smi::FromInt(env->arguments_stack_height()));
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000977 data->SetPc(i, Smi::FromInt(env->pc_offset()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000978 }
979 code->set_deoptimization_data(*data);
980}
981
982
983int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
984 int result = deoptimization_literals_.length();
985 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
986 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
987 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000988 deoptimization_literals_.Add(literal, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000989 return result;
990}
991
992
993void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
994 ASSERT(deoptimization_literals_.length() == 0);
995
996 const ZoneList<Handle<JSFunction> >* inlined_closures =
997 chunk()->inlined_closures();
998
999 for (int i = 0, length = inlined_closures->length();
1000 i < length;
1001 i++) {
1002 DefineDeoptimizationLiteral(inlined_closures->at(i));
1003 }
1004
1005 inlined_function_count_ = deoptimization_literals_.length();
1006}
1007
1008
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001009void LCodeGen::RecordSafepointWithLazyDeopt(
1010 LInstruction* instr, SafepointMode safepoint_mode) {
1011 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
1012 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
1013 } else {
1014 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
1015 RecordSafepointWithRegisters(
1016 instr->pointer_map(), 0, Safepoint::kLazyDeopt);
1017 }
1018}
1019
1020
ager@chromium.org378b34e2011-01-28 08:04:38 +00001021void LCodeGen::RecordSafepoint(
1022 LPointerMap* pointers,
1023 Safepoint::Kind kind,
1024 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001025 Safepoint::DeoptMode deopt_mode) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001026 ASSERT(kind == expected_safepoint_kind_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001027 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001028 Safepoint safepoint =
1029 safepoints_.DefineSafepoint(masm(), kind, arguments, deopt_mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001030 for (int i = 0; i < operands->length(); i++) {
1031 LOperand* pointer = operands->at(i);
1032 if (pointer->IsStackSlot()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001033 safepoint.DefinePointerSlot(pointer->index(), zone());
ager@chromium.org378b34e2011-01-28 08:04:38 +00001034 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001035 safepoint.DefinePointerRegister(ToRegister(pointer), zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001036 }
1037 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00001038}
1039
1040
1041void LCodeGen::RecordSafepoint(LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001042 Safepoint::DeoptMode mode) {
1043 RecordSafepoint(pointers, Safepoint::kSimple, 0, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001044}
1045
1046
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001047void LCodeGen::RecordSafepoint(Safepoint::DeoptMode mode) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001048 LPointerMap empty_pointers(RelocInfo::kNoPosition, zone());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001049 RecordSafepoint(&empty_pointers, mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001050}
1051
1052
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001053void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
1054 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001055 Safepoint::DeoptMode mode) {
1056 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001057}
1058
1059
1060void LCodeGen::RecordPosition(int position) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001061 if (position == RelocInfo::kNoPosition) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001062 masm()->positions_recorder()->RecordPosition(position);
1063}
1064
1065
1066void LCodeGen::DoLabel(LLabel* label) {
1067 if (label->is_loop_header()) {
1068 Comment(";;; B%d - LOOP entry", label->block_id());
1069 } else {
1070 Comment(";;; B%d", label->block_id());
1071 }
1072 __ bind(label->label());
1073 current_block_ = label->block_id();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001074 DoGap(label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001075}
1076
1077
1078void LCodeGen::DoParallelMove(LParallelMove* move) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001079 resolver_.Resolve(move);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001080}
1081
1082
1083void LCodeGen::DoGap(LGap* gap) {
1084 for (int i = LGap::FIRST_INNER_POSITION;
1085 i <= LGap::LAST_INNER_POSITION;
1086 i++) {
1087 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
1088 LParallelMove* move = gap->GetParallelMove(inner_pos);
1089 if (move != NULL) DoParallelMove(move);
1090 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001091}
1092
1093
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001094void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
1095 DoGap(instr);
1096}
1097
1098
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001099void LCodeGen::DoParameter(LParameter* instr) {
1100 // Nothing to do.
1101}
1102
1103
1104void LCodeGen::DoCallStub(LCallStub* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001105 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001106 ASSERT(ToRegister(instr->result()).is(eax));
1107 switch (instr->hydrogen()->major_key()) {
1108 case CodeStub::RegExpConstructResult: {
1109 RegExpConstructResultStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001110 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001111 break;
1112 }
1113 case CodeStub::RegExpExec: {
1114 RegExpExecStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001115 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001116 break;
1117 }
1118 case CodeStub::SubString: {
1119 SubStringStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001120 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001121 break;
1122 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001123 case CodeStub::NumberToString: {
1124 NumberToStringStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001125 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001126 break;
1127 }
1128 case CodeStub::StringAdd: {
1129 StringAddStub stub(NO_STRING_ADD_FLAGS);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001130 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001131 break;
1132 }
1133 case CodeStub::StringCompare: {
1134 StringCompareStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001135 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001136 break;
1137 }
1138 case CodeStub::TranscendentalCache: {
whesse@chromium.org023421e2010-12-21 12:19:12 +00001139 TranscendentalCacheStub stub(instr->transcendental_type(),
1140 TranscendentalCacheStub::TAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001141 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001142 break;
1143 }
1144 default:
1145 UNREACHABLE();
1146 }
1147}
1148
1149
1150void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
1151 // Nothing to do.
1152}
1153
1154
1155void LCodeGen::DoModI(LModI* instr) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001156 if (instr->hydrogen()->HasPowerOf2Divisor()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001157 Register dividend = ToRegister(instr->left());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001158
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001159 int32_t divisor =
1160 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001161
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001162 if (divisor < 0) divisor = -divisor;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001163
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001164 Label positive_dividend, done;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001165 __ test(dividend, Operand(dividend));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001166 __ j(not_sign, &positive_dividend, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001167 __ neg(dividend);
1168 __ and_(dividend, divisor - 1);
1169 __ neg(dividend);
1170 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001171 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001172 DeoptimizeIf(no_condition, instr->environment());
whesse@chromium.org7b260152011-06-20 15:33:18 +00001173 } else {
1174 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001175 }
1176 __ bind(&positive_dividend);
1177 __ and_(dividend, divisor - 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001178 __ bind(&done);
1179 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001180 Label done, remainder_eq_dividend, slow, do_subtraction, both_positive;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001181 Register left_reg = ToRegister(instr->left());
1182 Register right_reg = ToRegister(instr->right());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001183 Register result_reg = ToRegister(instr->result());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001184
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001185 ASSERT(left_reg.is(eax));
1186 ASSERT(result_reg.is(edx));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001187 ASSERT(!right_reg.is(eax));
1188 ASSERT(!right_reg.is(edx));
1189
1190 // Check for x % 0.
1191 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001192 __ test(right_reg, Operand(right_reg));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001193 DeoptimizeIf(zero, instr->environment());
1194 }
1195
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001196 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001197 __ j(zero, &remainder_eq_dividend, Label::kNear);
1198 __ j(sign, &slow, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001199
1200 __ test(right_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001201 __ j(not_sign, &both_positive, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001202 // The sign of the divisor doesn't matter.
1203 __ neg(right_reg);
1204
1205 __ bind(&both_positive);
1206 // If the dividend is smaller than the nonnegative
1207 // divisor, the dividend is the result.
1208 __ cmp(left_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001209 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001210
1211 // Check if the divisor is a PowerOfTwo integer.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001212 Register scratch = ToRegister(instr->temp());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001213 __ mov(scratch, right_reg);
1214 __ sub(Operand(scratch), Immediate(1));
1215 __ test(scratch, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001216 __ j(not_zero, &do_subtraction, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001217 __ and_(left_reg, Operand(scratch));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001218 __ jmp(&remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001219
1220 __ bind(&do_subtraction);
1221 const int kUnfolds = 3;
1222 // Try a few subtractions of the dividend.
1223 __ mov(scratch, left_reg);
1224 for (int i = 0; i < kUnfolds; i++) {
1225 // Reduce the dividend by the divisor.
1226 __ sub(left_reg, Operand(right_reg));
1227 // Check if the dividend is less than the divisor.
1228 __ cmp(left_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001229 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001230 }
1231 __ mov(left_reg, scratch);
1232
1233 // Slow case, using idiv instruction.
1234 __ bind(&slow);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001235
1236 // Check for (kMinInt % -1).
1237 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1238 Label left_not_min_int;
1239 __ cmp(left_reg, kMinInt);
1240 __ j(not_zero, &left_not_min_int, Label::kNear);
1241 __ cmp(right_reg, -1);
1242 DeoptimizeIf(zero, instr->environment());
1243 __ bind(&left_not_min_int);
1244 }
1245
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001246 // Sign extend to edx.
1247 __ cdq();
1248
1249 // Check for (0 % -x) that will produce negative zero.
1250 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001251 Label positive_left;
1252 Label done;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001253 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001254 __ j(not_sign, &positive_left, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001255 __ idiv(right_reg);
1256
1257 // Test the remainder for 0, because then the result would be -0.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001258 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001259 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001260
1261 DeoptimizeIf(no_condition, instr->environment());
1262 __ bind(&positive_left);
1263 __ idiv(right_reg);
1264 __ bind(&done);
1265 } else {
1266 __ idiv(right_reg);
1267 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001268 __ jmp(&done, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001269
1270 __ bind(&remainder_eq_dividend);
1271 __ mov(result_reg, left_reg);
1272
1273 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001274 }
1275}
1276
1277
1278void LCodeGen::DoDivI(LDivI* instr) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001279 if (!instr->is_flooring() && instr->hydrogen()->HasPowerOf2Divisor()) {
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001280 Register dividend = ToRegister(instr->left());
1281 int32_t divisor =
1282 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
1283 int32_t test_value = 0;
1284 int32_t power = 0;
1285
1286 if (divisor > 0) {
1287 test_value = divisor - 1;
1288 power = WhichPowerOf2(divisor);
1289 } else {
1290 // Check for (0 / -x) that will produce negative zero.
1291 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1292 __ test(dividend, Operand(dividend));
1293 DeoptimizeIf(zero, instr->environment());
1294 }
1295 // Check for (kMinInt / -1).
1296 if (divisor == -1 && instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1297 __ cmp(dividend, kMinInt);
1298 DeoptimizeIf(zero, instr->environment());
1299 }
1300 test_value = - divisor - 1;
1301 power = WhichPowerOf2(-divisor);
1302 }
1303
1304 if (test_value != 0) {
1305 // Deoptimize if remainder is not 0.
1306 __ test(dividend, Immediate(test_value));
1307 DeoptimizeIf(not_zero, instr->environment());
1308 __ sar(dividend, power);
1309 }
1310
1311 if (divisor < 0) __ neg(dividend);
1312
1313 return;
1314 }
1315
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001316 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001317 ASSERT(ToRegister(instr->result()).is(eax));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001318 ASSERT(ToRegister(instr->left()).is(eax));
1319 ASSERT(!ToRegister(instr->right()).is(eax));
1320 ASSERT(!ToRegister(instr->right()).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001321
1322 Register left_reg = eax;
1323
1324 // Check for x / 0.
1325 Register right_reg = ToRegister(right);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001326 if (instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001327 __ test(right_reg, ToOperand(right));
1328 DeoptimizeIf(zero, instr->environment());
1329 }
1330
1331 // Check for (0 / -x) that will produce negative zero.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001332 if (instr->hydrogen_value()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001333 Label left_not_zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001334 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001335 __ j(not_zero, &left_not_zero, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001336 __ test(right_reg, ToOperand(right));
1337 DeoptimizeIf(sign, instr->environment());
1338 __ bind(&left_not_zero);
1339 }
1340
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001341 // Check for (kMinInt / -1).
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001342 if (instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001343 Label left_not_min_int;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001344 __ cmp(left_reg, kMinInt);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001345 __ j(not_zero, &left_not_min_int, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001346 __ cmp(right_reg, -1);
1347 DeoptimizeIf(zero, instr->environment());
1348 __ bind(&left_not_min_int);
1349 }
1350
1351 // Sign extend to edx.
1352 __ cdq();
1353 __ idiv(right_reg);
1354
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001355 if (!instr->is_flooring()) {
1356 // Deoptimize if remainder is not 0.
1357 __ test(edx, Operand(edx));
1358 DeoptimizeIf(not_zero, instr->environment());
1359 } else {
1360 Label done;
1361 __ test(edx, edx);
1362 __ j(zero, &done, Label::kNear);
1363 __ xor_(edx, right_reg);
1364 __ sar(edx, 31);
1365 __ add(eax, edx);
1366 __ bind(&done);
1367 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001368}
1369
1370
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001371void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001372 ASSERT(instr->right()->IsConstantOperand());
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001373
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001374 Register dividend = ToRegister(instr->left());
1375 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001376 Register result = ToRegister(instr->result());
1377
1378 switch (divisor) {
1379 case 0:
1380 DeoptimizeIf(no_condition, instr->environment());
1381 return;
1382
1383 case 1:
1384 __ Move(result, dividend);
1385 return;
1386
1387 case -1:
1388 __ Move(result, dividend);
1389 __ neg(result);
1390 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1391 DeoptimizeIf(zero, instr->environment());
1392 }
1393 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1394 DeoptimizeIf(overflow, instr->environment());
1395 }
1396 return;
1397 }
1398
1399 uint32_t divisor_abs = abs(divisor);
1400 if (IsPowerOf2(divisor_abs)) {
1401 int32_t power = WhichPowerOf2(divisor_abs);
1402 if (divisor < 0) {
1403 // Input[dividend] is clobbered.
1404 // The sequence is tedious because neg(dividend) might overflow.
1405 __ mov(result, dividend);
1406 __ sar(dividend, 31);
1407 __ neg(result);
1408 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1409 DeoptimizeIf(zero, instr->environment());
1410 }
1411 __ shl(dividend, 32 - power);
1412 __ sar(result, power);
1413 __ not_(dividend);
1414 // Clear result.sign if dividend.sign is set.
1415 __ and_(result, dividend);
1416 } else {
1417 __ Move(result, dividend);
1418 __ sar(result, power);
1419 }
1420 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001421 ASSERT(ToRegister(instr->left()).is(eax));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001422 ASSERT(ToRegister(instr->result()).is(edx));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001423 Register scratch = ToRegister(instr->temp());
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001424
1425 // Find b which: 2^b < divisor_abs < 2^(b+1).
1426 unsigned b = 31 - CompilerIntrinsics::CountLeadingZeros(divisor_abs);
1427 unsigned shift = 32 + b; // Precision +1bit (effectively).
1428 double multiplier_f =
1429 static_cast<double>(static_cast<uint64_t>(1) << shift) / divisor_abs;
1430 int64_t multiplier;
1431 if (multiplier_f - floor(multiplier_f) < 0.5) {
1432 multiplier = static_cast<int64_t>(floor(multiplier_f));
1433 } else {
1434 multiplier = static_cast<int64_t>(floor(multiplier_f)) + 1;
1435 }
1436 // The multiplier is a uint32.
1437 ASSERT(multiplier > 0 &&
1438 multiplier < (static_cast<int64_t>(1) << 32));
1439 __ mov(scratch, dividend);
1440 if (divisor < 0 &&
1441 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1442 __ test(dividend, dividend);
1443 DeoptimizeIf(zero, instr->environment());
1444 }
1445 __ mov(edx, static_cast<int32_t>(multiplier));
1446 __ imul(edx);
1447 if (static_cast<int32_t>(multiplier) < 0) {
1448 __ add(edx, scratch);
1449 }
1450 Register reg_lo = eax;
1451 Register reg_byte_scratch = scratch;
1452 if (!reg_byte_scratch.is_byte_register()) {
1453 __ xchg(reg_lo, reg_byte_scratch);
1454 reg_lo = scratch;
1455 reg_byte_scratch = eax;
1456 }
1457 if (divisor < 0) {
1458 __ xor_(reg_byte_scratch, reg_byte_scratch);
1459 __ cmp(reg_lo, 0x40000000);
1460 __ setcc(above, reg_byte_scratch);
1461 __ neg(edx);
1462 __ sub(edx, reg_byte_scratch);
1463 } else {
1464 __ xor_(reg_byte_scratch, reg_byte_scratch);
1465 __ cmp(reg_lo, 0xC0000000);
1466 __ setcc(above_equal, reg_byte_scratch);
1467 __ add(edx, reg_byte_scratch);
1468 }
1469 __ sar(edx, shift - 32);
1470 }
1471}
1472
1473
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001474void LCodeGen::DoMulI(LMulI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001475 Register left = ToRegister(instr->left());
1476 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001477
1478 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001479 __ mov(ToRegister(instr->temp()), left);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001480 }
1481
1482 if (right->IsConstantOperand()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001483 // Try strength reductions on the multiplication.
1484 // All replacement instructions are at most as long as the imul
1485 // and have better latency.
1486 int constant = ToInteger32(LConstantOperand::cast(right));
1487 if (constant == -1) {
1488 __ neg(left);
1489 } else if (constant == 0) {
1490 __ xor_(left, Operand(left));
1491 } else if (constant == 2) {
1492 __ add(left, Operand(left));
1493 } else if (!instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1494 // If we know that the multiplication can't overflow, it's safe to
1495 // use instructions that don't set the overflow flag for the
1496 // multiplication.
1497 switch (constant) {
1498 case 1:
1499 // Do nothing.
1500 break;
1501 case 3:
1502 __ lea(left, Operand(left, left, times_2, 0));
1503 break;
1504 case 4:
1505 __ shl(left, 2);
1506 break;
1507 case 5:
1508 __ lea(left, Operand(left, left, times_4, 0));
1509 break;
1510 case 8:
1511 __ shl(left, 3);
1512 break;
1513 case 9:
1514 __ lea(left, Operand(left, left, times_8, 0));
1515 break;
1516 case 16:
1517 __ shl(left, 4);
1518 break;
1519 default:
1520 __ imul(left, left, constant);
1521 break;
1522 }
1523 } else {
1524 __ imul(left, left, constant);
1525 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001526 } else {
1527 __ imul(left, ToOperand(right));
1528 }
1529
1530 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1531 DeoptimizeIf(overflow, instr->environment());
1532 }
1533
1534 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1535 // Bail out if the result is supposed to be negative zero.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001536 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001537 __ test(left, Operand(left));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001538 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001539 if (right->IsConstantOperand()) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001540 if (ToInteger32(LConstantOperand::cast(right)) < 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001541 DeoptimizeIf(no_condition, instr->environment());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001542 } else if (ToInteger32(LConstantOperand::cast(right)) == 0) {
1543 __ cmp(ToRegister(instr->temp()), Immediate(0));
1544 DeoptimizeIf(less, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001545 }
1546 } else {
1547 // Test the non-zero operand for negative sign.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001548 __ or_(ToRegister(instr->temp()), ToOperand(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001549 DeoptimizeIf(sign, instr->environment());
1550 }
1551 __ bind(&done);
1552 }
1553}
1554
1555
1556void LCodeGen::DoBitI(LBitI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001557 LOperand* left = instr->left();
1558 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001559 ASSERT(left->Equals(instr->result()));
1560 ASSERT(left->IsRegister());
1561
1562 if (right->IsConstantOperand()) {
1563 int right_operand = ToInteger32(LConstantOperand::cast(right));
1564 switch (instr->op()) {
1565 case Token::BIT_AND:
1566 __ and_(ToRegister(left), right_operand);
1567 break;
1568 case Token::BIT_OR:
1569 __ or_(ToRegister(left), right_operand);
1570 break;
1571 case Token::BIT_XOR:
1572 __ xor_(ToRegister(left), right_operand);
1573 break;
1574 default:
1575 UNREACHABLE();
1576 break;
1577 }
1578 } else {
1579 switch (instr->op()) {
1580 case Token::BIT_AND:
1581 __ and_(ToRegister(left), ToOperand(right));
1582 break;
1583 case Token::BIT_OR:
1584 __ or_(ToRegister(left), ToOperand(right));
1585 break;
1586 case Token::BIT_XOR:
1587 __ xor_(ToRegister(left), ToOperand(right));
1588 break;
1589 default:
1590 UNREACHABLE();
1591 break;
1592 }
1593 }
1594}
1595
1596
1597void LCodeGen::DoShiftI(LShiftI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001598 LOperand* left = instr->left();
1599 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001600 ASSERT(left->Equals(instr->result()));
1601 ASSERT(left->IsRegister());
1602 if (right->IsRegister()) {
1603 ASSERT(ToRegister(right).is(ecx));
1604
1605 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001606 case Token::ROR:
1607 __ ror_cl(ToRegister(left));
1608 if (instr->can_deopt()) {
1609 __ test(ToRegister(left), Immediate(0x80000000));
1610 DeoptimizeIf(not_zero, instr->environment());
1611 }
1612 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001613 case Token::SAR:
1614 __ sar_cl(ToRegister(left));
1615 break;
1616 case Token::SHR:
1617 __ shr_cl(ToRegister(left));
1618 if (instr->can_deopt()) {
1619 __ test(ToRegister(left), Immediate(0x80000000));
1620 DeoptimizeIf(not_zero, instr->environment());
1621 }
1622 break;
1623 case Token::SHL:
1624 __ shl_cl(ToRegister(left));
1625 break;
1626 default:
1627 UNREACHABLE();
1628 break;
1629 }
1630 } else {
1631 int value = ToInteger32(LConstantOperand::cast(right));
1632 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1633 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001634 case Token::ROR:
1635 if (shift_count == 0 && instr->can_deopt()) {
1636 __ test(ToRegister(left), Immediate(0x80000000));
1637 DeoptimizeIf(not_zero, instr->environment());
1638 } else {
1639 __ ror(ToRegister(left), shift_count);
1640 }
1641 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001642 case Token::SAR:
1643 if (shift_count != 0) {
1644 __ sar(ToRegister(left), shift_count);
1645 }
1646 break;
1647 case Token::SHR:
1648 if (shift_count == 0 && instr->can_deopt()) {
1649 __ test(ToRegister(left), Immediate(0x80000000));
1650 DeoptimizeIf(not_zero, instr->environment());
1651 } else {
1652 __ shr(ToRegister(left), shift_count);
1653 }
1654 break;
1655 case Token::SHL:
1656 if (shift_count != 0) {
1657 __ shl(ToRegister(left), shift_count);
1658 }
1659 break;
1660 default:
1661 UNREACHABLE();
1662 break;
1663 }
1664 }
1665}
1666
1667
1668void LCodeGen::DoSubI(LSubI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001669 LOperand* left = instr->left();
1670 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001671 ASSERT(left->Equals(instr->result()));
1672
1673 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001674 __ sub(ToOperand(left), ToInteger32Immediate(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001675 } else {
1676 __ sub(ToRegister(left), ToOperand(right));
1677 }
1678 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1679 DeoptimizeIf(overflow, instr->environment());
1680 }
1681}
1682
1683
1684void LCodeGen::DoConstantI(LConstantI* instr) {
1685 ASSERT(instr->result()->IsRegister());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001686 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001687}
1688
1689
1690void LCodeGen::DoConstantD(LConstantD* instr) {
1691 ASSERT(instr->result()->IsDoubleRegister());
1692 XMMRegister res = ToDoubleRegister(instr->result());
1693 double v = instr->value();
1694 // Use xor to produce +0.0 in a fast and compact way, but avoid to
1695 // do so if the constant is -0.0.
1696 if (BitCast<uint64_t, double>(v) == 0) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001697 __ xorps(res, res);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001698 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001699 Register temp = ToRegister(instr->temp());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001700 uint64_t int_val = BitCast<uint64_t, double>(v);
1701 int32_t lower = static_cast<int32_t>(int_val);
1702 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001703 if (CpuFeatures::IsSupported(SSE4_1)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001704 CpuFeatureScope scope1(masm(), SSE2);
1705 CpuFeatureScope scope2(masm(), SSE4_1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001706 if (lower != 0) {
1707 __ Set(temp, Immediate(lower));
1708 __ movd(res, Operand(temp));
1709 __ Set(temp, Immediate(upper));
1710 __ pinsrd(res, Operand(temp), 1);
1711 } else {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001712 __ xorps(res, res);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001713 __ Set(temp, Immediate(upper));
1714 __ pinsrd(res, Operand(temp), 1);
1715 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001716 } else {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001717 CpuFeatureScope scope(masm(), SSE2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001718 __ Set(temp, Immediate(upper));
1719 __ movd(res, Operand(temp));
1720 __ psllq(res, 32);
1721 if (lower != 0) {
1722 __ Set(temp, Immediate(lower));
1723 __ movd(xmm0, Operand(temp));
1724 __ por(res, xmm0);
1725 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001726 }
1727 }
1728}
1729
1730
1731void LCodeGen::DoConstantT(LConstantT* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001732 Register reg = ToRegister(instr->result());
1733 Handle<Object> handle = instr->value();
1734 if (handle->IsHeapObject()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001735 __ LoadHeapObject(reg, Handle<HeapObject>::cast(handle));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001736 } else {
1737 __ Set(reg, Immediate(handle));
1738 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001739}
1740
1741
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001742void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001743 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001744 Register array = ToRegister(instr->value());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001745 __ mov(result, FieldOperand(array, JSArray::kLengthOffset));
1746}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001747
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001748
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001749void LCodeGen::DoFixedArrayBaseLength(
1750 LFixedArrayBaseLength* instr) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001751 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001752 Register array = ToRegister(instr->value());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001753 __ mov(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001754}
1755
1756
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001757void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
1758 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001759 Register map = ToRegister(instr->value());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001760 __ EnumLength(result, map);
1761}
1762
1763
whesse@chromium.org7b260152011-06-20 15:33:18 +00001764void LCodeGen::DoElementsKind(LElementsKind* instr) {
1765 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001766 Register input = ToRegister(instr->value());
whesse@chromium.org7b260152011-06-20 15:33:18 +00001767
1768 // Load map into |result|.
1769 __ mov(result, FieldOperand(input, HeapObject::kMapOffset));
1770 // Load the map's "bit field 2" into |result|. We only need the first byte,
1771 // but the following masking takes care of that anyway.
1772 __ mov(result, FieldOperand(result, Map::kBitField2Offset));
1773 // Retrieve elements_kind from bit field 2.
1774 __ and_(result, Map::kElementsKindMask);
1775 __ shr(result, Map::kElementsKindShift);
1776}
1777
1778
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001779void LCodeGen::DoValueOf(LValueOf* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001780 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001781 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001782 Register map = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001783 ASSERT(input.is(result));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001784
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001785 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001786 // If the object is a smi return the object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001787 __ JumpIfSmi(input, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001788
1789 // If the object is not a value type, return the object.
1790 __ CmpObjectType(input, JS_VALUE_TYPE, map);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001791 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001792 __ mov(result, FieldOperand(input, JSValue::kValueOffset));
1793
1794 __ bind(&done);
1795}
1796
1797
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001798void LCodeGen::DoDateField(LDateField* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001799 Register object = ToRegister(instr->date());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001800 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001801 Register scratch = ToRegister(instr->temp());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001802 Smi* index = instr->index();
1803 Label runtime, done;
1804 ASSERT(object.is(result));
1805 ASSERT(object.is(eax));
1806
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001807 __ test(object, Immediate(kSmiTagMask));
1808 DeoptimizeIf(zero, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001809 __ CmpObjectType(object, JS_DATE_TYPE, scratch);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001810 DeoptimizeIf(not_equal, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001811
1812 if (index->value() == 0) {
1813 __ mov(result, FieldOperand(object, JSDate::kValueOffset));
1814 } else {
1815 if (index->value() < JSDate::kFirstUncachedField) {
1816 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
1817 __ mov(scratch, Operand::StaticVariable(stamp));
1818 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
1819 __ j(not_equal, &runtime, Label::kNear);
1820 __ mov(result, FieldOperand(object, JSDate::kValueOffset +
1821 kPointerSize * index->value()));
1822 __ jmp(&done);
1823 }
1824 __ bind(&runtime);
1825 __ PrepareCallCFunction(2, scratch);
1826 __ mov(Operand(esp, 0), object);
1827 __ mov(Operand(esp, 1 * kPointerSize), Immediate(index));
1828 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
1829 __ bind(&done);
1830 }
1831}
1832
1833
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00001834void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
1835 SeqStringSetCharGenerator::Generate(masm(),
1836 instr->encoding(),
1837 ToRegister(instr->string()),
1838 ToRegister(instr->index()),
1839 ToRegister(instr->value()));
1840}
1841
1842
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001843void LCodeGen::DoBitNotI(LBitNotI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001844 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001845 ASSERT(input->Equals(instr->result()));
1846 __ not_(ToRegister(input));
1847}
1848
1849
1850void LCodeGen::DoThrow(LThrow* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001851 __ push(ToOperand(instr->value()));
1852 ASSERT(ToRegister(instr->context()).is(esi));
1853 CallRuntime(Runtime::kThrow, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001854
1855 if (FLAG_debug_code) {
1856 Comment("Unreachable code.");
1857 __ int3();
1858 }
1859}
1860
1861
1862void LCodeGen::DoAddI(LAddI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001863 LOperand* left = instr->left();
1864 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001865 ASSERT(left->Equals(instr->result()));
1866
1867 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001868 __ add(ToOperand(left), ToInteger32Immediate(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001869 } else {
1870 __ add(ToRegister(left), ToOperand(right));
1871 }
1872
1873 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1874 DeoptimizeIf(overflow, instr->environment());
1875 }
1876}
1877
1878
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001879void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001880 CpuFeatureScope scope(masm(), SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001881 LOperand* left = instr->left();
1882 LOperand* right = instr->right();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001883 ASSERT(left->Equals(instr->result()));
1884 HMathMinMax::Operation operation = instr->hydrogen()->operation();
1885 if (instr->hydrogen()->representation().IsInteger32()) {
1886 Label return_left;
1887 Condition condition = (operation == HMathMinMax::kMathMin)
1888 ? less_equal
1889 : greater_equal;
1890 if (right->IsConstantOperand()) {
1891 Operand left_op = ToOperand(left);
1892 Immediate right_imm = ToInteger32Immediate(right);
1893 __ cmp(left_op, right_imm);
1894 __ j(condition, &return_left, Label::kNear);
1895 __ mov(left_op, right_imm);
1896 } else {
1897 Register left_reg = ToRegister(left);
1898 Operand right_op = ToOperand(right);
1899 __ cmp(left_reg, right_op);
1900 __ j(condition, &return_left, Label::kNear);
1901 __ mov(left_reg, right_op);
1902 }
1903 __ bind(&return_left);
1904 } else {
1905 ASSERT(instr->hydrogen()->representation().IsDouble());
1906 Label check_nan_left, check_zero, return_left, return_right;
1907 Condition condition = (operation == HMathMinMax::kMathMin) ? below : above;
1908 XMMRegister left_reg = ToDoubleRegister(left);
1909 XMMRegister right_reg = ToDoubleRegister(right);
1910 __ ucomisd(left_reg, right_reg);
1911 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN.
1912 __ j(equal, &check_zero, Label::kNear); // left == right.
1913 __ j(condition, &return_left, Label::kNear);
1914 __ jmp(&return_right, Label::kNear);
1915
1916 __ bind(&check_zero);
1917 XMMRegister xmm_scratch = xmm0;
1918 __ xorps(xmm_scratch, xmm_scratch);
1919 __ ucomisd(left_reg, xmm_scratch);
1920 __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
1921 // At this point, both left and right are either 0 or -0.
1922 if (operation == HMathMinMax::kMathMin) {
1923 __ orpd(left_reg, right_reg);
1924 } else {
1925 // Since we operate on +0 and/or -0, addsd and andsd have the same effect.
1926 __ addsd(left_reg, right_reg);
1927 }
1928 __ jmp(&return_left, Label::kNear);
1929
1930 __ bind(&check_nan_left);
1931 __ ucomisd(left_reg, left_reg); // NaN check.
1932 __ j(parity_even, &return_left, Label::kNear); // left == NaN.
1933 __ bind(&return_right);
1934 __ movsd(left_reg, right_reg);
1935
1936 __ bind(&return_left);
1937 }
1938}
1939
1940
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001941void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001942 CpuFeatureScope scope(masm(), SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001943 XMMRegister left = ToDoubleRegister(instr->left());
1944 XMMRegister right = ToDoubleRegister(instr->right());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001945 XMMRegister result = ToDoubleRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001946 // Modulo uses a fixed result register.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001947 ASSERT(instr->op() == Token::MOD || left.is(result));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001948 switch (instr->op()) {
1949 case Token::ADD:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001950 __ addsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001951 break;
1952 case Token::SUB:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001953 __ subsd(left, right);
1954 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001955 case Token::MUL:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001956 __ mulsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001957 break;
1958 case Token::DIV:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001959 __ divsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001960 break;
1961 case Token::MOD: {
1962 // Pass two doubles as arguments on the stack.
1963 __ PrepareCallCFunction(4, eax);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001964 __ movdbl(Operand(esp, 0 * kDoubleSize), left);
1965 __ movdbl(Operand(esp, 1 * kDoubleSize), right);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001966 __ CallCFunction(
1967 ExternalReference::double_fp_operation(Token::MOD, isolate()),
1968 4);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001969
1970 // Return value is in st(0) on ia32.
1971 // Store it into the (fixed) result register.
1972 __ sub(Operand(esp), Immediate(kDoubleSize));
1973 __ fstp_d(Operand(esp, 0));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001974 __ movdbl(result, Operand(esp, 0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001975 __ add(Operand(esp), Immediate(kDoubleSize));
1976 break;
1977 }
1978 default:
1979 UNREACHABLE();
1980 break;
1981 }
1982}
1983
1984
1985void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001986 ASSERT(ToRegister(instr->context()).is(esi));
1987 ASSERT(ToRegister(instr->left()).is(edx));
1988 ASSERT(ToRegister(instr->right()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001989 ASSERT(ToRegister(instr->result()).is(eax));
1990
danno@chromium.org40cb8782011-05-25 07:58:50 +00001991 BinaryOpStub stub(instr->op(), NO_OVERWRITE);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001992 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001993 __ nop(); // Signals no inlined code.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001994}
1995
1996
1997int LCodeGen::GetNextEmittedBlock(int block) {
1998 for (int i = block + 1; i < graph()->blocks()->length(); ++i) {
1999 LLabel* label = chunk_->GetLabel(i);
2000 if (!label->HasReplacement()) return i;
2001 }
2002 return -1;
2003}
2004
2005
2006void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
2007 int next_block = GetNextEmittedBlock(current_block_);
2008 right_block = chunk_->LookupDestination(right_block);
2009 left_block = chunk_->LookupDestination(left_block);
2010
2011 if (right_block == left_block) {
2012 EmitGoto(left_block);
2013 } else if (left_block == next_block) {
2014 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
2015 } else if (right_block == next_block) {
2016 __ j(cc, chunk_->GetAssemblyLabel(left_block));
2017 } else {
2018 __ j(cc, chunk_->GetAssemblyLabel(left_block));
2019 __ jmp(chunk_->GetAssemblyLabel(right_block));
2020 }
2021}
2022
2023
2024void LCodeGen::DoBranch(LBranch* instr) {
2025 int true_block = chunk_->LookupDestination(instr->true_block_id());
2026 int false_block = chunk_->LookupDestination(instr->false_block_id());
ulan@chromium.org750145a2013-03-07 15:14:13 +00002027 CpuFeatureScope scope(masm(), SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002028
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002029 Representation r = instr->hydrogen()->value()->representation();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002030 if (r.IsInteger32()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002031 Register reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002032 __ test(reg, Operand(reg));
2033 EmitBranch(true_block, false_block, not_zero);
2034 } else if (r.IsDouble()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002035 XMMRegister reg = ToDoubleRegister(instr->value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00002036 __ xorps(xmm0, xmm0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002037 __ ucomisd(reg, xmm0);
2038 EmitBranch(true_block, false_block, not_equal);
2039 } else {
2040 ASSERT(r.IsTagged());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002041 Register reg = ToRegister(instr->value());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002042 HType type = instr->hydrogen()->value()->type();
2043 if (type.IsBoolean()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002044 __ cmp(reg, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002045 EmitBranch(true_block, false_block, equal);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002046 } else if (type.IsSmi()) {
2047 __ test(reg, Operand(reg));
2048 EmitBranch(true_block, false_block, not_equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002049 } else {
2050 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2051 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2052
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002053 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
2054 // Avoid deopts in the case where we've never executed this path before.
2055 if (expected.IsEmpty()) expected = ToBooleanStub::all_types();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002056
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002057 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
2058 // undefined -> false.
2059 __ cmp(reg, factory()->undefined_value());
2060 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002061 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002062 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
2063 // true -> true.
2064 __ cmp(reg, factory()->true_value());
2065 __ j(equal, true_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002066 // false -> false.
2067 __ cmp(reg, factory()->false_value());
2068 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002069 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002070 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
2071 // 'null' -> false.
2072 __ cmp(reg, factory()->null_value());
2073 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002074 }
2075
2076 if (expected.Contains(ToBooleanStub::SMI)) {
2077 // Smis: 0 -> false, all other -> true.
2078 __ test(reg, Operand(reg));
2079 __ j(equal, false_label);
2080 __ JumpIfSmi(reg, true_label);
2081 } else if (expected.NeedsMap()) {
2082 // If we need a map later and have a Smi -> deopt.
2083 __ test(reg, Immediate(kSmiTagMask));
2084 DeoptimizeIf(zero, instr->environment());
2085 }
2086
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002087 Register map = no_reg; // Keep the compiler happy.
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002088 if (expected.NeedsMap()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002089 map = ToRegister(instr->temp());
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002090 ASSERT(!map.is(reg));
2091 __ mov(map, FieldOperand(reg, HeapObject::kMapOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002092
2093 if (expected.CanBeUndetectable()) {
2094 // Undetectable -> false.
2095 __ test_b(FieldOperand(map, Map::kBitFieldOffset),
2096 1 << Map::kIsUndetectable);
2097 __ j(not_zero, false_label);
2098 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002099 }
2100
2101 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
2102 // spec object -> true.
2103 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
2104 __ j(above_equal, true_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002105 }
2106
2107 if (expected.Contains(ToBooleanStub::STRING)) {
2108 // String value -> false iff empty.
2109 Label not_string;
2110 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
2111 __ j(above_equal, &not_string, Label::kNear);
2112 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
2113 __ j(not_zero, true_label);
2114 __ jmp(false_label);
2115 __ bind(&not_string);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002116 }
2117
2118 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
2119 // heap number -> false iff +0, -0, or NaN.
2120 Label not_heap_number;
2121 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
2122 factory()->heap_number_map());
2123 __ j(not_equal, &not_heap_number, Label::kNear);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002124 __ xorps(xmm0, xmm0);
2125 __ ucomisd(xmm0, FieldOperand(reg, HeapNumber::kValueOffset));
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002126 __ j(zero, false_label);
2127 __ jmp(true_label);
2128 __ bind(&not_heap_number);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002129 }
2130
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002131 // We've seen something for the first time -> deopt.
2132 DeoptimizeIf(no_condition, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002133 }
2134 }
2135}
2136
2137
ager@chromium.org04921a82011-06-27 13:21:41 +00002138void LCodeGen::EmitGoto(int block) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002139 block = chunk_->LookupDestination(block);
2140 int next_block = GetNextEmittedBlock(current_block_);
2141 if (block != next_block) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002142 __ jmp(chunk_->GetAssemblyLabel(block));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002143 }
2144}
2145
2146
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002147void LCodeGen::DoGoto(LGoto* instr) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002148 EmitGoto(instr->block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002149}
2150
2151
2152Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
2153 Condition cond = no_condition;
2154 switch (op) {
2155 case Token::EQ:
2156 case Token::EQ_STRICT:
2157 cond = equal;
2158 break;
2159 case Token::LT:
2160 cond = is_unsigned ? below : less;
2161 break;
2162 case Token::GT:
2163 cond = is_unsigned ? above : greater;
2164 break;
2165 case Token::LTE:
2166 cond = is_unsigned ? below_equal : less_equal;
2167 break;
2168 case Token::GTE:
2169 cond = is_unsigned ? above_equal : greater_equal;
2170 break;
2171 case Token::IN:
2172 case Token::INSTANCEOF:
2173 default:
2174 UNREACHABLE();
2175 }
2176 return cond;
2177}
2178
2179
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002180void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002181 LOperand* left = instr->left();
2182 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002183 int false_block = chunk_->LookupDestination(instr->false_block_id());
2184 int true_block = chunk_->LookupDestination(instr->true_block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002185 Condition cc = TokenToCondition(instr->op(), instr->is_double());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002186
2187 if (left->IsConstantOperand() && right->IsConstantOperand()) {
2188 // We can statically evaluate the comparison.
2189 double left_val = ToDouble(LConstantOperand::cast(left));
2190 double right_val = ToDouble(LConstantOperand::cast(right));
2191 int next_block =
2192 EvalComparison(instr->op(), left_val, right_val) ? true_block
2193 : false_block;
2194 EmitGoto(next_block);
2195 } else {
2196 if (instr->is_double()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002197 CpuFeatureScope scope(masm(), SSE2);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002198 // Don't base result on EFLAGS when a NaN is involved. Instead
2199 // jump to the false block.
2200 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
2201 __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
2202 } else {
2203 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00002204 __ cmp(ToRegister(left), ToInteger32Immediate(right));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002205 } else if (left->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00002206 __ cmp(ToOperand(right), ToInteger32Immediate(left));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002207 // We transposed the operands. Reverse the condition.
2208 cc = ReverseCondition(cc);
2209 } else {
2210 __ cmp(ToRegister(left), ToOperand(right));
2211 }
2212 }
2213 EmitBranch(true_block, false_block, cc);
2214 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002215}
2216
2217
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002218void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002219 Register left = ToRegister(instr->left());
2220 Operand right = ToOperand(instr->right());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002221 int false_block = chunk_->LookupDestination(instr->false_block_id());
2222 int true_block = chunk_->LookupDestination(instr->true_block_id());
2223
2224 __ cmp(left, Operand(right));
2225 EmitBranch(true_block, false_block, equal);
2226}
2227
2228
whesse@chromium.org7b260152011-06-20 15:33:18 +00002229void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002230 Register left = ToRegister(instr->left());
whesse@chromium.org7b260152011-06-20 15:33:18 +00002231 int true_block = chunk_->LookupDestination(instr->true_block_id());
2232 int false_block = chunk_->LookupDestination(instr->false_block_id());
2233
2234 __ cmp(left, instr->hydrogen()->right());
2235 EmitBranch(true_block, false_block, equal);
2236}
2237
2238
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002239void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002240 Register reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002241 int false_block = chunk_->LookupDestination(instr->false_block_id());
2242
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002243 // If the expression is known to be untagged or a smi, then it's definitely
2244 // not null, and it can't be a an undetectable object.
2245 if (instr->hydrogen()->representation().IsSpecialization() ||
2246 instr->hydrogen()->type().IsSmi()) {
2247 EmitGoto(false_block);
2248 return;
2249 }
2250
2251 int true_block = chunk_->LookupDestination(instr->true_block_id());
2252 Handle<Object> nil_value = instr->nil() == kNullValue ?
2253 factory()->null_value() :
2254 factory()->undefined_value();
2255 __ cmp(reg, nil_value);
2256 if (instr->kind() == kStrictEquality) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002257 EmitBranch(true_block, false_block, equal);
2258 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002259 Handle<Object> other_nil_value = instr->nil() == kNullValue ?
2260 factory()->undefined_value() :
2261 factory()->null_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002262 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2263 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2264 __ j(equal, true_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002265 __ cmp(reg, other_nil_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002266 __ j(equal, true_label);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002267 __ JumpIfSmi(reg, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002268 // Check for undetectable objects by looking in the bit field in
2269 // the map. The object has already been smi checked.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002270 Register scratch = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002271 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
2272 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
2273 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
2274 EmitBranch(true_block, false_block, not_zero);
2275 }
2276}
2277
2278
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002279Condition LCodeGen::EmitIsObject(Register input,
2280 Register temp1,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002281 Label* is_not_object,
2282 Label* is_object) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002283 __ JumpIfSmi(input, is_not_object);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002284
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002285 __ cmp(input, isolate()->factory()->null_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002286 __ j(equal, is_object);
2287
2288 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
2289 // Undetectable objects behave like undefined.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002290 __ test_b(FieldOperand(temp1, Map::kBitFieldOffset),
2291 1 << Map::kIsUndetectable);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002292 __ j(not_zero, is_not_object);
2293
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002294 __ movzx_b(temp1, FieldOperand(temp1, Map::kInstanceTypeOffset));
2295 __ cmp(temp1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002296 __ j(below, is_not_object);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002297 __ cmp(temp1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002298 return below_equal;
2299}
2300
2301
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002302void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002303 Register reg = ToRegister(instr->value());
2304 Register temp = ToRegister(instr->temp());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002305
2306 int true_block = chunk_->LookupDestination(instr->true_block_id());
2307 int false_block = chunk_->LookupDestination(instr->false_block_id());
2308 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2309 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2310
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002311 Condition true_cond = EmitIsObject(reg, temp, false_label, true_label);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002312
2313 EmitBranch(true_block, false_block, true_cond);
2314}
2315
2316
erikcorry0ad885c2011-11-21 13:51:57 +00002317Condition LCodeGen::EmitIsString(Register input,
2318 Register temp1,
2319 Label* is_not_string) {
2320 __ JumpIfSmi(input, is_not_string);
2321
2322 Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
2323
2324 return cond;
2325}
2326
2327
2328void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002329 Register reg = ToRegister(instr->value());
2330 Register temp = ToRegister(instr->temp());
erikcorry0ad885c2011-11-21 13:51:57 +00002331
2332 int true_block = chunk_->LookupDestination(instr->true_block_id());
2333 int false_block = chunk_->LookupDestination(instr->false_block_id());
2334 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2335
2336 Condition true_cond = EmitIsString(reg, temp, false_label);
2337
2338 EmitBranch(true_block, false_block, true_cond);
2339}
2340
2341
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002342void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002343 Operand input = ToOperand(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002344
2345 int true_block = chunk_->LookupDestination(instr->true_block_id());
2346 int false_block = chunk_->LookupDestination(instr->false_block_id());
2347
2348 __ test(input, Immediate(kSmiTagMask));
2349 EmitBranch(true_block, false_block, zero);
2350}
2351
2352
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002353void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002354 Register input = ToRegister(instr->value());
2355 Register temp = ToRegister(instr->temp());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002356
2357 int true_block = chunk_->LookupDestination(instr->true_block_id());
2358 int false_block = chunk_->LookupDestination(instr->false_block_id());
2359
2360 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002361 __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002362 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
2363 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
2364 1 << Map::kIsUndetectable);
2365 EmitBranch(true_block, false_block, not_zero);
2366}
2367
2368
erikcorry0ad885c2011-11-21 13:51:57 +00002369static Condition ComputeCompareCondition(Token::Value op) {
2370 switch (op) {
2371 case Token::EQ_STRICT:
2372 case Token::EQ:
2373 return equal;
2374 case Token::LT:
2375 return less;
2376 case Token::GT:
2377 return greater;
2378 case Token::LTE:
2379 return less_equal;
2380 case Token::GTE:
2381 return greater_equal;
2382 default:
2383 UNREACHABLE();
2384 return no_condition;
2385 }
2386}
2387
2388
2389void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
2390 Token::Value op = instr->op();
2391 int true_block = chunk_->LookupDestination(instr->true_block_id());
2392 int false_block = chunk_->LookupDestination(instr->false_block_id());
2393
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002394 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
erikcorry0ad885c2011-11-21 13:51:57 +00002395 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2396
2397 Condition condition = ComputeCompareCondition(op);
2398 __ test(eax, Operand(eax));
2399
2400 EmitBranch(true_block, false_block, condition);
2401}
2402
2403
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002404static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002405 InstanceType from = instr->from();
2406 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002407 if (from == FIRST_TYPE) return to;
2408 ASSERT(from == to || to == LAST_TYPE);
2409 return from;
2410}
2411
2412
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002413static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002414 InstanceType from = instr->from();
2415 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002416 if (from == to) return equal;
2417 if (to == LAST_TYPE) return above_equal;
2418 if (from == FIRST_TYPE) return below_equal;
2419 UNREACHABLE();
2420 return equal;
2421}
2422
2423
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002424void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002425 Register input = ToRegister(instr->value());
2426 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002427
2428 int true_block = chunk_->LookupDestination(instr->true_block_id());
2429 int false_block = chunk_->LookupDestination(instr->false_block_id());
2430
2431 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2432
whesse@chromium.org7b260152011-06-20 15:33:18 +00002433 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002434
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002435 __ CmpObjectType(input, TestType(instr->hydrogen()), temp);
2436 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002437}
2438
2439
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002440void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002441 Register input = ToRegister(instr->value());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002442 Register result = ToRegister(instr->result());
2443
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002444 __ AssertString(input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002445
2446 __ mov(result, FieldOperand(input, String::kHashFieldOffset));
2447 __ IndexFromHash(result, result);
2448}
2449
2450
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002451void LCodeGen::DoHasCachedArrayIndexAndBranch(
2452 LHasCachedArrayIndexAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002453 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002454
2455 int true_block = chunk_->LookupDestination(instr->true_block_id());
2456 int false_block = chunk_->LookupDestination(instr->false_block_id());
2457
2458 __ test(FieldOperand(input, String::kHashFieldOffset),
2459 Immediate(String::kContainsCachedArrayIndexMask));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002460 EmitBranch(true_block, false_block, equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002461}
2462
2463
2464// Branches to a label or falls through with the answer in the z flag. Trashes
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002465// the temp registers, but not the input.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002466void LCodeGen::EmitClassOfTest(Label* is_true,
2467 Label* is_false,
2468 Handle<String>class_name,
2469 Register input,
2470 Register temp,
2471 Register temp2) {
2472 ASSERT(!input.is(temp));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002473 ASSERT(!input.is(temp2));
2474 ASSERT(!temp.is(temp2));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002475 __ JumpIfSmi(input, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002476
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002477 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Function"))) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002478 // Assuming the following assertions, we can use the same compares to test
2479 // for both being a function type and being in the object type range.
2480 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2481 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2482 FIRST_SPEC_OBJECT_TYPE + 1);
2483 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2484 LAST_SPEC_OBJECT_TYPE - 1);
2485 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
2486 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
2487 __ j(below, is_false);
2488 __ j(equal, is_true);
2489 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
2490 __ j(equal, is_true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002491 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002492 // Faster code path to avoid two compares: subtract lower bound from the
2493 // actual type and do a signed compare with the width of the type range.
2494 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002495 __ movzx_b(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002496 __ sub(Operand(temp2), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002497 __ cmp(Operand(temp2), Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
2498 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002499 __ j(above, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002500 }
2501
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002502 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002503 // Check if the constructor in the map is a function.
2504 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002505 // Objects with a non-function constructor have class 'Object'.
2506 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002507 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002508 __ j(not_equal, is_true);
2509 } else {
2510 __ j(not_equal, is_false);
2511 }
2512
2513 // temp now contains the constructor function. Grab the
2514 // instance class name from there.
2515 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
2516 __ mov(temp, FieldOperand(temp,
2517 SharedFunctionInfo::kInstanceClassNameOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002518 // The class name we are testing against is internalized since it's a literal.
2519 // The name in the constructor is internalized because of the way the context
2520 // is booted. This routine isn't expected to work for random API-created
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002521 // classes and it doesn't have to because you can't access it with natives
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002522 // syntax. Since both sides are internalized it is sufficient to use an
2523 // identity comparison.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002524 __ cmp(temp, class_name);
2525 // End with the answer in the z flag.
2526}
2527
2528
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002529void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002530 Register input = ToRegister(instr->value());
2531 Register temp = ToRegister(instr->temp());
2532 Register temp2 = ToRegister(instr->temp2());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002533
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002534 Handle<String> class_name = instr->hydrogen()->class_name();
2535
2536 int true_block = chunk_->LookupDestination(instr->true_block_id());
2537 int false_block = chunk_->LookupDestination(instr->false_block_id());
2538
2539 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2540 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2541
2542 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2);
2543
2544 EmitBranch(true_block, false_block, equal);
2545}
2546
2547
2548void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002549 Register reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002550 int true_block = instr->true_block_id();
2551 int false_block = instr->false_block_id();
2552
2553 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
2554 EmitBranch(true_block, false_block, equal);
2555}
2556
2557
2558void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002559 // Object and function are in fixed registers defined by the stub.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002560 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002561 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002562 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002563
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002564 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002565 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002566 __ j(zero, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002567 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002568 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002569 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002570 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002571 __ bind(&done);
2572}
2573
2574
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002575void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
2576 class DeferredInstanceOfKnownGlobal: public LDeferredCode {
2577 public:
2578 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
2579 LInstanceOfKnownGlobal* instr)
2580 : LDeferredCode(codegen), instr_(instr) { }
2581 virtual void Generate() {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002582 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002583 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002584 virtual LInstruction* instr() { return instr_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002585 Label* map_check() { return &map_check_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002586 private:
2587 LInstanceOfKnownGlobal* instr_;
2588 Label map_check_;
2589 };
2590
2591 DeferredInstanceOfKnownGlobal* deferred;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002592 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002593
2594 Label done, false_result;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002595 Register object = ToRegister(instr->value());
2596 Register temp = ToRegister(instr->temp());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002597
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002598 // A Smi is not an instance of anything.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002599 __ JumpIfSmi(object, &false_result);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002600
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002601 // This is the inlined call site instanceof cache. The two occurences of the
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002602 // hole value will be patched to the last map/result pair generated by the
2603 // instanceof stub.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002604 Label cache_miss;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002605 Register map = ToRegister(instr->temp());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002606 __ mov(map, FieldOperand(object, HeapObject::kMapOffset));
2607 __ bind(deferred->map_check()); // Label for calculating code patching.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002608 Handle<JSGlobalPropertyCell> cache_cell =
2609 factory()->NewJSGlobalPropertyCell(factory()->the_hole_value());
2610 __ cmp(map, Operand::Cell(cache_cell)); // Patched to cached map.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002611 __ j(not_equal, &cache_miss, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002612 __ mov(eax, factory()->the_hole_value()); // Patched to either true or false.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002613 __ jmp(&done);
2614
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002615 // The inlined call site cache did not match. Check for null and string
2616 // before calling the deferred code.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002617 __ bind(&cache_miss);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002618 // Null is not an instance of anything.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002619 __ cmp(object, factory()->null_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002620 __ j(equal, &false_result);
2621
2622 // String values are not instances of anything.
2623 Condition is_string = masm_->IsObjectStringType(object, temp, temp);
2624 __ j(is_string, &false_result);
2625
2626 // Go to the deferred code.
2627 __ jmp(deferred->entry());
2628
2629 __ bind(&false_result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002630 __ mov(ToRegister(instr->result()), factory()->false_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002631
2632 // Here result has either true or false. Deferred code also produces true or
2633 // false object.
2634 __ bind(deferred->exit());
2635 __ bind(&done);
2636}
2637
2638
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002639void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2640 Label* map_check) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002641 PushSafepointRegistersScope scope(this);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002642
2643 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
2644 flags = static_cast<InstanceofStub::Flags>(
2645 flags | InstanceofStub::kArgsInRegisters);
2646 flags = static_cast<InstanceofStub::Flags>(
2647 flags | InstanceofStub::kCallSiteInlineCheck);
2648 flags = static_cast<InstanceofStub::Flags>(
2649 flags | InstanceofStub::kReturnTrueFalseObject);
2650 InstanceofStub stub(flags);
2651
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002652 // Get the temp register reserved by the instruction. This needs to be a
2653 // register which is pushed last by PushSafepointRegisters as top of the
2654 // stack is used to pass the offset to the location of the map check to
2655 // the stub.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002656 Register temp = ToRegister(instr->temp());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002657 ASSERT(MacroAssembler::SafepointRegisterStackIndex(temp) == 0);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002658 __ LoadHeapObject(InstanceofStub::right(), instr->function());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002659 static const int kAdditionalDelta = 13;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002660 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002661 __ mov(temp, Immediate(delta));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002662 __ StoreToSafepointRegisterSlot(temp, temp);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002663 CallCodeGeneric(stub.GetCode(isolate()),
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002664 RelocInfo::CODE_TARGET,
2665 instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002666 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002667 // Get the deoptimization index of the LLazyBailout-environment that
2668 // corresponds to this instruction.
2669 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002670 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
2671
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002672 // Put the result value into the eax slot and restore all registers.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002673 __ StoreToSafepointRegisterSlot(eax, eax);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002674}
2675
2676
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002677void LCodeGen::DoInstanceSize(LInstanceSize* instr) {
2678 Register object = ToRegister(instr->object());
2679 Register result = ToRegister(instr->result());
2680 __ mov(result, FieldOperand(object, HeapObject::kMapOffset));
2681 __ movzx_b(result, FieldOperand(result, Map::kInstanceSizeOffset));
2682}
2683
2684
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002685void LCodeGen::DoCmpT(LCmpT* instr) {
2686 Token::Value op = instr->op();
2687
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002688 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002689 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002690
2691 Condition condition = ComputeCompareCondition(op);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002692 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002693 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002694 __ j(condition, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002695 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002696 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002697 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002698 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002699 __ bind(&done);
2700}
2701
2702
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002703void LCodeGen::EmitReturn(LReturn* instr, bool dynamic_frame_alignment) {
2704 int extra_value_count = dynamic_frame_alignment ? 2 : 1;
2705
2706 if (instr->has_constant_parameter_count()) {
2707 int parameter_count = ToInteger32(instr->constant_parameter_count());
2708 if (dynamic_frame_alignment && FLAG_debug_code) {
2709 __ cmp(Operand(esp,
2710 (parameter_count + extra_value_count) * kPointerSize),
2711 Immediate(kAlignmentZapValue));
2712 __ Assert(equal, "expected alignment marker");
2713 }
2714 __ Ret((parameter_count + extra_value_count) * kPointerSize, ecx);
2715 } else {
2716 Register reg = ToRegister(instr->parameter_count());
2717 Register return_addr_reg = reg.is(ecx) ? ebx : ecx;
2718 if (dynamic_frame_alignment && FLAG_debug_code) {
2719 ASSERT(extra_value_count == 2);
2720 __ cmp(Operand(esp, reg, times_pointer_size,
2721 extra_value_count * kPointerSize),
2722 Immediate(kAlignmentZapValue));
2723 __ Assert(equal, "expected alignment marker");
2724 }
2725
2726 // emit code to restore stack based on instr->parameter_count()
2727 __ pop(return_addr_reg); // save return address
2728 if (dynamic_frame_alignment) {
2729 __ inc(reg); // 1 more for alignment
2730 }
2731 __ shl(reg, kPointerSizeLog2);
2732 __ add(esp, reg);
2733 __ jmp(return_addr_reg);
2734 }
2735}
2736
2737
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002738void LCodeGen::DoReturn(LReturn* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002739 if (FLAG_trace && info()->IsOptimizing()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002740 // Preserve the return value on the stack and rely on the runtime call
2741 // to return the value in the same register. We're leaving the code
2742 // managed by the register allocator and tearing down the frame, it's
2743 // safe to write to the context register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002744 __ push(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002745 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002746 __ CallRuntime(Runtime::kTraceExit, 1);
2747 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002748 if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(SSE2)) {
2749 ASSERT(NeedsEagerFrame());
ulan@chromium.org750145a2013-03-07 15:14:13 +00002750 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002751 BitVector* doubles = chunk()->allocated_double_registers();
2752 BitVector::Iterator save_iterator(doubles);
2753 int count = 0;
2754 while (!save_iterator.Done()) {
2755 __ movdbl(XMMRegister::FromAllocationIndex(save_iterator.Current()),
2756 MemOperand(esp, count * kDoubleSize));
2757 save_iterator.Advance();
2758 count++;
2759 }
2760 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002761 if (dynamic_frame_alignment_) {
2762 // Fetch the state of the dynamic frame alignment.
2763 __ mov(edx, Operand(ebp,
2764 JavaScriptFrameConstants::kDynamicAlignmentStateOffset));
2765 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002766 if (NeedsEagerFrame()) {
2767 __ mov(esp, ebp);
2768 __ pop(ebp);
2769 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002770 if (dynamic_frame_alignment_) {
2771 Label no_padding;
2772 __ cmp(edx, Immediate(kNoAlignmentPadding));
2773 __ j(equal, &no_padding);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002774
2775 EmitReturn(instr, true);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002776 __ bind(&no_padding);
2777 }
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002778
2779 EmitReturn(instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002780}
2781
2782
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002783void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002784 Register result = ToRegister(instr->result());
2785 __ mov(result, Operand::Cell(instr->hydrogen()->cell()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002786 if (instr->hydrogen()->RequiresHoleCheck()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002787 __ cmp(result, factory()->the_hole_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002788 DeoptimizeIf(equal, instr->environment());
2789 }
2790}
2791
2792
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002793void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2794 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002795 ASSERT(ToRegister(instr->global_object()).is(edx));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002796 ASSERT(ToRegister(instr->result()).is(eax));
2797
2798 __ mov(ecx, instr->name());
2799 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
2800 RelocInfo::CODE_TARGET_CONTEXT;
2801 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002802 CallCode(ic, mode, instr);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002803}
2804
2805
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002806void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002807 Register value = ToRegister(instr->value());
2808 Handle<JSGlobalPropertyCell> cell_handle = instr->hydrogen()->cell();
ager@chromium.org378b34e2011-01-28 08:04:38 +00002809
2810 // If the cell we are storing to contains the hole it could have
2811 // been deleted from the property dictionary. In that case, we need
2812 // to update the property details in the property dictionary to mark
2813 // it as no longer deleted. We deoptimize in that case.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002814 if (instr->hydrogen()->RequiresHoleCheck()) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002815 __ cmp(Operand::Cell(cell_handle), factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00002816 DeoptimizeIf(equal, instr->environment());
2817 }
2818
2819 // Store the value.
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002820 __ mov(Operand::Cell(cell_handle), value);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002821 // Cells are always rescanned, so no write barrier here.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002822}
2823
2824
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002825void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
2826 ASSERT(ToRegister(instr->context()).is(esi));
2827 ASSERT(ToRegister(instr->global_object()).is(edx));
2828 ASSERT(ToRegister(instr->value()).is(eax));
2829
2830 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002831 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002832 ? isolate()->builtins()->StoreIC_Initialize_Strict()
2833 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002834 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002835}
2836
2837
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002838void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002839 Register context = ToRegister(instr->context());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002840 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002841 __ mov(result, ContextOperand(context, instr->slot_index()));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002842
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002843 if (instr->hydrogen()->RequiresHoleCheck()) {
2844 __ cmp(result, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002845 if (instr->hydrogen()->DeoptimizesOnHole()) {
2846 DeoptimizeIf(equal, instr->environment());
2847 } else {
2848 Label is_not_hole;
2849 __ j(not_equal, &is_not_hole, Label::kNear);
2850 __ mov(result, factory()->undefined_value());
2851 __ bind(&is_not_hole);
2852 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002853 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002854}
2855
2856
2857void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2858 Register context = ToRegister(instr->context());
2859 Register value = ToRegister(instr->value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002860
2861 Label skip_assignment;
2862
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002863 Operand target = ContextOperand(context, instr->slot_index());
2864 if (instr->hydrogen()->RequiresHoleCheck()) {
2865 __ cmp(target, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002866 if (instr->hydrogen()->DeoptimizesOnHole()) {
2867 DeoptimizeIf(equal, instr->environment());
2868 } else {
2869 __ j(not_equal, &skip_assignment, Label::kNear);
2870 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002871 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002872
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002873 __ mov(target, value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002874 if (instr->hydrogen()->NeedsWriteBarrier()) {
2875 HType type = instr->hydrogen()->value()->type();
2876 SmiCheck check_needed =
2877 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002878 Register temp = ToRegister(instr->temp());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002879 int offset = Context::SlotOffset(instr->slot_index());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002880 __ RecordWriteContextSlot(context,
2881 offset,
2882 value,
2883 temp,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002884 GetSaveFPRegsMode(),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002885 EMIT_REMEMBERED_SET,
2886 check_needed);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002887 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002888
2889 __ bind(&skip_assignment);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002890}
2891
2892
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002893void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002894 Register object = ToRegister(instr->object());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002895 Register result = ToRegister(instr->result());
2896 if (instr->hydrogen()->is_in_object()) {
2897 __ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
2898 } else {
2899 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2900 __ mov(result, FieldOperand(result, instr->hydrogen()->offset()));
2901 }
2902}
2903
2904
lrn@chromium.org1c092762011-05-09 09:42:16 +00002905void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
2906 Register object,
2907 Handle<Map> type,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002908 Handle<String> name,
2909 LEnvironment* env) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002910 LookupResult lookup(isolate());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002911 type->LookupDescriptor(NULL, *name, &lookup);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002912 ASSERT(lookup.IsFound() || lookup.IsCacheable());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002913 if (lookup.IsField()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002914 int index = lookup.GetLocalFieldIndexFromMap(*type);
2915 int offset = index * kPointerSize;
2916 if (index < 0) {
2917 // Negative property indices are in-object properties, indexed
2918 // from the end of the fixed part of the object.
2919 __ mov(result, FieldOperand(object, offset + type->instance_size()));
2920 } else {
2921 // Non-negative property indices are in the properties array.
2922 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2923 __ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
2924 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002925 } else if (lookup.IsConstantFunction()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002926 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002927 __ LoadHeapObject(result, function);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002928 } else {
2929 // Negative lookup.
2930 // Check prototypes.
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002931 Handle<HeapObject> current(HeapObject::cast((*type)->prototype()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002932 Heap* heap = type->GetHeap();
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002933 while (*current != heap->null_value()) {
2934 __ LoadHeapObject(result, current);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002935 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002936 Handle<Map>(current->map()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002937 DeoptimizeIf(not_equal, env);
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002938 current =
2939 Handle<HeapObject>(HeapObject::cast(current->map()->prototype()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002940 }
2941 __ mov(result, factory()->undefined_value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002942 }
2943}
2944
2945
2946void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
2947 ASSERT(!operand->IsDoubleRegister());
2948 if (operand->IsConstantOperand()) {
2949 Handle<Object> object = ToHandle(LConstantOperand::cast(operand));
2950 if (object->IsSmi()) {
2951 __ Push(Handle<Smi>::cast(object));
2952 } else {
2953 __ PushHeapObject(Handle<HeapObject>::cast(object));
2954 }
2955 } else if (operand->IsRegister()) {
2956 __ push(ToRegister(operand));
2957 } else {
2958 __ push(ToOperand(operand));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002959 }
2960}
2961
2962
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002963// Check for cases where EmitLoadFieldOrConstantFunction needs to walk the
2964// prototype chain, which causes unbounded code generation.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002965static bool CompactEmit(SmallMapList* list,
2966 Handle<String> name,
2967 int i,
2968 Isolate* isolate) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002969 Handle<Map> map = list->at(i);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002970 // If the map has ElementsKind transitions, we will generate map checks
2971 // for each kind in __ CompareMap(..., ALLOW_ELEMENTS_TRANSITION_MAPS).
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002972 if (map->HasElementsTransition()) return false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002973 LookupResult lookup(isolate);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002974 map->LookupDescriptor(NULL, *name, &lookup);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002975 return lookup.IsField() || lookup.IsConstantFunction();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002976}
2977
2978
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002979void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
2980 Register object = ToRegister(instr->object());
2981 Register result = ToRegister(instr->result());
2982
2983 int map_count = instr->hydrogen()->types()->length();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002984 bool need_generic = instr->hydrogen()->need_generic();
2985
2986 if (map_count == 0 && !need_generic) {
2987 DeoptimizeIf(no_condition, instr->environment());
2988 return;
2989 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002990 Handle<String> name = instr->hydrogen()->name();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002991 Label done;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002992 bool all_are_compact = true;
2993 for (int i = 0; i < map_count; ++i) {
2994 if (!CompactEmit(instr->hydrogen()->types(), name, i, isolate())) {
2995 all_are_compact = false;
2996 break;
2997 }
2998 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002999 for (int i = 0; i < map_count; ++i) {
3000 bool last = (i == map_count - 1);
3001 Handle<Map> map = instr->hydrogen()->types()->at(i);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003002 Label check_passed;
3003 __ CompareMap(object, map, &check_passed, ALLOW_ELEMENT_TRANSITION_MAPS);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003004 if (last && !need_generic) {
3005 DeoptimizeIf(not_equal, instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003006 __ bind(&check_passed);
3007 EmitLoadFieldOrConstantFunction(
3008 result, object, map, name, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003009 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003010 Label next;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003011 bool compact = all_are_compact ? true :
3012 CompactEmit(instr->hydrogen()->types(), name, i, isolate());
3013 __ j(not_equal, &next, compact ? Label::kNear : Label::kFar);
3014 __ bind(&check_passed);
3015 EmitLoadFieldOrConstantFunction(
3016 result, object, map, name, instr->environment());
3017 __ jmp(&done, all_are_compact ? Label::kNear : Label::kFar);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003018 __ bind(&next);
3019 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003020 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003021 if (need_generic) {
3022 __ mov(ecx, name);
3023 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
3024 CallCode(ic, RelocInfo::CODE_TARGET, instr);
3025 }
3026 __ bind(&done);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003027}
3028
3029
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003030void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003031 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003032 ASSERT(ToRegister(instr->object()).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003033 ASSERT(ToRegister(instr->result()).is(eax));
3034
3035 __ mov(ecx, instr->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003036 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003037 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003038}
3039
3040
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003041void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
3042 Register function = ToRegister(instr->function());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003043 Register temp = ToRegister(instr->temp());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003044 Register result = ToRegister(instr->result());
3045
3046 // Check that the function really is a function.
3047 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
3048 DeoptimizeIf(not_equal, instr->environment());
3049
3050 // Check whether the function has an instance prototype.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003051 Label non_instance;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003052 __ test_b(FieldOperand(result, Map::kBitFieldOffset),
3053 1 << Map::kHasNonInstancePrototype);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003054 __ j(not_zero, &non_instance, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003055
3056 // Get the prototype or initial map from the function.
3057 __ mov(result,
3058 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
3059
3060 // Check that the function has a prototype or an initial map.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003061 __ cmp(Operand(result), Immediate(factory()->the_hole_value()));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003062 DeoptimizeIf(equal, instr->environment());
3063
3064 // If the function does not have an initial map, we're done.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003065 Label done;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003066 __ CmpObjectType(result, MAP_TYPE, temp);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003067 __ j(not_equal, &done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003068
3069 // Get the prototype from the initial map.
3070 __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003071 __ jmp(&done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003072
3073 // Non-instance prototype: Fetch prototype from constructor field
3074 // in the function's map.
3075 __ bind(&non_instance);
3076 __ mov(result, FieldOperand(result, Map::kConstructorOffset));
3077
3078 // All done.
3079 __ bind(&done);
3080}
3081
3082
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003083void LCodeGen::DoLoadElements(LLoadElements* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003084 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003085 Register input = ToRegister(instr->object());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003086 __ mov(result, FieldOperand(input, JSObject::kElementsOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003087 if (FLAG_debug_code) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003088 Label done, ok, fail;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003089 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003090 Immediate(factory()->fixed_array_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003091 __ j(equal, &done, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003092 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003093 Immediate(factory()->fixed_cow_array_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003094 __ j(equal, &done, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003095 Register temp((result.is(eax)) ? ebx : eax);
3096 __ push(temp);
3097 __ mov(temp, FieldOperand(result, HeapObject::kMapOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00003098 __ movzx_b(temp, FieldOperand(temp, Map::kBitField2Offset));
3099 __ and_(temp, Map::kElementsKindMask);
3100 __ shr(temp, Map::kElementsKindShift);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003101 __ cmp(temp, GetInitialFastElementsKind());
3102 __ j(less, &fail, Label::kNear);
3103 __ cmp(temp, TERMINAL_FAST_ELEMENTS_KIND);
3104 __ j(less_equal, &ok, Label::kNear);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003105 __ cmp(temp, FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003106 __ j(less, &fail, Label::kNear);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003107 __ cmp(temp, LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003108 __ j(less_equal, &ok, Label::kNear);
3109 __ bind(&fail);
3110 __ Abort("Check for fast or external elements failed.");
3111 __ bind(&ok);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003112 __ pop(temp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003113 __ bind(&done);
3114 }
3115}
3116
3117
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003118void LCodeGen::DoLoadExternalArrayPointer(
3119 LLoadExternalArrayPointer* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003120 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003121 Register input = ToRegister(instr->object());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003122 __ mov(result, FieldOperand(input,
3123 ExternalArray::kExternalPointerOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003124}
3125
3126
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003127void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
3128 Register arguments = ToRegister(instr->arguments());
3129 Register length = ToRegister(instr->length());
3130 Operand index = ToOperand(instr->index());
3131 Register result = ToRegister(instr->result());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003132 // There are two words between the frame pointer and the last argument.
3133 // Subtracting from length accounts for one of them add one more.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003134 __ sub(length, index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003135 __ mov(result, Operand(arguments, length, times_4, kPointerSize));
3136}
3137
3138
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003139void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003140 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003141 LOperand* key = instr->key();
3142 if (!key->IsConstantOperand() &&
3143 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
3144 elements_kind)) {
3145 __ SmiUntag(ToRegister(key));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003146 }
3147 Operand operand(BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003148 instr->elements(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003149 key,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003150 instr->hydrogen()->key()->representation(),
3151 elements_kind,
3152 0,
3153 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003154 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003155 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003156 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003157 XMMRegister result(ToDoubleRegister(instr->result()));
3158 __ movss(result, operand);
3159 __ cvtss2sd(result, result);
3160 } else {
3161 __ fld_s(operand);
3162 HandleX87FPReturnValue(instr);
3163 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003164 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003165 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003166 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003167 __ movdbl(ToDoubleRegister(instr->result()), operand);
3168 } else {
3169 __ fld_d(operand);
3170 HandleX87FPReturnValue(instr);
3171 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003172 } else {
3173 Register result(ToRegister(instr->result()));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003174 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003175 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003176 __ movsx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003177 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003178 case EXTERNAL_PIXEL_ELEMENTS:
3179 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003180 __ movzx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003181 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003182 case EXTERNAL_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003183 __ movsx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003184 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003185 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003186 __ movzx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003187 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003188 case EXTERNAL_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003189 __ mov(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003190 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003191 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003192 __ mov(result, operand);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003193 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
3194 __ test(result, Operand(result));
3195 DeoptimizeIf(negative, instr->environment());
3196 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003197 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003198 case EXTERNAL_FLOAT_ELEMENTS:
3199 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003200 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003201 case FAST_ELEMENTS:
3202 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003203 case FAST_HOLEY_SMI_ELEMENTS:
3204 case FAST_HOLEY_ELEMENTS:
3205 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003206 case DICTIONARY_ELEMENTS:
3207 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003208 UNREACHABLE();
3209 break;
3210 }
3211 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003212}
3213
3214
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003215void LCodeGen::HandleX87FPReturnValue(LInstruction* instr) {
3216 if (IsX87TopOfStack(instr->result())) {
3217 // Return value is already on stack. If the value has no uses, then
3218 // pop it off the FP stack. Otherwise, make sure that there are enough
3219 // copies of the value on the stack to feed all of the usages, e.g.
3220 // when the following instruction uses the return value in multiple
3221 // inputs.
3222 int count = instr->hydrogen_value()->UseCount();
3223 if (count == 0) {
3224 __ fstp(0);
3225 } else {
3226 count--;
3227 ASSERT(count <= 7);
3228 while (count-- > 0) {
3229 __ fld(0);
3230 }
3231 }
3232 } else {
3233 __ fstp_d(ToOperand(instr->result()));
3234 }
3235}
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00003236
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003237
3238void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003239 if (instr->hydrogen()->RequiresHoleCheck()) {
3240 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
3241 sizeof(kHoleNanLower32);
3242 Operand hole_check_operand = BuildFastArrayOperand(
3243 instr->elements(), instr->key(),
3244 instr->hydrogen()->key()->representation(),
3245 FAST_DOUBLE_ELEMENTS,
3246 offset,
3247 instr->additional_index());
3248 __ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
3249 DeoptimizeIf(equal, instr->environment());
3250 }
3251
3252 Operand double_load_operand = BuildFastArrayOperand(
3253 instr->elements(),
3254 instr->key(),
3255 instr->hydrogen()->key()->representation(),
3256 FAST_DOUBLE_ELEMENTS,
3257 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
3258 instr->additional_index());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003259 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003260 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003261 XMMRegister result = ToDoubleRegister(instr->result());
3262 __ movdbl(result, double_load_operand);
3263 } else {
3264 __ fld_d(double_load_operand);
3265 HandleX87FPReturnValue(instr);
3266 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003267}
3268
3269
3270void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
3271 Register result = ToRegister(instr->result());
3272
3273 // Load the result.
3274 __ mov(result,
3275 BuildFastArrayOperand(instr->elements(),
3276 instr->key(),
3277 instr->hydrogen()->key()->representation(),
3278 FAST_ELEMENTS,
3279 FixedArray::kHeaderSize - kHeapObjectTag,
3280 instr->additional_index()));
3281
3282 // Check for the hole value.
3283 if (instr->hydrogen()->RequiresHoleCheck()) {
3284 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
3285 __ test(result, Immediate(kSmiTagMask));
3286 DeoptimizeIf(not_equal, instr->environment());
3287 } else {
3288 __ cmp(result, factory()->the_hole_value());
3289 DeoptimizeIf(equal, instr->environment());
3290 }
3291 }
3292}
3293
3294
3295void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
3296 if (instr->is_external()) {
3297 DoLoadKeyedExternalArray(instr);
3298 } else if (instr->hydrogen()->representation().IsDouble()) {
3299 DoLoadKeyedFixedDoubleArray(instr);
3300 } else {
3301 DoLoadKeyedFixedArray(instr);
3302 }
3303}
3304
3305
3306Operand LCodeGen::BuildFastArrayOperand(
3307 LOperand* elements_pointer,
3308 LOperand* key,
3309 Representation key_representation,
3310 ElementsKind elements_kind,
3311 uint32_t offset,
3312 uint32_t additional_index) {
3313 Register elements_pointer_reg = ToRegister(elements_pointer);
3314 int shift_size = ElementsKindToShiftSize(elements_kind);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003315 if (key->IsConstantOperand()) {
3316 int constant_value = ToInteger32(LConstantOperand::cast(key));
3317 if (constant_value & 0xF0000000) {
3318 Abort("array index constant value too big");
3319 }
3320 return Operand(elements_pointer_reg,
3321 ((constant_value + additional_index) << shift_size)
3322 + offset);
3323 } else {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00003324 // Take the tag bit into account while computing the shift size.
3325 if (key_representation.IsTagged() && (shift_size >= 1)) {
3326 shift_size -= kSmiTagSize;
3327 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003328 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
3329 return Operand(elements_pointer_reg,
3330 ToRegister(key),
3331 scale_factor,
3332 offset + (additional_index << shift_size));
3333 }
3334}
3335
3336
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003337void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003338 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003339 ASSERT(ToRegister(instr->object()).is(edx));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003340 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003341
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003342 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003343 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003344}
3345
3346
3347void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
3348 Register result = ToRegister(instr->result());
3349
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003350 if (instr->hydrogen()->from_inlined()) {
3351 __ lea(result, Operand(esp, -2 * kPointerSize));
3352 } else {
3353 // Check for arguments adapter frame.
3354 Label done, adapted;
3355 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3356 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
3357 __ cmp(Operand(result),
3358 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3359 __ j(equal, &adapted, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003360
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003361 // No arguments adaptor frame.
3362 __ mov(result, Operand(ebp));
3363 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003364
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003365 // Arguments adaptor frame present.
3366 __ bind(&adapted);
3367 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003368
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003369 // Result is the frame pointer for the frame if not adapted and for the real
3370 // frame below the adaptor frame if adapted.
3371 __ bind(&done);
3372 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003373}
3374
3375
3376void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003377 Operand elem = ToOperand(instr->elements());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003378 Register result = ToRegister(instr->result());
3379
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003380 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003381
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003382 // If no arguments adaptor frame the number of arguments is fixed.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003383 __ cmp(ebp, elem);
3384 __ mov(result, Immediate(scope()->num_parameters()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003385 __ j(equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003386
3387 // Arguments adaptor frame present. Get argument length from there.
3388 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3389 __ mov(result, Operand(result,
3390 ArgumentsAdaptorFrameConstants::kLengthOffset));
3391 __ SmiUntag(result);
3392
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003393 // Argument length is in result register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003394 __ bind(&done);
3395}
3396
3397
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003398void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003399 Register receiver = ToRegister(instr->receiver());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003400 Register function = ToRegister(instr->function());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003401 Register scratch = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003402
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003403 // If the receiver is null or undefined, we have to pass the global
3404 // object as a receiver to normal functions. Values have to be
3405 // passed unchanged to builtins and strict-mode functions.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003406 Label global_object, receiver_ok;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003407
3408 // Do not transform the receiver to object for strict mode
3409 // functions.
3410 __ mov(scratch,
3411 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
3412 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset),
3413 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
danno@chromium.org412fa512012-09-14 13:28:26 +00003414 __ j(not_equal, &receiver_ok); // A near jump is not sufficient here!
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003415
3416 // Do not transform the receiver to object for builtins.
3417 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset),
3418 1 << SharedFunctionInfo::kNativeBitWithinByte);
danno@chromium.org412fa512012-09-14 13:28:26 +00003419 __ j(not_equal, &receiver_ok);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003420
3421 // Normal function. Replace undefined or null with global receiver.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003422 __ cmp(receiver, factory()->null_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003423 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003424 __ cmp(receiver, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003425 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003426
3427 // The receiver should be a JS object.
3428 __ test(receiver, Immediate(kSmiTagMask));
3429 DeoptimizeIf(equal, instr->environment());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003430 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, scratch);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003431 DeoptimizeIf(below, instr->environment());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003432 __ jmp(&receiver_ok, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003433
3434 __ bind(&global_object);
3435 // TODO(kmillikin): We have a hydrogen value for the global object. See
3436 // if it's better to use it than to explicitly fetch it from the context
3437 // here.
3438 __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003439 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_OBJECT_INDEX));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003440 __ mov(receiver,
3441 FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003442 __ bind(&receiver_ok);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003443}
3444
3445
3446void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
3447 Register receiver = ToRegister(instr->receiver());
3448 Register function = ToRegister(instr->function());
3449 Register length = ToRegister(instr->length());
3450 Register elements = ToRegister(instr->elements());
3451 ASSERT(receiver.is(eax)); // Used for parameter count.
3452 ASSERT(function.is(edi)); // Required by InvokeFunction.
3453 ASSERT(ToRegister(instr->result()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003454
3455 // Copy the arguments to this function possibly from the
3456 // adaptor frame below it.
3457 const uint32_t kArgumentsLimit = 1 * KB;
3458 __ cmp(length, kArgumentsLimit);
3459 DeoptimizeIf(above, instr->environment());
3460
3461 __ push(receiver);
3462 __ mov(receiver, length);
3463
3464 // Loop through the arguments pushing them onto the execution
3465 // stack.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003466 Label invoke, loop;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003467 // length is a small non-negative integer, due to the test above.
3468 __ test(length, Operand(length));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003469 __ j(zero, &invoke, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003470 __ bind(&loop);
3471 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
3472 __ dec(length);
3473 __ j(not_zero, &loop);
3474
3475 // Invoke the function.
3476 __ bind(&invoke);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003477 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003478 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003479 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003480 SafepointGenerator safepoint_generator(
3481 this, pointers, Safepoint::kLazyDeopt);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003482 ParameterCount actual(eax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003483 __ InvokeFunction(function, actual, CALL_FUNCTION,
3484 safepoint_generator, CALL_AS_METHOD);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003485}
3486
3487
3488void LCodeGen::DoPushArgument(LPushArgument* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003489 LOperand* argument = instr->value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003490 EmitPushTaggedOperand(argument);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003491}
3492
3493
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003494void LCodeGen::DoDrop(LDrop* instr) {
3495 __ Drop(instr->count());
3496}
3497
3498
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003499void LCodeGen::DoThisFunction(LThisFunction* instr) {
3500 Register result = ToRegister(instr->result());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003501 __ mov(result, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003502}
3503
3504
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003505void LCodeGen::DoContext(LContext* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003506 Register result = ToRegister(instr->result());
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00003507 if (info()->IsOptimizing()) {
3508 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
3509 } else {
3510 // If there is no frame, the context must be in esi.
3511 ASSERT(result.is(esi));
3512 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003513}
3514
3515
3516void LCodeGen::DoOuterContext(LOuterContext* instr) {
3517 Register context = ToRegister(instr->context());
3518 Register result = ToRegister(instr->result());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003519 __ mov(result,
3520 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003521}
3522
3523
yangguo@chromium.org56454712012-02-16 15:33:53 +00003524void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003525 ASSERT(ToRegister(instr->context()).is(esi));
yangguo@chromium.org56454712012-02-16 15:33:53 +00003526 __ push(esi); // The context is the first argument.
3527 __ push(Immediate(instr->hydrogen()->pairs()));
3528 __ push(Immediate(Smi::FromInt(instr->hydrogen()->flags())));
3529 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
3530}
3531
3532
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003533void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
3534 Register context = ToRegister(instr->context());
3535 Register result = ToRegister(instr->result());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003536 __ mov(result,
3537 Operand(context, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003538}
3539
3540
3541void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003542 Register global = ToRegister(instr->global());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003543 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003544 __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003545}
3546
3547
3548void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
3549 int arity,
danno@chromium.org40cb8782011-05-25 07:58:50 +00003550 LInstruction* instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003551 CallKind call_kind,
3552 EDIState edi_state) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003553 bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
3554 function->shared()->formal_parameter_count() == arity;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003555
3556 LPointerMap* pointers = instr->pointer_map();
3557 RecordPosition(pointers->position());
3558
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003559 if (can_invoke_directly) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003560 if (edi_state == EDI_UNINITIALIZED) {
3561 __ LoadHeapObject(edi, function);
3562 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003563
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00003564 // Change context.
3565 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003566
3567 // Set eax to arguments count if adaption is not needed. Assumes that eax
3568 // is available to write to at this point.
3569 if (!function->NeedsArgumentsAdaption()) {
3570 __ mov(eax, arity);
3571 }
3572
3573 // Invoke function directly.
3574 __ SetCallKind(ecx, call_kind);
3575 if (*function == *info()->closure()) {
3576 __ CallSelf();
3577 } else {
3578 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
3579 }
3580 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
3581 } else {
3582 // We need to adapt arguments.
3583 SafepointGenerator generator(
3584 this, pointers, Safepoint::kLazyDeopt);
3585 ParameterCount count(arity);
3586 __ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind);
3587 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003588}
3589
3590
3591void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
3592 ASSERT(ToRegister(instr->result()).is(eax));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003593 CallKnownFunction(instr->function(),
3594 instr->arity(),
3595 instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003596 CALL_AS_METHOD,
3597 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003598}
3599
3600
3601void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003602 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003603 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003604 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003605 DeoptimizeIf(not_equal, instr->environment());
3606
3607 Label done;
3608 Register tmp = input_reg.is(eax) ? ecx : eax;
3609 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx;
3610
3611 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003612 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003613
3614 Label negative;
3615 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003616 // Check the sign of the argument. If the argument is positive, just
3617 // return it. We do not need to patch the stack since |input| and
3618 // |result| are the same register and |input| will be restored
3619 // unchanged by popping safepoint registers.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003620 __ test(tmp, Immediate(HeapNumber::kSignMask));
3621 __ j(not_zero, &negative);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003622 __ jmp(&done);
3623
3624 __ bind(&negative);
3625
3626 Label allocated, slow;
3627 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow);
3628 __ jmp(&allocated);
3629
3630 // Slow case: Call the runtime system to do the number allocation.
3631 __ bind(&slow);
3632
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003633 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0,
3634 instr, instr->context());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003635
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003636 // Set the pointer to the new heap number in tmp.
3637 if (!tmp.is(eax)) __ mov(tmp, eax);
3638
3639 // Restore input_reg after call to runtime.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003640 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003641
3642 __ bind(&allocated);
3643 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3644 __ and_(tmp2, ~HeapNumber::kSignMask);
3645 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
3646 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
3647 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003648 __ StoreToSafepointRegisterSlot(input_reg, tmp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003649
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003650 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003651}
3652
3653
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003654void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003655 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003656 __ test(input_reg, Operand(input_reg));
3657 Label is_positive;
3658 __ j(not_sign, &is_positive);
3659 __ neg(input_reg);
3660 __ test(input_reg, Operand(input_reg));
3661 DeoptimizeIf(negative, instr->environment());
3662 __ bind(&is_positive);
3663}
3664
3665
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003666void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
3667 // Class for deferred case.
3668 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
3669 public:
3670 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
3671 LUnaryMathOperation* instr)
3672 : LDeferredCode(codegen), instr_(instr) { }
3673 virtual void Generate() {
3674 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3675 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003676 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003677 private:
3678 LUnaryMathOperation* instr_;
3679 };
3680
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003681 ASSERT(instr->value()->Equals(instr->result()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003682 Representation r = instr->hydrogen()->value()->representation();
3683
ulan@chromium.org750145a2013-03-07 15:14:13 +00003684 CpuFeatureScope scope(masm(), SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003685 if (r.IsDouble()) {
3686 XMMRegister scratch = xmm0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003687 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003688 __ xorps(scratch, scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003689 __ subsd(scratch, input_reg);
3690 __ pand(input_reg, scratch);
3691 } else if (r.IsInteger32()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003692 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003693 } else { // Tagged case.
3694 DeferredMathAbsTaggedHeapNumber* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003695 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003696 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003697 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003698 __ JumpIfNotSmi(input_reg, deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003699 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003700 __ bind(deferred->exit());
3701 }
3702}
3703
3704
3705void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003706 CpuFeatureScope scope(masm(), SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003707 XMMRegister xmm_scratch = xmm0;
3708 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003709 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003710
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003711 if (CpuFeatures::IsSupported(SSE4_1)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003712 CpuFeatureScope scope(masm(), SSE4_1);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003713 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3714 // Deoptimize on negative zero.
3715 Label non_zero;
3716 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3717 __ ucomisd(input_reg, xmm_scratch);
3718 __ j(not_equal, &non_zero, Label::kNear);
3719 __ movmskpd(output_reg, input_reg);
3720 __ test(output_reg, Immediate(1));
3721 DeoptimizeIf(not_zero, instr->environment());
3722 __ bind(&non_zero);
3723 }
3724 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
3725 __ cvttsd2si(output_reg, Operand(xmm_scratch));
3726 // Overflow is signalled with minint.
3727 __ cmp(output_reg, 0x80000000u);
3728 DeoptimizeIf(equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003729 } else {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003730 Label negative_sign, done;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003731 // Deoptimize on unordered.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003732 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3733 __ ucomisd(input_reg, xmm_scratch);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003734 DeoptimizeIf(parity_even, instr->environment());
3735 __ j(below, &negative_sign, Label::kNear);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003736
3737 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3738 // Check for negative zero.
3739 Label positive_sign;
3740 __ j(above, &positive_sign, Label::kNear);
3741 __ movmskpd(output_reg, input_reg);
3742 __ test(output_reg, Immediate(1));
3743 DeoptimizeIf(not_zero, instr->environment());
3744 __ Set(output_reg, Immediate(0));
3745 __ jmp(&done, Label::kNear);
3746 __ bind(&positive_sign);
3747 }
3748
3749 // Use truncating instruction (OK because input is positive).
3750 __ cvttsd2si(output_reg, Operand(input_reg));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003751 // Overflow is signalled with minint.
3752 __ cmp(output_reg, 0x80000000u);
3753 DeoptimizeIf(equal, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003754 __ jmp(&done, Label::kNear);
3755
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003756 // Non-zero negative reaches here.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003757 __ bind(&negative_sign);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003758 // Truncate, then compare and compensate.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003759 __ cvttsd2si(output_reg, Operand(input_reg));
3760 __ cvtsi2sd(xmm_scratch, output_reg);
3761 __ ucomisd(input_reg, xmm_scratch);
3762 __ j(equal, &done, Label::kNear);
3763 __ sub(output_reg, Immediate(1));
3764 DeoptimizeIf(overflow, instr->environment());
3765
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003766 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003767 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003768}
3769
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003770void LCodeGen::DoMathRound(LMathRound* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003771 CpuFeatureScope scope(masm(), SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003772 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003773 XMMRegister input_reg = ToDoubleRegister(instr->value());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003774 XMMRegister xmm_scratch = xmm0;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003775 XMMRegister input_temp = ToDoubleRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003776 ExternalReference one_half = ExternalReference::address_of_one_half();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003777 ExternalReference minus_one_half =
3778 ExternalReference::address_of_minus_one_half();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003779
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003780 Label done, round_to_zero, below_one_half, do_not_compensate;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003781 __ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003782 __ ucomisd(xmm_scratch, input_reg);
3783 __ j(above, &below_one_half);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003784
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003785 // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x).
3786 __ addsd(xmm_scratch, input_reg);
3787 __ cvttsd2si(output_reg, Operand(xmm_scratch));
3788 // Overflow is signalled with minint.
3789 __ cmp(output_reg, 0x80000000u);
3790 __ RecordComment("D2I conversion overflow");
3791 DeoptimizeIf(equal, instr->environment());
3792 __ jmp(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003793
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003794 __ bind(&below_one_half);
3795 __ movdbl(xmm_scratch, Operand::StaticVariable(minus_one_half));
3796 __ ucomisd(xmm_scratch, input_reg);
3797 __ j(below_equal, &round_to_zero);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003798
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003799 // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then
3800 // compare and compensate.
3801 __ movsd(input_temp, input_reg); // Do not alter input_reg.
3802 __ subsd(input_temp, xmm_scratch);
3803 __ cvttsd2si(output_reg, Operand(input_temp));
3804 // Catch minint due to overflow, and to prevent overflow when compensating.
3805 __ cmp(output_reg, 0x80000000u);
3806 __ RecordComment("D2I conversion overflow");
3807 DeoptimizeIf(equal, instr->environment());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003808
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003809 __ cvtsi2sd(xmm_scratch, output_reg);
3810 __ ucomisd(xmm_scratch, input_temp);
3811 __ j(equal, &done);
3812 __ sub(output_reg, Immediate(1));
3813 // No overflow because we already ruled out minint.
3814 __ jmp(&done);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003815
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003816 __ bind(&round_to_zero);
3817 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
3818 // we can ignore the difference between a result of -0 and +0.
3819 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3820 // If the sign is positive, we return +0.
3821 __ movmskpd(output_reg, input_reg);
3822 __ test(output_reg, Immediate(1));
3823 __ RecordComment("Minus zero");
3824 DeoptimizeIf(not_zero, instr->environment());
danno@chromium.org160a7b02011-04-18 15:51:38 +00003825 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003826 __ Set(output_reg, Immediate(0));
3827 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003828}
3829
3830
3831void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003832 CpuFeatureScope scope(masm(), SSE2);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003833 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003834 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
3835 __ sqrtsd(input_reg, input_reg);
3836}
3837
3838
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003839void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003840 CpuFeatureScope scope(masm(), SSE2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003841 XMMRegister xmm_scratch = xmm0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003842 XMMRegister input_reg = ToDoubleRegister(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003843 Register scratch = ToRegister(instr->temp());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003844 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003845
3846 // Note that according to ECMA-262 15.8.2.13:
3847 // Math.pow(-Infinity, 0.5) == Infinity
3848 // Math.sqrt(-Infinity) == NaN
3849 Label done, sqrt;
3850 // Check base for -Infinity. According to IEEE-754, single-precision
3851 // -Infinity has the highest 9 bits set and the lowest 23 bits cleared.
3852 __ mov(scratch, 0xFF800000);
3853 __ movd(xmm_scratch, scratch);
3854 __ cvtss2sd(xmm_scratch, xmm_scratch);
3855 __ ucomisd(input_reg, xmm_scratch);
3856 // Comparing -Infinity with NaN results in "unordered", which sets the
3857 // zero flag as if both were equal. However, it also sets the carry flag.
3858 __ j(not_equal, &sqrt, Label::kNear);
3859 __ j(carry, &sqrt, Label::kNear);
3860 // If input is -Infinity, return Infinity.
3861 __ xorps(input_reg, input_reg);
3862 __ subsd(input_reg, xmm_scratch);
3863 __ jmp(&done, Label::kNear);
3864
3865 // Square root.
3866 __ bind(&sqrt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003867 __ xorps(xmm_scratch, xmm_scratch);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003868 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003869 __ sqrtsd(input_reg, input_reg);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003870 __ bind(&done);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003871}
3872
3873
3874void LCodeGen::DoPower(LPower* instr) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003875 Representation exponent_type = instr->hydrogen()->right()->representation();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003876 // Having marked this as a call, we can use any registers.
3877 // Just make sure that the input/output registers are the expected ones.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003878 ASSERT(!instr->right()->IsDoubleRegister() ||
3879 ToDoubleRegister(instr->right()).is(xmm1));
3880 ASSERT(!instr->right()->IsRegister() ||
3881 ToRegister(instr->right()).is(eax));
3882 ASSERT(ToDoubleRegister(instr->left()).is(xmm2));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003883 ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003884
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003885 if (exponent_type.IsTagged()) {
3886 Label no_deopt;
3887 __ JumpIfSmi(eax, &no_deopt);
3888 __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003889 DeoptimizeIf(not_equal, instr->environment());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003890 __ bind(&no_deopt);
3891 MathPowStub stub(MathPowStub::TAGGED);
3892 __ CallStub(&stub);
3893 } else if (exponent_type.IsInteger32()) {
3894 MathPowStub stub(MathPowStub::INTEGER);
3895 __ CallStub(&stub);
3896 } else {
3897 ASSERT(exponent_type.IsDouble());
3898 MathPowStub stub(MathPowStub::DOUBLE);
3899 __ CallStub(&stub);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003900 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003901}
3902
3903
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003904void LCodeGen::DoRandom(LRandom* instr) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003905 class DeferredDoRandom: public LDeferredCode {
3906 public:
3907 DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
3908 : LDeferredCode(codegen), instr_(instr) { }
3909 virtual void Generate() { codegen()->DoDeferredRandom(instr_); }
3910 virtual LInstruction* instr() { return instr_; }
3911 private:
3912 LRandom* instr_;
3913 };
3914
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003915 DeferredDoRandom* deferred = new(zone()) DeferredDoRandom(this, instr);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003916
ulan@chromium.org750145a2013-03-07 15:14:13 +00003917 CpuFeatureScope scope(masm(), SSE2);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003918 // Having marked this instruction as a call we can use any
3919 // registers.
3920 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003921 ASSERT(ToRegister(instr->global_object()).is(eax));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003922 // Assert that the register size is indeed the size of each seed.
3923 static const int kSeedSize = sizeof(uint32_t);
3924 STATIC_ASSERT(kPointerSize == kSeedSize);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003925
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003926 __ mov(eax, FieldOperand(eax, GlobalObject::kNativeContextOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003927 static const int kRandomSeedOffset =
3928 FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
3929 __ mov(ebx, FieldOperand(eax, kRandomSeedOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003930 // ebx: FixedArray of the native context's random seeds
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003931
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003932 // Load state[0].
3933 __ mov(ecx, FieldOperand(ebx, ByteArray::kHeaderSize));
3934 // If state[0] == 0, call runtime to initialize seeds.
3935 __ test(ecx, ecx);
3936 __ j(zero, deferred->entry());
3937 // Load state[1].
3938 __ mov(eax, FieldOperand(ebx, ByteArray::kHeaderSize + kSeedSize));
3939 // ecx: state[0]
3940 // eax: state[1]
3941
3942 // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
3943 __ movzx_w(edx, ecx);
3944 __ imul(edx, edx, 18273);
3945 __ shr(ecx, 16);
3946 __ add(ecx, edx);
3947 // Save state[0].
3948 __ mov(FieldOperand(ebx, ByteArray::kHeaderSize), ecx);
3949
3950 // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
3951 __ movzx_w(edx, eax);
3952 __ imul(edx, edx, 36969);
3953 __ shr(eax, 16);
3954 __ add(eax, edx);
3955 // Save state[1].
3956 __ mov(FieldOperand(ebx, ByteArray::kHeaderSize + kSeedSize), eax);
3957
3958 // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
3959 __ shl(ecx, 14);
3960 __ and_(eax, Immediate(0x3FFFF));
3961 __ add(eax, ecx);
3962
3963 __ bind(deferred->exit());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003964 // Convert 32 random bits in eax to 0.(32 random bits) in a double
3965 // by computing:
3966 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
3967 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
3968 __ movd(xmm2, ebx);
3969 __ movd(xmm1, eax);
3970 __ cvtss2sd(xmm2, xmm2);
3971 __ xorps(xmm1, xmm2);
3972 __ subsd(xmm1, xmm2);
3973}
3974
3975
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003976void LCodeGen::DoDeferredRandom(LRandom* instr) {
3977 __ PrepareCallCFunction(1, ebx);
3978 __ mov(Operand(esp, 0), eax);
3979 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
3980 // Return value is in eax.
3981}
3982
3983
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003984void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003985 CpuFeatureScope scope(masm(), SSE2);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003986 ASSERT(instr->value()->Equals(instr->result()));
3987 XMMRegister input_reg = ToDoubleRegister(instr->value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003988 Label positive, done, zero;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003989 __ xorps(xmm0, xmm0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003990 __ ucomisd(input_reg, xmm0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003991 __ j(above, &positive, Label::kNear);
3992 __ j(equal, &zero, Label::kNear);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003993 ExternalReference nan =
3994 ExternalReference::address_of_canonical_non_hole_nan();
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003995 __ movdbl(input_reg, Operand::StaticVariable(nan));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003996 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003997 __ bind(&zero);
3998 __ push(Immediate(0xFFF00000));
3999 __ push(Immediate(0));
4000 __ movdbl(input_reg, Operand(esp, 0));
4001 __ add(Operand(esp), Immediate(kDoubleSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004002 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004003 __ bind(&positive);
4004 __ fldln2();
4005 __ sub(Operand(esp), Immediate(kDoubleSize));
4006 __ movdbl(Operand(esp, 0), input_reg);
4007 __ fld_d(Operand(esp, 0));
4008 __ fyl2x();
4009 __ fstp_d(Operand(esp, 0));
4010 __ movdbl(input_reg, Operand(esp, 0));
4011 __ add(Operand(esp), Immediate(kDoubleSize));
4012 __ bind(&done);
whesse@chromium.org023421e2010-12-21 12:19:12 +00004013}
4014
4015
danno@chromium.org1f34ad32012-11-26 14:53:56 +00004016void LCodeGen::DoMathExp(LMathExp* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004017 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00004018 XMMRegister input = ToDoubleRegister(instr->value());
4019 XMMRegister result = ToDoubleRegister(instr->result());
4020 Register temp1 = ToRegister(instr->temp1());
4021 Register temp2 = ToRegister(instr->temp2());
4022
4023 MathExpGenerator::EmitMathExp(masm(), input, result, xmm0, temp1, temp2);
4024}
4025
4026
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004027void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
4028 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
4029 TranscendentalCacheStub stub(TranscendentalCache::TAN,
4030 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004031 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004032}
4033
4034
whesse@chromium.org023421e2010-12-21 12:19:12 +00004035void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
4036 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
4037 TranscendentalCacheStub stub(TranscendentalCache::COS,
4038 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004039 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org023421e2010-12-21 12:19:12 +00004040}
4041
4042
4043void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
4044 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
4045 TranscendentalCacheStub stub(TranscendentalCache::SIN,
4046 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004047 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004048}
4049
4050
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004051void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
4052 switch (instr->op()) {
4053 case kMathAbs:
4054 DoMathAbs(instr);
4055 break;
4056 case kMathFloor:
4057 DoMathFloor(instr);
4058 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004059 case kMathSqrt:
4060 DoMathSqrt(instr);
4061 break;
whesse@chromium.org023421e2010-12-21 12:19:12 +00004062 case kMathCos:
4063 DoMathCos(instr);
4064 break;
4065 case kMathSin:
4066 DoMathSin(instr);
4067 break;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004068 case kMathTan:
4069 DoMathTan(instr);
4070 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004071 case kMathLog:
4072 DoMathLog(instr);
4073 break;
4074
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004075 default:
4076 UNREACHABLE();
4077 }
4078}
4079
4080
danno@chromium.org160a7b02011-04-18 15:51:38 +00004081void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
4082 ASSERT(ToRegister(instr->context()).is(esi));
4083 ASSERT(ToRegister(instr->function()).is(edi));
4084 ASSERT(instr->HasPointerMap());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004085
4086 if (instr->known_function().is_null()) {
4087 LPointerMap* pointers = instr->pointer_map();
4088 RecordPosition(pointers->position());
4089 SafepointGenerator generator(
4090 this, pointers, Safepoint::kLazyDeopt);
4091 ParameterCount count(instr->arity());
4092 __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
4093 } else {
4094 CallKnownFunction(instr->known_function(),
4095 instr->arity(),
4096 instr,
4097 CALL_AS_METHOD,
4098 EDI_CONTAINS_TARGET);
4099 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00004100}
4101
4102
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004103void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004104 ASSERT(ToRegister(instr->context()).is(esi));
4105 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004106 ASSERT(ToRegister(instr->result()).is(eax));
4107
4108 int arity = instr->arity();
lrn@chromium.org34e60782011-09-15 07:25:40 +00004109 Handle<Code> ic =
4110 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004111 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004112}
4113
4114
4115void LCodeGen::DoCallNamed(LCallNamed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004116 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004117 ASSERT(ToRegister(instr->result()).is(eax));
4118
4119 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00004120 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
4121 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00004122 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004123 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004124 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004125}
4126
4127
4128void LCodeGen::DoCallFunction(LCallFunction* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004129 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.orgc612e022011-11-10 11:38:15 +00004130 ASSERT(ToRegister(instr->function()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004131 ASSERT(ToRegister(instr->result()).is(eax));
4132
4133 int arity = instr->arity();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004134 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004135 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004136}
4137
4138
4139void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004140 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004141 ASSERT(ToRegister(instr->result()).is(eax));
4142
4143 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00004144 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
4145 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00004146 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004147 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004148 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004149}
4150
4151
4152void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
4153 ASSERT(ToRegister(instr->result()).is(eax));
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004154 CallKnownFunction(instr->target(),
4155 instr->arity(),
4156 instr,
4157 CALL_AS_FUNCTION,
4158 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004159}
4160
4161
4162void LCodeGen::DoCallNew(LCallNew* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004163 ASSERT(ToRegister(instr->context()).is(esi));
4164 ASSERT(ToRegister(instr->constructor()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004165 ASSERT(ToRegister(instr->result()).is(eax));
4166
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004167 if (FLAG_optimize_constructed_arrays) {
4168 // No cell in ebx for construct type feedback in optimized code
4169 Handle<Object> undefined_value(isolate()->heap()->undefined_value(),
4170 isolate());
4171 __ mov(ebx, Immediate(undefined_value));
4172 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004173 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004174 __ Set(eax, Immediate(instr->arity()));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004175 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004176}
4177
4178
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004179void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
4180 ASSERT(ToRegister(instr->context()).is(esi));
4181 ASSERT(ToRegister(instr->constructor()).is(edi));
4182 ASSERT(ToRegister(instr->result()).is(eax));
4183 ASSERT(FLAG_optimize_constructed_arrays);
4184
4185 __ mov(ebx, instr->hydrogen()->property_cell());
4186 Handle<Code> array_construct_code =
4187 isolate()->builtins()->ArrayConstructCode();
4188 __ Set(eax, Immediate(instr->arity()));
4189 CallCode(array_construct_code, RelocInfo::CONSTRUCT_CALL, instr);
4190}
4191
4192
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004193void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004194 CallRuntime(instr->function(), instr->arity(), instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004195}
4196
4197
4198void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
4199 Register object = ToRegister(instr->object());
4200 Register value = ToRegister(instr->value());
4201 int offset = instr->offset();
4202
4203 if (!instr->transition().is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +00004204 if (!instr->hydrogen()->NeedsWriteBarrierForMap()) {
4205 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition());
4206 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004207 Register temp = ToRegister(instr->temp());
4208 Register temp_map = ToRegister(instr->temp_map());
verwaest@chromium.org37141392012-05-31 13:27:02 +00004209 __ mov(temp_map, instr->transition());
4210 __ mov(FieldOperand(object, HeapObject::kMapOffset), temp_map);
4211 // Update the write barrier for the map field.
4212 __ RecordWriteField(object,
4213 HeapObject::kMapOffset,
4214 temp_map,
4215 temp,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004216 GetSaveFPRegsMode(),
verwaest@chromium.org37141392012-05-31 13:27:02 +00004217 OMIT_REMEMBERED_SET,
4218 OMIT_SMI_CHECK);
4219 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004220 }
4221
4222 // Do the store.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004223 HType type = instr->hydrogen()->value()->type();
4224 SmiCheck check_needed =
4225 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004226 if (instr->is_in_object()) {
4227 __ mov(FieldOperand(object, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004228 if (instr->hydrogen()->NeedsWriteBarrier()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004229 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004230 // Update the write barrier for the object for in-object properties.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004231 __ RecordWriteField(object,
4232 offset,
4233 value,
4234 temp,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004235 GetSaveFPRegsMode(),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004236 EMIT_REMEMBERED_SET,
4237 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004238 }
4239 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004240 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004241 __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset));
4242 __ mov(FieldOperand(temp, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004243 if (instr->hydrogen()->NeedsWriteBarrier()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004244 // Update the write barrier for the properties array.
4245 // object is used as a scratch register.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004246 __ RecordWriteField(temp,
4247 offset,
4248 value,
4249 object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004250 GetSaveFPRegsMode(),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004251 EMIT_REMEMBERED_SET,
4252 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004253 }
4254 }
4255}
4256
4257
4258void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004259 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004260 ASSERT(ToRegister(instr->object()).is(edx));
4261 ASSERT(ToRegister(instr->value()).is(eax));
4262
4263 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004264 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004265 ? isolate()->builtins()->StoreIC_Initialize_Strict()
4266 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004267 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004268}
4269
4270
4271void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004272 if (instr->hydrogen()->skip_check()) return;
4273
danno@chromium.orgb6451162011-08-17 14:33:23 +00004274 if (instr->index()->IsConstantOperand()) {
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004275 int constant_index =
4276 ToInteger32(LConstantOperand::cast(instr->index()));
4277 if (instr->hydrogen()->length()->representation().IsTagged()) {
4278 __ cmp(ToOperand(instr->length()),
4279 Immediate(Smi::FromInt(constant_index)));
4280 } else {
4281 __ cmp(ToOperand(instr->length()), Immediate(constant_index));
4282 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00004283 DeoptimizeIf(below_equal, instr->environment());
4284 } else {
4285 __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
4286 DeoptimizeIf(above_equal, instr->environment());
4287 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004288}
4289
4290
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004291void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004292 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004293 LOperand* key = instr->key();
4294 if (!key->IsConstantOperand() &&
4295 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
4296 elements_kind)) {
4297 __ SmiUntag(ToRegister(key));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004298 }
4299 Operand operand(BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004300 instr->elements(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004301 key,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004302 instr->hydrogen()->key()->representation(),
4303 elements_kind,
4304 0,
4305 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004306 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004307 CpuFeatureScope scope(masm(), SSE2);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004308 __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004309 __ movss(operand, xmm0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004310 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004311 CpuFeatureScope scope(masm(), SSE2);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004312 __ movdbl(operand, ToDoubleRegister(instr->value()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004313 } else {
4314 Register value = ToRegister(instr->value());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004315 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004316 case EXTERNAL_PIXEL_ELEMENTS:
4317 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4318 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004319 __ mov_b(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004320 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004321 case EXTERNAL_SHORT_ELEMENTS:
4322 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004323 __ mov_w(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004324 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004325 case EXTERNAL_INT_ELEMENTS:
4326 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004327 __ mov(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004328 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004329 case EXTERNAL_FLOAT_ELEMENTS:
4330 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004331 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004332 case FAST_ELEMENTS:
4333 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004334 case FAST_HOLEY_SMI_ELEMENTS:
4335 case FAST_HOLEY_ELEMENTS:
4336 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004337 case DICTIONARY_ELEMENTS:
4338 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004339 UNREACHABLE();
4340 break;
4341 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004342 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004343}
4344
4345
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004346void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004347 CpuFeatureScope scope(masm(), SSE2);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004348 XMMRegister value = ToDoubleRegister(instr->value());
4349
4350 if (instr->NeedsCanonicalization()) {
4351 Label have_value;
4352
4353 __ ucomisd(value, value);
4354 __ j(parity_odd, &have_value); // NaN.
4355
4356 ExternalReference canonical_nan_reference =
4357 ExternalReference::address_of_canonical_non_hole_nan();
4358 __ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
4359 __ bind(&have_value);
4360 }
4361
4362 Operand double_store_operand = BuildFastArrayOperand(
4363 instr->elements(),
4364 instr->key(),
4365 instr->hydrogen()->key()->representation(),
4366 FAST_DOUBLE_ELEMENTS,
4367 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
4368 instr->additional_index());
4369 __ movdbl(double_store_operand, value);
4370}
4371
4372
4373void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004374 Register value = ToRegister(instr->value());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004375 Register elements = ToRegister(instr->elements());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004376 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
4377
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004378 Operand operand = BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004379 instr->elements(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004380 instr->key(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004381 instr->hydrogen()->key()->representation(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004382 FAST_ELEMENTS,
4383 FixedArray::kHeaderSize - kHeapObjectTag,
4384 instr->additional_index());
4385 __ mov(operand, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004386
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004387 if (instr->hydrogen()->NeedsWriteBarrier()) {
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004388 ASSERT(!instr->key()->IsConstantOperand());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004389 HType type = instr->hydrogen()->value()->type();
4390 SmiCheck check_needed =
4391 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004392 // Compute address of modified element and store it into key register.
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004393 __ lea(key, operand);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004394 __ RecordWrite(elements,
4395 key,
4396 value,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004397 GetSaveFPRegsMode(),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004398 EMIT_REMEMBERED_SET,
4399 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004400 }
4401}
4402
4403
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004404void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
4405 // By cases...external, fast-double, fast
4406 if (instr->is_external()) {
4407 DoStoreKeyedExternalArray(instr);
4408 } else if (instr->hydrogen()->value()->representation().IsDouble()) {
4409 DoStoreKeyedFixedDoubleArray(instr);
4410 } else {
4411 DoStoreKeyedFixedArray(instr);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004412 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004413}
4414
4415
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004416void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004417 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004418 ASSERT(ToRegister(instr->object()).is(edx));
4419 ASSERT(ToRegister(instr->key()).is(ecx));
4420 ASSERT(ToRegister(instr->value()).is(eax));
4421
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004422 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004423 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
4424 : isolate()->builtins()->KeyedStoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004425 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004426}
4427
4428
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004429void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
4430 Register object = ToRegister(instr->object());
4431 Register temp = ToRegister(instr->temp());
4432 __ TestJSArrayForAllocationSiteInfo(object, temp);
4433 DeoptimizeIf(equal, instr->environment());
4434}
4435
4436
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004437void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
4438 Register object_reg = ToRegister(instr->object());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004439
4440 Handle<Map> from_map = instr->original_map();
4441 Handle<Map> to_map = instr->transitioned_map();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00004442 ElementsKind from_kind = instr->from_kind();
4443 ElementsKind to_kind = instr->to_kind();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004444
4445 Label not_applicable;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004446 bool is_simple_map_transition =
4447 IsSimpleMapChangeTransition(from_kind, to_kind);
4448 Label::Distance branch_distance =
4449 is_simple_map_transition ? Label::kNear : Label::kFar;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004450 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004451 __ j(not_equal, &not_applicable, branch_distance);
4452 if (is_simple_map_transition) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004453 Register new_map_reg = ToRegister(instr->new_map_temp());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004454 Handle<Map> map = instr->hydrogen()->transitioned_map();
4455 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset),
4456 Immediate(map));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004457 // Write barrier.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004458 ASSERT_NE(instr->temp(), NULL);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004459 __ RecordWriteForMap(object_reg, to_map, new_map_reg,
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004460 ToRegister(instr->temp()),
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004461 kDontSaveFPRegs);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004462 } else if (FLAG_compiled_transitions) {
4463 PushSafepointRegistersScope scope(this);
4464 if (!object_reg.is(eax)) {
4465 __ push(object_reg);
4466 }
4467 LoadContextFromDeferred(instr->context());
4468 if (!object_reg.is(eax)) {
4469 __ pop(eax);
4470 }
4471 __ mov(ebx, to_map);
4472 TransitionElementsKindStub stub(from_kind, to_kind);
4473 __ CallStub(&stub);
4474 RecordSafepointWithRegisters(
4475 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004476 } else if (IsFastSmiElementsKind(from_kind) &&
4477 IsFastDoubleElementsKind(to_kind)) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004478 Register new_map_reg = ToRegister(instr->new_map_temp());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004479 __ mov(new_map_reg, to_map);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004480 Register fixed_object_reg = ToRegister(instr->temp());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004481 ASSERT(fixed_object_reg.is(edx));
4482 ASSERT(new_map_reg.is(ebx));
4483 __ mov(fixed_object_reg, object_reg);
4484 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
4485 RelocInfo::CODE_TARGET, instr);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004486 } else if (IsFastDoubleElementsKind(from_kind) &&
4487 IsFastObjectElementsKind(to_kind)) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004488 Register new_map_reg = ToRegister(instr->new_map_temp());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004489 __ mov(new_map_reg, to_map);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004490 Register fixed_object_reg = ToRegister(instr->temp());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004491 ASSERT(fixed_object_reg.is(edx));
4492 ASSERT(new_map_reg.is(ebx));
4493 __ mov(fixed_object_reg, object_reg);
4494 CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
4495 RelocInfo::CODE_TARGET, instr);
4496 } else {
4497 UNREACHABLE();
4498 }
4499 __ bind(&not_applicable);
4500}
4501
4502
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004503void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
4504 class DeferredStringCharCodeAt: public LDeferredCode {
4505 public:
4506 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
4507 : LDeferredCode(codegen), instr_(instr) { }
4508 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004509 virtual LInstruction* instr() { return instr_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004510 private:
4511 LStringCharCodeAt* instr_;
4512 };
4513
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004514 DeferredStringCharCodeAt* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004515 new(zone()) DeferredStringCharCodeAt(this, instr);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004516
erikcorry0ad885c2011-11-21 13:51:57 +00004517 StringCharLoadGenerator::Generate(masm(),
4518 factory(),
4519 ToRegister(instr->string()),
4520 ToRegister(instr->index()),
4521 ToRegister(instr->result()),
4522 deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004523 __ bind(deferred->exit());
4524}
4525
4526
4527void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
4528 Register string = ToRegister(instr->string());
4529 Register result = ToRegister(instr->result());
4530
4531 // TODO(3095996): Get rid of this. For now, we need to make the
4532 // result register contain a valid pointer because it is already
4533 // contained in the register pointer map.
4534 __ Set(result, Immediate(0));
4535
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004536 PushSafepointRegistersScope scope(this);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004537 __ push(string);
4538 // Push the index as a smi. This is safe because of the checks in
4539 // DoStringCharCodeAt above.
4540 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
4541 if (instr->index()->IsConstantOperand()) {
4542 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
4543 __ push(Immediate(Smi::FromInt(const_index)));
4544 } else {
4545 Register index = ToRegister(instr->index());
4546 __ SmiTag(index);
4547 __ push(index);
4548 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004549 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2,
4550 instr, instr->context());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004551 __ AssertSmi(eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004552 __ SmiUntag(eax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004553 __ StoreToSafepointRegisterSlot(result, eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004554}
4555
4556
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004557void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
4558 class DeferredStringCharFromCode: public LDeferredCode {
4559 public:
4560 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
4561 : LDeferredCode(codegen), instr_(instr) { }
4562 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004563 virtual LInstruction* instr() { return instr_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004564 private:
4565 LStringCharFromCode* instr_;
4566 };
4567
4568 DeferredStringCharFromCode* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004569 new(zone()) DeferredStringCharFromCode(this, instr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004570
4571 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
4572 Register char_code = ToRegister(instr->char_code());
4573 Register result = ToRegister(instr->result());
4574 ASSERT(!char_code.is(result));
4575
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004576 __ cmp(char_code, String::kMaxOneByteCharCode);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004577 __ j(above, deferred->entry());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004578 __ Set(result, Immediate(factory()->single_character_string_cache()));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004579 __ mov(result, FieldOperand(result,
4580 char_code, times_pointer_size,
4581 FixedArray::kHeaderSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004582 __ cmp(result, factory()->undefined_value());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004583 __ j(equal, deferred->entry());
4584 __ bind(deferred->exit());
4585}
4586
4587
4588void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4589 Register char_code = ToRegister(instr->char_code());
4590 Register result = ToRegister(instr->result());
4591
4592 // TODO(3095996): Get rid of this. For now, we need to make the
4593 // result register contain a valid pointer because it is already
4594 // contained in the register pointer map.
4595 __ Set(result, Immediate(0));
4596
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004597 PushSafepointRegistersScope scope(this);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004598 __ SmiTag(char_code);
4599 __ push(char_code);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004600 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004601 __ StoreToSafepointRegisterSlot(result, eax);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004602}
4603
4604
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004605void LCodeGen::DoStringLength(LStringLength* instr) {
4606 Register string = ToRegister(instr->string());
4607 Register result = ToRegister(instr->result());
4608 __ mov(result, FieldOperand(string, String::kLengthOffset));
4609}
4610
4611
danno@chromium.org160a7b02011-04-18 15:51:38 +00004612void LCodeGen::DoStringAdd(LStringAdd* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004613 EmitPushTaggedOperand(instr->left());
4614 EmitPushTaggedOperand(instr->right());
danno@chromium.org160a7b02011-04-18 15:51:38 +00004615 StringAddStub stub(NO_STRING_CHECK_IN_STUB);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004616 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
danno@chromium.org160a7b02011-04-18 15:51:38 +00004617}
4618
4619
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004620void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004621 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004622 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004623 LOperand* input = instr->value();
4624 ASSERT(input->IsRegister() || input->IsStackSlot());
4625 LOperand* output = instr->result();
4626 ASSERT(output->IsDoubleRegister());
4627 __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
4628 } else {
4629 UNREACHABLE();
4630 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004631}
4632
4633
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004634void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004635 CpuFeatureScope scope(masm(), SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004636 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004637 LOperand* output = instr->result();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004638 LOperand* temp = instr->temp();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004639
4640 __ LoadUint32(ToDoubleRegister(output),
4641 ToRegister(input),
4642 ToDoubleRegister(temp));
4643}
4644
4645
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004646void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
4647 class DeferredNumberTagI: public LDeferredCode {
4648 public:
4649 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
4650 : LDeferredCode(codegen), instr_(instr) { }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004651 virtual void Generate() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004652 codegen()->DoDeferredNumberTagI(instr_, instr_->value(), SIGNED_INT32);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004653 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004654 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004655 private:
4656 LNumberTagI* instr_;
4657 };
4658
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004659 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004660 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4661 Register reg = ToRegister(input);
4662
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004663 DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004664 __ SmiTag(reg);
4665 __ j(overflow, deferred->entry());
4666 __ bind(deferred->exit());
4667}
4668
4669
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004670void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
4671 class DeferredNumberTagU: public LDeferredCode {
4672 public:
4673 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
4674 : LDeferredCode(codegen), instr_(instr) { }
4675 virtual void Generate() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004676 codegen()->DoDeferredNumberTagI(instr_, instr_->value(), UNSIGNED_INT32);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004677 }
4678 virtual LInstruction* instr() { return instr_; }
4679 private:
4680 LNumberTagU* instr_;
4681 };
4682
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004683 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004684 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4685 Register reg = ToRegister(input);
4686
4687 DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
4688 __ cmp(reg, Immediate(Smi::kMaxValue));
4689 __ j(above, deferred->entry());
4690 __ SmiTag(reg);
4691 __ bind(deferred->exit());
4692}
4693
4694
4695void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
4696 LOperand* value,
4697 IntegerSignedness signedness) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004698 Label slow;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004699 Register reg = ToRegister(value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004700 Register tmp = reg.is(eax) ? ecx : eax;
4701
4702 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004703 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004704
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004705 Label done;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004706
4707 if (signedness == SIGNED_INT32) {
4708 // There was overflow, so bits 30 and 31 of the original integer
4709 // disagree. Try to allocate a heap number in new space and store
4710 // the value in there. If that fails, call the runtime system.
4711 __ SmiUntag(reg);
4712 __ xor_(reg, 0x80000000);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004713 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004714 CpuFeatureScope feature_scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004715 __ cvtsi2sd(xmm0, Operand(reg));
4716 } else {
4717 __ push(reg);
4718 __ fild_s(Operand(esp, 0));
4719 __ pop(reg);
4720 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004721 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004722 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004723 CpuFeatureScope feature_scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004724 __ LoadUint32(xmm0, reg, xmm1);
4725 } else {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00004726 // There's no fild variant for unsigned values, so zero-extend to a 64-bit
4727 // int manually.
4728 __ push(Immediate(0));
4729 __ push(reg);
4730 __ fild_d(Operand(esp, 0));
4731 __ pop(reg);
4732 __ pop(reg);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004733 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004734 }
4735
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004736 if (FLAG_inline_new) {
4737 __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004738 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004739 }
4740
4741 // Slow case: Call the runtime system to do the number allocation.
4742 __ bind(&slow);
4743
4744 // TODO(3095996): Put a valid pointer value in the stack slot where the result
4745 // register is stored, as this register is in the pointer map, but contains an
4746 // integer value.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004747 __ StoreToSafepointRegisterSlot(reg, Immediate(0));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004748 // NumberTagI and NumberTagD use the context from the frame, rather than
4749 // the environment's HContext or HInlinedContext value.
4750 // They only call Runtime::kAllocateHeapNumber.
4751 // The corresponding HChange instructions are added in a phase that does
4752 // not have easy access to the local context.
4753 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4754 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4755 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004756 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004757 if (!reg.is(eax)) __ mov(reg, eax);
4758
4759 // Done. Put the value in xmm0 into the value of the allocated heap
4760 // number.
4761 __ bind(&done);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004762 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004763 CpuFeatureScope feature_scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004764 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0);
4765 } else {
4766 __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
4767 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004768 __ StoreToSafepointRegisterSlot(reg, reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004769}
4770
4771
4772void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
4773 class DeferredNumberTagD: public LDeferredCode {
4774 public:
4775 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
4776 : LDeferredCode(codegen), instr_(instr) { }
4777 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004778 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004779 private:
4780 LNumberTagD* instr_;
4781 };
4782
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004783 Register reg = ToRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004784
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004785 bool convert_hole = false;
4786 HValue* change_input = instr->hydrogen()->value();
4787 if (change_input->IsLoadKeyed()) {
4788 HLoadKeyed* load = HLoadKeyed::cast(change_input);
4789 convert_hole = load->UsesMustHandleHole();
4790 }
4791
4792 Label no_special_nan_handling;
4793 Label done;
4794 if (convert_hole) {
4795 bool use_sse2 = CpuFeatures::IsSupported(SSE2);
4796 if (use_sse2) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004797 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004798 XMMRegister input_reg = ToDoubleRegister(instr->value());
4799 __ ucomisd(input_reg, input_reg);
4800 } else {
4801 if (!IsX87TopOfStack(instr->value())) {
4802 __ fld_d(ToOperand(instr->value()));
4803 }
4804 __ fld(0);
4805 __ fld(0);
4806 __ FCmp();
4807 }
4808
4809 __ j(parity_odd, &no_special_nan_handling);
4810 __ sub(esp, Immediate(kDoubleSize));
4811 if (use_sse2) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004812 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004813 XMMRegister input_reg = ToDoubleRegister(instr->value());
4814 __ movdbl(MemOperand(esp, 0), input_reg);
4815 } else {
4816 __ fld(0);
4817 __ fstp_d(MemOperand(esp, 0));
4818 }
4819 __ cmp(MemOperand(esp, sizeof(kHoleNanLower32)),
4820 Immediate(kHoleNanUpper32));
4821 Label canonicalize;
4822 __ j(not_equal, &canonicalize);
4823 __ add(esp, Immediate(kDoubleSize));
4824 __ mov(reg, factory()->the_hole_value());
4825 __ jmp(&done);
4826 __ bind(&canonicalize);
4827 __ add(esp, Immediate(kDoubleSize));
4828 ExternalReference nan =
4829 ExternalReference::address_of_canonical_non_hole_nan();
4830 if (use_sse2) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004831 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004832 XMMRegister input_reg = ToDoubleRegister(instr->value());
4833 __ movdbl(input_reg, Operand::StaticVariable(nan));
4834 } else {
4835 __ fstp(0);
4836 __ fld_d(Operand::StaticVariable(nan));
4837 }
4838 }
4839
4840 __ bind(&no_special_nan_handling);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004841 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004842 if (FLAG_inline_new) {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00004843 Register tmp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004844 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
4845 } else {
4846 __ jmp(deferred->entry());
4847 }
4848 __ bind(deferred->exit());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004849 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004850 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004851 XMMRegister input_reg = ToDoubleRegister(instr->value());
4852 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
4853 } else {
4854 if (!IsX87TopOfStack(instr->value())) {
4855 __ fld_d(ToOperand(instr->value()));
4856 }
4857 __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
4858 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004859 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004860}
4861
4862
4863void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
4864 // TODO(3095996): Get rid of this. For now, we need to make the
4865 // result register contain a valid pointer because it is already
4866 // contained in the register pointer map.
4867 Register reg = ToRegister(instr->result());
4868 __ Set(reg, Immediate(0));
4869
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004870 PushSafepointRegistersScope scope(this);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004871 // NumberTagI and NumberTagD use the context from the frame, rather than
4872 // the environment's HContext or HInlinedContext value.
4873 // They only call Runtime::kAllocateHeapNumber.
4874 // The corresponding HChange instructions are added in a phase that does
4875 // not have easy access to the local context.
4876 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4877 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004878 RecordSafepointWithRegisters(
4879 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004880 __ StoreToSafepointRegisterSlot(reg, eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004881}
4882
4883
4884void LCodeGen::DoSmiTag(LSmiTag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004885 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004886 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4887 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
4888 __ SmiTag(ToRegister(input));
4889}
4890
4891
4892void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004893 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004894 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4895 if (instr->needs_check()) {
4896 __ test(ToRegister(input), Immediate(kSmiTagMask));
4897 DeoptimizeIf(not_zero, instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004898 } else {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004899 __ AssertSmi(ToRegister(input));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004900 }
4901 __ SmiUntag(ToRegister(input));
4902}
4903
4904
4905void LCodeGen::EmitNumberUntagD(Register input_reg,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004906 Register temp_reg,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004907 XMMRegister result_reg,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004908 bool deoptimize_on_undefined,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004909 bool deoptimize_on_minus_zero,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004910 LEnvironment* env,
4911 NumberUntagDMode mode) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004912 Label load_smi, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004913
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004914 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
4915 // Smi check.
4916 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004917
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004918 // Heap number map check.
4919 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
4920 factory()->heap_number_map());
4921 if (deoptimize_on_undefined) {
4922 DeoptimizeIf(not_equal, env);
4923 } else {
4924 Label heap_number;
4925 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004926
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004927 __ cmp(input_reg, factory()->undefined_value());
4928 DeoptimizeIf(not_equal, env);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004929
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004930 // Convert undefined to NaN.
4931 ExternalReference nan =
4932 ExternalReference::address_of_canonical_non_hole_nan();
4933 __ movdbl(result_reg, Operand::StaticVariable(nan));
4934 __ jmp(&done, Label::kNear);
4935
4936 __ bind(&heap_number);
4937 }
4938 // Heap number to XMM conversion.
4939 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
4940 if (deoptimize_on_minus_zero) {
4941 XMMRegister xmm_scratch = xmm0;
4942 __ xorps(xmm_scratch, xmm_scratch);
4943 __ ucomisd(result_reg, xmm_scratch);
4944 __ j(not_zero, &done, Label::kNear);
4945 __ movmskpd(temp_reg, result_reg);
4946 __ test_b(temp_reg, 1);
4947 DeoptimizeIf(not_zero, env);
4948 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004949 __ jmp(&done, Label::kNear);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004950 } else if (mode == NUMBER_CANDIDATE_IS_SMI_OR_HOLE) {
4951 __ test(input_reg, Immediate(kSmiTagMask));
4952 DeoptimizeIf(not_equal, env);
4953 } else if (mode == NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE) {
4954 __ test(input_reg, Immediate(kSmiTagMask));
4955 __ j(zero, &load_smi);
4956 ExternalReference hole_nan_reference =
4957 ExternalReference::address_of_the_hole_nan();
4958 __ movdbl(result_reg, Operand::StaticVariable(hole_nan_reference));
4959 __ jmp(&done, Label::kNear);
4960 } else {
4961 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004962 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004963
4964 // Smi to XMM conversion
4965 __ bind(&load_smi);
4966 __ SmiUntag(input_reg); // Untag smi before converting to float.
4967 __ cvtsi2sd(result_reg, Operand(input_reg));
4968 __ SmiTag(input_reg); // Retag smi.
4969 __ bind(&done);
4970}
4971
4972
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004973void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004974 Label done, heap_number;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004975 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004976
4977 // Heap number map check.
4978 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004979 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004980
4981 if (instr->truncating()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004982 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004983 // Check for undefined. Undefined is converted to zero for truncating
4984 // conversions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004985 __ cmp(input_reg, factory()->undefined_value());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004986 __ RecordComment("Deferred TaggedToI: cannot truncate");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004987 DeoptimizeIf(not_equal, instr->environment());
4988 __ mov(input_reg, 0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004989 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004990
4991 __ bind(&heap_number);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004992 if (CpuFeatures::IsSupported(SSE3)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004993 CpuFeatureScope scope(masm(), SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004994 Label convert;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004995 // Use more powerful conversion when sse3 is available.
4996 // Load x87 register with heap number.
4997 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
4998 // Get exponent alone and check for too-big exponent.
4999 __ mov(input_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
5000 __ and_(input_reg, HeapNumber::kExponentMask);
5001 const uint32_t kTooBigExponent =
5002 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
5003 __ cmp(Operand(input_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005004 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005005 // Pop FPU stack before deoptimizing.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005006 __ fstp(0);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005007 __ RecordComment("Deferred TaggedToI: exponent too big");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005008 DeoptimizeIf(no_condition, instr->environment());
5009
5010 // Reserve space for 64 bit answer.
5011 __ bind(&convert);
5012 __ sub(Operand(esp), Immediate(kDoubleSize));
5013 // Do conversion, which cannot fail because we checked the exponent.
5014 __ fisttp_d(Operand(esp, 0));
5015 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result.
5016 __ add(Operand(esp), Immediate(kDoubleSize));
5017 } else {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005018 CpuFeatureScope scope(masm(), SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005019 XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005020 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
5021 __ cvttsd2si(input_reg, Operand(xmm0));
5022 __ cmp(input_reg, 0x80000000u);
5023 __ j(not_equal, &done);
5024 // Check if the input was 0x8000000 (kMinInt).
5025 // If no, then we got an overflow and we deoptimize.
5026 ExternalReference min_int = ExternalReference::address_of_min_int();
5027 __ movdbl(xmm_temp, Operand::StaticVariable(min_int));
5028 __ ucomisd(xmm_temp, xmm0);
5029 DeoptimizeIf(not_equal, instr->environment());
5030 DeoptimizeIf(parity_even, instr->environment()); // NaN.
5031 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005032 } else if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005033 CpuFeatureScope scope(masm(), SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005034 // Deoptimize if we don't have a heap number.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005035 __ RecordComment("Deferred TaggedToI: not a heap number");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005036 DeoptimizeIf(not_equal, instr->environment());
5037
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005038 XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005039 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
5040 __ cvttsd2si(input_reg, Operand(xmm0));
5041 __ cvtsi2sd(xmm_temp, Operand(input_reg));
5042 __ ucomisd(xmm0, xmm_temp);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005043 __ RecordComment("Deferred TaggedToI: lost precision");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005044 DeoptimizeIf(not_equal, instr->environment());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005045 __ RecordComment("Deferred TaggedToI: NaN");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005046 DeoptimizeIf(parity_even, instr->environment()); // NaN.
5047 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
5048 __ test(input_reg, Operand(input_reg));
5049 __ j(not_zero, &done);
5050 __ movmskpd(input_reg, xmm0);
5051 __ and_(input_reg, 1);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005052 __ RecordComment("Deferred TaggedToI: minus zero");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005053 DeoptimizeIf(not_zero, instr->environment());
5054 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005055 } else {
5056 UNREACHABLE();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005057 }
5058 __ bind(&done);
5059}
5060
5061
5062void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005063 class DeferredTaggedToI: public LDeferredCode {
5064 public:
5065 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
5066 : LDeferredCode(codegen), instr_(instr) { }
5067 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
5068 virtual LInstruction* instr() { return instr_; }
5069 private:
5070 LTaggedToI* instr_;
5071 };
5072
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005073 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005074 ASSERT(input->IsRegister());
5075 ASSERT(input->Equals(instr->result()));
5076
5077 Register input_reg = ToRegister(input);
5078
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005079 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005080
5081 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00005082 __ JumpIfNotSmi(input_reg, deferred->entry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005083
5084 // Smi to int32 conversion
5085 __ SmiUntag(input_reg); // Untag smi.
5086
5087 __ bind(deferred->exit());
5088}
5089
5090
5091void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005092 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005093 ASSERT(input->IsRegister());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005094 LOperand* temp = instr->temp();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005095 ASSERT(temp == NULL || temp->IsRegister());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005096 LOperand* result = instr->result();
5097 ASSERT(result->IsDoubleRegister());
5098
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005099 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005100 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005101 Register input_reg = ToRegister(input);
5102 XMMRegister result_reg = ToDoubleRegister(result);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005103
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005104 bool deoptimize_on_minus_zero =
5105 instr->hydrogen()->deoptimize_on_minus_zero();
5106 Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005107
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005108 NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED;
5109 HValue* value = instr->hydrogen()->value();
5110 if (value->type().IsSmi()) {
5111 if (value->IsLoadKeyed()) {
5112 HLoadKeyed* load = HLoadKeyed::cast(value);
5113 if (load->UsesMustHandleHole()) {
5114 if (load->hole_mode() == ALLOW_RETURN_HOLE) {
5115 mode = NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE;
5116 } else {
5117 mode = NUMBER_CANDIDATE_IS_SMI_OR_HOLE;
5118 }
5119 } else {
5120 mode = NUMBER_CANDIDATE_IS_SMI;
5121 }
5122 }
5123 }
5124
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005125 EmitNumberUntagD(input_reg,
5126 temp_reg,
5127 result_reg,
5128 instr->hydrogen()->deoptimize_on_undefined(),
5129 deoptimize_on_minus_zero,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005130 instr->environment(),
5131 mode);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005132 } else {
5133 UNIMPLEMENTED();
5134 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005135}
5136
5137
5138void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005139 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005140 ASSERT(input->IsDoubleRegister());
5141 LOperand* result = instr->result();
5142 ASSERT(result->IsRegister());
ulan@chromium.org750145a2013-03-07 15:14:13 +00005143 CpuFeatureScope scope(masm(), SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005144
5145 XMMRegister input_reg = ToDoubleRegister(input);
5146 Register result_reg = ToRegister(result);
5147
5148 if (instr->truncating()) {
5149 // Performs a truncating conversion of a floating point number as used by
5150 // the JS bitwise operations.
5151 __ cvttsd2si(result_reg, Operand(input_reg));
5152 __ cmp(result_reg, 0x80000000u);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005153 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005154 // This will deoptimize if the exponent of the input in out of range.
ulan@chromium.org750145a2013-03-07 15:14:13 +00005155 CpuFeatureScope scope(masm(), SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005156 Label convert, done;
5157 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005158 __ sub(Operand(esp), Immediate(kDoubleSize));
5159 __ movdbl(Operand(esp, 0), input_reg);
5160 // Get exponent alone and check for too-big exponent.
5161 __ mov(result_reg, Operand(esp, sizeof(int32_t)));
5162 __ and_(result_reg, HeapNumber::kExponentMask);
5163 const uint32_t kTooBigExponent =
5164 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
5165 __ cmp(Operand(result_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005166 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005167 __ add(Operand(esp), Immediate(kDoubleSize));
5168 DeoptimizeIf(no_condition, instr->environment());
5169 __ bind(&convert);
5170 // Do conversion, which cannot fail because we checked the exponent.
5171 __ fld_d(Operand(esp, 0));
5172 __ fisttp_d(Operand(esp, 0));
5173 __ mov(result_reg, Operand(esp, 0)); // Low word of answer is the result.
5174 __ add(Operand(esp), Immediate(kDoubleSize));
5175 __ bind(&done);
5176 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005177 Label done;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005178 Register temp_reg = ToRegister(instr->temp());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005179 XMMRegister xmm_scratch = xmm0;
5180
5181 // If cvttsd2si succeeded, we're done. Otherwise, we attempt
5182 // manual conversion.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005183 __ j(not_equal, &done, Label::kNear);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005184
5185 // Get high 32 bits of the input in result_reg and temp_reg.
5186 __ pshufd(xmm_scratch, input_reg, 1);
5187 __ movd(Operand(temp_reg), xmm_scratch);
5188 __ mov(result_reg, temp_reg);
5189
5190 // Prepare negation mask in temp_reg.
5191 __ sar(temp_reg, kBitsPerInt - 1);
5192
5193 // Extract the exponent from result_reg and subtract adjusted
5194 // bias from it. The adjustment is selected in a way such that
5195 // when the difference is zero, the answer is in the low 32 bits
5196 // of the input, otherwise a shift has to be performed.
5197 __ shr(result_reg, HeapNumber::kExponentShift);
5198 __ and_(result_reg,
5199 HeapNumber::kExponentMask >> HeapNumber::kExponentShift);
5200 __ sub(Operand(result_reg),
5201 Immediate(HeapNumber::kExponentBias +
5202 HeapNumber::kExponentBits +
5203 HeapNumber::kMantissaBits));
5204 // Don't handle big (> kMantissaBits + kExponentBits == 63) or
5205 // special exponents.
5206 DeoptimizeIf(greater, instr->environment());
5207
5208 // Zero out the sign and the exponent in the input (by shifting
5209 // it to the left) and restore the implicit mantissa bit,
5210 // i.e. convert the input to unsigned int64 shifted left by
5211 // kExponentBits.
5212 ExternalReference minus_zero = ExternalReference::address_of_minus_zero();
5213 // Minus zero has the most significant bit set and the other
5214 // bits cleared.
5215 __ movdbl(xmm_scratch, Operand::StaticVariable(minus_zero));
5216 __ psllq(input_reg, HeapNumber::kExponentBits);
5217 __ por(input_reg, xmm_scratch);
5218
5219 // Get the amount to shift the input right in xmm_scratch.
5220 __ neg(result_reg);
5221 __ movd(xmm_scratch, Operand(result_reg));
5222
5223 // Shift the input right and extract low 32 bits.
5224 __ psrlq(input_reg, xmm_scratch);
5225 __ movd(Operand(result_reg), input_reg);
5226
5227 // Use the prepared mask in temp_reg to negate the result if necessary.
5228 __ xor_(result_reg, Operand(temp_reg));
5229 __ sub(result_reg, Operand(temp_reg));
5230 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005231 }
5232 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005233 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005234 __ cvttsd2si(result_reg, Operand(input_reg));
5235 __ cvtsi2sd(xmm0, Operand(result_reg));
5236 __ ucomisd(xmm0, input_reg);
5237 DeoptimizeIf(not_equal, instr->environment());
5238 DeoptimizeIf(parity_even, instr->environment()); // NaN.
5239 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
5240 // The integer converted back is equal to the original. We
5241 // only have to test if we got -0 as an input.
5242 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005243 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005244 __ movmskpd(result_reg, input_reg);
5245 // Bit 0 contains the sign of the double in input_reg.
5246 // If input was positive, we are ok and return 0, otherwise
5247 // deoptimize.
5248 __ and_(result_reg, 1);
5249 DeoptimizeIf(not_zero, instr->environment());
5250 }
5251 __ bind(&done);
5252 }
5253}
5254
5255
5256void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005257 LOperand* input = instr->value();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005258 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005259 DeoptimizeIf(not_zero, instr->environment());
5260}
5261
5262
5263void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005264 LOperand* input = instr->value();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005265 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005266 DeoptimizeIf(zero, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005267}
5268
5269
5270void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005271 Register input = ToRegister(instr->value());
5272 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005273
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005274 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005275
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005276 if (instr->hydrogen()->is_interval_check()) {
5277 InstanceType first;
5278 InstanceType last;
5279 instr->hydrogen()->GetCheckInterval(&first, &last);
5280
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005281 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
5282 static_cast<int8_t>(first));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005283
5284 // If there is only one type in the interval check for equality.
5285 if (first == last) {
5286 DeoptimizeIf(not_equal, instr->environment());
5287 } else {
5288 DeoptimizeIf(below, instr->environment());
5289 // Omit check for the last type.
5290 if (last != LAST_TYPE) {
5291 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
5292 static_cast<int8_t>(last));
5293 DeoptimizeIf(above, instr->environment());
5294 }
5295 }
5296 } else {
5297 uint8_t mask;
5298 uint8_t tag;
5299 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
5300
5301 if (IsPowerOf2(mask)) {
5302 ASSERT(tag == 0 || IsPowerOf2(tag));
5303 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), mask);
5304 DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
5305 } else {
5306 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
5307 __ and_(temp, mask);
yangguo@chromium.org56454712012-02-16 15:33:53 +00005308 __ cmp(temp, tag);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005309 DeoptimizeIf(not_equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005310 }
5311 }
5312}
5313
5314
5315void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005316 Handle<JSFunction> target = instr->hydrogen()->target();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00005317 if (instr->hydrogen()->target_in_new_space()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005318 Register reg = ToRegister(instr->value());
5319 Handle<JSGlobalPropertyCell> cell =
5320 isolate()->factory()->NewJSGlobalPropertyCell(target);
5321 __ cmp(reg, Operand::Cell(cell));
5322 } else {
5323 Operand operand = ToOperand(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005324 __ cmp(operand, target);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005325 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005326 DeoptimizeIf(not_equal, instr->environment());
5327}
5328
5329
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005330void LCodeGen::DoCheckMapCommon(Register reg,
5331 Handle<Map> map,
5332 CompareMapMode mode,
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005333 LInstruction* instr) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005334 Label success;
5335 __ CompareMap(reg, map, &success, mode);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005336 DeoptimizeIf(not_equal, instr->environment());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005337 __ bind(&success);
5338}
5339
5340
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005341void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005342 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005343 ASSERT(input->IsRegister());
5344 Register reg = ToRegister(input);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005345
5346 Label success;
5347 SmallMapList* map_set = instr->hydrogen()->map_set();
5348 for (int i = 0; i < map_set->length() - 1; i++) {
5349 Handle<Map> map = map_set->at(i);
5350 __ CompareMap(reg, map, &success, REQUIRE_EXACT_MAP);
5351 __ j(equal, &success);
5352 }
5353 Handle<Map> map = map_set->last();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005354 DoCheckMapCommon(reg, map, REQUIRE_EXACT_MAP, instr);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005355 __ bind(&success);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005356}
5357
5358
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005359void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005360 CpuFeatureScope scope(masm(), SSE2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005361 XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
5362 Register result_reg = ToRegister(instr->result());
5363 __ ClampDoubleToUint8(value_reg, xmm0, result_reg);
5364}
5365
5366
5367void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
5368 ASSERT(instr->unclamped()->Equals(instr->result()));
5369 Register value_reg = ToRegister(instr->result());
5370 __ ClampUint8(value_reg);
5371}
5372
5373
5374void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005375 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005376
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005377 ASSERT(instr->unclamped()->Equals(instr->result()));
5378 Register input_reg = ToRegister(instr->unclamped());
5379 Label is_smi, done, heap_number;
5380
5381 __ JumpIfSmi(input_reg, &is_smi);
5382
5383 // Check for heap number
5384 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5385 factory()->heap_number_map());
5386 __ j(equal, &heap_number, Label::kNear);
5387
5388 // Check for undefined. Undefined is converted to zero for clamping
5389 // conversions.
5390 __ cmp(input_reg, factory()->undefined_value());
5391 DeoptimizeIf(not_equal, instr->environment());
5392 __ mov(input_reg, 0);
5393 __ jmp(&done, Label::kNear);
5394
5395 // Heap number
5396 __ bind(&heap_number);
5397 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
5398 __ ClampDoubleToUint8(xmm0, xmm1, input_reg);
5399 __ jmp(&done, Label::kNear);
5400
5401 // smi
5402 __ bind(&is_smi);
5403 __ SmiUntag(input_reg);
5404 __ ClampUint8(input_reg);
5405
5406 __ bind(&done);
5407}
5408
5409
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005410void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00005411 ASSERT(instr->temp()->Equals(instr->result()));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005412 Register reg = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005413
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00005414 ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
5415 ZoneList<Handle<Map> >* maps = instr->maps();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005416
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00005417 ASSERT(prototypes->length() == maps->length());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005418
ulan@chromium.org2e04b582013-02-21 14:06:02 +00005419 // TODO(ulan): Move this check to hydrogen and split HCheckPrototypeMaps
5420 // into two instruction: one that checks the prototypes and another that
5421 // loads the holder (HConstant). Find a way to do it without breaking
5422 // parallel recompilation.
5423 if (instr->hydrogen()->CanOmitPrototypeChecks()) {
5424 for (int i = 0; i < maps->length(); i++) {
5425 prototype_maps_.Add(maps->at(i), info()->zone());
5426 }
5427 __ LoadHeapObject(reg, prototypes->at(prototypes->length() - 1));
5428 } else {
5429 for (int i = 0; i < prototypes->length(); i++) {
5430 __ LoadHeapObject(reg, prototypes->at(i));
5431 DoCheckMapCommon(reg, maps->at(i), ALLOW_ELEMENT_TRANSITION_MAPS, instr);
5432 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005433 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005434}
5435
5436
ulan@chromium.org967e2702012-02-28 09:49:15 +00005437void LCodeGen::DoAllocateObject(LAllocateObject* instr) {
5438 class DeferredAllocateObject: public LDeferredCode {
5439 public:
5440 DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr)
5441 : LDeferredCode(codegen), instr_(instr) { }
5442 virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); }
5443 virtual LInstruction* instr() { return instr_; }
5444 private:
5445 LAllocateObject* instr_;
5446 };
5447
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005448 DeferredAllocateObject* deferred =
5449 new(zone()) DeferredAllocateObject(this, instr);
ulan@chromium.org967e2702012-02-28 09:49:15 +00005450
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005451 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005452 Register scratch = ToRegister(instr->temp());
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005453 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
5454 Handle<Map> initial_map(constructor->initial_map());
5455 int instance_size = initial_map->instance_size();
5456 ASSERT(initial_map->pre_allocated_property_fields() +
5457 initial_map->unused_property_fields() -
5458 initial_map->inobject_properties() == 0);
5459
5460 // Allocate memory for the object. The initial map might change when
5461 // the constructor's prototype changes, but instance size and property
5462 // counts remain unchanged (if slack tracking finished).
5463 ASSERT(!constructor->shared()->IsInobjectSlackTrackingInProgress());
5464 __ AllocateInNewSpace(instance_size,
5465 result,
5466 no_reg,
5467 scratch,
5468 deferred->entry(),
5469 TAG_OBJECT);
5470
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005471 __ bind(deferred->exit());
5472 if (FLAG_debug_code) {
5473 Label is_in_new_space;
5474 __ JumpIfInNewSpace(result, scratch, &is_in_new_space);
5475 __ Abort("Allocated object is not in new-space");
5476 __ bind(&is_in_new_space);
5477 }
5478
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005479 // Load the initial map.
5480 Register map = scratch;
5481 __ LoadHeapObject(scratch, constructor);
5482 __ mov(map, FieldOperand(scratch, JSFunction::kPrototypeOrInitialMapOffset));
5483
5484 if (FLAG_debug_code) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005485 __ AssertNotSmi(map);
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005486 __ cmpb(FieldOperand(map, Map::kInstanceSizeOffset),
5487 instance_size >> kPointerSizeLog2);
5488 __ Assert(equal, "Unexpected instance size");
5489 __ cmpb(FieldOperand(map, Map::kPreAllocatedPropertyFieldsOffset),
5490 initial_map->pre_allocated_property_fields());
5491 __ Assert(equal, "Unexpected pre-allocated property fields count");
5492 __ cmpb(FieldOperand(map, Map::kUnusedPropertyFieldsOffset),
5493 initial_map->unused_property_fields());
5494 __ Assert(equal, "Unexpected unused property fields count");
5495 __ cmpb(FieldOperand(map, Map::kInObjectPropertiesOffset),
5496 initial_map->inobject_properties());
5497 __ Assert(equal, "Unexpected in-object property fields count");
5498 }
5499
5500 // Initialize map and fields of the newly allocated object.
5501 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE);
5502 __ mov(FieldOperand(result, JSObject::kMapOffset), map);
5503 __ mov(scratch, factory()->empty_fixed_array());
5504 __ mov(FieldOperand(result, JSObject::kElementsOffset), scratch);
5505 __ mov(FieldOperand(result, JSObject::kPropertiesOffset), scratch);
5506 if (initial_map->inobject_properties() != 0) {
5507 __ mov(scratch, factory()->undefined_value());
5508 for (int i = 0; i < initial_map->inobject_properties(); i++) {
5509 int property_offset = JSObject::kHeaderSize + i * kPointerSize;
5510 __ mov(FieldOperand(result, property_offset), scratch);
5511 }
5512 }
ulan@chromium.org967e2702012-02-28 09:49:15 +00005513}
5514
5515
5516void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) {
5517 Register result = ToRegister(instr->result());
5518 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005519 Handle<Map> initial_map(constructor->initial_map());
5520 int instance_size = initial_map->instance_size();
ulan@chromium.org967e2702012-02-28 09:49:15 +00005521
5522 // TODO(3095996): Get rid of this. For now, we need to make the
5523 // result register contain a valid pointer because it is already
5524 // contained in the register pointer map.
5525 __ Set(result, Immediate(0));
5526
5527 PushSafepointRegistersScope scope(this);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005528 __ push(Immediate(Smi::FromInt(instance_size)));
5529 CallRuntimeFromDeferred(
5530 Runtime::kAllocateInNewSpace, 1, instr, instr->context());
ulan@chromium.org967e2702012-02-28 09:49:15 +00005531 __ StoreToSafepointRegisterSlot(result, eax);
5532}
5533
5534
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005535void LCodeGen::DoAllocate(LAllocate* instr) {
5536 class DeferredAllocate: public LDeferredCode {
5537 public:
5538 DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
5539 : LDeferredCode(codegen), instr_(instr) { }
5540 virtual void Generate() { codegen()->DoDeferredAllocate(instr_); }
5541 virtual LInstruction* instr() { return instr_; }
5542 private:
5543 LAllocate* instr_;
5544 };
5545
5546 DeferredAllocate* deferred =
5547 new(zone()) DeferredAllocate(this, instr);
5548
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005549 Register result = ToRegister(instr->result());
5550 Register temp = ToRegister(instr->temp());
5551
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005552 // Allocate memory for the object.
5553 AllocationFlags flags = TAG_OBJECT;
5554 if (instr->hydrogen()->MustAllocateDoubleAligned()) {
5555 flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
5556 }
5557 if (instr->size()->IsConstantOperand()) {
5558 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5559 __ AllocateInNewSpace(size, result, temp, no_reg, deferred->entry(), flags);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005560 } else {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005561 Register size = ToRegister(instr->size());
5562 __ AllocateInNewSpace(size, result, temp, no_reg, deferred->entry(), flags);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005563 }
5564
5565 __ bind(deferred->exit());
5566}
5567
5568
5569void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
5570 Register size = ToRegister(instr->size());
5571 Register result = ToRegister(instr->result());
5572
5573 __ SmiTag(size);
5574 PushSafepointRegistersScope scope(this);
5575 // TODO(3095996): Get rid of this. For now, we need to make the
5576 // result register contain a valid pointer because it is already
5577 // contained in the register pointer map.
5578 if (!size.is(result)) {
5579 __ StoreToSafepointRegisterSlot(result, size);
5580 }
5581 __ push(size);
5582 CallRuntimeFromDeferred(
5583 Runtime::kAllocateInNewSpace, 1, instr, instr->context());
5584 __ StoreToSafepointRegisterSlot(result, eax);
5585}
5586
5587
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005588void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005589 ASSERT(ToRegister(instr->context()).is(esi));
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005590 Handle<FixedArray> literals(instr->environment()->closure()->literals());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005591 ElementsKind boilerplate_elements_kind =
5592 instr->hydrogen()->boilerplate_elements_kind();
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005593 AllocationSiteMode allocation_site_mode =
5594 instr->hydrogen()->allocation_site_mode();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005595
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005596 // Deopt if the array literal boilerplate ElementsKind is of a type different
5597 // than the expected one. The check isn't necessary if the boilerplate has
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005598 // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
5599 if (CanTransitionToMoreGeneralFastElementsKind(
5600 boilerplate_elements_kind, true)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005601 __ LoadHeapObject(eax, instr->hydrogen()->boilerplate_object());
5602 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
5603 // Load the map's "bit field 2". We only need the first byte,
5604 // but the following masking takes care of that anyway.
5605 __ mov(ebx, FieldOperand(ebx, Map::kBitField2Offset));
5606 // Retrieve elements_kind from bit field 2.
5607 __ and_(ebx, Map::kElementsKindMask);
5608 __ cmp(ebx, boilerplate_elements_kind << Map::kElementsKindShift);
5609 DeoptimizeIf(not_equal, instr->environment());
5610 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005611
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005612 // Set up the parameters to the stub/runtime call.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005613 __ PushHeapObject(literals);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005614 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005615 // Boilerplate already exists, constant elements are never accessed.
5616 // Pass an empty fixed array.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005617 __ push(Immediate(isolate()->factory()->empty_fixed_array()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005618
5619 // Pick the right runtime function or stub to call.
5620 int length = instr->hydrogen()->length();
5621 if (instr->hydrogen()->IsCopyOnWrite()) {
5622 ASSERT(instr->hydrogen()->depth() == 1);
5623 FastCloneShallowArrayStub::Mode mode =
5624 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005625 FastCloneShallowArrayStub stub(mode, DONT_TRACK_ALLOCATION_SITE, length);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005626 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005627 } else if (instr->hydrogen()->depth() > 1) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005628 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005629 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005630 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005631 } else {
5632 FastCloneShallowArrayStub::Mode mode =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005633 boilerplate_elements_kind == FAST_DOUBLE_ELEMENTS
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005634 ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
5635 : FastCloneShallowArrayStub::CLONE_ELEMENTS;
5636 FastCloneShallowArrayStub stub(mode, allocation_site_mode, length);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005637 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005638 }
5639}
5640
5641
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005642void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
5643 Register result,
5644 Register source,
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005645 int* offset,
5646 AllocationSiteMode mode) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005647 ASSERT(!source.is(ecx));
5648 ASSERT(!result.is(ecx));
5649
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005650 bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
5651 object->map()->CanTrackAllocationSite();
5652
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005653 if (FLAG_debug_code) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005654 __ LoadHeapObject(ecx, object);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005655 __ cmp(source, ecx);
5656 __ Assert(equal, "Unexpected object literal boilerplate");
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005657 __ mov(ecx, FieldOperand(source, HeapObject::kMapOffset));
5658 __ cmp(ecx, Handle<Map>(object->map()));
5659 __ Assert(equal, "Unexpected boilerplate map");
5660 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
5661 __ and_(ecx, Map::kElementsKindMask);
5662 __ cmp(ecx, object->GetElementsKind() << Map::kElementsKindShift);
5663 __ Assert(equal, "Unexpected boilerplate elements kind");
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005664 }
5665
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005666 // Only elements backing stores for non-COW arrays need to be copied.
5667 Handle<FixedArrayBase> elements(object->elements());
5668 bool has_elements = elements->length() > 0 &&
5669 elements->map() != isolate()->heap()->fixed_cow_array_map();
5670
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005671 // Increase the offset so that subsequent objects end up right after
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005672 // this object and its backing store.
5673 int object_offset = *offset;
5674 int object_size = object->map()->instance_size();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005675 int elements_size = has_elements ? elements->Size() : 0;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005676 int elements_offset = *offset + object_size;
5677 if (create_allocation_site_info) {
5678 elements_offset += AllocationSiteInfo::kSize;
5679 *offset += AllocationSiteInfo::kSize;
5680 }
5681
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005682 *offset += object_size + elements_size;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005683
5684 // Copy object header.
5685 ASSERT(object->properties()->length() == 0);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005686 int inobject_properties = object->map()->inobject_properties();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005687 int header_size = object_size - inobject_properties * kPointerSize;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005688 for (int i = 0; i < header_size; i += kPointerSize) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005689 if (has_elements && i == JSObject::kElementsOffset) {
5690 __ lea(ecx, Operand(result, elements_offset));
5691 } else {
5692 __ mov(ecx, FieldOperand(source, i));
5693 }
5694 __ mov(FieldOperand(result, object_offset + i), ecx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005695 }
5696
5697 // Copy in-object properties.
5698 for (int i = 0; i < inobject_properties; i++) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005699 int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005700 Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i),
5701 isolate());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005702 if (value->IsJSObject()) {
5703 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5704 __ lea(ecx, Operand(result, *offset));
5705 __ mov(FieldOperand(result, total_offset), ecx);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005706 __ LoadHeapObject(source, value_object);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005707 EmitDeepCopy(value_object, result, source, offset,
5708 DONT_TRACK_ALLOCATION_SITE);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005709 } else if (value->IsHeapObject()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005710 __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005711 __ mov(FieldOperand(result, total_offset), ecx);
5712 } else {
5713 __ mov(FieldOperand(result, total_offset), Immediate(value));
5714 }
5715 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005716
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005717 // Build Allocation Site Info if desired
5718 if (create_allocation_site_info) {
5719 __ mov(FieldOperand(result, object_size),
5720 Immediate(Handle<Map>(isolate()->heap()->
5721 allocation_site_info_map())));
5722 __ mov(FieldOperand(result, object_size + kPointerSize), source);
5723 }
5724
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005725 if (has_elements) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005726 // Copy elements backing store header.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005727 __ LoadHeapObject(source, elements);
5728 for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
5729 __ mov(ecx, FieldOperand(source, i));
5730 __ mov(FieldOperand(result, elements_offset + i), ecx);
5731 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005732
danno@chromium.org88aa0582012-03-23 15:11:57 +00005733 // Copy elements backing store content.
5734 int elements_length = elements->length();
5735 if (elements->IsFixedDoubleArray()) {
5736 Handle<FixedDoubleArray> double_array =
5737 Handle<FixedDoubleArray>::cast(elements);
5738 for (int i = 0; i < elements_length; i++) {
5739 int64_t value = double_array->get_representation(i);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00005740 int32_t value_low = static_cast<int32_t>(value & 0xFFFFFFFF);
5741 int32_t value_high = static_cast<int32_t>(value >> 32);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005742 int total_offset =
5743 elements_offset + FixedDoubleArray::OffsetOfElementAt(i);
5744 __ mov(FieldOperand(result, total_offset), Immediate(value_low));
5745 __ mov(FieldOperand(result, total_offset + 4), Immediate(value_high));
5746 }
5747 } else if (elements->IsFixedArray()) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005748 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005749 for (int i = 0; i < elements_length; i++) {
5750 int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005751 Handle<Object> value(fast_elements->get(i), isolate());
danno@chromium.org88aa0582012-03-23 15:11:57 +00005752 if (value->IsJSObject()) {
5753 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5754 __ lea(ecx, Operand(result, *offset));
5755 __ mov(FieldOperand(result, total_offset), ecx);
5756 __ LoadHeapObject(source, value_object);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005757 EmitDeepCopy(value_object, result, source, offset,
5758 DONT_TRACK_ALLOCATION_SITE);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005759 } else if (value->IsHeapObject()) {
5760 __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
5761 __ mov(FieldOperand(result, total_offset), ecx);
5762 } else {
5763 __ mov(FieldOperand(result, total_offset), Immediate(value));
5764 }
5765 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005766 } else {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005767 UNREACHABLE();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005768 }
5769 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005770}
5771
5772
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005773void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005774 ASSERT(ToRegister(instr->context()).is(esi));
5775 int size = instr->hydrogen()->total_size();
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005776 ElementsKind boilerplate_elements_kind =
5777 instr->hydrogen()->boilerplate()->GetElementsKind();
5778
5779 // Deopt if the literal boilerplate ElementsKind is of a type different than
5780 // the expected one. The check isn't necessary if the boilerplate has already
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005781 // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
5782 if (CanTransitionToMoreGeneralFastElementsKind(
5783 boilerplate_elements_kind, true)) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005784 __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
5785 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
5786 // Load the map's "bit field 2". We only need the first byte,
5787 // but the following masking takes care of that anyway.
5788 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
5789 // Retrieve elements_kind from bit field 2.
5790 __ and_(ecx, Map::kElementsKindMask);
5791 __ cmp(ecx, boilerplate_elements_kind << Map::kElementsKindShift);
5792 DeoptimizeIf(not_equal, instr->environment());
5793 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005794
5795 // Allocate all objects that are part of the literal in one big
5796 // allocation. This avoids multiple limit checks.
5797 Label allocated, runtime_allocate;
5798 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
5799 __ jmp(&allocated);
5800
5801 __ bind(&runtime_allocate);
5802 __ push(Immediate(Smi::FromInt(size)));
5803 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
5804
5805 __ bind(&allocated);
5806 int offset = 0;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005807 __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005808 EmitDeepCopy(instr->hydrogen()->boilerplate(), eax, ebx, &offset,
5809 instr->hydrogen()->allocation_site_mode());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005810 ASSERT_EQ(size, offset);
5811}
5812
5813
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005814void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005815 ASSERT(ToRegister(instr->context()).is(esi));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005816 Handle<FixedArray> literals(instr->environment()->closure()->literals());
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005817 Handle<FixedArray> constant_properties =
5818 instr->hydrogen()->constant_properties();
5819
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005820 int flags = instr->hydrogen()->fast_elements()
5821 ? ObjectLiteral::kFastElements
5822 : ObjectLiteral::kNoFlags;
5823 flags |= instr->hydrogen()->has_function()
5824 ? ObjectLiteral::kHasFunction
5825 : ObjectLiteral::kNoFlags;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005826
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005827 // Set up the parameters to the stub/runtime call and pick the right
5828 // runtime function or stub to call.
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005829 int properties_count = constant_properties->length() / 2;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005830 if (instr->hydrogen()->depth() > 1) {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005831 __ PushHeapObject(literals);
5832 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
5833 __ push(Immediate(constant_properties));
5834 __ push(Immediate(Smi::FromInt(flags)));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005835 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005836 } else if (flags != ObjectLiteral::kFastElements ||
5837 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005838 __ PushHeapObject(literals);
5839 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
5840 __ push(Immediate(constant_properties));
5841 __ push(Immediate(Smi::FromInt(flags)));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005842 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005843 } else {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005844 __ LoadHeapObject(eax, literals);
5845 __ mov(ebx, Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
5846 __ mov(ecx, Immediate(constant_properties));
5847 __ mov(edx, Immediate(Smi::FromInt(flags)));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005848 FastCloneShallowObjectStub stub(properties_count);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005849 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005850 }
5851}
5852
5853
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005854void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005855 ASSERT(ToRegister(instr->value()).is(eax));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005856 __ push(eax);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005857 CallRuntime(Runtime::kToFastProperties, 1, instr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005858}
5859
5860
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005861void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005862 ASSERT(ToRegister(instr->context()).is(esi));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005863 Label materialized;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005864 // Registers will be used as follows:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005865 // ecx = literals array.
5866 // ebx = regexp literal.
5867 // eax = regexp literal clone.
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005868 // esi = context.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005869 int literal_offset =
5870 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
5871 __ LoadHeapObject(ecx, instr->hydrogen()->literals());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005872 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005873 __ cmp(ebx, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005874 __ j(not_equal, &materialized, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005875
5876 // Create regexp literal using runtime function
5877 // Result will be in eax.
5878 __ push(ecx);
5879 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
5880 __ push(Immediate(instr->hydrogen()->pattern()));
5881 __ push(Immediate(instr->hydrogen()->flags()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005882 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005883 __ mov(ebx, eax);
5884
5885 __ bind(&materialized);
5886 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
5887 Label allocated, runtime_allocate;
5888 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
5889 __ jmp(&allocated);
5890
5891 __ bind(&runtime_allocate);
5892 __ push(ebx);
5893 __ push(Immediate(Smi::FromInt(size)));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005894 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005895 __ pop(ebx);
5896
5897 __ bind(&allocated);
5898 // Copy the content into the newly allocated memory.
5899 // (Unroll copy loop once for better throughput).
5900 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
5901 __ mov(edx, FieldOperand(ebx, i));
5902 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
5903 __ mov(FieldOperand(eax, i), edx);
5904 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
5905 }
5906 if ((size % (2 * kPointerSize)) != 0) {
5907 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
5908 __ mov(FieldOperand(eax, size - kPointerSize), edx);
5909 }
5910}
5911
5912
5913void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005914 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005915 // Use the fast case closure allocation code that allocates in new
5916 // space for nested functions that don't need literals cloning.
5917 Handle<SharedFunctionInfo> shared_info = instr->shared_info();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005918 bool pretenure = instr->hydrogen()->pretenure();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005919 if (!pretenure && shared_info->num_literals() == 0) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005920 FastNewClosureStub stub(shared_info->language_mode());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005921 __ push(Immediate(shared_info));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005922 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005923 } else {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005924 __ push(esi);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005925 __ push(Immediate(shared_info));
5926 __ push(Immediate(pretenure
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005927 ? factory()->true_value()
5928 : factory()->false_value()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005929 CallRuntime(Runtime::kNewClosure, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005930 }
5931}
5932
5933
5934void LCodeGen::DoTypeof(LTypeof* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005935 LOperand* input = instr->value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005936 EmitPushTaggedOperand(input);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005937 CallRuntime(Runtime::kTypeof, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005938}
5939
5940
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005941void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005942 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005943 int true_block = chunk_->LookupDestination(instr->true_block_id());
5944 int false_block = chunk_->LookupDestination(instr->false_block_id());
5945 Label* true_label = chunk_->GetAssemblyLabel(true_block);
5946 Label* false_label = chunk_->GetAssemblyLabel(false_block);
5947
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005948 Condition final_branch_condition =
5949 EmitTypeofIs(true_label, false_label, input, instr->type_literal());
5950 if (final_branch_condition != no_condition) {
5951 EmitBranch(true_block, false_block, final_branch_condition);
5952 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005953}
5954
5955
5956Condition LCodeGen::EmitTypeofIs(Label* true_label,
5957 Label* false_label,
5958 Register input,
5959 Handle<String> type_name) {
5960 Condition final_branch_condition = no_condition;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005961 if (type_name->Equals(heap()->number_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005962 __ JumpIfSmi(input, true_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005963 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005964 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005965 final_branch_condition = equal;
5966
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005967 } else if (type_name->Equals(heap()->string_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005968 __ JumpIfSmi(input, false_label);
5969 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
5970 __ j(above_equal, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005971 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5972 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005973 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005974
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005975 } else if (type_name->Equals(heap()->boolean_string())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005976 __ cmp(input, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005977 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005978 __ cmp(input, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005979 final_branch_condition = equal;
5980
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005981 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005982 __ cmp(input, factory()->null_value());
5983 final_branch_condition = equal;
5984
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005985 } else if (type_name->Equals(heap()->undefined_string())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005986 __ cmp(input, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005987 __ j(equal, true_label);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005988 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005989 // Check for undetectable objects => true.
5990 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
5991 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5992 1 << Map::kIsUndetectable);
5993 final_branch_condition = not_zero;
5994
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005995 } else if (type_name->Equals(heap()->function_string())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005996 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005997 __ JumpIfSmi(input, false_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005998 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
5999 __ j(equal, true_label);
6000 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
6001 final_branch_condition = equal;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006002
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006003 } else if (type_name->Equals(heap()->object_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006004 __ JumpIfSmi(input, false_label);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00006005 if (!FLAG_harmony_typeof) {
6006 __ cmp(input, factory()->null_value());
6007 __ j(equal, true_label);
6008 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006009 if (FLAG_harmony_symbols) {
6010 __ CmpObjectType(input, SYMBOL_TYPE, input);
6011 __ j(equal, true_label);
6012 __ CmpInstanceType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
6013 } else {
6014 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
6015 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006016 __ j(below, false_label);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00006017 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
6018 __ j(above, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006019 // Check for undetectable objects => false.
6020 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
6021 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006022 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006023
6024 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006025 __ jmp(false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006026 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006027 return final_branch_condition;
6028}
6029
6030
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006031void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00006032 Register temp = ToRegister(instr->temp());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006033 int true_block = chunk_->LookupDestination(instr->true_block_id());
6034 int false_block = chunk_->LookupDestination(instr->false_block_id());
6035
6036 EmitIsConstructCall(temp);
6037 EmitBranch(true_block, false_block, equal);
6038}
6039
6040
6041void LCodeGen::EmitIsConstructCall(Register temp) {
6042 // Get the frame pointer for the calling frame.
6043 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
6044
6045 // Skip the arguments adaptor frame if it exists.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00006046 Label check_frame_marker;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006047 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
6048 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00006049 __ j(not_equal, &check_frame_marker, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006050 __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
6051
6052 // Check the marker in the calling frame.
6053 __ bind(&check_frame_marker);
6054 __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
6055 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
6056}
6057
6058
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006059void LCodeGen::EnsureSpaceForLazyDeopt() {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00006060 if (!info()->IsStub()) {
6061 // Ensure that we have enough space after the previous lazy-bailout
6062 // instruction for patching the code here.
6063 int current_pc = masm()->pc_offset();
6064 int patch_size = Deoptimizer::patch_size();
6065 if (current_pc < last_lazy_deopt_pc_ + patch_size) {
6066 int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc;
6067 __ Nop(padding_size);
6068 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006069 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00006070 last_lazy_deopt_pc_ = masm()->pc_offset();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006071}
6072
6073
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006074void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006075 EnsureSpaceForLazyDeopt();
6076 ASSERT(instr->HasEnvironment());
6077 LEnvironment* env = instr->environment();
6078 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
6079 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006080}
6081
6082
6083void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
6084 DeoptimizeIf(no_condition, instr->environment());
6085}
6086
6087
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006088void LCodeGen::DoDummyUse(LDummyUse* instr) {
6089 // Nothing to see here, move on!
6090}
6091
6092
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006093void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
6094 LOperand* obj = instr->object();
6095 LOperand* key = instr->key();
6096 __ push(ToOperand(obj));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006097 EmitPushTaggedOperand(key);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00006098 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00006099 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00006100 RecordPosition(pointers->position());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006101 // Create safepoint generator that will also ensure enough space in the
6102 // reloc info for patching in deoptimization (since this is invoking a
6103 // builtin)
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006104 SafepointGenerator safepoint_generator(
6105 this, pointers, Safepoint::kLazyDeopt);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006106 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00006107 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006108}
6109
6110
ager@chromium.org04921a82011-06-27 13:21:41 +00006111void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006112 PushSafepointRegistersScope scope(this);
6113 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
6114 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
6115 RecordSafepointWithLazyDeopt(
6116 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
6117 ASSERT(instr->HasEnvironment());
6118 LEnvironment* env = instr->environment();
6119 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00006120}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006121
ager@chromium.org04921a82011-06-27 13:21:41 +00006122
6123void LCodeGen::DoStackCheck(LStackCheck* instr) {
6124 class DeferredStackCheck: public LDeferredCode {
6125 public:
6126 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
6127 : LDeferredCode(codegen), instr_(instr) { }
6128 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006129 virtual LInstruction* instr() { return instr_; }
ager@chromium.org04921a82011-06-27 13:21:41 +00006130 private:
6131 LStackCheck* instr_;
6132 };
6133
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006134 ASSERT(instr->HasEnvironment());
6135 LEnvironment* env = instr->environment();
6136 // There is no LLazyBailout instruction for stack-checks. We have to
6137 // prepare for lazy deoptimization explicitly here.
ager@chromium.org04921a82011-06-27 13:21:41 +00006138 if (instr->hydrogen()->is_function_entry()) {
6139 // Perform stack overflow check.
6140 Label done;
6141 ExternalReference stack_limit =
6142 ExternalReference::address_of_stack_limit(isolate());
6143 __ cmp(esp, Operand::StaticVariable(stack_limit));
6144 __ j(above_equal, &done, Label::kNear);
6145
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006146 ASSERT(instr->context()->IsRegister());
6147 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org04921a82011-06-27 13:21:41 +00006148 StackCheckStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00006149 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006150 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00006151 __ bind(&done);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006152 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
6153 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00006154 } else {
6155 ASSERT(instr->hydrogen()->is_backwards_branch());
6156 // Perform stack overflow check if this goto needs it before jumping.
6157 DeferredStackCheck* deferred_stack_check =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00006158 new(zone()) DeferredStackCheck(this, instr);
ager@chromium.org04921a82011-06-27 13:21:41 +00006159 ExternalReference stack_limit =
6160 ExternalReference::address_of_stack_limit(isolate());
6161 __ cmp(esp, Operand::StaticVariable(stack_limit));
6162 __ j(below, deferred_stack_check->entry());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006163 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00006164 __ bind(instr->done_label());
6165 deferred_stack_check->SetExit(instr->done_label());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006166 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
6167 // Don't record a deoptimization index for the safepoint here.
6168 // This will be done explicitly when emitting call and the safepoint in
6169 // the deferred code.
ager@chromium.org04921a82011-06-27 13:21:41 +00006170 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006171}
6172
6173
6174void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
6175 // This is a pseudo-instruction that ensures that the environment here is
6176 // properly registered for deoptimization and records the assembler's PC
6177 // offset.
6178 LEnvironment* environment = instr->environment();
6179 environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
6180 instr->SpilledDoubleRegisterArray());
6181
6182 // If the environment were already registered, we would have no way of
6183 // backpatching it with the spill slot operands.
6184 ASSERT(!environment->HasBeenRegistered());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006185 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006186 ASSERT(osr_pc_offset_ == -1);
6187 osr_pc_offset_ = masm()->pc_offset();
6188}
6189
6190
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006191void LCodeGen::DoIn(LIn* instr) {
6192 LOperand* obj = instr->object();
6193 LOperand* key = instr->key();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006194 EmitPushTaggedOperand(key);
6195 EmitPushTaggedOperand(obj);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00006196 ASSERT(instr->HasPointerMap());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006197 LPointerMap* pointers = instr->pointer_map();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006198 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006199 SafepointGenerator safepoint_generator(
6200 this, pointers, Safepoint::kLazyDeopt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00006201 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006202}
6203
6204
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006205void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
6206 __ cmp(eax, isolate()->factory()->undefined_value());
6207 DeoptimizeIf(equal, instr->environment());
6208
6209 __ cmp(eax, isolate()->factory()->null_value());
6210 DeoptimizeIf(equal, instr->environment());
6211
6212 __ test(eax, Immediate(kSmiTagMask));
6213 DeoptimizeIf(zero, instr->environment());
6214
6215 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
6216 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
6217 DeoptimizeIf(below_equal, instr->environment());
6218
6219 Label use_cache, call_runtime;
6220 __ CheckEnumCache(&call_runtime);
6221
6222 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
6223 __ jmp(&use_cache, Label::kNear);
6224
6225 // Get the set of properties to enumerate.
6226 __ bind(&call_runtime);
6227 __ push(eax);
6228 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
6229
6230 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
6231 isolate()->factory()->meta_map());
6232 DeoptimizeIf(not_equal, instr->environment());
6233 __ bind(&use_cache);
6234}
6235
6236
6237void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
6238 Register map = ToRegister(instr->map());
6239 Register result = ToRegister(instr->result());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00006240 Label load_cache, done;
6241 __ EnumLength(result, map);
6242 __ cmp(result, Immediate(Smi::FromInt(0)));
6243 __ j(not_equal, &load_cache);
6244 __ mov(result, isolate()->factory()->empty_fixed_array());
6245 __ jmp(&done);
6246
6247 __ bind(&load_cache);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006248 __ LoadInstanceDescriptors(map, result);
6249 __ mov(result,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006250 FieldOperand(result, DescriptorArray::kEnumCacheOffset));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006251 __ mov(result,
6252 FieldOperand(result, FixedArray::SizeFor(instr->idx())));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00006253 __ bind(&done);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006254 __ test(result, result);
6255 DeoptimizeIf(equal, instr->environment());
6256}
6257
6258
6259void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
6260 Register object = ToRegister(instr->value());
6261 __ cmp(ToRegister(instr->map()),
6262 FieldOperand(object, HeapObject::kMapOffset));
6263 DeoptimizeIf(not_equal, instr->environment());
6264}
6265
6266
6267void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
6268 Register object = ToRegister(instr->object());
6269 Register index = ToRegister(instr->index());
6270
6271 Label out_of_object, done;
6272 __ cmp(index, Immediate(0));
6273 __ j(less, &out_of_object);
6274 __ mov(object, FieldOperand(object,
6275 index,
6276 times_half_pointer_size,
6277 JSObject::kHeaderSize));
6278 __ jmp(&done, Label::kNear);
6279
6280 __ bind(&out_of_object);
6281 __ mov(object, FieldOperand(object, JSObject::kPropertiesOffset));
6282 __ neg(index);
6283 // Index is now equal to out of object property index plus 1.
6284 __ mov(object, FieldOperand(object,
6285 index,
6286 times_half_pointer_size,
6287 FixedArray::kHeaderSize - kPointerSize));
6288 __ bind(&done);
6289}
6290
6291
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006292#undef __
6293
6294} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006295
6296#endif // V8_TARGET_ARCH_IA32