blob: 0cd5f1fce9e31fe24a7e7f8ddc85069365ee06e0 [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
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004198void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
4199 Register result = ToRegister(instr->result());
4200 Register base = ToRegister(instr->base_object());
4201 __ lea(result, Operand(base, instr->offset()));
4202}
4203
4204
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004205void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
4206 Register object = ToRegister(instr->object());
4207 Register value = ToRegister(instr->value());
4208 int offset = instr->offset();
4209
4210 if (!instr->transition().is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +00004211 if (!instr->hydrogen()->NeedsWriteBarrierForMap()) {
4212 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition());
4213 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004214 Register temp = ToRegister(instr->temp());
4215 Register temp_map = ToRegister(instr->temp_map());
verwaest@chromium.org37141392012-05-31 13:27:02 +00004216 __ mov(temp_map, instr->transition());
4217 __ mov(FieldOperand(object, HeapObject::kMapOffset), temp_map);
4218 // Update the write barrier for the map field.
4219 __ RecordWriteField(object,
4220 HeapObject::kMapOffset,
4221 temp_map,
4222 temp,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004223 GetSaveFPRegsMode(),
verwaest@chromium.org37141392012-05-31 13:27:02 +00004224 OMIT_REMEMBERED_SET,
4225 OMIT_SMI_CHECK);
4226 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004227 }
4228
4229 // Do the store.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004230 HType type = instr->hydrogen()->value()->type();
4231 SmiCheck check_needed =
4232 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004233 if (instr->is_in_object()) {
4234 __ mov(FieldOperand(object, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004235 if (instr->hydrogen()->NeedsWriteBarrier()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004236 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004237 // Update the write barrier for the object for in-object properties.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004238 __ RecordWriteField(object,
4239 offset,
4240 value,
4241 temp,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004242 GetSaveFPRegsMode(),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004243 EMIT_REMEMBERED_SET,
4244 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004245 }
4246 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004247 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004248 __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset));
4249 __ mov(FieldOperand(temp, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004250 if (instr->hydrogen()->NeedsWriteBarrier()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004251 // Update the write barrier for the properties array.
4252 // object is used as a scratch register.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004253 __ RecordWriteField(temp,
4254 offset,
4255 value,
4256 object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004257 GetSaveFPRegsMode(),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004258 EMIT_REMEMBERED_SET,
4259 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004260 }
4261 }
4262}
4263
4264
4265void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004266 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004267 ASSERT(ToRegister(instr->object()).is(edx));
4268 ASSERT(ToRegister(instr->value()).is(eax));
4269
4270 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004271 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004272 ? isolate()->builtins()->StoreIC_Initialize_Strict()
4273 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004274 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004275}
4276
4277
4278void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004279 if (instr->hydrogen()->skip_check()) return;
4280
danno@chromium.orgb6451162011-08-17 14:33:23 +00004281 if (instr->index()->IsConstantOperand()) {
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004282 int constant_index =
4283 ToInteger32(LConstantOperand::cast(instr->index()));
4284 if (instr->hydrogen()->length()->representation().IsTagged()) {
4285 __ cmp(ToOperand(instr->length()),
4286 Immediate(Smi::FromInt(constant_index)));
4287 } else {
4288 __ cmp(ToOperand(instr->length()), Immediate(constant_index));
4289 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00004290 DeoptimizeIf(below_equal, instr->environment());
4291 } else {
4292 __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
4293 DeoptimizeIf(above_equal, instr->environment());
4294 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004295}
4296
4297
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004298void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004299 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004300 LOperand* key = instr->key();
4301 if (!key->IsConstantOperand() &&
4302 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
4303 elements_kind)) {
4304 __ SmiUntag(ToRegister(key));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004305 }
4306 Operand operand(BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004307 instr->elements(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004308 key,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004309 instr->hydrogen()->key()->representation(),
4310 elements_kind,
4311 0,
4312 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004313 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004314 CpuFeatureScope scope(masm(), SSE2);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004315 __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004316 __ movss(operand, xmm0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004317 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004318 CpuFeatureScope scope(masm(), SSE2);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004319 __ movdbl(operand, ToDoubleRegister(instr->value()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004320 } else {
4321 Register value = ToRegister(instr->value());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004322 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004323 case EXTERNAL_PIXEL_ELEMENTS:
4324 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4325 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004326 __ mov_b(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004327 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004328 case EXTERNAL_SHORT_ELEMENTS:
4329 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004330 __ mov_w(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004331 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004332 case EXTERNAL_INT_ELEMENTS:
4333 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004334 __ mov(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004335 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004336 case EXTERNAL_FLOAT_ELEMENTS:
4337 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004338 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004339 case FAST_ELEMENTS:
4340 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004341 case FAST_HOLEY_SMI_ELEMENTS:
4342 case FAST_HOLEY_ELEMENTS:
4343 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004344 case DICTIONARY_ELEMENTS:
4345 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004346 UNREACHABLE();
4347 break;
4348 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004349 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004350}
4351
4352
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004353void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004354 CpuFeatureScope scope(masm(), SSE2);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004355 XMMRegister value = ToDoubleRegister(instr->value());
4356
4357 if (instr->NeedsCanonicalization()) {
4358 Label have_value;
4359
4360 __ ucomisd(value, value);
4361 __ j(parity_odd, &have_value); // NaN.
4362
4363 ExternalReference canonical_nan_reference =
4364 ExternalReference::address_of_canonical_non_hole_nan();
4365 __ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
4366 __ bind(&have_value);
4367 }
4368
4369 Operand double_store_operand = BuildFastArrayOperand(
4370 instr->elements(),
4371 instr->key(),
4372 instr->hydrogen()->key()->representation(),
4373 FAST_DOUBLE_ELEMENTS,
4374 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
4375 instr->additional_index());
4376 __ movdbl(double_store_operand, value);
4377}
4378
4379
4380void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004381 Register value = ToRegister(instr->value());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004382 Register elements = ToRegister(instr->elements());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004383 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
4384
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004385 Operand operand = BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004386 instr->elements(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004387 instr->key(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004388 instr->hydrogen()->key()->representation(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004389 FAST_ELEMENTS,
4390 FixedArray::kHeaderSize - kHeapObjectTag,
4391 instr->additional_index());
4392 __ mov(operand, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004393
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004394 if (instr->hydrogen()->NeedsWriteBarrier()) {
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004395 ASSERT(!instr->key()->IsConstantOperand());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004396 HType type = instr->hydrogen()->value()->type();
4397 SmiCheck check_needed =
4398 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004399 // Compute address of modified element and store it into key register.
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004400 __ lea(key, operand);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004401 __ RecordWrite(elements,
4402 key,
4403 value,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004404 GetSaveFPRegsMode(),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004405 EMIT_REMEMBERED_SET,
4406 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004407 }
4408}
4409
4410
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004411void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
4412 // By cases...external, fast-double, fast
4413 if (instr->is_external()) {
4414 DoStoreKeyedExternalArray(instr);
4415 } else if (instr->hydrogen()->value()->representation().IsDouble()) {
4416 DoStoreKeyedFixedDoubleArray(instr);
4417 } else {
4418 DoStoreKeyedFixedArray(instr);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004419 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004420}
4421
4422
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004423void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004424 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004425 ASSERT(ToRegister(instr->object()).is(edx));
4426 ASSERT(ToRegister(instr->key()).is(ecx));
4427 ASSERT(ToRegister(instr->value()).is(eax));
4428
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004429 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004430 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
4431 : isolate()->builtins()->KeyedStoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004432 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004433}
4434
4435
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004436void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
4437 Register object = ToRegister(instr->object());
4438 Register temp = ToRegister(instr->temp());
4439 __ TestJSArrayForAllocationSiteInfo(object, temp);
4440 DeoptimizeIf(equal, instr->environment());
4441}
4442
4443
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004444void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
4445 Register object_reg = ToRegister(instr->object());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004446
4447 Handle<Map> from_map = instr->original_map();
4448 Handle<Map> to_map = instr->transitioned_map();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00004449 ElementsKind from_kind = instr->from_kind();
4450 ElementsKind to_kind = instr->to_kind();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004451
4452 Label not_applicable;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004453 bool is_simple_map_transition =
4454 IsSimpleMapChangeTransition(from_kind, to_kind);
4455 Label::Distance branch_distance =
4456 is_simple_map_transition ? Label::kNear : Label::kFar;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004457 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004458 __ j(not_equal, &not_applicable, branch_distance);
4459 if (is_simple_map_transition) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004460 Register new_map_reg = ToRegister(instr->new_map_temp());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004461 Handle<Map> map = instr->hydrogen()->transitioned_map();
4462 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset),
4463 Immediate(map));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004464 // Write barrier.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004465 ASSERT_NE(instr->temp(), NULL);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004466 __ RecordWriteForMap(object_reg, to_map, new_map_reg,
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004467 ToRegister(instr->temp()),
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004468 kDontSaveFPRegs);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004469 } else if (FLAG_compiled_transitions) {
4470 PushSafepointRegistersScope scope(this);
4471 if (!object_reg.is(eax)) {
4472 __ push(object_reg);
4473 }
4474 LoadContextFromDeferred(instr->context());
4475 if (!object_reg.is(eax)) {
4476 __ pop(eax);
4477 }
4478 __ mov(ebx, to_map);
4479 TransitionElementsKindStub stub(from_kind, to_kind);
4480 __ CallStub(&stub);
4481 RecordSafepointWithRegisters(
4482 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004483 } else if (IsFastSmiElementsKind(from_kind) &&
4484 IsFastDoubleElementsKind(to_kind)) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004485 Register new_map_reg = ToRegister(instr->new_map_temp());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004486 __ mov(new_map_reg, to_map);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004487 Register fixed_object_reg = ToRegister(instr->temp());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004488 ASSERT(fixed_object_reg.is(edx));
4489 ASSERT(new_map_reg.is(ebx));
4490 __ mov(fixed_object_reg, object_reg);
4491 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
4492 RelocInfo::CODE_TARGET, instr);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004493 } else if (IsFastDoubleElementsKind(from_kind) &&
4494 IsFastObjectElementsKind(to_kind)) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004495 Register new_map_reg = ToRegister(instr->new_map_temp());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004496 __ mov(new_map_reg, to_map);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004497 Register fixed_object_reg = ToRegister(instr->temp());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004498 ASSERT(fixed_object_reg.is(edx));
4499 ASSERT(new_map_reg.is(ebx));
4500 __ mov(fixed_object_reg, object_reg);
4501 CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
4502 RelocInfo::CODE_TARGET, instr);
4503 } else {
4504 UNREACHABLE();
4505 }
4506 __ bind(&not_applicable);
4507}
4508
4509
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004510void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
4511 class DeferredStringCharCodeAt: public LDeferredCode {
4512 public:
4513 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
4514 : LDeferredCode(codegen), instr_(instr) { }
4515 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004516 virtual LInstruction* instr() { return instr_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004517 private:
4518 LStringCharCodeAt* instr_;
4519 };
4520
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004521 DeferredStringCharCodeAt* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004522 new(zone()) DeferredStringCharCodeAt(this, instr);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004523
erikcorry0ad885c2011-11-21 13:51:57 +00004524 StringCharLoadGenerator::Generate(masm(),
4525 factory(),
4526 ToRegister(instr->string()),
4527 ToRegister(instr->index()),
4528 ToRegister(instr->result()),
4529 deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004530 __ bind(deferred->exit());
4531}
4532
4533
4534void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
4535 Register string = ToRegister(instr->string());
4536 Register result = ToRegister(instr->result());
4537
4538 // TODO(3095996): Get rid of this. For now, we need to make the
4539 // result register contain a valid pointer because it is already
4540 // contained in the register pointer map.
4541 __ Set(result, Immediate(0));
4542
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004543 PushSafepointRegistersScope scope(this);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004544 __ push(string);
4545 // Push the index as a smi. This is safe because of the checks in
4546 // DoStringCharCodeAt above.
4547 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
4548 if (instr->index()->IsConstantOperand()) {
4549 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
4550 __ push(Immediate(Smi::FromInt(const_index)));
4551 } else {
4552 Register index = ToRegister(instr->index());
4553 __ SmiTag(index);
4554 __ push(index);
4555 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004556 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2,
4557 instr, instr->context());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004558 __ AssertSmi(eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004559 __ SmiUntag(eax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004560 __ StoreToSafepointRegisterSlot(result, eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004561}
4562
4563
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004564void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
4565 class DeferredStringCharFromCode: public LDeferredCode {
4566 public:
4567 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
4568 : LDeferredCode(codegen), instr_(instr) { }
4569 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004570 virtual LInstruction* instr() { return instr_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004571 private:
4572 LStringCharFromCode* instr_;
4573 };
4574
4575 DeferredStringCharFromCode* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004576 new(zone()) DeferredStringCharFromCode(this, instr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004577
4578 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
4579 Register char_code = ToRegister(instr->char_code());
4580 Register result = ToRegister(instr->result());
4581 ASSERT(!char_code.is(result));
4582
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004583 __ cmp(char_code, String::kMaxOneByteCharCode);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004584 __ j(above, deferred->entry());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004585 __ Set(result, Immediate(factory()->single_character_string_cache()));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004586 __ mov(result, FieldOperand(result,
4587 char_code, times_pointer_size,
4588 FixedArray::kHeaderSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004589 __ cmp(result, factory()->undefined_value());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004590 __ j(equal, deferred->entry());
4591 __ bind(deferred->exit());
4592}
4593
4594
4595void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4596 Register char_code = ToRegister(instr->char_code());
4597 Register result = ToRegister(instr->result());
4598
4599 // TODO(3095996): Get rid of this. For now, we need to make the
4600 // result register contain a valid pointer because it is already
4601 // contained in the register pointer map.
4602 __ Set(result, Immediate(0));
4603
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004604 PushSafepointRegistersScope scope(this);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004605 __ SmiTag(char_code);
4606 __ push(char_code);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004607 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004608 __ StoreToSafepointRegisterSlot(result, eax);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004609}
4610
4611
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004612void LCodeGen::DoStringLength(LStringLength* instr) {
4613 Register string = ToRegister(instr->string());
4614 Register result = ToRegister(instr->result());
4615 __ mov(result, FieldOperand(string, String::kLengthOffset));
4616}
4617
4618
danno@chromium.org160a7b02011-04-18 15:51:38 +00004619void LCodeGen::DoStringAdd(LStringAdd* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004620 EmitPushTaggedOperand(instr->left());
4621 EmitPushTaggedOperand(instr->right());
danno@chromium.org160a7b02011-04-18 15:51:38 +00004622 StringAddStub stub(NO_STRING_CHECK_IN_STUB);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004623 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
danno@chromium.org160a7b02011-04-18 15:51:38 +00004624}
4625
4626
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004627void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004628 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004629 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004630 LOperand* input = instr->value();
4631 ASSERT(input->IsRegister() || input->IsStackSlot());
4632 LOperand* output = instr->result();
4633 ASSERT(output->IsDoubleRegister());
4634 __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
4635 } else {
4636 UNREACHABLE();
4637 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004638}
4639
4640
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004641void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004642 CpuFeatureScope scope(masm(), SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004643 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004644 LOperand* output = instr->result();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004645 LOperand* temp = instr->temp();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004646
4647 __ LoadUint32(ToDoubleRegister(output),
4648 ToRegister(input),
4649 ToDoubleRegister(temp));
4650}
4651
4652
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004653void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
4654 class DeferredNumberTagI: public LDeferredCode {
4655 public:
4656 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
4657 : LDeferredCode(codegen), instr_(instr) { }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004658 virtual void Generate() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004659 codegen()->DoDeferredNumberTagI(instr_, instr_->value(), SIGNED_INT32);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004660 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004661 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004662 private:
4663 LNumberTagI* instr_;
4664 };
4665
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004666 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004667 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4668 Register reg = ToRegister(input);
4669
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004670 DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004671 __ SmiTag(reg);
4672 __ j(overflow, deferred->entry());
4673 __ bind(deferred->exit());
4674}
4675
4676
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004677void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
4678 class DeferredNumberTagU: public LDeferredCode {
4679 public:
4680 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
4681 : LDeferredCode(codegen), instr_(instr) { }
4682 virtual void Generate() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004683 codegen()->DoDeferredNumberTagI(instr_, instr_->value(), UNSIGNED_INT32);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004684 }
4685 virtual LInstruction* instr() { return instr_; }
4686 private:
4687 LNumberTagU* instr_;
4688 };
4689
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004690 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004691 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4692 Register reg = ToRegister(input);
4693
4694 DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
4695 __ cmp(reg, Immediate(Smi::kMaxValue));
4696 __ j(above, deferred->entry());
4697 __ SmiTag(reg);
4698 __ bind(deferred->exit());
4699}
4700
4701
4702void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
4703 LOperand* value,
4704 IntegerSignedness signedness) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004705 Label slow;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004706 Register reg = ToRegister(value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004707 Register tmp = reg.is(eax) ? ecx : eax;
4708
4709 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004710 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004711
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004712 Label done;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004713
4714 if (signedness == SIGNED_INT32) {
4715 // There was overflow, so bits 30 and 31 of the original integer
4716 // disagree. Try to allocate a heap number in new space and store
4717 // the value in there. If that fails, call the runtime system.
4718 __ SmiUntag(reg);
4719 __ xor_(reg, 0x80000000);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004720 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004721 CpuFeatureScope feature_scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004722 __ cvtsi2sd(xmm0, Operand(reg));
4723 } else {
4724 __ push(reg);
4725 __ fild_s(Operand(esp, 0));
4726 __ pop(reg);
4727 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004728 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004729 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004730 CpuFeatureScope feature_scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004731 __ LoadUint32(xmm0, reg, xmm1);
4732 } else {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00004733 // There's no fild variant for unsigned values, so zero-extend to a 64-bit
4734 // int manually.
4735 __ push(Immediate(0));
4736 __ push(reg);
4737 __ fild_d(Operand(esp, 0));
4738 __ pop(reg);
4739 __ pop(reg);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004740 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004741 }
4742
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004743 if (FLAG_inline_new) {
4744 __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004745 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004746 }
4747
4748 // Slow case: Call the runtime system to do the number allocation.
4749 __ bind(&slow);
4750
4751 // TODO(3095996): Put a valid pointer value in the stack slot where the result
4752 // register is stored, as this register is in the pointer map, but contains an
4753 // integer value.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004754 __ StoreToSafepointRegisterSlot(reg, Immediate(0));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004755 // NumberTagI and NumberTagD use the context from the frame, rather than
4756 // the environment's HContext or HInlinedContext value.
4757 // They only call Runtime::kAllocateHeapNumber.
4758 // The corresponding HChange instructions are added in a phase that does
4759 // not have easy access to the local context.
4760 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4761 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4762 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004763 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004764 if (!reg.is(eax)) __ mov(reg, eax);
4765
4766 // Done. Put the value in xmm0 into the value of the allocated heap
4767 // number.
4768 __ bind(&done);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004769 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004770 CpuFeatureScope feature_scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004771 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0);
4772 } else {
4773 __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
4774 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004775 __ StoreToSafepointRegisterSlot(reg, reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004776}
4777
4778
4779void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
4780 class DeferredNumberTagD: public LDeferredCode {
4781 public:
4782 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
4783 : LDeferredCode(codegen), instr_(instr) { }
4784 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004785 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004786 private:
4787 LNumberTagD* instr_;
4788 };
4789
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004790 Register reg = ToRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004791
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004792 bool convert_hole = false;
4793 HValue* change_input = instr->hydrogen()->value();
4794 if (change_input->IsLoadKeyed()) {
4795 HLoadKeyed* load = HLoadKeyed::cast(change_input);
4796 convert_hole = load->UsesMustHandleHole();
4797 }
4798
4799 Label no_special_nan_handling;
4800 Label done;
4801 if (convert_hole) {
4802 bool use_sse2 = CpuFeatures::IsSupported(SSE2);
4803 if (use_sse2) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004804 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004805 XMMRegister input_reg = ToDoubleRegister(instr->value());
4806 __ ucomisd(input_reg, input_reg);
4807 } else {
4808 if (!IsX87TopOfStack(instr->value())) {
4809 __ fld_d(ToOperand(instr->value()));
4810 }
4811 __ fld(0);
4812 __ fld(0);
4813 __ FCmp();
4814 }
4815
4816 __ j(parity_odd, &no_special_nan_handling);
4817 __ sub(esp, Immediate(kDoubleSize));
4818 if (use_sse2) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004819 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004820 XMMRegister input_reg = ToDoubleRegister(instr->value());
4821 __ movdbl(MemOperand(esp, 0), input_reg);
4822 } else {
4823 __ fld(0);
4824 __ fstp_d(MemOperand(esp, 0));
4825 }
4826 __ cmp(MemOperand(esp, sizeof(kHoleNanLower32)),
4827 Immediate(kHoleNanUpper32));
4828 Label canonicalize;
4829 __ j(not_equal, &canonicalize);
4830 __ add(esp, Immediate(kDoubleSize));
4831 __ mov(reg, factory()->the_hole_value());
4832 __ jmp(&done);
4833 __ bind(&canonicalize);
4834 __ add(esp, Immediate(kDoubleSize));
4835 ExternalReference nan =
4836 ExternalReference::address_of_canonical_non_hole_nan();
4837 if (use_sse2) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004838 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004839 XMMRegister input_reg = ToDoubleRegister(instr->value());
4840 __ movdbl(input_reg, Operand::StaticVariable(nan));
4841 } else {
4842 __ fstp(0);
4843 __ fld_d(Operand::StaticVariable(nan));
4844 }
4845 }
4846
4847 __ bind(&no_special_nan_handling);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004848 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004849 if (FLAG_inline_new) {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00004850 Register tmp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004851 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
4852 } else {
4853 __ jmp(deferred->entry());
4854 }
4855 __ bind(deferred->exit());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004856 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004857 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004858 XMMRegister input_reg = ToDoubleRegister(instr->value());
4859 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
4860 } else {
4861 if (!IsX87TopOfStack(instr->value())) {
4862 __ fld_d(ToOperand(instr->value()));
4863 }
4864 __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
4865 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004866 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004867}
4868
4869
4870void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
4871 // TODO(3095996): Get rid of this. For now, we need to make the
4872 // result register contain a valid pointer because it is already
4873 // contained in the register pointer map.
4874 Register reg = ToRegister(instr->result());
4875 __ Set(reg, Immediate(0));
4876
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004877 PushSafepointRegistersScope scope(this);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004878 // NumberTagI and NumberTagD use the context from the frame, rather than
4879 // the environment's HContext or HInlinedContext value.
4880 // They only call Runtime::kAllocateHeapNumber.
4881 // The corresponding HChange instructions are added in a phase that does
4882 // not have easy access to the local context.
4883 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4884 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004885 RecordSafepointWithRegisters(
4886 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004887 __ StoreToSafepointRegisterSlot(reg, eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004888}
4889
4890
4891void LCodeGen::DoSmiTag(LSmiTag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004892 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004893 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4894 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
4895 __ SmiTag(ToRegister(input));
4896}
4897
4898
4899void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004900 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004901 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4902 if (instr->needs_check()) {
4903 __ test(ToRegister(input), Immediate(kSmiTagMask));
4904 DeoptimizeIf(not_zero, instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004905 } else {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004906 __ AssertSmi(ToRegister(input));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004907 }
4908 __ SmiUntag(ToRegister(input));
4909}
4910
4911
4912void LCodeGen::EmitNumberUntagD(Register input_reg,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004913 Register temp_reg,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004914 XMMRegister result_reg,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004915 bool deoptimize_on_undefined,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004916 bool deoptimize_on_minus_zero,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004917 LEnvironment* env,
4918 NumberUntagDMode mode) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004919 Label load_smi, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004920
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004921 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
4922 // Smi check.
4923 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004924
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004925 // Heap number map check.
4926 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
4927 factory()->heap_number_map());
4928 if (deoptimize_on_undefined) {
4929 DeoptimizeIf(not_equal, env);
4930 } else {
4931 Label heap_number;
4932 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004933
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004934 __ cmp(input_reg, factory()->undefined_value());
4935 DeoptimizeIf(not_equal, env);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004936
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004937 // Convert undefined to NaN.
4938 ExternalReference nan =
4939 ExternalReference::address_of_canonical_non_hole_nan();
4940 __ movdbl(result_reg, Operand::StaticVariable(nan));
4941 __ jmp(&done, Label::kNear);
4942
4943 __ bind(&heap_number);
4944 }
4945 // Heap number to XMM conversion.
4946 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
4947 if (deoptimize_on_minus_zero) {
4948 XMMRegister xmm_scratch = xmm0;
4949 __ xorps(xmm_scratch, xmm_scratch);
4950 __ ucomisd(result_reg, xmm_scratch);
4951 __ j(not_zero, &done, Label::kNear);
4952 __ movmskpd(temp_reg, result_reg);
4953 __ test_b(temp_reg, 1);
4954 DeoptimizeIf(not_zero, env);
4955 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004956 __ jmp(&done, Label::kNear);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004957 } else if (mode == NUMBER_CANDIDATE_IS_SMI_OR_HOLE) {
4958 __ test(input_reg, Immediate(kSmiTagMask));
4959 DeoptimizeIf(not_equal, env);
4960 } else if (mode == NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE) {
4961 __ test(input_reg, Immediate(kSmiTagMask));
4962 __ j(zero, &load_smi);
4963 ExternalReference hole_nan_reference =
4964 ExternalReference::address_of_the_hole_nan();
4965 __ movdbl(result_reg, Operand::StaticVariable(hole_nan_reference));
4966 __ jmp(&done, Label::kNear);
4967 } else {
4968 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004969 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004970
4971 // Smi to XMM conversion
4972 __ bind(&load_smi);
4973 __ SmiUntag(input_reg); // Untag smi before converting to float.
4974 __ cvtsi2sd(result_reg, Operand(input_reg));
4975 __ SmiTag(input_reg); // Retag smi.
4976 __ bind(&done);
4977}
4978
4979
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004980void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004981 Label done, heap_number;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004982 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004983
4984 // Heap number map check.
4985 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004986 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004987
4988 if (instr->truncating()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004989 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004990 // Check for undefined. Undefined is converted to zero for truncating
4991 // conversions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004992 __ cmp(input_reg, factory()->undefined_value());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004993 __ RecordComment("Deferred TaggedToI: cannot truncate");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004994 DeoptimizeIf(not_equal, instr->environment());
4995 __ mov(input_reg, 0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004996 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004997
4998 __ bind(&heap_number);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004999 if (CpuFeatures::IsSupported(SSE3)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005000 CpuFeatureScope scope(masm(), SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005001 Label convert;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005002 // Use more powerful conversion when sse3 is available.
5003 // Load x87 register with heap number.
5004 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
5005 // Get exponent alone and check for too-big exponent.
5006 __ mov(input_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
5007 __ and_(input_reg, HeapNumber::kExponentMask);
5008 const uint32_t kTooBigExponent =
5009 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
5010 __ cmp(Operand(input_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005011 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005012 // Pop FPU stack before deoptimizing.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005013 __ fstp(0);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005014 __ RecordComment("Deferred TaggedToI: exponent too big");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005015 DeoptimizeIf(no_condition, instr->environment());
5016
5017 // Reserve space for 64 bit answer.
5018 __ bind(&convert);
5019 __ sub(Operand(esp), Immediate(kDoubleSize));
5020 // Do conversion, which cannot fail because we checked the exponent.
5021 __ fisttp_d(Operand(esp, 0));
5022 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result.
5023 __ add(Operand(esp), Immediate(kDoubleSize));
5024 } else {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005025 CpuFeatureScope scope(masm(), SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005026 XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005027 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
5028 __ cvttsd2si(input_reg, Operand(xmm0));
5029 __ cmp(input_reg, 0x80000000u);
5030 __ j(not_equal, &done);
5031 // Check if the input was 0x8000000 (kMinInt).
5032 // If no, then we got an overflow and we deoptimize.
5033 ExternalReference min_int = ExternalReference::address_of_min_int();
5034 __ movdbl(xmm_temp, Operand::StaticVariable(min_int));
5035 __ ucomisd(xmm_temp, xmm0);
5036 DeoptimizeIf(not_equal, instr->environment());
5037 DeoptimizeIf(parity_even, instr->environment()); // NaN.
5038 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005039 } else if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005040 CpuFeatureScope scope(masm(), SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005041 // Deoptimize if we don't have a heap number.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005042 __ RecordComment("Deferred TaggedToI: not a heap number");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005043 DeoptimizeIf(not_equal, instr->environment());
5044
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005045 XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005046 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
5047 __ cvttsd2si(input_reg, Operand(xmm0));
5048 __ cvtsi2sd(xmm_temp, Operand(input_reg));
5049 __ ucomisd(xmm0, xmm_temp);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005050 __ RecordComment("Deferred TaggedToI: lost precision");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005051 DeoptimizeIf(not_equal, instr->environment());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005052 __ RecordComment("Deferred TaggedToI: NaN");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005053 DeoptimizeIf(parity_even, instr->environment()); // NaN.
5054 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
5055 __ test(input_reg, Operand(input_reg));
5056 __ j(not_zero, &done);
5057 __ movmskpd(input_reg, xmm0);
5058 __ and_(input_reg, 1);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005059 __ RecordComment("Deferred TaggedToI: minus zero");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005060 DeoptimizeIf(not_zero, instr->environment());
5061 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005062 } else {
5063 UNREACHABLE();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005064 }
5065 __ bind(&done);
5066}
5067
5068
5069void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005070 class DeferredTaggedToI: public LDeferredCode {
5071 public:
5072 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
5073 : LDeferredCode(codegen), instr_(instr) { }
5074 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
5075 virtual LInstruction* instr() { return instr_; }
5076 private:
5077 LTaggedToI* instr_;
5078 };
5079
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005080 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005081 ASSERT(input->IsRegister());
5082 ASSERT(input->Equals(instr->result()));
5083
5084 Register input_reg = ToRegister(input);
5085
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005086 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005087
5088 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00005089 __ JumpIfNotSmi(input_reg, deferred->entry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005090
5091 // Smi to int32 conversion
5092 __ SmiUntag(input_reg); // Untag smi.
5093
5094 __ bind(deferred->exit());
5095}
5096
5097
5098void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005099 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005100 ASSERT(input->IsRegister());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005101 LOperand* temp = instr->temp();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005102 ASSERT(temp == NULL || temp->IsRegister());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005103 LOperand* result = instr->result();
5104 ASSERT(result->IsDoubleRegister());
5105
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005106 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005107 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005108 Register input_reg = ToRegister(input);
5109 XMMRegister result_reg = ToDoubleRegister(result);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005110
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005111 bool deoptimize_on_minus_zero =
5112 instr->hydrogen()->deoptimize_on_minus_zero();
5113 Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005114
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005115 NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED;
5116 HValue* value = instr->hydrogen()->value();
5117 if (value->type().IsSmi()) {
5118 if (value->IsLoadKeyed()) {
5119 HLoadKeyed* load = HLoadKeyed::cast(value);
5120 if (load->UsesMustHandleHole()) {
5121 if (load->hole_mode() == ALLOW_RETURN_HOLE) {
5122 mode = NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE;
5123 } else {
5124 mode = NUMBER_CANDIDATE_IS_SMI_OR_HOLE;
5125 }
5126 } else {
5127 mode = NUMBER_CANDIDATE_IS_SMI;
5128 }
5129 }
5130 }
5131
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005132 EmitNumberUntagD(input_reg,
5133 temp_reg,
5134 result_reg,
5135 instr->hydrogen()->deoptimize_on_undefined(),
5136 deoptimize_on_minus_zero,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005137 instr->environment(),
5138 mode);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005139 } else {
5140 UNIMPLEMENTED();
5141 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005142}
5143
5144
5145void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005146 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005147 ASSERT(input->IsDoubleRegister());
5148 LOperand* result = instr->result();
5149 ASSERT(result->IsRegister());
ulan@chromium.org750145a2013-03-07 15:14:13 +00005150 CpuFeatureScope scope(masm(), SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005151
5152 XMMRegister input_reg = ToDoubleRegister(input);
5153 Register result_reg = ToRegister(result);
5154
5155 if (instr->truncating()) {
5156 // Performs a truncating conversion of a floating point number as used by
5157 // the JS bitwise operations.
5158 __ cvttsd2si(result_reg, Operand(input_reg));
5159 __ cmp(result_reg, 0x80000000u);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005160 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005161 // This will deoptimize if the exponent of the input in out of range.
ulan@chromium.org750145a2013-03-07 15:14:13 +00005162 CpuFeatureScope scope(masm(), SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005163 Label convert, done;
5164 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005165 __ sub(Operand(esp), Immediate(kDoubleSize));
5166 __ movdbl(Operand(esp, 0), input_reg);
5167 // Get exponent alone and check for too-big exponent.
5168 __ mov(result_reg, Operand(esp, sizeof(int32_t)));
5169 __ and_(result_reg, HeapNumber::kExponentMask);
5170 const uint32_t kTooBigExponent =
5171 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
5172 __ cmp(Operand(result_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005173 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005174 __ add(Operand(esp), Immediate(kDoubleSize));
5175 DeoptimizeIf(no_condition, instr->environment());
5176 __ bind(&convert);
5177 // Do conversion, which cannot fail because we checked the exponent.
5178 __ fld_d(Operand(esp, 0));
5179 __ fisttp_d(Operand(esp, 0));
5180 __ mov(result_reg, Operand(esp, 0)); // Low word of answer is the result.
5181 __ add(Operand(esp), Immediate(kDoubleSize));
5182 __ bind(&done);
5183 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005184 Label done;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005185 Register temp_reg = ToRegister(instr->temp());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005186 XMMRegister xmm_scratch = xmm0;
5187
5188 // If cvttsd2si succeeded, we're done. Otherwise, we attempt
5189 // manual conversion.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005190 __ j(not_equal, &done, Label::kNear);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005191
5192 // Get high 32 bits of the input in result_reg and temp_reg.
5193 __ pshufd(xmm_scratch, input_reg, 1);
5194 __ movd(Operand(temp_reg), xmm_scratch);
5195 __ mov(result_reg, temp_reg);
5196
5197 // Prepare negation mask in temp_reg.
5198 __ sar(temp_reg, kBitsPerInt - 1);
5199
5200 // Extract the exponent from result_reg and subtract adjusted
5201 // bias from it. The adjustment is selected in a way such that
5202 // when the difference is zero, the answer is in the low 32 bits
5203 // of the input, otherwise a shift has to be performed.
5204 __ shr(result_reg, HeapNumber::kExponentShift);
5205 __ and_(result_reg,
5206 HeapNumber::kExponentMask >> HeapNumber::kExponentShift);
5207 __ sub(Operand(result_reg),
5208 Immediate(HeapNumber::kExponentBias +
5209 HeapNumber::kExponentBits +
5210 HeapNumber::kMantissaBits));
5211 // Don't handle big (> kMantissaBits + kExponentBits == 63) or
5212 // special exponents.
5213 DeoptimizeIf(greater, instr->environment());
5214
5215 // Zero out the sign and the exponent in the input (by shifting
5216 // it to the left) and restore the implicit mantissa bit,
5217 // i.e. convert the input to unsigned int64 shifted left by
5218 // kExponentBits.
5219 ExternalReference minus_zero = ExternalReference::address_of_minus_zero();
5220 // Minus zero has the most significant bit set and the other
5221 // bits cleared.
5222 __ movdbl(xmm_scratch, Operand::StaticVariable(minus_zero));
5223 __ psllq(input_reg, HeapNumber::kExponentBits);
5224 __ por(input_reg, xmm_scratch);
5225
5226 // Get the amount to shift the input right in xmm_scratch.
5227 __ neg(result_reg);
5228 __ movd(xmm_scratch, Operand(result_reg));
5229
5230 // Shift the input right and extract low 32 bits.
5231 __ psrlq(input_reg, xmm_scratch);
5232 __ movd(Operand(result_reg), input_reg);
5233
5234 // Use the prepared mask in temp_reg to negate the result if necessary.
5235 __ xor_(result_reg, Operand(temp_reg));
5236 __ sub(result_reg, Operand(temp_reg));
5237 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005238 }
5239 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005240 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005241 __ cvttsd2si(result_reg, Operand(input_reg));
5242 __ cvtsi2sd(xmm0, Operand(result_reg));
5243 __ ucomisd(xmm0, input_reg);
5244 DeoptimizeIf(not_equal, instr->environment());
5245 DeoptimizeIf(parity_even, instr->environment()); // NaN.
5246 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
5247 // The integer converted back is equal to the original. We
5248 // only have to test if we got -0 as an input.
5249 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005250 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005251 __ movmskpd(result_reg, input_reg);
5252 // Bit 0 contains the sign of the double in input_reg.
5253 // If input was positive, we are ok and return 0, otherwise
5254 // deoptimize.
5255 __ and_(result_reg, 1);
5256 DeoptimizeIf(not_zero, instr->environment());
5257 }
5258 __ bind(&done);
5259 }
5260}
5261
5262
5263void LCodeGen::DoCheckSmi(LCheckSmi* 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(not_zero, instr->environment());
5267}
5268
5269
5270void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005271 LOperand* input = instr->value();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005272 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005273 DeoptimizeIf(zero, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005274}
5275
5276
5277void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005278 Register input = ToRegister(instr->value());
5279 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005280
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005281 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005282
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005283 if (instr->hydrogen()->is_interval_check()) {
5284 InstanceType first;
5285 InstanceType last;
5286 instr->hydrogen()->GetCheckInterval(&first, &last);
5287
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005288 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
5289 static_cast<int8_t>(first));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005290
5291 // If there is only one type in the interval check for equality.
5292 if (first == last) {
5293 DeoptimizeIf(not_equal, instr->environment());
5294 } else {
5295 DeoptimizeIf(below, instr->environment());
5296 // Omit check for the last type.
5297 if (last != LAST_TYPE) {
5298 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
5299 static_cast<int8_t>(last));
5300 DeoptimizeIf(above, instr->environment());
5301 }
5302 }
5303 } else {
5304 uint8_t mask;
5305 uint8_t tag;
5306 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
5307
5308 if (IsPowerOf2(mask)) {
5309 ASSERT(tag == 0 || IsPowerOf2(tag));
5310 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), mask);
5311 DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
5312 } else {
5313 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
5314 __ and_(temp, mask);
yangguo@chromium.org56454712012-02-16 15:33:53 +00005315 __ cmp(temp, tag);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005316 DeoptimizeIf(not_equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005317 }
5318 }
5319}
5320
5321
5322void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005323 Handle<JSFunction> target = instr->hydrogen()->target();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00005324 if (instr->hydrogen()->target_in_new_space()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005325 Register reg = ToRegister(instr->value());
5326 Handle<JSGlobalPropertyCell> cell =
5327 isolate()->factory()->NewJSGlobalPropertyCell(target);
5328 __ cmp(reg, Operand::Cell(cell));
5329 } else {
5330 Operand operand = ToOperand(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005331 __ cmp(operand, target);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005332 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005333 DeoptimizeIf(not_equal, instr->environment());
5334}
5335
5336
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005337void LCodeGen::DoCheckMapCommon(Register reg,
5338 Handle<Map> map,
5339 CompareMapMode mode,
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005340 LInstruction* instr) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005341 Label success;
5342 __ CompareMap(reg, map, &success, mode);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005343 DeoptimizeIf(not_equal, instr->environment());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005344 __ bind(&success);
5345}
5346
5347
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005348void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005349 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005350 ASSERT(input->IsRegister());
5351 Register reg = ToRegister(input);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005352
5353 Label success;
5354 SmallMapList* map_set = instr->hydrogen()->map_set();
5355 for (int i = 0; i < map_set->length() - 1; i++) {
5356 Handle<Map> map = map_set->at(i);
5357 __ CompareMap(reg, map, &success, REQUIRE_EXACT_MAP);
5358 __ j(equal, &success);
5359 }
5360 Handle<Map> map = map_set->last();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005361 DoCheckMapCommon(reg, map, REQUIRE_EXACT_MAP, instr);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005362 __ bind(&success);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005363}
5364
5365
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005366void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005367 CpuFeatureScope scope(masm(), SSE2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005368 XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
5369 Register result_reg = ToRegister(instr->result());
5370 __ ClampDoubleToUint8(value_reg, xmm0, result_reg);
5371}
5372
5373
5374void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
5375 ASSERT(instr->unclamped()->Equals(instr->result()));
5376 Register value_reg = ToRegister(instr->result());
5377 __ ClampUint8(value_reg);
5378}
5379
5380
5381void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005382 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005383
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005384 ASSERT(instr->unclamped()->Equals(instr->result()));
5385 Register input_reg = ToRegister(instr->unclamped());
5386 Label is_smi, done, heap_number;
5387
5388 __ JumpIfSmi(input_reg, &is_smi);
5389
5390 // Check for heap number
5391 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5392 factory()->heap_number_map());
5393 __ j(equal, &heap_number, Label::kNear);
5394
5395 // Check for undefined. Undefined is converted to zero for clamping
5396 // conversions.
5397 __ cmp(input_reg, factory()->undefined_value());
5398 DeoptimizeIf(not_equal, instr->environment());
5399 __ mov(input_reg, 0);
5400 __ jmp(&done, Label::kNear);
5401
5402 // Heap number
5403 __ bind(&heap_number);
5404 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
5405 __ ClampDoubleToUint8(xmm0, xmm1, input_reg);
5406 __ jmp(&done, Label::kNear);
5407
5408 // smi
5409 __ bind(&is_smi);
5410 __ SmiUntag(input_reg);
5411 __ ClampUint8(input_reg);
5412
5413 __ bind(&done);
5414}
5415
5416
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005417void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00005418 ASSERT(instr->temp()->Equals(instr->result()));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005419 Register reg = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005420
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00005421 ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
5422 ZoneList<Handle<Map> >* maps = instr->maps();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005423
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00005424 ASSERT(prototypes->length() == maps->length());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005425
ulan@chromium.org2e04b582013-02-21 14:06:02 +00005426 // TODO(ulan): Move this check to hydrogen and split HCheckPrototypeMaps
5427 // into two instruction: one that checks the prototypes and another that
5428 // loads the holder (HConstant). Find a way to do it without breaking
5429 // parallel recompilation.
5430 if (instr->hydrogen()->CanOmitPrototypeChecks()) {
5431 for (int i = 0; i < maps->length(); i++) {
5432 prototype_maps_.Add(maps->at(i), info()->zone());
5433 }
5434 __ LoadHeapObject(reg, prototypes->at(prototypes->length() - 1));
5435 } else {
5436 for (int i = 0; i < prototypes->length(); i++) {
5437 __ LoadHeapObject(reg, prototypes->at(i));
5438 DoCheckMapCommon(reg, maps->at(i), ALLOW_ELEMENT_TRANSITION_MAPS, instr);
5439 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005440 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005441}
5442
5443
ulan@chromium.org967e2702012-02-28 09:49:15 +00005444void LCodeGen::DoAllocateObject(LAllocateObject* instr) {
5445 class DeferredAllocateObject: public LDeferredCode {
5446 public:
5447 DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr)
5448 : LDeferredCode(codegen), instr_(instr) { }
5449 virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); }
5450 virtual LInstruction* instr() { return instr_; }
5451 private:
5452 LAllocateObject* instr_;
5453 };
5454
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005455 DeferredAllocateObject* deferred =
5456 new(zone()) DeferredAllocateObject(this, instr);
ulan@chromium.org967e2702012-02-28 09:49:15 +00005457
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005458 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005459 Register scratch = ToRegister(instr->temp());
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005460 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
5461 Handle<Map> initial_map(constructor->initial_map());
5462 int instance_size = initial_map->instance_size();
5463 ASSERT(initial_map->pre_allocated_property_fields() +
5464 initial_map->unused_property_fields() -
5465 initial_map->inobject_properties() == 0);
5466
5467 // Allocate memory for the object. The initial map might change when
5468 // the constructor's prototype changes, but instance size and property
5469 // counts remain unchanged (if slack tracking finished).
5470 ASSERT(!constructor->shared()->IsInobjectSlackTrackingInProgress());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005471 __ Allocate(instance_size, result, no_reg, scratch, deferred->entry(),
5472 TAG_OBJECT);
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005473
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005474 __ bind(deferred->exit());
5475 if (FLAG_debug_code) {
5476 Label is_in_new_space;
5477 __ JumpIfInNewSpace(result, scratch, &is_in_new_space);
5478 __ Abort("Allocated object is not in new-space");
5479 __ bind(&is_in_new_space);
5480 }
5481
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005482 // Load the initial map.
5483 Register map = scratch;
5484 __ LoadHeapObject(scratch, constructor);
5485 __ mov(map, FieldOperand(scratch, JSFunction::kPrototypeOrInitialMapOffset));
5486
5487 if (FLAG_debug_code) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005488 __ AssertNotSmi(map);
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005489 __ cmpb(FieldOperand(map, Map::kInstanceSizeOffset),
5490 instance_size >> kPointerSizeLog2);
5491 __ Assert(equal, "Unexpected instance size");
5492 __ cmpb(FieldOperand(map, Map::kPreAllocatedPropertyFieldsOffset),
5493 initial_map->pre_allocated_property_fields());
5494 __ Assert(equal, "Unexpected pre-allocated property fields count");
5495 __ cmpb(FieldOperand(map, Map::kUnusedPropertyFieldsOffset),
5496 initial_map->unused_property_fields());
5497 __ Assert(equal, "Unexpected unused property fields count");
5498 __ cmpb(FieldOperand(map, Map::kInObjectPropertiesOffset),
5499 initial_map->inobject_properties());
5500 __ Assert(equal, "Unexpected in-object property fields count");
5501 }
5502
5503 // Initialize map and fields of the newly allocated object.
5504 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE);
5505 __ mov(FieldOperand(result, JSObject::kMapOffset), map);
5506 __ mov(scratch, factory()->empty_fixed_array());
5507 __ mov(FieldOperand(result, JSObject::kElementsOffset), scratch);
5508 __ mov(FieldOperand(result, JSObject::kPropertiesOffset), scratch);
5509 if (initial_map->inobject_properties() != 0) {
5510 __ mov(scratch, factory()->undefined_value());
5511 for (int i = 0; i < initial_map->inobject_properties(); i++) {
5512 int property_offset = JSObject::kHeaderSize + i * kPointerSize;
5513 __ mov(FieldOperand(result, property_offset), scratch);
5514 }
5515 }
ulan@chromium.org967e2702012-02-28 09:49:15 +00005516}
5517
5518
5519void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) {
5520 Register result = ToRegister(instr->result());
5521 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005522 Handle<Map> initial_map(constructor->initial_map());
5523 int instance_size = initial_map->instance_size();
ulan@chromium.org967e2702012-02-28 09:49:15 +00005524
5525 // TODO(3095996): Get rid of this. For now, we need to make the
5526 // result register contain a valid pointer because it is already
5527 // contained in the register pointer map.
5528 __ Set(result, Immediate(0));
5529
5530 PushSafepointRegistersScope scope(this);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005531 __ push(Immediate(Smi::FromInt(instance_size)));
5532 CallRuntimeFromDeferred(
5533 Runtime::kAllocateInNewSpace, 1, instr, instr->context());
ulan@chromium.org967e2702012-02-28 09:49:15 +00005534 __ StoreToSafepointRegisterSlot(result, eax);
5535}
5536
5537
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005538void LCodeGen::DoAllocate(LAllocate* instr) {
5539 class DeferredAllocate: public LDeferredCode {
5540 public:
5541 DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
5542 : LDeferredCode(codegen), instr_(instr) { }
5543 virtual void Generate() { codegen()->DoDeferredAllocate(instr_); }
5544 virtual LInstruction* instr() { return instr_; }
5545 private:
5546 LAllocate* instr_;
5547 };
5548
5549 DeferredAllocate* deferred =
5550 new(zone()) DeferredAllocate(this, instr);
5551
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005552 Register result = ToRegister(instr->result());
5553 Register temp = ToRegister(instr->temp());
5554
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005555 // Allocate memory for the object.
5556 AllocationFlags flags = TAG_OBJECT;
5557 if (instr->hydrogen()->MustAllocateDoubleAligned()) {
5558 flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
5559 }
5560 if (instr->size()->IsConstantOperand()) {
5561 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005562 if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
5563 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
5564 }
5565 __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005566 } else {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005567 Register size = ToRegister(instr->size());
5568 __ AllocateInNewSpace(size, result, temp, no_reg, deferred->entry(), flags);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005569 }
5570
5571 __ bind(deferred->exit());
5572}
5573
5574
5575void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
5576 Register size = ToRegister(instr->size());
5577 Register result = ToRegister(instr->result());
5578
5579 __ SmiTag(size);
5580 PushSafepointRegistersScope scope(this);
5581 // TODO(3095996): Get rid of this. For now, we need to make the
5582 // result register contain a valid pointer because it is already
5583 // contained in the register pointer map.
5584 if (!size.is(result)) {
5585 __ StoreToSafepointRegisterSlot(result, size);
5586 }
5587 __ push(size);
5588 CallRuntimeFromDeferred(
5589 Runtime::kAllocateInNewSpace, 1, instr, instr->context());
5590 __ StoreToSafepointRegisterSlot(result, eax);
5591}
5592
5593
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005594void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005595 ASSERT(ToRegister(instr->context()).is(esi));
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005596 Handle<FixedArray> literals(instr->environment()->closure()->literals());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005597 ElementsKind boilerplate_elements_kind =
5598 instr->hydrogen()->boilerplate_elements_kind();
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005599 AllocationSiteMode allocation_site_mode =
5600 instr->hydrogen()->allocation_site_mode();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005601
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005602 // Deopt if the array literal boilerplate ElementsKind is of a type different
5603 // than the expected one. The check isn't necessary if the boilerplate has
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005604 // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
5605 if (CanTransitionToMoreGeneralFastElementsKind(
5606 boilerplate_elements_kind, true)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005607 __ LoadHeapObject(eax, instr->hydrogen()->boilerplate_object());
5608 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
5609 // Load the map's "bit field 2". We only need the first byte,
5610 // but the following masking takes care of that anyway.
5611 __ mov(ebx, FieldOperand(ebx, Map::kBitField2Offset));
5612 // Retrieve elements_kind from bit field 2.
5613 __ and_(ebx, Map::kElementsKindMask);
5614 __ cmp(ebx, boilerplate_elements_kind << Map::kElementsKindShift);
5615 DeoptimizeIf(not_equal, instr->environment());
5616 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005617
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005618 // Set up the parameters to the stub/runtime call.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005619 __ PushHeapObject(literals);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005620 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005621 // Boilerplate already exists, constant elements are never accessed.
5622 // Pass an empty fixed array.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005623 __ push(Immediate(isolate()->factory()->empty_fixed_array()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005624
5625 // Pick the right runtime function or stub to call.
5626 int length = instr->hydrogen()->length();
5627 if (instr->hydrogen()->IsCopyOnWrite()) {
5628 ASSERT(instr->hydrogen()->depth() == 1);
5629 FastCloneShallowArrayStub::Mode mode =
5630 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005631 FastCloneShallowArrayStub stub(mode, DONT_TRACK_ALLOCATION_SITE, length);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005632 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005633 } else if (instr->hydrogen()->depth() > 1) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005634 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005635 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005636 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005637 } else {
5638 FastCloneShallowArrayStub::Mode mode =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005639 boilerplate_elements_kind == FAST_DOUBLE_ELEMENTS
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005640 ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
5641 : FastCloneShallowArrayStub::CLONE_ELEMENTS;
5642 FastCloneShallowArrayStub stub(mode, allocation_site_mode, length);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005643 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005644 }
5645}
5646
5647
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005648void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
5649 Register result,
5650 Register source,
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005651 int* offset,
5652 AllocationSiteMode mode) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005653 ASSERT(!source.is(ecx));
5654 ASSERT(!result.is(ecx));
5655
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005656 bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
5657 object->map()->CanTrackAllocationSite();
5658
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005659 if (FLAG_debug_code) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005660 __ LoadHeapObject(ecx, object);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005661 __ cmp(source, ecx);
5662 __ Assert(equal, "Unexpected object literal boilerplate");
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005663 __ mov(ecx, FieldOperand(source, HeapObject::kMapOffset));
5664 __ cmp(ecx, Handle<Map>(object->map()));
5665 __ Assert(equal, "Unexpected boilerplate map");
5666 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
5667 __ and_(ecx, Map::kElementsKindMask);
5668 __ cmp(ecx, object->GetElementsKind() << Map::kElementsKindShift);
5669 __ Assert(equal, "Unexpected boilerplate elements kind");
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005670 }
5671
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005672 // Only elements backing stores for non-COW arrays need to be copied.
5673 Handle<FixedArrayBase> elements(object->elements());
5674 bool has_elements = elements->length() > 0 &&
5675 elements->map() != isolate()->heap()->fixed_cow_array_map();
5676
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005677 // Increase the offset so that subsequent objects end up right after
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005678 // this object and its backing store.
5679 int object_offset = *offset;
5680 int object_size = object->map()->instance_size();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005681 int elements_size = has_elements ? elements->Size() : 0;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005682 int elements_offset = *offset + object_size;
5683 if (create_allocation_site_info) {
5684 elements_offset += AllocationSiteInfo::kSize;
5685 *offset += AllocationSiteInfo::kSize;
5686 }
5687
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005688 *offset += object_size + elements_size;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005689
5690 // Copy object header.
5691 ASSERT(object->properties()->length() == 0);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005692 int inobject_properties = object->map()->inobject_properties();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005693 int header_size = object_size - inobject_properties * kPointerSize;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005694 for (int i = 0; i < header_size; i += kPointerSize) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005695 if (has_elements && i == JSObject::kElementsOffset) {
5696 __ lea(ecx, Operand(result, elements_offset));
5697 } else {
5698 __ mov(ecx, FieldOperand(source, i));
5699 }
5700 __ mov(FieldOperand(result, object_offset + i), ecx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005701 }
5702
5703 // Copy in-object properties.
5704 for (int i = 0; i < inobject_properties; i++) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005705 int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005706 Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i),
5707 isolate());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005708 if (value->IsJSObject()) {
5709 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5710 __ lea(ecx, Operand(result, *offset));
5711 __ mov(FieldOperand(result, total_offset), ecx);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005712 __ LoadHeapObject(source, value_object);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005713 EmitDeepCopy(value_object, result, source, offset,
5714 DONT_TRACK_ALLOCATION_SITE);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005715 } else if (value->IsHeapObject()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005716 __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005717 __ mov(FieldOperand(result, total_offset), ecx);
5718 } else {
5719 __ mov(FieldOperand(result, total_offset), Immediate(value));
5720 }
5721 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005722
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005723 // Build Allocation Site Info if desired
5724 if (create_allocation_site_info) {
5725 __ mov(FieldOperand(result, object_size),
5726 Immediate(Handle<Map>(isolate()->heap()->
5727 allocation_site_info_map())));
5728 __ mov(FieldOperand(result, object_size + kPointerSize), source);
5729 }
5730
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005731 if (has_elements) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005732 // Copy elements backing store header.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005733 __ LoadHeapObject(source, elements);
5734 for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
5735 __ mov(ecx, FieldOperand(source, i));
5736 __ mov(FieldOperand(result, elements_offset + i), ecx);
5737 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005738
danno@chromium.org88aa0582012-03-23 15:11:57 +00005739 // Copy elements backing store content.
5740 int elements_length = elements->length();
5741 if (elements->IsFixedDoubleArray()) {
5742 Handle<FixedDoubleArray> double_array =
5743 Handle<FixedDoubleArray>::cast(elements);
5744 for (int i = 0; i < elements_length; i++) {
5745 int64_t value = double_array->get_representation(i);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00005746 int32_t value_low = static_cast<int32_t>(value & 0xFFFFFFFF);
5747 int32_t value_high = static_cast<int32_t>(value >> 32);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005748 int total_offset =
5749 elements_offset + FixedDoubleArray::OffsetOfElementAt(i);
5750 __ mov(FieldOperand(result, total_offset), Immediate(value_low));
5751 __ mov(FieldOperand(result, total_offset + 4), Immediate(value_high));
5752 }
5753 } else if (elements->IsFixedArray()) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005754 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005755 for (int i = 0; i < elements_length; i++) {
5756 int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005757 Handle<Object> value(fast_elements->get(i), isolate());
danno@chromium.org88aa0582012-03-23 15:11:57 +00005758 if (value->IsJSObject()) {
5759 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5760 __ lea(ecx, Operand(result, *offset));
5761 __ mov(FieldOperand(result, total_offset), ecx);
5762 __ LoadHeapObject(source, value_object);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005763 EmitDeepCopy(value_object, result, source, offset,
5764 DONT_TRACK_ALLOCATION_SITE);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005765 } else if (value->IsHeapObject()) {
5766 __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
5767 __ mov(FieldOperand(result, total_offset), ecx);
5768 } else {
5769 __ mov(FieldOperand(result, total_offset), Immediate(value));
5770 }
5771 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005772 } else {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005773 UNREACHABLE();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005774 }
5775 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005776}
5777
5778
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005779void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005780 ASSERT(ToRegister(instr->context()).is(esi));
5781 int size = instr->hydrogen()->total_size();
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005782 ElementsKind boilerplate_elements_kind =
5783 instr->hydrogen()->boilerplate()->GetElementsKind();
5784
5785 // Deopt if the literal boilerplate ElementsKind is of a type different than
5786 // the expected one. The check isn't necessary if the boilerplate has already
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005787 // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
5788 if (CanTransitionToMoreGeneralFastElementsKind(
5789 boilerplate_elements_kind, true)) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005790 __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
5791 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
5792 // Load the map's "bit field 2". We only need the first byte,
5793 // but the following masking takes care of that anyway.
5794 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
5795 // Retrieve elements_kind from bit field 2.
5796 __ and_(ecx, Map::kElementsKindMask);
5797 __ cmp(ecx, boilerplate_elements_kind << Map::kElementsKindShift);
5798 DeoptimizeIf(not_equal, instr->environment());
5799 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005800
5801 // Allocate all objects that are part of the literal in one big
5802 // allocation. This avoids multiple limit checks.
5803 Label allocated, runtime_allocate;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005804 __ Allocate(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005805 __ jmp(&allocated);
5806
5807 __ bind(&runtime_allocate);
5808 __ push(Immediate(Smi::FromInt(size)));
5809 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
5810
5811 __ bind(&allocated);
5812 int offset = 0;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005813 __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005814 EmitDeepCopy(instr->hydrogen()->boilerplate(), eax, ebx, &offset,
5815 instr->hydrogen()->allocation_site_mode());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005816 ASSERT_EQ(size, offset);
5817}
5818
5819
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005820void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005821 ASSERT(ToRegister(instr->context()).is(esi));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005822 Handle<FixedArray> literals(instr->environment()->closure()->literals());
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005823 Handle<FixedArray> constant_properties =
5824 instr->hydrogen()->constant_properties();
5825
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005826 int flags = instr->hydrogen()->fast_elements()
5827 ? ObjectLiteral::kFastElements
5828 : ObjectLiteral::kNoFlags;
5829 flags |= instr->hydrogen()->has_function()
5830 ? ObjectLiteral::kHasFunction
5831 : ObjectLiteral::kNoFlags;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005832
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005833 // Set up the parameters to the stub/runtime call and pick the right
5834 // runtime function or stub to call.
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005835 int properties_count = constant_properties->length() / 2;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005836 if (instr->hydrogen()->depth() > 1) {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005837 __ PushHeapObject(literals);
5838 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
5839 __ push(Immediate(constant_properties));
5840 __ push(Immediate(Smi::FromInt(flags)));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005841 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005842 } else if (flags != ObjectLiteral::kFastElements ||
5843 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005844 __ PushHeapObject(literals);
5845 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
5846 __ push(Immediate(constant_properties));
5847 __ push(Immediate(Smi::FromInt(flags)));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005848 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005849 } else {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005850 __ LoadHeapObject(eax, literals);
5851 __ mov(ebx, Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
5852 __ mov(ecx, Immediate(constant_properties));
5853 __ mov(edx, Immediate(Smi::FromInt(flags)));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005854 FastCloneShallowObjectStub stub(properties_count);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005855 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005856 }
5857}
5858
5859
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005860void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005861 ASSERT(ToRegister(instr->value()).is(eax));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005862 __ push(eax);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005863 CallRuntime(Runtime::kToFastProperties, 1, instr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005864}
5865
5866
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005867void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005868 ASSERT(ToRegister(instr->context()).is(esi));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005869 Label materialized;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005870 // Registers will be used as follows:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005871 // ecx = literals array.
5872 // ebx = regexp literal.
5873 // eax = regexp literal clone.
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005874 // esi = context.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005875 int literal_offset =
5876 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
5877 __ LoadHeapObject(ecx, instr->hydrogen()->literals());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005878 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005879 __ cmp(ebx, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005880 __ j(not_equal, &materialized, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005881
5882 // Create regexp literal using runtime function
5883 // Result will be in eax.
5884 __ push(ecx);
5885 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
5886 __ push(Immediate(instr->hydrogen()->pattern()));
5887 __ push(Immediate(instr->hydrogen()->flags()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005888 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005889 __ mov(ebx, eax);
5890
5891 __ bind(&materialized);
5892 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
5893 Label allocated, runtime_allocate;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005894 __ Allocate(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005895 __ jmp(&allocated);
5896
5897 __ bind(&runtime_allocate);
5898 __ push(ebx);
5899 __ push(Immediate(Smi::FromInt(size)));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005900 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005901 __ pop(ebx);
5902
5903 __ bind(&allocated);
5904 // Copy the content into the newly allocated memory.
5905 // (Unroll copy loop once for better throughput).
5906 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
5907 __ mov(edx, FieldOperand(ebx, i));
5908 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
5909 __ mov(FieldOperand(eax, i), edx);
5910 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
5911 }
5912 if ((size % (2 * kPointerSize)) != 0) {
5913 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
5914 __ mov(FieldOperand(eax, size - kPointerSize), edx);
5915 }
5916}
5917
5918
5919void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005920 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005921 // Use the fast case closure allocation code that allocates in new
5922 // space for nested functions that don't need literals cloning.
5923 Handle<SharedFunctionInfo> shared_info = instr->shared_info();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005924 bool pretenure = instr->hydrogen()->pretenure();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005925 if (!pretenure && shared_info->num_literals() == 0) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005926 FastNewClosureStub stub(shared_info->language_mode());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005927 __ push(Immediate(shared_info));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005928 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005929 } else {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005930 __ push(esi);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005931 __ push(Immediate(shared_info));
5932 __ push(Immediate(pretenure
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005933 ? factory()->true_value()
5934 : factory()->false_value()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005935 CallRuntime(Runtime::kNewClosure, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005936 }
5937}
5938
5939
5940void LCodeGen::DoTypeof(LTypeof* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005941 LOperand* input = instr->value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005942 EmitPushTaggedOperand(input);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005943 CallRuntime(Runtime::kTypeof, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005944}
5945
5946
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005947void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005948 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005949 int true_block = chunk_->LookupDestination(instr->true_block_id());
5950 int false_block = chunk_->LookupDestination(instr->false_block_id());
5951 Label* true_label = chunk_->GetAssemblyLabel(true_block);
5952 Label* false_label = chunk_->GetAssemblyLabel(false_block);
5953
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005954 Condition final_branch_condition =
5955 EmitTypeofIs(true_label, false_label, input, instr->type_literal());
5956 if (final_branch_condition != no_condition) {
5957 EmitBranch(true_block, false_block, final_branch_condition);
5958 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005959}
5960
5961
5962Condition LCodeGen::EmitTypeofIs(Label* true_label,
5963 Label* false_label,
5964 Register input,
5965 Handle<String> type_name) {
5966 Condition final_branch_condition = no_condition;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005967 if (type_name->Equals(heap()->number_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005968 __ JumpIfSmi(input, true_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005969 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005970 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005971 final_branch_condition = equal;
5972
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005973 } else if (type_name->Equals(heap()->string_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005974 __ JumpIfSmi(input, false_label);
5975 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
5976 __ j(above_equal, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005977 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5978 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005979 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005980
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005981 } else if (type_name->Equals(heap()->boolean_string())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005982 __ cmp(input, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005983 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005984 __ cmp(input, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005985 final_branch_condition = equal;
5986
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005987 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005988 __ cmp(input, factory()->null_value());
5989 final_branch_condition = equal;
5990
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005991 } else if (type_name->Equals(heap()->undefined_string())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005992 __ cmp(input, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005993 __ j(equal, true_label);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005994 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005995 // Check for undetectable objects => true.
5996 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
5997 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5998 1 << Map::kIsUndetectable);
5999 final_branch_condition = not_zero;
6000
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006001 } else if (type_name->Equals(heap()->function_string())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006002 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006003 __ JumpIfSmi(input, false_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006004 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
6005 __ j(equal, true_label);
6006 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
6007 final_branch_condition = equal;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006008
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006009 } else if (type_name->Equals(heap()->object_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006010 __ JumpIfSmi(input, false_label);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00006011 if (!FLAG_harmony_typeof) {
6012 __ cmp(input, factory()->null_value());
6013 __ j(equal, true_label);
6014 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006015 if (FLAG_harmony_symbols) {
6016 __ CmpObjectType(input, SYMBOL_TYPE, input);
6017 __ j(equal, true_label);
6018 __ CmpInstanceType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
6019 } else {
6020 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
6021 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006022 __ j(below, false_label);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00006023 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
6024 __ j(above, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006025 // Check for undetectable objects => false.
6026 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
6027 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006028 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006029
6030 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006031 __ jmp(false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006032 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006033 return final_branch_condition;
6034}
6035
6036
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006037void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00006038 Register temp = ToRegister(instr->temp());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006039 int true_block = chunk_->LookupDestination(instr->true_block_id());
6040 int false_block = chunk_->LookupDestination(instr->false_block_id());
6041
6042 EmitIsConstructCall(temp);
6043 EmitBranch(true_block, false_block, equal);
6044}
6045
6046
6047void LCodeGen::EmitIsConstructCall(Register temp) {
6048 // Get the frame pointer for the calling frame.
6049 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
6050
6051 // Skip the arguments adaptor frame if it exists.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00006052 Label check_frame_marker;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006053 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
6054 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00006055 __ j(not_equal, &check_frame_marker, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006056 __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
6057
6058 // Check the marker in the calling frame.
6059 __ bind(&check_frame_marker);
6060 __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
6061 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
6062}
6063
6064
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006065void LCodeGen::EnsureSpaceForLazyDeopt() {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00006066 if (!info()->IsStub()) {
6067 // Ensure that we have enough space after the previous lazy-bailout
6068 // instruction for patching the code here.
6069 int current_pc = masm()->pc_offset();
6070 int patch_size = Deoptimizer::patch_size();
6071 if (current_pc < last_lazy_deopt_pc_ + patch_size) {
6072 int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc;
6073 __ Nop(padding_size);
6074 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006075 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00006076 last_lazy_deopt_pc_ = masm()->pc_offset();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006077}
6078
6079
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006080void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006081 EnsureSpaceForLazyDeopt();
6082 ASSERT(instr->HasEnvironment());
6083 LEnvironment* env = instr->environment();
6084 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
6085 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006086}
6087
6088
6089void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
6090 DeoptimizeIf(no_condition, instr->environment());
6091}
6092
6093
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006094void LCodeGen::DoDummyUse(LDummyUse* instr) {
6095 // Nothing to see here, move on!
6096}
6097
6098
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006099void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
6100 LOperand* obj = instr->object();
6101 LOperand* key = instr->key();
6102 __ push(ToOperand(obj));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006103 EmitPushTaggedOperand(key);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00006104 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00006105 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00006106 RecordPosition(pointers->position());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006107 // Create safepoint generator that will also ensure enough space in the
6108 // reloc info for patching in deoptimization (since this is invoking a
6109 // builtin)
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006110 SafepointGenerator safepoint_generator(
6111 this, pointers, Safepoint::kLazyDeopt);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006112 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00006113 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006114}
6115
6116
ager@chromium.org04921a82011-06-27 13:21:41 +00006117void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006118 PushSafepointRegistersScope scope(this);
6119 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
6120 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
6121 RecordSafepointWithLazyDeopt(
6122 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
6123 ASSERT(instr->HasEnvironment());
6124 LEnvironment* env = instr->environment();
6125 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00006126}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006127
ager@chromium.org04921a82011-06-27 13:21:41 +00006128
6129void LCodeGen::DoStackCheck(LStackCheck* instr) {
6130 class DeferredStackCheck: public LDeferredCode {
6131 public:
6132 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
6133 : LDeferredCode(codegen), instr_(instr) { }
6134 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006135 virtual LInstruction* instr() { return instr_; }
ager@chromium.org04921a82011-06-27 13:21:41 +00006136 private:
6137 LStackCheck* instr_;
6138 };
6139
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006140 ASSERT(instr->HasEnvironment());
6141 LEnvironment* env = instr->environment();
6142 // There is no LLazyBailout instruction for stack-checks. We have to
6143 // prepare for lazy deoptimization explicitly here.
ager@chromium.org04921a82011-06-27 13:21:41 +00006144 if (instr->hydrogen()->is_function_entry()) {
6145 // Perform stack overflow check.
6146 Label done;
6147 ExternalReference stack_limit =
6148 ExternalReference::address_of_stack_limit(isolate());
6149 __ cmp(esp, Operand::StaticVariable(stack_limit));
6150 __ j(above_equal, &done, Label::kNear);
6151
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006152 ASSERT(instr->context()->IsRegister());
6153 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org04921a82011-06-27 13:21:41 +00006154 StackCheckStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00006155 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006156 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00006157 __ bind(&done);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006158 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
6159 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00006160 } else {
6161 ASSERT(instr->hydrogen()->is_backwards_branch());
6162 // Perform stack overflow check if this goto needs it before jumping.
6163 DeferredStackCheck* deferred_stack_check =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00006164 new(zone()) DeferredStackCheck(this, instr);
ager@chromium.org04921a82011-06-27 13:21:41 +00006165 ExternalReference stack_limit =
6166 ExternalReference::address_of_stack_limit(isolate());
6167 __ cmp(esp, Operand::StaticVariable(stack_limit));
6168 __ j(below, deferred_stack_check->entry());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006169 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00006170 __ bind(instr->done_label());
6171 deferred_stack_check->SetExit(instr->done_label());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006172 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
6173 // Don't record a deoptimization index for the safepoint here.
6174 // This will be done explicitly when emitting call and the safepoint in
6175 // the deferred code.
ager@chromium.org04921a82011-06-27 13:21:41 +00006176 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006177}
6178
6179
6180void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
6181 // This is a pseudo-instruction that ensures that the environment here is
6182 // properly registered for deoptimization and records the assembler's PC
6183 // offset.
6184 LEnvironment* environment = instr->environment();
6185 environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
6186 instr->SpilledDoubleRegisterArray());
6187
6188 // If the environment were already registered, we would have no way of
6189 // backpatching it with the spill slot operands.
6190 ASSERT(!environment->HasBeenRegistered());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006191 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006192 ASSERT(osr_pc_offset_ == -1);
6193 osr_pc_offset_ = masm()->pc_offset();
6194}
6195
6196
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006197void LCodeGen::DoIn(LIn* instr) {
6198 LOperand* obj = instr->object();
6199 LOperand* key = instr->key();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006200 EmitPushTaggedOperand(key);
6201 EmitPushTaggedOperand(obj);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00006202 ASSERT(instr->HasPointerMap());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006203 LPointerMap* pointers = instr->pointer_map();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006204 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006205 SafepointGenerator safepoint_generator(
6206 this, pointers, Safepoint::kLazyDeopt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00006207 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006208}
6209
6210
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006211void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
6212 __ cmp(eax, isolate()->factory()->undefined_value());
6213 DeoptimizeIf(equal, instr->environment());
6214
6215 __ cmp(eax, isolate()->factory()->null_value());
6216 DeoptimizeIf(equal, instr->environment());
6217
6218 __ test(eax, Immediate(kSmiTagMask));
6219 DeoptimizeIf(zero, instr->environment());
6220
6221 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
6222 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
6223 DeoptimizeIf(below_equal, instr->environment());
6224
6225 Label use_cache, call_runtime;
6226 __ CheckEnumCache(&call_runtime);
6227
6228 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
6229 __ jmp(&use_cache, Label::kNear);
6230
6231 // Get the set of properties to enumerate.
6232 __ bind(&call_runtime);
6233 __ push(eax);
6234 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
6235
6236 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
6237 isolate()->factory()->meta_map());
6238 DeoptimizeIf(not_equal, instr->environment());
6239 __ bind(&use_cache);
6240}
6241
6242
6243void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
6244 Register map = ToRegister(instr->map());
6245 Register result = ToRegister(instr->result());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00006246 Label load_cache, done;
6247 __ EnumLength(result, map);
6248 __ cmp(result, Immediate(Smi::FromInt(0)));
6249 __ j(not_equal, &load_cache);
6250 __ mov(result, isolate()->factory()->empty_fixed_array());
6251 __ jmp(&done);
6252
6253 __ bind(&load_cache);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006254 __ LoadInstanceDescriptors(map, result);
6255 __ mov(result,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006256 FieldOperand(result, DescriptorArray::kEnumCacheOffset));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006257 __ mov(result,
6258 FieldOperand(result, FixedArray::SizeFor(instr->idx())));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00006259 __ bind(&done);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006260 __ test(result, result);
6261 DeoptimizeIf(equal, instr->environment());
6262}
6263
6264
6265void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
6266 Register object = ToRegister(instr->value());
6267 __ cmp(ToRegister(instr->map()),
6268 FieldOperand(object, HeapObject::kMapOffset));
6269 DeoptimizeIf(not_equal, instr->environment());
6270}
6271
6272
6273void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
6274 Register object = ToRegister(instr->object());
6275 Register index = ToRegister(instr->index());
6276
6277 Label out_of_object, done;
6278 __ cmp(index, Immediate(0));
6279 __ j(less, &out_of_object);
6280 __ mov(object, FieldOperand(object,
6281 index,
6282 times_half_pointer_size,
6283 JSObject::kHeaderSize));
6284 __ jmp(&done, Label::kNear);
6285
6286 __ bind(&out_of_object);
6287 __ mov(object, FieldOperand(object, JSObject::kPropertiesOffset));
6288 __ neg(index);
6289 // Index is now equal to out of object property index plus 1.
6290 __ mov(object, FieldOperand(object,
6291 index,
6292 times_half_pointer_size,
6293 FixedArray::kHeaderSize - kPointerSize));
6294 __ bind(&done);
6295}
6296
6297
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006298#undef __
6299
6300} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006301
6302#endif // V8_TARGET_ARCH_IA32