blob: bbecdcc9f7f86f0f0fa69c1469d19e7dfc9ecd33 [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 }
danno@chromium.org1fd77d52013-06-07 16:01:45 +0000112 info()->CommitDependentMaps(code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000113}
114
115
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000116void LCodeGen::Abort(const char* reason) {
117 info()->set_bailout_reason(reason);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000118 status_ = ABORTED;
119}
120
121
122void LCodeGen::Comment(const char* format, ...) {
123 if (!FLAG_code_comments) return;
124 char buffer[4 * KB];
125 StringBuilder builder(buffer, ARRAY_SIZE(buffer));
126 va_list arguments;
127 va_start(arguments, format);
128 builder.AddFormattedList(format, arguments);
129 va_end(arguments);
130
131 // Copy the string before recording it in the assembler to avoid
132 // issues when the stack allocated buffer goes out of scope.
133 size_t length = builder.position();
134 Vector<char> copy = Vector<char>::New(length + 1);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000135 OS::MemCopy(copy.start(), builder.Finalize(), copy.length());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000136 masm()->RecordComment(copy.start());
137}
138
139
140bool LCodeGen::GeneratePrologue() {
141 ASSERT(is_generating());
142
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000143 if (info()->IsOptimizing()) {
144 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000145
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000146#ifdef DEBUG
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000147 if (strlen(FLAG_stop_at) > 0 &&
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000148 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000149 __ int3();
150 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000151#endif
152
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000153 // Strict mode functions and builtins need to replace the receiver
154 // with undefined when called as functions (without an explicit
155 // receiver object). ecx is zero for method calls and non-zero for
156 // function calls.
157 if (!info_->is_classic_mode() || info_->is_native()) {
158 Label ok;
159 __ test(ecx, Operand(ecx));
160 __ j(zero, &ok, Label::kNear);
161 // +1 for return address.
162 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
163 __ mov(Operand(esp, receiver_offset),
164 Immediate(isolate()->factory()->undefined_value()));
165 __ bind(&ok);
166 }
danno@chromium.org40cb8782011-05-25 07:58:50 +0000167
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000168 if (support_aligned_spilled_doubles_ && dynamic_frame_alignment_) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000169 // Move state of dynamic frame alignment into edx.
170 __ mov(edx, Immediate(kNoAlignmentPadding));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000171
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000172 Label do_not_pad, align_loop;
173 STATIC_ASSERT(kDoubleSize == 2 * kPointerSize);
174 // Align esp + 4 to a multiple of 2 * kPointerSize.
175 __ test(esp, Immediate(kPointerSize));
176 __ j(not_zero, &do_not_pad, Label::kNear);
177 __ push(Immediate(0));
178 __ mov(ebx, esp);
179 __ mov(edx, Immediate(kAlignmentPaddingPushed));
180 // Copy arguments, receiver, and return address.
181 __ mov(ecx, Immediate(scope()->num_parameters() + 2));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000182
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000183 __ bind(&align_loop);
184 __ mov(eax, Operand(ebx, 1 * kPointerSize));
185 __ mov(Operand(ebx, 0), eax);
186 __ add(Operand(ebx), Immediate(kPointerSize));
187 __ dec(ecx);
188 __ j(not_zero, &align_loop, Label::kNear);
189 __ mov(Operand(ebx, 0), Immediate(kAlignmentZapValue));
190 __ bind(&do_not_pad);
191 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000192 }
193
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000194 info()->set_prologue_offset(masm_->pc_offset());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000195 if (NeedsEagerFrame()) {
196 ASSERT(!frame_is_built_);
197 frame_is_built_ = true;
198 __ push(ebp); // Caller's frame pointer.
199 __ mov(ebp, esp);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000200 info()->AddNoFrameRange(0, masm_->pc_offset());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000201 __ push(esi); // Callee's context.
202 if (info()->IsStub()) {
203 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
204 } else {
205 __ push(edi); // Callee's JS function.
206 }
207 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000208
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000209 if (info()->IsOptimizing() &&
210 dynamic_frame_alignment_ &&
211 FLAG_debug_code) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000212 __ test(esp, Immediate(kPointerSize));
213 __ Assert(zero, "frame is expected to be aligned");
214 }
215
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000216 // Reserve space for the stack slots needed by the code.
danno@chromium.org160a7b02011-04-18 15:51:38 +0000217 int slots = GetStackSlotCount();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000218 ASSERT(slots != 0 || !info()->IsOptimizing());
219 if (slots > 0) {
220 if (slots == 1) {
221 if (dynamic_frame_alignment_) {
222 __ push(edx);
223 } else {
224 __ push(Immediate(kNoAlignmentPadding));
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +0000225 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000226 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000227 if (FLAG_debug_code) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000228 __ sub(Operand(esp), Immediate(slots * kPointerSize));
229 __ push(eax);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000230 __ mov(Operand(eax), Immediate(slots));
231 Label loop;
232 __ bind(&loop);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000233 __ mov(MemOperand(esp, eax, times_4, 0),
234 Immediate(kSlotsZapValue));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000235 __ dec(eax);
236 __ j(not_zero, &loop);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000237 __ pop(eax);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000238 } else {
239 __ sub(Operand(esp), Immediate(slots * kPointerSize));
240#ifdef _MSC_VER
241 // On windows, you may not access the stack more than one page below
242 // the most recently mapped page. To make the allocated area randomly
243 // accessible, we write to each page in turn (the value is irrelevant).
244 const int kPageSize = 4 * KB;
245 for (int offset = slots * kPointerSize - kPageSize;
246 offset > 0;
247 offset -= kPageSize) {
248 __ mov(Operand(esp, offset), eax);
249 }
250#endif
251 }
252
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000253 if (support_aligned_spilled_doubles_) {
254 Comment(";;; Store dynamic frame alignment tag for spilled doubles");
255 // Store dynamic frame alignment state in the first local.
256 int offset = JavaScriptFrameConstants::kDynamicAlignmentStateOffset;
257 if (dynamic_frame_alignment_) {
258 __ mov(Operand(ebp, offset), edx);
259 } else {
260 __ mov(Operand(ebp, offset), Immediate(kNoAlignmentPadding));
261 }
262 }
263 }
264
265 if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(SSE2)) {
266 Comment(";;; Save clobbered callee double registers");
ulan@chromium.org750145a2013-03-07 15:14:13 +0000267 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000268 int count = 0;
269 BitVector* doubles = chunk()->allocated_double_registers();
270 BitVector::Iterator save_iterator(doubles);
271 while (!save_iterator.Done()) {
272 __ movdbl(MemOperand(esp, count * kDoubleSize),
273 XMMRegister::FromAllocationIndex(save_iterator.Current()));
274 save_iterator.Advance();
275 count++;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000276 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000277 }
278 }
279
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000280 // Possibly allocate a local context.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000281 int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000282 if (heap_slots > 0) {
283 Comment(";;; Allocate local context");
284 // Argument to NewContext is the function, which is still in edi.
285 __ push(edi);
286 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
287 FastNewContextStub stub(heap_slots);
288 __ CallStub(&stub);
289 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000290 __ CallRuntime(Runtime::kNewFunctionContext, 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000291 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000292 RecordSafepoint(Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000293 // Context is returned in both eax and esi. It replaces the context
294 // passed to us. It's saved in the stack and kept live in esi.
295 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
296
297 // Copy parameters into context if necessary.
298 int num_parameters = scope()->num_parameters();
299 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000300 Variable* var = scope()->parameter(i);
301 if (var->IsContextSlot()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000302 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
303 (num_parameters - 1 - i) * kPointerSize;
304 // Load parameter from stack.
305 __ mov(eax, Operand(ebp, parameter_offset));
306 // Store it in the context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000307 int context_offset = Context::SlotOffset(var->index());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000308 __ mov(Operand(esi, context_offset), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000309 // Update the write barrier. This clobbers eax and ebx.
310 __ RecordWriteContextSlot(esi,
311 context_offset,
312 eax,
313 ebx,
314 kDontSaveFPRegs);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000315 }
316 }
317 Comment(";;; End allocate local context");
318 }
319
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000320 // Trace the call.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000321 if (FLAG_trace && info()->IsOptimizing()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000322 // We have not executed any compiled code yet, so esi still holds the
323 // incoming context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000324 __ CallRuntime(Runtime::kTraceEnter, 0);
325 }
326 return !is_aborted();
327}
328
329
330bool LCodeGen::GenerateBody() {
331 ASSERT(is_generating());
332 bool emit_instructions = true;
333 for (current_instruction_ = 0;
334 !is_aborted() && current_instruction_ < instructions_->length();
335 current_instruction_++) {
336 LInstruction* instr = instructions_->at(current_instruction_);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000337
338 // Don't emit code for basic blocks with a replacement.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000339 if (instr->IsLabel()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000340 emit_instructions = !LLabel::cast(instr)->HasReplacement();
341 }
342 if (!emit_instructions) continue;
343
344 if (FLAG_code_comments && instr->HasInterestingComment(this)) {
345 Comment(";;; <@%d,#%d> %s",
346 current_instruction_,
347 instr->hydrogen_value()->id(),
348 instr->Mnemonic());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000349 }
350
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000351 if (!CpuFeatures::IsSupported(SSE2)) FlushX87StackIfNecessary(instr);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000352
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000353 instr->CompileToNative(this);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000354
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000355 if (!CpuFeatures::IsSupported(SSE2)) {
356 ASSERT(!instr->HasDoubleRegisterResult() || x87_stack_depth_ == 1);
357 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
358 __ VerifyX87StackDepth(x87_stack_depth_);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000359 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000360 }
361 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000362 EnsureSpaceForLazyDeopt();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000363 return !is_aborted();
364}
365
366
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000367bool LCodeGen::GenerateJumpTable() {
368 Label needs_frame_not_call;
369 Label needs_frame_is_call;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000370 if (jump_table_.length() > 0) {
371 Comment(";;; -------------------- Jump table --------------------");
372 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000373 for (int i = 0; i < jump_table_.length(); i++) {
374 __ bind(&jump_table_[i].label);
375 Address entry = jump_table_[i].address;
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000376 Deoptimizer::BailoutType type = jump_table_[i].bailout_type;
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000377 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000378 if (id == Deoptimizer::kNotDeoptimizationEntry) {
379 Comment(";;; jump table entry %d.", i);
380 } else {
381 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id);
382 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000383 if (jump_table_[i].needs_frame) {
384 __ push(Immediate(ExternalReference::ForDeoptEntry(entry)));
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000385 if (type == Deoptimizer::LAZY) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000386 if (needs_frame_is_call.is_bound()) {
387 __ jmp(&needs_frame_is_call);
388 } else {
389 __ bind(&needs_frame_is_call);
390 __ push(MemOperand(ebp, StandardFrameConstants::kContextOffset));
391 // This variant of deopt can only be used with stubs. Since we don't
392 // have a function pointer to install in the stack frame that we're
393 // building, install a special marker there instead.
394 ASSERT(info()->IsStub());
395 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
396 // Push a PC inside the function so that the deopt code can find where
397 // the deopt comes from. It doesn't have to be the precise return
398 // address of a "calling" LAZY deopt, it only has to be somewhere
399 // inside the code body.
400 Label push_approx_pc;
401 __ call(&push_approx_pc);
402 __ bind(&push_approx_pc);
403 // Push the continuation which was stashed were the ebp should
404 // be. Replace it with the saved ebp.
405 __ push(MemOperand(esp, 3 * kPointerSize));
406 __ mov(MemOperand(esp, 4 * kPointerSize), ebp);
407 __ lea(ebp, MemOperand(esp, 4 * kPointerSize));
408 __ ret(0); // Call the continuation without clobbering registers.
409 }
410 } else {
411 if (needs_frame_not_call.is_bound()) {
412 __ jmp(&needs_frame_not_call);
413 } else {
414 __ bind(&needs_frame_not_call);
415 __ push(MemOperand(ebp, StandardFrameConstants::kContextOffset));
416 // This variant of deopt can only be used with stubs. Since we don't
417 // have a function pointer to install in the stack frame that we're
418 // building, install a special marker there instead.
419 ASSERT(info()->IsStub());
420 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
421 // Push the continuation which was stashed were the ebp should
422 // be. Replace it with the saved ebp.
423 __ push(MemOperand(esp, 2 * kPointerSize));
424 __ mov(MemOperand(esp, 3 * kPointerSize), ebp);
425 __ lea(ebp, MemOperand(esp, 3 * kPointerSize));
426 __ ret(0); // Call the continuation without clobbering registers.
427 }
428 }
429 } else {
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000430 if (type == Deoptimizer::LAZY) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000431 __ call(entry, RelocInfo::RUNTIME_ENTRY);
432 } else {
433 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
434 }
435 }
436 }
437 return !is_aborted();
438}
439
440
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000441bool LCodeGen::GenerateDeferredCode() {
442 ASSERT(is_generating());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000443 if (deferred_.length() > 0) {
444 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
445 LDeferredCode* code = deferred_[i];
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000446 Comment(";;; <@%d,#%d> "
447 "-------------------- Deferred %s --------------------",
448 code->instruction_index(),
449 code->instr()->hydrogen_value()->id(),
450 code->instr()->Mnemonic());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000451 __ bind(code->entry());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000452 if (NeedsDeferredFrame()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000453 Comment(";;; Build frame");
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000454 ASSERT(!frame_is_built_);
455 ASSERT(info()->IsStub());
456 frame_is_built_ = true;
457 // Build the frame in such a way that esi isn't trashed.
458 __ push(ebp); // Caller's frame pointer.
459 __ push(Operand(ebp, StandardFrameConstants::kContextOffset));
460 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
461 __ lea(ebp, Operand(esp, 2 * kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000462 Comment(";;; Deferred code");
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000463 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000464 code->Generate();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000465 if (NeedsDeferredFrame()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000466 Comment(";;; Destroy frame");
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000467 ASSERT(frame_is_built_);
468 frame_is_built_ = false;
469 __ mov(esp, ebp);
470 __ pop(ebp);
471 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000472 __ jmp(code->exit());
473 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000474 }
475
476 // Deferred code is the last part of the instruction sequence. Mark
477 // the generated code as done unless we bailed out.
478 if (!is_aborted()) status_ = DONE;
479 return !is_aborted();
480}
481
482
483bool LCodeGen::GenerateSafepointTable() {
484 ASSERT(is_done());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000485 if (!info()->IsStub()) {
486 // For lazy deoptimization we need space to patch a call after every call.
487 // Ensure there is always space for such patching, even if the code ends
488 // in a call.
489 int target_offset = masm()->pc_offset() + Deoptimizer::patch_size();
490 while (masm()->pc_offset() < target_offset) {
491 masm()->nop();
492 }
493 }
danno@chromium.org160a7b02011-04-18 15:51:38 +0000494 safepoints_.Emit(masm(), GetStackSlotCount());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000495 return !is_aborted();
496}
497
498
499Register LCodeGen::ToRegister(int index) const {
500 return Register::FromAllocationIndex(index);
501}
502
503
504XMMRegister LCodeGen::ToDoubleRegister(int index) const {
505 return XMMRegister::FromAllocationIndex(index);
506}
507
508
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000509bool LCodeGen::IsX87TopOfStack(LOperand* op) const {
510 return op->IsDoubleRegister();
511}
512
513
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000514void LCodeGen::ReadX87Operand(Operand dst) {
515 ASSERT(x87_stack_depth_ == 1);
516 __ fst_d(dst);
517}
518
519
520void LCodeGen::PushX87DoubleOperand(Operand src) {
521 ASSERT(x87_stack_depth_ == 0);
522 x87_stack_depth_++;
523 __ fld_d(src);
524}
525
526
527void LCodeGen::PushX87FloatOperand(Operand src) {
528 ASSERT(x87_stack_depth_ == 0);
529 x87_stack_depth_++;
530 __ fld_s(src);
531}
532
533
534void LCodeGen::PopX87() {
535 ASSERT(x87_stack_depth_ == 1);
536 x87_stack_depth_--;
537 __ fstp(0);
538}
539
540
541void LCodeGen::CurrentInstructionReturnsX87Result() {
542 ASSERT(x87_stack_depth_ <= 1);
543 if (x87_stack_depth_ == 0) {
544 x87_stack_depth_ = 1;
545 }
546}
547
548
549void LCodeGen::FlushX87StackIfNecessary(LInstruction* instr) {
550 if (x87_stack_depth_ > 0) {
551 if ((instr->ClobbersDoubleRegisters() ||
552 instr->HasDoubleRegisterResult()) &&
553 !instr->HasDoubleRegisterInput()) {
554 PopX87();
555 }
556 }
557}
558
559
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000560Register LCodeGen::ToRegister(LOperand* op) const {
561 ASSERT(op->IsRegister());
562 return ToRegister(op->index());
563}
564
565
566XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
567 ASSERT(op->IsDoubleRegister());
568 return ToDoubleRegister(op->index());
569}
570
571
572int LCodeGen::ToInteger32(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000573 HConstant* constant = chunk_->LookupConstant(op);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000574 return constant->Integer32Value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000575}
576
577
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000578Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000579 HConstant* constant = chunk_->LookupConstant(op);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000580 ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000581 return constant->handle();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000582}
583
584
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000585double LCodeGen::ToDouble(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000586 HConstant* constant = chunk_->LookupConstant(op);
587 ASSERT(constant->HasDoubleValue());
588 return constant->DoubleValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000589}
590
591
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000592bool LCodeGen::IsInteger32(LConstantOperand* op) const {
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +0000593 return chunk_->LookupLiteralRepresentation(op).IsSmiOrInteger32();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000594}
595
596
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000597bool LCodeGen::IsSmi(LConstantOperand* op) const {
598 return chunk_->LookupLiteralRepresentation(op).IsSmi();
599}
600
601
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000602Operand LCodeGen::ToOperand(LOperand* op) const {
603 if (op->IsRegister()) return Operand(ToRegister(op));
604 if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
605 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
jkummerow@chromium.orgac360712013-02-11 09:00:07 +0000606 return Operand(ebp, StackSlotOffset(op->index()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000607}
608
609
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000610Operand LCodeGen::HighOperand(LOperand* op) {
611 ASSERT(op->IsDoubleStackSlot());
jkummerow@chromium.orgac360712013-02-11 09:00:07 +0000612 return Operand(ebp, StackSlotOffset(op->index()) + kPointerSize);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000613}
614
615
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000616void LCodeGen::WriteTranslation(LEnvironment* environment,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000617 Translation* translation,
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000618 int* pushed_arguments_index,
619 int* pushed_arguments_count) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000620 if (environment == NULL) return;
621
622 // The translation includes one command per value in the environment.
623 int translation_size = environment->values()->length();
624 // The output frame height does not include the parameters.
625 int height = translation_size - environment->parameter_count();
626
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000627 // Function parameters are arguments to the outermost environment. The
628 // arguments index points to the first element of a sequence of tagged
629 // values on the stack that represent the arguments. This needs to be
630 // kept in sync with the LArgumentsElements implementation.
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000631 *pushed_arguments_index = -environment->parameter_count();
632 *pushed_arguments_count = environment->parameter_count();
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000633
634 WriteTranslation(environment->outer(),
635 translation,
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000636 pushed_arguments_index,
637 pushed_arguments_count);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000638 bool has_closure_id = !info()->closure().is_null() &&
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000639 !info()->closure().is_identical_to(environment->closure());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000640 int closure_id = has_closure_id
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000641 ? DefineDeoptimizationLiteral(environment->closure())
642 : Translation::kSelfLiteralId;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000643 switch (environment->frame_type()) {
644 case JS_FUNCTION:
645 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
646 break;
647 case JS_CONSTRUCT:
648 translation->BeginConstructStubFrame(closure_id, translation_size);
649 break;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000650 case JS_GETTER:
651 ASSERT(translation_size == 1);
652 ASSERT(height == 0);
653 translation->BeginGetterStubFrame(closure_id);
654 break;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000655 case JS_SETTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000656 ASSERT(translation_size == 2);
657 ASSERT(height == 0);
658 translation->BeginSetterStubFrame(closure_id);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000659 break;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000660 case ARGUMENTS_ADAPTOR:
661 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
662 break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000663 case STUB:
664 translation->BeginCompiledStubFrame();
665 break;
666 default:
667 UNREACHABLE();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000668 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000669
670 // Inlined frames which push their arguments cause the index to be
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000671 // bumped and another stack area to be used for materialization,
672 // otherwise actual argument values are unknown for inlined frames.
673 bool arguments_known = true;
674 int arguments_index = *pushed_arguments_index;
675 int arguments_count = *pushed_arguments_count;
676 if (environment->entry() != NULL) {
677 arguments_known = environment->entry()->arguments_pushed();
678 arguments_index = arguments_index < 0
679 ? GetStackSlotCount() : arguments_index + arguments_count;
680 arguments_count = environment->entry()->arguments_count() + 1;
681 if (environment->entry()->arguments_pushed()) {
682 *pushed_arguments_index = arguments_index;
683 *pushed_arguments_count = arguments_count;
684 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000685 }
686
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000687 for (int i = 0; i < translation_size; ++i) {
688 LOperand* value = environment->values()->at(i);
689 // spilled_registers_ and spilled_double_registers_ are either
690 // both NULL or both set.
691 if (environment->spilled_registers() != NULL && value != NULL) {
692 if (value->IsRegister() &&
693 environment->spilled_registers()[value->index()] != NULL) {
694 translation->MarkDuplicate();
695 AddToTranslation(translation,
696 environment->spilled_registers()[value->index()],
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000697 environment->HasTaggedValueAt(i),
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000698 environment->HasUint32ValueAt(i),
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000699 arguments_known,
700 arguments_index,
701 arguments_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000702 } else if (
703 value->IsDoubleRegister() &&
704 environment->spilled_double_registers()[value->index()] != NULL) {
705 translation->MarkDuplicate();
706 AddToTranslation(
707 translation,
708 environment->spilled_double_registers()[value->index()],
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000709 false,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000710 false,
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000711 arguments_known,
712 arguments_index,
713 arguments_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000714 }
715 }
716
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000717 AddToTranslation(translation,
718 value,
719 environment->HasTaggedValueAt(i),
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000720 environment->HasUint32ValueAt(i),
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000721 arguments_known,
722 arguments_index,
723 arguments_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000724 }
725}
726
727
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000728void LCodeGen::AddToTranslation(Translation* translation,
729 LOperand* op,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000730 bool is_tagged,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000731 bool is_uint32,
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000732 bool arguments_known,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000733 int arguments_index,
734 int arguments_count) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000735 if (op == NULL) {
736 // TODO(twuerthinger): Introduce marker operands to indicate that this value
737 // is not present and must be reconstructed from the deoptimizer. Currently
738 // this is only used for the arguments object.
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000739 translation->StoreArgumentsObject(
740 arguments_known, arguments_index, arguments_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000741 } else if (op->IsStackSlot()) {
742 if (is_tagged) {
743 translation->StoreStackSlot(op->index());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000744 } else if (is_uint32) {
745 translation->StoreUint32StackSlot(op->index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000746 } else {
747 translation->StoreInt32StackSlot(op->index());
748 }
749 } else if (op->IsDoubleStackSlot()) {
750 translation->StoreDoubleStackSlot(op->index());
751 } else if (op->IsArgument()) {
752 ASSERT(is_tagged);
danno@chromium.org160a7b02011-04-18 15:51:38 +0000753 int src_index = GetStackSlotCount() + op->index();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000754 translation->StoreStackSlot(src_index);
755 } else if (op->IsRegister()) {
756 Register reg = ToRegister(op);
757 if (is_tagged) {
758 translation->StoreRegister(reg);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000759 } else if (is_uint32) {
760 translation->StoreUint32Register(reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000761 } else {
762 translation->StoreInt32Register(reg);
763 }
764 } else if (op->IsDoubleRegister()) {
765 XMMRegister reg = ToDoubleRegister(op);
766 translation->StoreDoubleRegister(reg);
767 } else if (op->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000768 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
769 int src_index = DefineDeoptimizationLiteral(constant->handle());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000770 translation->StoreLiteral(src_index);
771 } else {
772 UNREACHABLE();
773 }
774}
775
776
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000777void LCodeGen::CallCodeGeneric(Handle<Code> code,
778 RelocInfo::Mode mode,
779 LInstruction* instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000780 SafepointMode safepoint_mode) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000781 ASSERT(instr != NULL);
782 LPointerMap* pointers = instr->pointer_map();
783 RecordPosition(pointers->position());
784 __ call(code, mode);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000785 RecordSafepointWithLazyDeopt(instr, safepoint_mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000786
787 // Signal that we don't inline smi code before these stubs in the
788 // optimizing code generator.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000789 if (code->kind() == Code::BINARY_OP_IC ||
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000790 code->kind() == Code::COMPARE_IC) {
791 __ nop();
792 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000793}
794
795
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000796void LCodeGen::CallCode(Handle<Code> code,
797 RelocInfo::Mode mode,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000798 LInstruction* instr) {
799 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000800}
801
802
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000803void LCodeGen::CallRuntime(const Runtime::Function* fun,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000804 int argc,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000805 LInstruction* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000806 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000807 ASSERT(instr->HasPointerMap());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000808 LPointerMap* pointers = instr->pointer_map();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000809 RecordPosition(pointers->position());
810
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000811 __ CallRuntime(fun, argc);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000812
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000813 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000814
815 ASSERT(info()->is_calling());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000816}
817
818
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000819void LCodeGen::LoadContextFromDeferred(LOperand* context) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000820 if (context->IsRegister()) {
821 if (!ToRegister(context).is(esi)) {
822 __ mov(esi, ToRegister(context));
823 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000824 } else if (context->IsStackSlot()) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000825 __ mov(esi, ToOperand(context));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000826 } else if (context->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000827 HConstant* constant =
828 chunk_->LookupConstant(LConstantOperand::cast(context));
829 __ LoadHeapObject(esi, Handle<Context>::cast(constant->handle()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000830 } else {
831 UNREACHABLE();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000832 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000833}
834
835void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
836 int argc,
837 LInstruction* instr,
838 LOperand* context) {
839 LoadContextFromDeferred(context);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000840
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000841 __ CallRuntimeSaveDoubles(id);
842 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000843 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000844
845 ASSERT(info()->is_calling());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000846}
847
848
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000849void LCodeGen::RegisterEnvironmentForDeoptimization(
850 LEnvironment* environment, Safepoint::DeoptMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000851 if (!environment->HasBeenRegistered()) {
852 // Physical stack frame layout:
853 // -x ............. -4 0 ..................................... y
854 // [incoming arguments] [spill slots] [pushed outgoing arguments]
855
856 // Layout of the environment:
857 // 0 ..................................................... size-1
858 // [parameters] [locals] [expression stack including arguments]
859
860 // Layout of the translation:
861 // 0 ........................................................ size - 1 + 4
862 // [expression stack including arguments] [locals] [4 words] [parameters]
863 // |>------------ translation_size ------------<|
864
865 int frame_count = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000866 int jsframe_count = 0;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000867 int args_index = 0;
868 int args_count = 0;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000869 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
870 ++frame_count;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000871 if (e->frame_type() == JS_FUNCTION) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000872 ++jsframe_count;
873 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000874 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000875 Translation translation(&translations_, frame_count, jsframe_count, zone());
876 WriteTranslation(environment, &translation, &args_index, &args_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000877 int deoptimization_index = deoptimizations_.length();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000878 int pc_offset = masm()->pc_offset();
879 environment->Register(deoptimization_index,
880 translation.index(),
881 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000882 deoptimizations_.Add(environment, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000883 }
884}
885
886
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000887void LCodeGen::DeoptimizeIf(Condition cc,
888 LEnvironment* environment,
889 Deoptimizer::BailoutType bailout_type) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000890 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000891 ASSERT(environment->HasBeenRegistered());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000892 // It's an error to deoptimize with the x87 fp stack in use.
893 ASSERT(x87_stack_depth_ == 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000894 int id = environment->deoptimization_index();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000895 ASSERT(info()->IsOptimizing() || info()->IsStub());
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000896 Address entry =
897 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000898 if (entry == NULL) {
899 Abort("bailout was not prepared");
900 return;
901 }
902
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000903 if (FLAG_deopt_every_n_times != 0 && !info()->IsStub()) {
904 Handle<SharedFunctionInfo> shared(info()->shared_info());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000905 Label no_deopt;
906 __ pushfd();
907 __ push(eax);
908 __ push(ebx);
909 __ mov(ebx, shared);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000910 __ mov(eax,
911 FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000912 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000913 __ j(not_zero, &no_deopt, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000914 if (FLAG_trap_on_deopt) __ int3();
915 __ mov(eax, Immediate(Smi::FromInt(FLAG_deopt_every_n_times)));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000916 __ mov(FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset),
917 eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000918 __ pop(ebx);
919 __ pop(eax);
920 __ popfd();
921 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
922
923 __ bind(&no_deopt);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000924 __ mov(FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset),
925 eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000926 __ pop(ebx);
927 __ pop(eax);
928 __ popfd();
929 }
930
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000931 if (FLAG_trap_on_deopt) {
932 Label done;
933 if (cc != no_condition) {
934 __ j(NegateCondition(cc), &done, Label::kNear);
935 }
936 __ int3();
937 __ bind(&done);
938 }
939
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000940 ASSERT(info()->IsStub() || frame_is_built_);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000941 if (cc == no_condition && frame_is_built_) {
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000942 if (bailout_type == Deoptimizer::LAZY) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000943 __ call(entry, RelocInfo::RUNTIME_ENTRY);
944 } else {
945 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
946 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000947 } else {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000948 // We often have several deopts to the same entry, reuse the last
949 // jump entry if this is the case.
950 if (jump_table_.is_empty() ||
951 jump_table_.last().address != entry ||
952 jump_table_.last().needs_frame != !frame_is_built_ ||
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000953 jump_table_.last().bailout_type != bailout_type) {
954 Deoptimizer::JumpTableEntry table_entry(entry,
955 bailout_type,
956 !frame_is_built_);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000957 jump_table_.Add(table_entry, zone());
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +0000958 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000959 if (cc == no_condition) {
960 __ jmp(&jump_table_.last().label);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000961 } else {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000962 __ j(cc, &jump_table_.last().label);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000963 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000964 }
965}
966
967
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000968void LCodeGen::DeoptimizeIf(Condition cc,
969 LEnvironment* environment) {
970 Deoptimizer::BailoutType bailout_type = info()->IsStub()
971 ? Deoptimizer::LAZY
972 : Deoptimizer::EAGER;
973 DeoptimizeIf(cc, environment, bailout_type);
974}
975
976
977void LCodeGen::SoftDeoptimize(LEnvironment* environment) {
978 ASSERT(!info()->IsStub());
979 DeoptimizeIf(no_condition, environment, Deoptimizer::SOFT);
980}
981
982
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +0000983void LCodeGen::RegisterDependentCodeForEmbeddedMaps(Handle<Code> code) {
984 ZoneList<Handle<Map> > maps(1, zone());
985 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
986 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) {
987 RelocInfo::Mode mode = it.rinfo()->rmode();
988 if (mode == RelocInfo::EMBEDDED_OBJECT &&
989 it.rinfo()->target_object()->IsMap()) {
990 Handle<Map> map(Map::cast(it.rinfo()->target_object()));
991 if (map->CanTransition()) {
992 maps.Add(map, zone());
993 }
994 }
995 }
996#ifdef VERIFY_HEAP
997 // This disables verification of weak embedded maps after full GC.
998 // AddDependentCode can cause a GC, which would observe the state where
999 // this code is not yet in the depended code lists of the embedded maps.
1000 NoWeakEmbeddedMapsVerificationScope disable_verification_of_embedded_maps;
1001#endif
1002 for (int i = 0; i < maps.length(); i++) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +00001003 maps.at(i)->AddDependentCode(DependentCode::kWeaklyEmbeddedGroup, code);
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +00001004 }
1005}
1006
1007
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001008void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
1009 int length = deoptimizations_.length();
1010 if (length == 0) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001011 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001012 factory()->NewDeoptimizationInputData(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001013
svenpanne@chromium.org876cca82013-03-18 14:43:20 +00001014 Handle<ByteArray> translations =
1015 translations_.CreateByteArray(isolate()->factory());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001016 data->SetTranslationByteArray(*translations);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001017 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
1018
1019 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001020 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001021 { AllowDeferredHandleDereference copy_handles;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001022 for (int i = 0; i < deoptimization_literals_.length(); i++) {
1023 literals->set(i, *deoptimization_literals_[i]);
1024 }
1025 data->SetLiteralArray(*literals);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001026 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001027
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001028 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001029 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
1030
1031 // Populate the deoptimization entries.
1032 for (int i = 0; i < length; i++) {
1033 LEnvironment* env = deoptimizations_[i];
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001034 data->SetAstId(i, env->ast_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001035 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
1036 data->SetArgumentsStackHeight(i,
1037 Smi::FromInt(env->arguments_stack_height()));
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001038 data->SetPc(i, Smi::FromInt(env->pc_offset()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001039 }
1040 code->set_deoptimization_data(*data);
1041}
1042
1043
1044int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
1045 int result = deoptimization_literals_.length();
1046 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
1047 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
1048 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001049 deoptimization_literals_.Add(literal, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001050 return result;
1051}
1052
1053
1054void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
1055 ASSERT(deoptimization_literals_.length() == 0);
1056
1057 const ZoneList<Handle<JSFunction> >* inlined_closures =
1058 chunk()->inlined_closures();
1059
1060 for (int i = 0, length = inlined_closures->length();
1061 i < length;
1062 i++) {
1063 DefineDeoptimizationLiteral(inlined_closures->at(i));
1064 }
1065
1066 inlined_function_count_ = deoptimization_literals_.length();
1067}
1068
1069
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001070void LCodeGen::RecordSafepointWithLazyDeopt(
1071 LInstruction* instr, SafepointMode safepoint_mode) {
1072 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
1073 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
1074 } else {
1075 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
1076 RecordSafepointWithRegisters(
1077 instr->pointer_map(), 0, Safepoint::kLazyDeopt);
1078 }
1079}
1080
1081
ager@chromium.org378b34e2011-01-28 08:04:38 +00001082void LCodeGen::RecordSafepoint(
1083 LPointerMap* pointers,
1084 Safepoint::Kind kind,
1085 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001086 Safepoint::DeoptMode deopt_mode) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001087 ASSERT(kind == expected_safepoint_kind_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001088 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001089 Safepoint safepoint =
1090 safepoints_.DefineSafepoint(masm(), kind, arguments, deopt_mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001091 for (int i = 0; i < operands->length(); i++) {
1092 LOperand* pointer = operands->at(i);
1093 if (pointer->IsStackSlot()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001094 safepoint.DefinePointerSlot(pointer->index(), zone());
ager@chromium.org378b34e2011-01-28 08:04:38 +00001095 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001096 safepoint.DefinePointerRegister(ToRegister(pointer), zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001097 }
1098 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00001099}
1100
1101
1102void LCodeGen::RecordSafepoint(LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001103 Safepoint::DeoptMode mode) {
1104 RecordSafepoint(pointers, Safepoint::kSimple, 0, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001105}
1106
1107
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001108void LCodeGen::RecordSafepoint(Safepoint::DeoptMode mode) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001109 LPointerMap empty_pointers(RelocInfo::kNoPosition, zone());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001110 RecordSafepoint(&empty_pointers, mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001111}
1112
1113
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001114void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
1115 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001116 Safepoint::DeoptMode mode) {
1117 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001118}
1119
1120
1121void LCodeGen::RecordPosition(int position) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001122 if (position == RelocInfo::kNoPosition) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001123 masm()->positions_recorder()->RecordPosition(position);
1124}
1125
1126
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001127static const char* LabelType(LLabel* label) {
1128 if (label->is_loop_header()) return " (loop header)";
1129 if (label->is_osr_entry()) return " (OSR entry)";
1130 return "";
1131}
1132
1133
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001134void LCodeGen::DoLabel(LLabel* label) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001135 Comment(";;; <@%d,#%d> -------------------- B%d%s --------------------",
1136 current_instruction_,
1137 label->hydrogen_value()->id(),
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00001138 label->block_id(),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001139 LabelType(label));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001140 __ bind(label->label());
1141 current_block_ = label->block_id();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001142 DoGap(label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001143}
1144
1145
1146void LCodeGen::DoParallelMove(LParallelMove* move) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001147 resolver_.Resolve(move);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001148}
1149
1150
1151void LCodeGen::DoGap(LGap* gap) {
1152 for (int i = LGap::FIRST_INNER_POSITION;
1153 i <= LGap::LAST_INNER_POSITION;
1154 i++) {
1155 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
1156 LParallelMove* move = gap->GetParallelMove(inner_pos);
1157 if (move != NULL) DoParallelMove(move);
1158 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001159}
1160
1161
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001162void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
1163 DoGap(instr);
1164}
1165
1166
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001167void LCodeGen::DoParameter(LParameter* instr) {
1168 // Nothing to do.
1169}
1170
1171
1172void LCodeGen::DoCallStub(LCallStub* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001173 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001174 ASSERT(ToRegister(instr->result()).is(eax));
1175 switch (instr->hydrogen()->major_key()) {
1176 case CodeStub::RegExpConstructResult: {
1177 RegExpConstructResultStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001178 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001179 break;
1180 }
1181 case CodeStub::RegExpExec: {
1182 RegExpExecStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001183 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001184 break;
1185 }
1186 case CodeStub::SubString: {
1187 SubStringStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001188 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001189 break;
1190 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001191 case CodeStub::NumberToString: {
1192 NumberToStringStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001193 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001194 break;
1195 }
1196 case CodeStub::StringAdd: {
1197 StringAddStub stub(NO_STRING_ADD_FLAGS);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001198 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001199 break;
1200 }
1201 case CodeStub::StringCompare: {
1202 StringCompareStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001203 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001204 break;
1205 }
1206 case CodeStub::TranscendentalCache: {
whesse@chromium.org023421e2010-12-21 12:19:12 +00001207 TranscendentalCacheStub stub(instr->transcendental_type(),
1208 TranscendentalCacheStub::TAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001209 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001210 break;
1211 }
1212 default:
1213 UNREACHABLE();
1214 }
1215}
1216
1217
1218void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
1219 // Nothing to do.
1220}
1221
1222
1223void LCodeGen::DoModI(LModI* instr) {
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001224 HMod* hmod = instr->hydrogen();
1225 HValue* left = hmod->left();
1226 HValue* right = hmod->right();
1227 if (hmod->HasPowerOf2Divisor()) {
1228 // TODO(svenpanne) We should really do the strength reduction on the
1229 // Hydrogen level.
1230 Register left_reg = ToRegister(instr->left());
1231 ASSERT(left_reg.is(ToRegister(instr->result())));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001232
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001233 // Note: The code below even works when right contains kMinInt.
1234 int32_t divisor = Abs(right->GetInteger32Constant());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001235
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001236 Label left_is_not_negative, done;
1237 if (left->CanBeNegative()) {
1238 __ test(left_reg, Operand(left_reg));
1239 __ j(not_sign, &left_is_not_negative, Label::kNear);
1240 __ neg(left_reg);
1241 __ and_(left_reg, divisor - 1);
1242 __ neg(left_reg);
1243 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1244 DeoptimizeIf(zero, instr->environment());
1245 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001246 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001247 }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001248
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001249 __ bind(&left_is_not_negative);
1250 __ and_(left_reg, divisor - 1);
1251 __ bind(&done);
1252
1253 } else if (hmod->has_fixed_right_arg()) {
1254 Register left_reg = ToRegister(instr->left());
1255 ASSERT(left_reg.is(ToRegister(instr->result())));
1256 Register right_reg = ToRegister(instr->right());
1257
1258 int32_t divisor = hmod->fixed_right_arg_value();
1259 ASSERT(IsPowerOf2(divisor));
1260
1261 // Check if our assumption of a fixed right operand still holds.
1262 __ cmp(right_reg, Immediate(divisor));
1263 DeoptimizeIf(not_equal, instr->environment());
1264
1265 Label left_is_not_negative, done;
1266 if (left->CanBeNegative()) {
1267 __ test(left_reg, Operand(left_reg));
1268 __ j(not_sign, &left_is_not_negative, Label::kNear);
1269 __ neg(left_reg);
1270 __ and_(left_reg, divisor - 1);
1271 __ neg(left_reg);
1272 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1273 DeoptimizeIf(zero, instr->environment());
1274 }
1275 __ jmp(&done, Label::kNear);
1276 }
1277
1278 __ bind(&left_is_not_negative);
1279 __ and_(left_reg, divisor - 1);
1280 __ bind(&done);
1281
1282 } else {
1283 Register left_reg = ToRegister(instr->left());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001284 ASSERT(left_reg.is(eax));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001285 Register right_reg = ToRegister(instr->right());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001286 ASSERT(!right_reg.is(eax));
1287 ASSERT(!right_reg.is(edx));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001288 Register result_reg = ToRegister(instr->result());
1289 ASSERT(result_reg.is(edx));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001290
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001291 Label done;
1292 // Check for x % 0, idiv would signal a divide error. We have to
1293 // deopt in this case because we can't return a NaN.
1294 if (right->CanBeZero()) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001295 __ test(right_reg, Operand(right_reg));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001296 DeoptimizeIf(zero, instr->environment());
1297 }
1298
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001299 // Check for kMinInt % -1, idiv would signal a divide error. We
1300 // have to deopt if we care about -0, because we can't return that.
1301 if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) {
1302 Label no_overflow_possible;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001303 __ cmp(left_reg, kMinInt);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001304 __ j(not_equal, &no_overflow_possible, Label::kNear);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001305 __ cmp(right_reg, -1);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001306 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1307 DeoptimizeIf(equal, instr->environment());
1308 } else {
1309 __ j(not_equal, &no_overflow_possible, Label::kNear);
1310 __ Set(result_reg, Immediate(0));
1311 __ jmp(&done, Label::kNear);
1312 }
1313 __ bind(&no_overflow_possible);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001314 }
1315
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001316 // Sign extend dividend in eax into edx:eax.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001317 __ cdq();
1318
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001319 // If we care about -0, test if the dividend is <0 and the result is 0.
1320 if (left->CanBeNegative() &&
1321 hmod->CanBeZero() &&
1322 hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001323 Label positive_left;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001324 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001325 __ j(not_sign, &positive_left, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001326 __ idiv(right_reg);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001327 __ test(result_reg, Operand(result_reg));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001328 DeoptimizeIf(zero, instr->environment());
1329 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001330 __ bind(&positive_left);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001331 }
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001332 __ idiv(right_reg);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001333 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001334 }
1335}
1336
1337
1338void LCodeGen::DoDivI(LDivI* instr) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001339 if (!instr->is_flooring() && instr->hydrogen()->HasPowerOf2Divisor()) {
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001340 Register dividend = ToRegister(instr->left());
1341 int32_t divisor =
1342 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
1343 int32_t test_value = 0;
1344 int32_t power = 0;
1345
1346 if (divisor > 0) {
1347 test_value = divisor - 1;
1348 power = WhichPowerOf2(divisor);
1349 } else {
1350 // Check for (0 / -x) that will produce negative zero.
1351 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1352 __ test(dividend, Operand(dividend));
1353 DeoptimizeIf(zero, instr->environment());
1354 }
1355 // Check for (kMinInt / -1).
1356 if (divisor == -1 && instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1357 __ cmp(dividend, kMinInt);
1358 DeoptimizeIf(zero, instr->environment());
1359 }
1360 test_value = - divisor - 1;
1361 power = WhichPowerOf2(-divisor);
1362 }
1363
1364 if (test_value != 0) {
1365 // Deoptimize if remainder is not 0.
1366 __ test(dividend, Immediate(test_value));
1367 DeoptimizeIf(not_zero, instr->environment());
1368 __ sar(dividend, power);
1369 }
1370
1371 if (divisor < 0) __ neg(dividend);
1372
1373 return;
1374 }
1375
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001376 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001377 ASSERT(ToRegister(instr->result()).is(eax));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001378 ASSERT(ToRegister(instr->left()).is(eax));
1379 ASSERT(!ToRegister(instr->right()).is(eax));
1380 ASSERT(!ToRegister(instr->right()).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001381
1382 Register left_reg = eax;
1383
1384 // Check for x / 0.
1385 Register right_reg = ToRegister(right);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001386 if (instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001387 __ test(right_reg, ToOperand(right));
1388 DeoptimizeIf(zero, instr->environment());
1389 }
1390
1391 // Check for (0 / -x) that will produce negative zero.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001392 if (instr->hydrogen_value()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001393 Label left_not_zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001394 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001395 __ j(not_zero, &left_not_zero, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001396 __ test(right_reg, ToOperand(right));
1397 DeoptimizeIf(sign, instr->environment());
1398 __ bind(&left_not_zero);
1399 }
1400
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001401 // Check for (kMinInt / -1).
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001402 if (instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001403 Label left_not_min_int;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001404 __ cmp(left_reg, kMinInt);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001405 __ j(not_zero, &left_not_min_int, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001406 __ cmp(right_reg, -1);
1407 DeoptimizeIf(zero, instr->environment());
1408 __ bind(&left_not_min_int);
1409 }
1410
1411 // Sign extend to edx.
1412 __ cdq();
1413 __ idiv(right_reg);
1414
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001415 if (!instr->is_flooring()) {
1416 // Deoptimize if remainder is not 0.
1417 __ test(edx, Operand(edx));
1418 DeoptimizeIf(not_zero, instr->environment());
1419 } else {
1420 Label done;
1421 __ test(edx, edx);
1422 __ j(zero, &done, Label::kNear);
1423 __ xor_(edx, right_reg);
1424 __ sar(edx, 31);
1425 __ add(eax, edx);
1426 __ bind(&done);
1427 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001428}
1429
1430
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001431void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001432 ASSERT(instr->right()->IsConstantOperand());
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001433
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001434 Register dividend = ToRegister(instr->left());
1435 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001436 Register result = ToRegister(instr->result());
1437
1438 switch (divisor) {
1439 case 0:
1440 DeoptimizeIf(no_condition, instr->environment());
1441 return;
1442
1443 case 1:
1444 __ Move(result, dividend);
1445 return;
1446
1447 case -1:
1448 __ Move(result, dividend);
1449 __ neg(result);
1450 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1451 DeoptimizeIf(zero, instr->environment());
1452 }
1453 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1454 DeoptimizeIf(overflow, instr->environment());
1455 }
1456 return;
1457 }
1458
1459 uint32_t divisor_abs = abs(divisor);
1460 if (IsPowerOf2(divisor_abs)) {
1461 int32_t power = WhichPowerOf2(divisor_abs);
1462 if (divisor < 0) {
1463 // Input[dividend] is clobbered.
1464 // The sequence is tedious because neg(dividend) might overflow.
1465 __ mov(result, dividend);
1466 __ sar(dividend, 31);
1467 __ neg(result);
1468 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1469 DeoptimizeIf(zero, instr->environment());
1470 }
1471 __ shl(dividend, 32 - power);
1472 __ sar(result, power);
1473 __ not_(dividend);
1474 // Clear result.sign if dividend.sign is set.
1475 __ and_(result, dividend);
1476 } else {
1477 __ Move(result, dividend);
1478 __ sar(result, power);
1479 }
1480 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001481 ASSERT(ToRegister(instr->left()).is(eax));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001482 ASSERT(ToRegister(instr->result()).is(edx));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001483 Register scratch = ToRegister(instr->temp());
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001484
1485 // Find b which: 2^b < divisor_abs < 2^(b+1).
1486 unsigned b = 31 - CompilerIntrinsics::CountLeadingZeros(divisor_abs);
1487 unsigned shift = 32 + b; // Precision +1bit (effectively).
1488 double multiplier_f =
1489 static_cast<double>(static_cast<uint64_t>(1) << shift) / divisor_abs;
1490 int64_t multiplier;
1491 if (multiplier_f - floor(multiplier_f) < 0.5) {
1492 multiplier = static_cast<int64_t>(floor(multiplier_f));
1493 } else {
1494 multiplier = static_cast<int64_t>(floor(multiplier_f)) + 1;
1495 }
1496 // The multiplier is a uint32.
1497 ASSERT(multiplier > 0 &&
1498 multiplier < (static_cast<int64_t>(1) << 32));
1499 __ mov(scratch, dividend);
1500 if (divisor < 0 &&
1501 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1502 __ test(dividend, dividend);
1503 DeoptimizeIf(zero, instr->environment());
1504 }
1505 __ mov(edx, static_cast<int32_t>(multiplier));
1506 __ imul(edx);
1507 if (static_cast<int32_t>(multiplier) < 0) {
1508 __ add(edx, scratch);
1509 }
1510 Register reg_lo = eax;
1511 Register reg_byte_scratch = scratch;
1512 if (!reg_byte_scratch.is_byte_register()) {
1513 __ xchg(reg_lo, reg_byte_scratch);
1514 reg_lo = scratch;
1515 reg_byte_scratch = eax;
1516 }
1517 if (divisor < 0) {
1518 __ xor_(reg_byte_scratch, reg_byte_scratch);
1519 __ cmp(reg_lo, 0x40000000);
1520 __ setcc(above, reg_byte_scratch);
1521 __ neg(edx);
1522 __ sub(edx, reg_byte_scratch);
1523 } else {
1524 __ xor_(reg_byte_scratch, reg_byte_scratch);
1525 __ cmp(reg_lo, 0xC0000000);
1526 __ setcc(above_equal, reg_byte_scratch);
1527 __ add(edx, reg_byte_scratch);
1528 }
1529 __ sar(edx, shift - 32);
1530 }
1531}
1532
1533
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001534void LCodeGen::DoMulI(LMulI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001535 Register left = ToRegister(instr->left());
1536 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001537
1538 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001539 __ mov(ToRegister(instr->temp()), left);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001540 }
1541
1542 if (right->IsConstantOperand()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001543 // Try strength reductions on the multiplication.
1544 // All replacement instructions are at most as long as the imul
1545 // and have better latency.
1546 int constant = ToInteger32(LConstantOperand::cast(right));
1547 if (constant == -1) {
1548 __ neg(left);
1549 } else if (constant == 0) {
1550 __ xor_(left, Operand(left));
1551 } else if (constant == 2) {
1552 __ add(left, Operand(left));
1553 } else if (!instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1554 // If we know that the multiplication can't overflow, it's safe to
1555 // use instructions that don't set the overflow flag for the
1556 // multiplication.
1557 switch (constant) {
1558 case 1:
1559 // Do nothing.
1560 break;
1561 case 3:
1562 __ lea(left, Operand(left, left, times_2, 0));
1563 break;
1564 case 4:
1565 __ shl(left, 2);
1566 break;
1567 case 5:
1568 __ lea(left, Operand(left, left, times_4, 0));
1569 break;
1570 case 8:
1571 __ shl(left, 3);
1572 break;
1573 case 9:
1574 __ lea(left, Operand(left, left, times_8, 0));
1575 break;
1576 case 16:
1577 __ shl(left, 4);
1578 break;
1579 default:
1580 __ imul(left, left, constant);
1581 break;
1582 }
1583 } else {
1584 __ imul(left, left, constant);
1585 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001586 } else {
1587 __ imul(left, ToOperand(right));
1588 }
1589
1590 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1591 DeoptimizeIf(overflow, instr->environment());
1592 }
1593
1594 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1595 // Bail out if the result is supposed to be negative zero.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001596 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001597 __ test(left, Operand(left));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001598 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001599 if (right->IsConstantOperand()) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001600 if (ToInteger32(LConstantOperand::cast(right)) < 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001601 DeoptimizeIf(no_condition, instr->environment());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001602 } else if (ToInteger32(LConstantOperand::cast(right)) == 0) {
1603 __ cmp(ToRegister(instr->temp()), Immediate(0));
1604 DeoptimizeIf(less, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001605 }
1606 } else {
1607 // Test the non-zero operand for negative sign.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001608 __ or_(ToRegister(instr->temp()), ToOperand(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001609 DeoptimizeIf(sign, instr->environment());
1610 }
1611 __ bind(&done);
1612 }
1613}
1614
1615
1616void LCodeGen::DoBitI(LBitI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001617 LOperand* left = instr->left();
1618 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001619 ASSERT(left->Equals(instr->result()));
1620 ASSERT(left->IsRegister());
1621
1622 if (right->IsConstantOperand()) {
1623 int right_operand = ToInteger32(LConstantOperand::cast(right));
1624 switch (instr->op()) {
1625 case Token::BIT_AND:
1626 __ and_(ToRegister(left), right_operand);
1627 break;
1628 case Token::BIT_OR:
1629 __ or_(ToRegister(left), right_operand);
1630 break;
1631 case Token::BIT_XOR:
1632 __ xor_(ToRegister(left), right_operand);
1633 break;
1634 default:
1635 UNREACHABLE();
1636 break;
1637 }
1638 } else {
1639 switch (instr->op()) {
1640 case Token::BIT_AND:
1641 __ and_(ToRegister(left), ToOperand(right));
1642 break;
1643 case Token::BIT_OR:
1644 __ or_(ToRegister(left), ToOperand(right));
1645 break;
1646 case Token::BIT_XOR:
1647 __ xor_(ToRegister(left), ToOperand(right));
1648 break;
1649 default:
1650 UNREACHABLE();
1651 break;
1652 }
1653 }
1654}
1655
1656
1657void LCodeGen::DoShiftI(LShiftI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001658 LOperand* left = instr->left();
1659 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001660 ASSERT(left->Equals(instr->result()));
1661 ASSERT(left->IsRegister());
1662 if (right->IsRegister()) {
1663 ASSERT(ToRegister(right).is(ecx));
1664
1665 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001666 case Token::ROR:
1667 __ ror_cl(ToRegister(left));
1668 if (instr->can_deopt()) {
1669 __ test(ToRegister(left), Immediate(0x80000000));
1670 DeoptimizeIf(not_zero, instr->environment());
1671 }
1672 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001673 case Token::SAR:
1674 __ sar_cl(ToRegister(left));
1675 break;
1676 case Token::SHR:
1677 __ shr_cl(ToRegister(left));
1678 if (instr->can_deopt()) {
1679 __ test(ToRegister(left), Immediate(0x80000000));
1680 DeoptimizeIf(not_zero, instr->environment());
1681 }
1682 break;
1683 case Token::SHL:
1684 __ shl_cl(ToRegister(left));
1685 break;
1686 default:
1687 UNREACHABLE();
1688 break;
1689 }
1690 } else {
1691 int value = ToInteger32(LConstantOperand::cast(right));
1692 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1693 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001694 case Token::ROR:
1695 if (shift_count == 0 && instr->can_deopt()) {
1696 __ test(ToRegister(left), Immediate(0x80000000));
1697 DeoptimizeIf(not_zero, instr->environment());
1698 } else {
1699 __ ror(ToRegister(left), shift_count);
1700 }
1701 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001702 case Token::SAR:
1703 if (shift_count != 0) {
1704 __ sar(ToRegister(left), shift_count);
1705 }
1706 break;
1707 case Token::SHR:
1708 if (shift_count == 0 && instr->can_deopt()) {
1709 __ test(ToRegister(left), Immediate(0x80000000));
1710 DeoptimizeIf(not_zero, instr->environment());
1711 } else {
1712 __ shr(ToRegister(left), shift_count);
1713 }
1714 break;
1715 case Token::SHL:
1716 if (shift_count != 0) {
1717 __ shl(ToRegister(left), shift_count);
1718 }
1719 break;
1720 default:
1721 UNREACHABLE();
1722 break;
1723 }
1724 }
1725}
1726
1727
1728void LCodeGen::DoSubI(LSubI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001729 LOperand* left = instr->left();
1730 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001731 ASSERT(left->Equals(instr->result()));
1732
1733 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001734 __ sub(ToOperand(left), ToInteger32Immediate(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001735 } else {
1736 __ sub(ToRegister(left), ToOperand(right));
1737 }
1738 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1739 DeoptimizeIf(overflow, instr->environment());
1740 }
1741}
1742
1743
1744void LCodeGen::DoConstantI(LConstantI* instr) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001745 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
1746}
1747
1748
1749void LCodeGen::DoConstantS(LConstantS* instr) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001750 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001751}
1752
1753
1754void LCodeGen::DoConstantD(LConstantD* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001755 double v = instr->value();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001756 uint64_t int_val = BitCast<uint64_t, double>(v);
1757 int32_t lower = static_cast<int32_t>(int_val);
1758 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
1759
1760 if (!CpuFeatures::IsSafeForSnapshot(SSE2)) {
1761 __ push(Immediate(lower));
1762 __ push(Immediate(upper));
1763 PushX87DoubleOperand(Operand(esp, 0));
1764 __ add(Operand(esp), Immediate(kDoubleSize));
1765 CurrentInstructionReturnsX87Result();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001766 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001767 CpuFeatureScope scope1(masm(), SSE2);
1768 ASSERT(instr->result()->IsDoubleRegister());
1769 XMMRegister res = ToDoubleRegister(instr->result());
1770 if (int_val == 0) {
1771 __ xorps(res, res);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001772 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001773 Register temp = ToRegister(instr->temp());
1774 if (CpuFeatures::IsSupported(SSE4_1)) {
1775 CpuFeatureScope scope2(masm(), SSE4_1);
1776 if (lower != 0) {
1777 __ Set(temp, Immediate(lower));
1778 __ movd(res, Operand(temp));
1779 __ Set(temp, Immediate(upper));
1780 __ pinsrd(res, Operand(temp), 1);
1781 } else {
1782 __ xorps(res, res);
1783 __ Set(temp, Immediate(upper));
1784 __ pinsrd(res, Operand(temp), 1);
1785 }
1786 } else {
1787 __ Set(temp, Immediate(upper));
1788 __ movd(res, Operand(temp));
1789 __ psllq(res, 32);
1790 if (lower != 0) {
1791 __ Set(temp, Immediate(lower));
1792 __ movd(xmm0, Operand(temp));
1793 __ por(res, xmm0);
1794 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001795 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001796 }
1797 }
1798}
1799
1800
1801void LCodeGen::DoConstantT(LConstantT* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001802 Register reg = ToRegister(instr->result());
1803 Handle<Object> handle = instr->value();
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001804 AllowDeferredHandleDereference smi_check;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001805 if (handle->IsHeapObject()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001806 __ LoadHeapObject(reg, Handle<HeapObject>::cast(handle));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001807 } else {
1808 __ Set(reg, Immediate(handle));
1809 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001810}
1811
1812
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001813void LCodeGen::DoFixedArrayBaseLength(
1814 LFixedArrayBaseLength* instr) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001815 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001816 Register array = ToRegister(instr->value());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001817 __ mov(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001818}
1819
1820
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001821void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
1822 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001823 Register map = ToRegister(instr->value());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001824 __ EnumLength(result, map);
1825}
1826
1827
whesse@chromium.org7b260152011-06-20 15:33:18 +00001828void LCodeGen::DoElementsKind(LElementsKind* instr) {
1829 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001830 Register input = ToRegister(instr->value());
whesse@chromium.org7b260152011-06-20 15:33:18 +00001831
1832 // Load map into |result|.
1833 __ mov(result, FieldOperand(input, HeapObject::kMapOffset));
1834 // Load the map's "bit field 2" into |result|. We only need the first byte,
1835 // but the following masking takes care of that anyway.
1836 __ mov(result, FieldOperand(result, Map::kBitField2Offset));
1837 // Retrieve elements_kind from bit field 2.
1838 __ and_(result, Map::kElementsKindMask);
1839 __ shr(result, Map::kElementsKindShift);
1840}
1841
1842
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001843void LCodeGen::DoValueOf(LValueOf* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001844 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001845 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001846 Register map = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001847 ASSERT(input.is(result));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001848
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001849 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001850 // If the object is a smi return the object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001851 __ JumpIfSmi(input, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001852
1853 // If the object is not a value type, return the object.
1854 __ CmpObjectType(input, JS_VALUE_TYPE, map);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001855 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001856 __ mov(result, FieldOperand(input, JSValue::kValueOffset));
1857
1858 __ bind(&done);
1859}
1860
1861
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001862void LCodeGen::DoDateField(LDateField* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001863 Register object = ToRegister(instr->date());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001864 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001865 Register scratch = ToRegister(instr->temp());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001866 Smi* index = instr->index();
1867 Label runtime, done;
1868 ASSERT(object.is(result));
1869 ASSERT(object.is(eax));
1870
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001871 __ test(object, Immediate(kSmiTagMask));
1872 DeoptimizeIf(zero, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001873 __ CmpObjectType(object, JS_DATE_TYPE, scratch);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001874 DeoptimizeIf(not_equal, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001875
1876 if (index->value() == 0) {
1877 __ mov(result, FieldOperand(object, JSDate::kValueOffset));
1878 } else {
1879 if (index->value() < JSDate::kFirstUncachedField) {
1880 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
1881 __ mov(scratch, Operand::StaticVariable(stamp));
1882 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
1883 __ j(not_equal, &runtime, Label::kNear);
1884 __ mov(result, FieldOperand(object, JSDate::kValueOffset +
1885 kPointerSize * index->value()));
1886 __ jmp(&done);
1887 }
1888 __ bind(&runtime);
1889 __ PrepareCallCFunction(2, scratch);
1890 __ mov(Operand(esp, 0), object);
1891 __ mov(Operand(esp, 1 * kPointerSize), Immediate(index));
1892 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
1893 __ bind(&done);
1894 }
1895}
1896
1897
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00001898void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001899 Register string = ToRegister(instr->string());
1900 Register index = ToRegister(instr->index());
1901 Register value = ToRegister(instr->value());
1902 String::Encoding encoding = instr->encoding();
1903
1904 if (FLAG_debug_code) {
1905 __ push(value);
1906 __ mov(value, FieldOperand(string, HeapObject::kMapOffset));
1907 __ movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset));
1908
1909 __ and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
1910 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
1911 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
1912 __ cmp(value, Immediate(encoding == String::ONE_BYTE_ENCODING
1913 ? one_byte_seq_type : two_byte_seq_type));
1914 __ Check(equal, "Unexpected string type");
1915 __ pop(value);
1916 }
1917
1918 if (encoding == String::ONE_BYTE_ENCODING) {
1919 __ mov_b(FieldOperand(string, index, times_1, SeqString::kHeaderSize),
1920 value);
1921 } else {
1922 __ mov_w(FieldOperand(string, index, times_2, SeqString::kHeaderSize),
1923 value);
1924 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00001925}
1926
1927
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001928void LCodeGen::DoBitNotI(LBitNotI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001929 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001930 ASSERT(input->Equals(instr->result()));
1931 __ not_(ToRegister(input));
1932}
1933
1934
1935void LCodeGen::DoThrow(LThrow* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001936 __ push(ToOperand(instr->value()));
1937 ASSERT(ToRegister(instr->context()).is(esi));
1938 CallRuntime(Runtime::kThrow, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001939
1940 if (FLAG_debug_code) {
1941 Comment("Unreachable code.");
1942 __ int3();
1943 }
1944}
1945
1946
1947void LCodeGen::DoAddI(LAddI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001948 LOperand* left = instr->left();
1949 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001950
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001951 if (LAddI::UseLea(instr->hydrogen()) && !left->Equals(instr->result())) {
1952 if (right->IsConstantOperand()) {
1953 int32_t offset = ToInteger32(LConstantOperand::cast(right));
1954 __ lea(ToRegister(instr->result()), MemOperand(ToRegister(left), offset));
1955 } else {
1956 Operand address(ToRegister(left), ToRegister(right), times_1, 0);
1957 __ lea(ToRegister(instr->result()), address);
1958 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001959 } else {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001960 if (right->IsConstantOperand()) {
1961 __ add(ToOperand(left), ToInteger32Immediate(right));
1962 } else {
1963 __ add(ToRegister(left), ToOperand(right));
1964 }
1965 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1966 DeoptimizeIf(overflow, instr->environment());
1967 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001968 }
1969}
1970
1971
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001972void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001973 CpuFeatureScope scope(masm(), SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001974 LOperand* left = instr->left();
1975 LOperand* right = instr->right();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001976 ASSERT(left->Equals(instr->result()));
1977 HMathMinMax::Operation operation = instr->hydrogen()->operation();
1978 if (instr->hydrogen()->representation().IsInteger32()) {
1979 Label return_left;
1980 Condition condition = (operation == HMathMinMax::kMathMin)
1981 ? less_equal
1982 : greater_equal;
1983 if (right->IsConstantOperand()) {
1984 Operand left_op = ToOperand(left);
1985 Immediate right_imm = ToInteger32Immediate(right);
1986 __ cmp(left_op, right_imm);
1987 __ j(condition, &return_left, Label::kNear);
1988 __ mov(left_op, right_imm);
1989 } else {
1990 Register left_reg = ToRegister(left);
1991 Operand right_op = ToOperand(right);
1992 __ cmp(left_reg, right_op);
1993 __ j(condition, &return_left, Label::kNear);
1994 __ mov(left_reg, right_op);
1995 }
1996 __ bind(&return_left);
1997 } else {
1998 ASSERT(instr->hydrogen()->representation().IsDouble());
1999 Label check_nan_left, check_zero, return_left, return_right;
2000 Condition condition = (operation == HMathMinMax::kMathMin) ? below : above;
2001 XMMRegister left_reg = ToDoubleRegister(left);
2002 XMMRegister right_reg = ToDoubleRegister(right);
2003 __ ucomisd(left_reg, right_reg);
2004 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN.
2005 __ j(equal, &check_zero, Label::kNear); // left == right.
2006 __ j(condition, &return_left, Label::kNear);
2007 __ jmp(&return_right, Label::kNear);
2008
2009 __ bind(&check_zero);
2010 XMMRegister xmm_scratch = xmm0;
2011 __ xorps(xmm_scratch, xmm_scratch);
2012 __ ucomisd(left_reg, xmm_scratch);
2013 __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
2014 // At this point, both left and right are either 0 or -0.
2015 if (operation == HMathMinMax::kMathMin) {
2016 __ orpd(left_reg, right_reg);
2017 } else {
2018 // Since we operate on +0 and/or -0, addsd and andsd have the same effect.
2019 __ addsd(left_reg, right_reg);
2020 }
2021 __ jmp(&return_left, Label::kNear);
2022
2023 __ bind(&check_nan_left);
2024 __ ucomisd(left_reg, left_reg); // NaN check.
2025 __ j(parity_even, &return_left, Label::kNear); // left == NaN.
2026 __ bind(&return_right);
2027 __ movsd(left_reg, right_reg);
2028
2029 __ bind(&return_left);
2030 }
2031}
2032
2033
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002034void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002035 CpuFeatureScope scope(masm(), SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002036 XMMRegister left = ToDoubleRegister(instr->left());
2037 XMMRegister right = ToDoubleRegister(instr->right());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002038 XMMRegister result = ToDoubleRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002039 // Modulo uses a fixed result register.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002040 ASSERT(instr->op() == Token::MOD || left.is(result));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002041 switch (instr->op()) {
2042 case Token::ADD:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002043 __ addsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002044 break;
2045 case Token::SUB:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002046 __ subsd(left, right);
2047 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002048 case Token::MUL:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002049 __ mulsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002050 break;
2051 case Token::DIV:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002052 __ divsd(left, right);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002053 // Don't delete this mov. It may improve performance on some CPUs,
2054 // when there is a mulsd depending on the result
2055 __ movaps(left, left);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002056 break;
2057 case Token::MOD: {
2058 // Pass two doubles as arguments on the stack.
2059 __ PrepareCallCFunction(4, eax);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002060 __ movdbl(Operand(esp, 0 * kDoubleSize), left);
2061 __ movdbl(Operand(esp, 1 * kDoubleSize), right);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002062 __ CallCFunction(
2063 ExternalReference::double_fp_operation(Token::MOD, isolate()),
2064 4);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002065
2066 // Return value is in st(0) on ia32.
2067 // Store it into the (fixed) result register.
2068 __ sub(Operand(esp), Immediate(kDoubleSize));
2069 __ fstp_d(Operand(esp, 0));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002070 __ movdbl(result, Operand(esp, 0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002071 __ add(Operand(esp), Immediate(kDoubleSize));
2072 break;
2073 }
2074 default:
2075 UNREACHABLE();
2076 break;
2077 }
2078}
2079
2080
2081void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002082 ASSERT(ToRegister(instr->context()).is(esi));
2083 ASSERT(ToRegister(instr->left()).is(edx));
2084 ASSERT(ToRegister(instr->right()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002085 ASSERT(ToRegister(instr->result()).is(eax));
2086
danno@chromium.org40cb8782011-05-25 07:58:50 +00002087 BinaryOpStub stub(instr->op(), NO_OVERWRITE);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002088 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00002089 __ nop(); // Signals no inlined code.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002090}
2091
2092
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002093int LCodeGen::GetNextEmittedBlock() const {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002094 for (int i = current_block_ + 1; i < graph()->blocks()->length(); ++i) {
2095 if (!chunk_->GetLabel(i)->HasReplacement()) return i;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002096 }
2097 return -1;
2098}
2099
2100
2101void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002102 int next_block = GetNextEmittedBlock();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002103 right_block = chunk_->LookupDestination(right_block);
2104 left_block = chunk_->LookupDestination(left_block);
2105
2106 if (right_block == left_block) {
2107 EmitGoto(left_block);
2108 } else if (left_block == next_block) {
2109 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
2110 } else if (right_block == next_block) {
2111 __ j(cc, chunk_->GetAssemblyLabel(left_block));
2112 } else {
2113 __ j(cc, chunk_->GetAssemblyLabel(left_block));
2114 __ jmp(chunk_->GetAssemblyLabel(right_block));
2115 }
2116}
2117
2118
2119void LCodeGen::DoBranch(LBranch* instr) {
2120 int true_block = chunk_->LookupDestination(instr->true_block_id());
2121 int false_block = chunk_->LookupDestination(instr->false_block_id());
2122
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002123 Representation r = instr->hydrogen()->value()->representation();
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00002124 if (r.IsSmiOrInteger32()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002125 ASSERT(!info()->IsStub());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002126 Register reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002127 __ test(reg, Operand(reg));
2128 EmitBranch(true_block, false_block, not_zero);
2129 } else if (r.IsDouble()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002130 ASSERT(!info()->IsStub());
2131 CpuFeatureScope scope(masm(), SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002132 XMMRegister reg = ToDoubleRegister(instr->value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00002133 __ xorps(xmm0, xmm0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002134 __ ucomisd(reg, xmm0);
2135 EmitBranch(true_block, false_block, not_equal);
2136 } else {
2137 ASSERT(r.IsTagged());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002138 Register reg = ToRegister(instr->value());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002139 HType type = instr->hydrogen()->value()->type();
2140 if (type.IsBoolean()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002141 ASSERT(!info()->IsStub());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002142 __ cmp(reg, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002143 EmitBranch(true_block, false_block, equal);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002144 } else if (type.IsSmi()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002145 ASSERT(!info()->IsStub());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002146 __ test(reg, Operand(reg));
2147 EmitBranch(true_block, false_block, not_equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002148 } else {
2149 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2150 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2151
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002152 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
2153 // Avoid deopts in the case where we've never executed this path before.
2154 if (expected.IsEmpty()) expected = ToBooleanStub::all_types();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002155
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002156 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
2157 // undefined -> false.
2158 __ cmp(reg, factory()->undefined_value());
2159 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002160 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002161 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
2162 // true -> true.
2163 __ cmp(reg, factory()->true_value());
2164 __ j(equal, true_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002165 // false -> false.
2166 __ cmp(reg, factory()->false_value());
2167 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002168 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002169 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
2170 // 'null' -> false.
2171 __ cmp(reg, factory()->null_value());
2172 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002173 }
2174
2175 if (expected.Contains(ToBooleanStub::SMI)) {
2176 // Smis: 0 -> false, all other -> true.
2177 __ test(reg, Operand(reg));
2178 __ j(equal, false_label);
2179 __ JumpIfSmi(reg, true_label);
2180 } else if (expected.NeedsMap()) {
2181 // If we need a map later and have a Smi -> deopt.
2182 __ test(reg, Immediate(kSmiTagMask));
2183 DeoptimizeIf(zero, instr->environment());
2184 }
2185
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002186 Register map = no_reg; // Keep the compiler happy.
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002187 if (expected.NeedsMap()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002188 map = ToRegister(instr->temp());
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002189 ASSERT(!map.is(reg));
2190 __ mov(map, FieldOperand(reg, HeapObject::kMapOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002191
2192 if (expected.CanBeUndetectable()) {
2193 // Undetectable -> false.
2194 __ test_b(FieldOperand(map, Map::kBitFieldOffset),
2195 1 << Map::kIsUndetectable);
2196 __ j(not_zero, false_label);
2197 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002198 }
2199
2200 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
2201 // spec object -> true.
2202 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
2203 __ j(above_equal, true_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002204 }
2205
2206 if (expected.Contains(ToBooleanStub::STRING)) {
2207 // String value -> false iff empty.
2208 Label not_string;
2209 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
2210 __ j(above_equal, &not_string, Label::kNear);
2211 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
2212 __ j(not_zero, true_label);
2213 __ jmp(false_label);
2214 __ bind(&not_string);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002215 }
2216
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002217 if (expected.Contains(ToBooleanStub::SYMBOL)) {
2218 // Symbol value -> true.
2219 __ CmpInstanceType(map, SYMBOL_TYPE);
2220 __ j(equal, true_label);
2221 }
2222
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002223 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
2224 // heap number -> false iff +0, -0, or NaN.
2225 Label not_heap_number;
2226 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
2227 factory()->heap_number_map());
2228 __ j(not_equal, &not_heap_number, Label::kNear);
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002229 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
2230 CpuFeatureScope scope(masm(), SSE2);
2231 __ xorps(xmm0, xmm0);
2232 __ ucomisd(xmm0, FieldOperand(reg, HeapNumber::kValueOffset));
2233 } else {
2234 __ fldz();
2235 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset));
2236 __ FCmp();
2237 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002238 __ j(zero, false_label);
2239 __ jmp(true_label);
2240 __ bind(&not_heap_number);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002241 }
2242
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002243 // We've seen something for the first time -> deopt.
2244 DeoptimizeIf(no_condition, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002245 }
2246 }
2247}
2248
2249
ager@chromium.org04921a82011-06-27 13:21:41 +00002250void LCodeGen::EmitGoto(int block) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002251 if (!IsNextEmittedBlock(block)) {
2252 __ jmp(chunk_->GetAssemblyLabel(chunk_->LookupDestination(block)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002253 }
2254}
2255
2256
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002257void LCodeGen::DoGoto(LGoto* instr) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002258 EmitGoto(instr->block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002259}
2260
2261
2262Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
2263 Condition cond = no_condition;
2264 switch (op) {
2265 case Token::EQ:
2266 case Token::EQ_STRICT:
2267 cond = equal;
2268 break;
2269 case Token::LT:
2270 cond = is_unsigned ? below : less;
2271 break;
2272 case Token::GT:
2273 cond = is_unsigned ? above : greater;
2274 break;
2275 case Token::LTE:
2276 cond = is_unsigned ? below_equal : less_equal;
2277 break;
2278 case Token::GTE:
2279 cond = is_unsigned ? above_equal : greater_equal;
2280 break;
2281 case Token::IN:
2282 case Token::INSTANCEOF:
2283 default:
2284 UNREACHABLE();
2285 }
2286 return cond;
2287}
2288
2289
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002290void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002291 LOperand* left = instr->left();
2292 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002293 int false_block = chunk_->LookupDestination(instr->false_block_id());
2294 int true_block = chunk_->LookupDestination(instr->true_block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002295 Condition cc = TokenToCondition(instr->op(), instr->is_double());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002296
2297 if (left->IsConstantOperand() && right->IsConstantOperand()) {
2298 // We can statically evaluate the comparison.
2299 double left_val = ToDouble(LConstantOperand::cast(left));
2300 double right_val = ToDouble(LConstantOperand::cast(right));
2301 int next_block =
2302 EvalComparison(instr->op(), left_val, right_val) ? true_block
2303 : false_block;
2304 EmitGoto(next_block);
2305 } else {
2306 if (instr->is_double()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002307 CpuFeatureScope scope(masm(), SSE2);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002308 // Don't base result on EFLAGS when a NaN is involved. Instead
2309 // jump to the false block.
2310 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
2311 __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
2312 } else {
2313 if (right->IsConstantOperand()) {
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00002314 int32_t const_value = ToInteger32(LConstantOperand::cast(right));
2315 if (instr->hydrogen_value()->representation().IsSmi()) {
2316 __ cmp(ToOperand(left), Immediate(Smi::FromInt(const_value)));
2317 } else {
2318 __ cmp(ToOperand(left), Immediate(const_value));
2319 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002320 } else if (left->IsConstantOperand()) {
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00002321 int32_t const_value = ToInteger32(LConstantOperand::cast(left));
2322 if (instr->hydrogen_value()->representation().IsSmi()) {
2323 __ cmp(ToOperand(right), Immediate(Smi::FromInt(const_value)));
2324 } else {
2325 __ cmp(ToOperand(right), Immediate(const_value));
2326 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002327 // We transposed the operands. Reverse the condition.
2328 cc = ReverseCondition(cc);
2329 } else {
2330 __ cmp(ToRegister(left), ToOperand(right));
2331 }
2332 }
2333 EmitBranch(true_block, false_block, cc);
2334 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002335}
2336
2337
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002338void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002339 Register left = ToRegister(instr->left());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002340 int false_block = chunk_->LookupDestination(instr->false_block_id());
2341 int true_block = chunk_->LookupDestination(instr->true_block_id());
2342
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002343 if (instr->right()->IsConstantOperand()) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002344 Handle<Object> right = ToHandle(LConstantOperand::cast(instr->right()));
2345 __ CmpObject(left, right);
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002346 } else {
2347 Operand right = ToOperand(instr->right());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002348 __ cmp(left, right);
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002349 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002350 EmitBranch(true_block, false_block, equal);
2351}
2352
2353
whesse@chromium.org7b260152011-06-20 15:33:18 +00002354void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002355 Register left = ToRegister(instr->left());
whesse@chromium.org7b260152011-06-20 15:33:18 +00002356 int true_block = chunk_->LookupDestination(instr->true_block_id());
2357 int false_block = chunk_->LookupDestination(instr->false_block_id());
2358
2359 __ cmp(left, instr->hydrogen()->right());
2360 EmitBranch(true_block, false_block, equal);
2361}
2362
2363
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002364Condition LCodeGen::EmitIsObject(Register input,
2365 Register temp1,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002366 Label* is_not_object,
2367 Label* is_object) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002368 __ JumpIfSmi(input, is_not_object);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002369
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002370 __ cmp(input, isolate()->factory()->null_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002371 __ j(equal, is_object);
2372
2373 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
2374 // Undetectable objects behave like undefined.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002375 __ test_b(FieldOperand(temp1, Map::kBitFieldOffset),
2376 1 << Map::kIsUndetectable);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002377 __ j(not_zero, is_not_object);
2378
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002379 __ movzx_b(temp1, FieldOperand(temp1, Map::kInstanceTypeOffset));
2380 __ cmp(temp1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002381 __ j(below, is_not_object);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002382 __ cmp(temp1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002383 return below_equal;
2384}
2385
2386
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002387void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002388 Register reg = ToRegister(instr->value());
2389 Register temp = ToRegister(instr->temp());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002390
2391 int true_block = chunk_->LookupDestination(instr->true_block_id());
2392 int false_block = chunk_->LookupDestination(instr->false_block_id());
2393 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2394 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2395
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002396 Condition true_cond = EmitIsObject(reg, temp, false_label, true_label);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002397
2398 EmitBranch(true_block, false_block, true_cond);
2399}
2400
2401
erikcorry0ad885c2011-11-21 13:51:57 +00002402Condition LCodeGen::EmitIsString(Register input,
2403 Register temp1,
2404 Label* is_not_string) {
2405 __ JumpIfSmi(input, is_not_string);
2406
2407 Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
2408
2409 return cond;
2410}
2411
2412
2413void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002414 Register reg = ToRegister(instr->value());
2415 Register temp = ToRegister(instr->temp());
erikcorry0ad885c2011-11-21 13:51:57 +00002416
2417 int true_block = chunk_->LookupDestination(instr->true_block_id());
2418 int false_block = chunk_->LookupDestination(instr->false_block_id());
2419 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2420
2421 Condition true_cond = EmitIsString(reg, temp, false_label);
2422
2423 EmitBranch(true_block, false_block, true_cond);
2424}
2425
2426
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002427void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002428 Operand input = ToOperand(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002429
2430 int true_block = chunk_->LookupDestination(instr->true_block_id());
2431 int false_block = chunk_->LookupDestination(instr->false_block_id());
2432
2433 __ test(input, Immediate(kSmiTagMask));
2434 EmitBranch(true_block, false_block, zero);
2435}
2436
2437
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002438void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002439 Register input = ToRegister(instr->value());
2440 Register temp = ToRegister(instr->temp());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002441
2442 int true_block = chunk_->LookupDestination(instr->true_block_id());
2443 int false_block = chunk_->LookupDestination(instr->false_block_id());
2444
2445 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002446 __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002447 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
2448 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
2449 1 << Map::kIsUndetectable);
2450 EmitBranch(true_block, false_block, not_zero);
2451}
2452
2453
erikcorry0ad885c2011-11-21 13:51:57 +00002454static Condition ComputeCompareCondition(Token::Value op) {
2455 switch (op) {
2456 case Token::EQ_STRICT:
2457 case Token::EQ:
2458 return equal;
2459 case Token::LT:
2460 return less;
2461 case Token::GT:
2462 return greater;
2463 case Token::LTE:
2464 return less_equal;
2465 case Token::GTE:
2466 return greater_equal;
2467 default:
2468 UNREACHABLE();
2469 return no_condition;
2470 }
2471}
2472
2473
2474void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
2475 Token::Value op = instr->op();
2476 int true_block = chunk_->LookupDestination(instr->true_block_id());
2477 int false_block = chunk_->LookupDestination(instr->false_block_id());
2478
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002479 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
erikcorry0ad885c2011-11-21 13:51:57 +00002480 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2481
2482 Condition condition = ComputeCompareCondition(op);
2483 __ test(eax, Operand(eax));
2484
2485 EmitBranch(true_block, false_block, condition);
2486}
2487
2488
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002489static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002490 InstanceType from = instr->from();
2491 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002492 if (from == FIRST_TYPE) return to;
2493 ASSERT(from == to || to == LAST_TYPE);
2494 return from;
2495}
2496
2497
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002498static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002499 InstanceType from = instr->from();
2500 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002501 if (from == to) return equal;
2502 if (to == LAST_TYPE) return above_equal;
2503 if (from == FIRST_TYPE) return below_equal;
2504 UNREACHABLE();
2505 return equal;
2506}
2507
2508
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002509void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002510 Register input = ToRegister(instr->value());
2511 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002512
2513 int true_block = chunk_->LookupDestination(instr->true_block_id());
2514 int false_block = chunk_->LookupDestination(instr->false_block_id());
2515
2516 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2517
whesse@chromium.org7b260152011-06-20 15:33:18 +00002518 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002519
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002520 __ CmpObjectType(input, TestType(instr->hydrogen()), temp);
2521 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002522}
2523
2524
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002525void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002526 Register input = ToRegister(instr->value());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002527 Register result = ToRegister(instr->result());
2528
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002529 __ AssertString(input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002530
2531 __ mov(result, FieldOperand(input, String::kHashFieldOffset));
2532 __ IndexFromHash(result, result);
2533}
2534
2535
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002536void LCodeGen::DoHasCachedArrayIndexAndBranch(
2537 LHasCachedArrayIndexAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002538 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002539
2540 int true_block = chunk_->LookupDestination(instr->true_block_id());
2541 int false_block = chunk_->LookupDestination(instr->false_block_id());
2542
2543 __ test(FieldOperand(input, String::kHashFieldOffset),
2544 Immediate(String::kContainsCachedArrayIndexMask));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002545 EmitBranch(true_block, false_block, equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002546}
2547
2548
2549// Branches to a label or falls through with the answer in the z flag. Trashes
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002550// the temp registers, but not the input.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002551void LCodeGen::EmitClassOfTest(Label* is_true,
2552 Label* is_false,
2553 Handle<String>class_name,
2554 Register input,
2555 Register temp,
2556 Register temp2) {
2557 ASSERT(!input.is(temp));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002558 ASSERT(!input.is(temp2));
2559 ASSERT(!temp.is(temp2));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002560 __ JumpIfSmi(input, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002561
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002562 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Function"))) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002563 // Assuming the following assertions, we can use the same compares to test
2564 // for both being a function type and being in the object type range.
2565 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2566 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2567 FIRST_SPEC_OBJECT_TYPE + 1);
2568 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2569 LAST_SPEC_OBJECT_TYPE - 1);
2570 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
2571 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
2572 __ j(below, is_false);
2573 __ j(equal, is_true);
2574 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
2575 __ j(equal, is_true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002576 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002577 // Faster code path to avoid two compares: subtract lower bound from the
2578 // actual type and do a signed compare with the width of the type range.
2579 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002580 __ movzx_b(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002581 __ sub(Operand(temp2), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002582 __ cmp(Operand(temp2), Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
2583 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002584 __ j(above, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002585 }
2586
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002587 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002588 // Check if the constructor in the map is a function.
2589 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002590 // Objects with a non-function constructor have class 'Object'.
2591 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002592 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002593 __ j(not_equal, is_true);
2594 } else {
2595 __ j(not_equal, is_false);
2596 }
2597
2598 // temp now contains the constructor function. Grab the
2599 // instance class name from there.
2600 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
2601 __ mov(temp, FieldOperand(temp,
2602 SharedFunctionInfo::kInstanceClassNameOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002603 // The class name we are testing against is internalized since it's a literal.
2604 // The name in the constructor is internalized because of the way the context
2605 // is booted. This routine isn't expected to work for random API-created
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002606 // classes and it doesn't have to because you can't access it with natives
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002607 // syntax. Since both sides are internalized it is sufficient to use an
2608 // identity comparison.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002609 __ cmp(temp, class_name);
2610 // End with the answer in the z flag.
2611}
2612
2613
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002614void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002615 Register input = ToRegister(instr->value());
2616 Register temp = ToRegister(instr->temp());
2617 Register temp2 = ToRegister(instr->temp2());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002618
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002619 Handle<String> class_name = instr->hydrogen()->class_name();
2620
2621 int true_block = chunk_->LookupDestination(instr->true_block_id());
2622 int false_block = chunk_->LookupDestination(instr->false_block_id());
2623
2624 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2625 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2626
2627 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2);
2628
2629 EmitBranch(true_block, false_block, equal);
2630}
2631
2632
2633void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002634 Register reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002635 int true_block = instr->true_block_id();
2636 int false_block = instr->false_block_id();
2637
2638 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
2639 EmitBranch(true_block, false_block, equal);
2640}
2641
2642
2643void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002644 // Object and function are in fixed registers defined by the stub.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002645 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002646 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002647 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002648
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002649 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002650 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002651 __ j(zero, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002652 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002653 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002654 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002655 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002656 __ bind(&done);
2657}
2658
2659
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002660void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
2661 class DeferredInstanceOfKnownGlobal: public LDeferredCode {
2662 public:
2663 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
2664 LInstanceOfKnownGlobal* instr)
2665 : LDeferredCode(codegen), instr_(instr) { }
2666 virtual void Generate() {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002667 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002668 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002669 virtual LInstruction* instr() { return instr_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002670 Label* map_check() { return &map_check_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002671 private:
2672 LInstanceOfKnownGlobal* instr_;
2673 Label map_check_;
2674 };
2675
2676 DeferredInstanceOfKnownGlobal* deferred;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002677 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002678
2679 Label done, false_result;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002680 Register object = ToRegister(instr->value());
2681 Register temp = ToRegister(instr->temp());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002682
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002683 // A Smi is not an instance of anything.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002684 __ JumpIfSmi(object, &false_result);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002685
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002686 // This is the inlined call site instanceof cache. The two occurences of the
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002687 // hole value will be patched to the last map/result pair generated by the
2688 // instanceof stub.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002689 Label cache_miss;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002690 Register map = ToRegister(instr->temp());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002691 __ mov(map, FieldOperand(object, HeapObject::kMapOffset));
2692 __ bind(deferred->map_check()); // Label for calculating code patching.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002693 Handle<JSGlobalPropertyCell> cache_cell =
2694 factory()->NewJSGlobalPropertyCell(factory()->the_hole_value());
2695 __ cmp(map, Operand::Cell(cache_cell)); // Patched to cached map.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002696 __ j(not_equal, &cache_miss, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002697 __ mov(eax, factory()->the_hole_value()); // Patched to either true or false.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002698 __ jmp(&done);
2699
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002700 // The inlined call site cache did not match. Check for null and string
2701 // before calling the deferred code.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002702 __ bind(&cache_miss);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002703 // Null is not an instance of anything.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002704 __ cmp(object, factory()->null_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002705 __ j(equal, &false_result);
2706
2707 // String values are not instances of anything.
2708 Condition is_string = masm_->IsObjectStringType(object, temp, temp);
2709 __ j(is_string, &false_result);
2710
2711 // Go to the deferred code.
2712 __ jmp(deferred->entry());
2713
2714 __ bind(&false_result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002715 __ mov(ToRegister(instr->result()), factory()->false_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002716
2717 // Here result has either true or false. Deferred code also produces true or
2718 // false object.
2719 __ bind(deferred->exit());
2720 __ bind(&done);
2721}
2722
2723
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002724void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2725 Label* map_check) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002726 PushSafepointRegistersScope scope(this);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002727
2728 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
2729 flags = static_cast<InstanceofStub::Flags>(
2730 flags | InstanceofStub::kArgsInRegisters);
2731 flags = static_cast<InstanceofStub::Flags>(
2732 flags | InstanceofStub::kCallSiteInlineCheck);
2733 flags = static_cast<InstanceofStub::Flags>(
2734 flags | InstanceofStub::kReturnTrueFalseObject);
2735 InstanceofStub stub(flags);
2736
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002737 // Get the temp register reserved by the instruction. This needs to be a
2738 // register which is pushed last by PushSafepointRegisters as top of the
2739 // stack is used to pass the offset to the location of the map check to
2740 // the stub.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002741 Register temp = ToRegister(instr->temp());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002742 ASSERT(MacroAssembler::SafepointRegisterStackIndex(temp) == 0);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002743 __ LoadHeapObject(InstanceofStub::right(), instr->function());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002744 static const int kAdditionalDelta = 13;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002745 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002746 __ mov(temp, Immediate(delta));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002747 __ StoreToSafepointRegisterSlot(temp, temp);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002748 CallCodeGeneric(stub.GetCode(isolate()),
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002749 RelocInfo::CODE_TARGET,
2750 instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002751 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002752 // Get the deoptimization index of the LLazyBailout-environment that
2753 // corresponds to this instruction.
2754 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002755 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
2756
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002757 // Put the result value into the eax slot and restore all registers.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002758 __ StoreToSafepointRegisterSlot(eax, eax);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002759}
2760
2761
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00002762void LCodeGen::DoInstanceSize(LInstanceSize* instr) {
2763 Register object = ToRegister(instr->object());
2764 Register result = ToRegister(instr->result());
2765 __ mov(result, FieldOperand(object, HeapObject::kMapOffset));
2766 __ movzx_b(result, FieldOperand(result, Map::kInstanceSizeOffset));
2767}
2768
2769
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002770void LCodeGen::DoCmpT(LCmpT* instr) {
2771 Token::Value op = instr->op();
2772
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002773 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002774 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002775
2776 Condition condition = ComputeCompareCondition(op);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002777 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002778 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002779 __ j(condition, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002780 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002781 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002782 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002783 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002784 __ bind(&done);
2785}
2786
2787
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002788void LCodeGen::EmitReturn(LReturn* instr, bool dynamic_frame_alignment) {
2789 int extra_value_count = dynamic_frame_alignment ? 2 : 1;
2790
2791 if (instr->has_constant_parameter_count()) {
2792 int parameter_count = ToInteger32(instr->constant_parameter_count());
2793 if (dynamic_frame_alignment && FLAG_debug_code) {
2794 __ cmp(Operand(esp,
2795 (parameter_count + extra_value_count) * kPointerSize),
2796 Immediate(kAlignmentZapValue));
2797 __ Assert(equal, "expected alignment marker");
2798 }
2799 __ Ret((parameter_count + extra_value_count) * kPointerSize, ecx);
2800 } else {
2801 Register reg = ToRegister(instr->parameter_count());
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002802 // The argument count parameter is a smi
2803 __ SmiUntag(reg);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002804 Register return_addr_reg = reg.is(ecx) ? ebx : ecx;
2805 if (dynamic_frame_alignment && FLAG_debug_code) {
2806 ASSERT(extra_value_count == 2);
2807 __ cmp(Operand(esp, reg, times_pointer_size,
2808 extra_value_count * kPointerSize),
2809 Immediate(kAlignmentZapValue));
2810 __ Assert(equal, "expected alignment marker");
2811 }
2812
2813 // emit code to restore stack based on instr->parameter_count()
2814 __ pop(return_addr_reg); // save return address
2815 if (dynamic_frame_alignment) {
2816 __ inc(reg); // 1 more for alignment
2817 }
2818 __ shl(reg, kPointerSizeLog2);
2819 __ add(esp, reg);
2820 __ jmp(return_addr_reg);
2821 }
2822}
2823
2824
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002825void LCodeGen::DoReturn(LReturn* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002826 if (FLAG_trace && info()->IsOptimizing()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002827 // Preserve the return value on the stack and rely on the runtime call
2828 // to return the value in the same register. We're leaving the code
2829 // managed by the register allocator and tearing down the frame, it's
2830 // safe to write to the context register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002831 __ push(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002832 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002833 __ CallRuntime(Runtime::kTraceExit, 1);
2834 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002835 if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(SSE2)) {
2836 ASSERT(NeedsEagerFrame());
ulan@chromium.org750145a2013-03-07 15:14:13 +00002837 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002838 BitVector* doubles = chunk()->allocated_double_registers();
2839 BitVector::Iterator save_iterator(doubles);
2840 int count = 0;
2841 while (!save_iterator.Done()) {
2842 __ movdbl(XMMRegister::FromAllocationIndex(save_iterator.Current()),
2843 MemOperand(esp, count * kDoubleSize));
2844 save_iterator.Advance();
2845 count++;
2846 }
2847 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002848 if (dynamic_frame_alignment_) {
2849 // Fetch the state of the dynamic frame alignment.
2850 __ mov(edx, Operand(ebp,
2851 JavaScriptFrameConstants::kDynamicAlignmentStateOffset));
2852 }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002853 int no_frame_start = -1;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002854 if (NeedsEagerFrame()) {
2855 __ mov(esp, ebp);
2856 __ pop(ebp);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002857 no_frame_start = masm_->pc_offset();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002858 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002859 if (dynamic_frame_alignment_) {
2860 Label no_padding;
2861 __ cmp(edx, Immediate(kNoAlignmentPadding));
2862 __ j(equal, &no_padding);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002863
2864 EmitReturn(instr, true);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002865 __ bind(&no_padding);
2866 }
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002867
2868 EmitReturn(instr, false);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002869 if (no_frame_start != -1) {
2870 info()->AddNoFrameRange(no_frame_start, masm_->pc_offset());
2871 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002872}
2873
2874
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002875void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002876 Register result = ToRegister(instr->result());
2877 __ mov(result, Operand::Cell(instr->hydrogen()->cell()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002878 if (instr->hydrogen()->RequiresHoleCheck()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002879 __ cmp(result, factory()->the_hole_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002880 DeoptimizeIf(equal, instr->environment());
2881 }
2882}
2883
2884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002885void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2886 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002887 ASSERT(ToRegister(instr->global_object()).is(edx));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002888 ASSERT(ToRegister(instr->result()).is(eax));
2889
2890 __ mov(ecx, instr->name());
2891 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
2892 RelocInfo::CODE_TARGET_CONTEXT;
2893 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002894 CallCode(ic, mode, instr);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002895}
2896
2897
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002898void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002899 Register value = ToRegister(instr->value());
2900 Handle<JSGlobalPropertyCell> cell_handle = instr->hydrogen()->cell();
ager@chromium.org378b34e2011-01-28 08:04:38 +00002901
2902 // If the cell we are storing to contains the hole it could have
2903 // been deleted from the property dictionary. In that case, we need
2904 // to update the property details in the property dictionary to mark
2905 // it as no longer deleted. We deoptimize in that case.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002906 if (instr->hydrogen()->RequiresHoleCheck()) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002907 __ cmp(Operand::Cell(cell_handle), factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00002908 DeoptimizeIf(equal, instr->environment());
2909 }
2910
2911 // Store the value.
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002912 __ mov(Operand::Cell(cell_handle), value);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002913 // Cells are always rescanned, so no write barrier here.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002914}
2915
2916
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002917void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
2918 ASSERT(ToRegister(instr->context()).is(esi));
2919 ASSERT(ToRegister(instr->global_object()).is(edx));
2920 ASSERT(ToRegister(instr->value()).is(eax));
2921
2922 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002923 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002924 ? isolate()->builtins()->StoreIC_Initialize_Strict()
2925 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002926 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002927}
2928
2929
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002930void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002931 Register context = ToRegister(instr->context());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002932 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002933 __ mov(result, ContextOperand(context, instr->slot_index()));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002934
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002935 if (instr->hydrogen()->RequiresHoleCheck()) {
2936 __ cmp(result, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002937 if (instr->hydrogen()->DeoptimizesOnHole()) {
2938 DeoptimizeIf(equal, instr->environment());
2939 } else {
2940 Label is_not_hole;
2941 __ j(not_equal, &is_not_hole, Label::kNear);
2942 __ mov(result, factory()->undefined_value());
2943 __ bind(&is_not_hole);
2944 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002945 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002946}
2947
2948
2949void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2950 Register context = ToRegister(instr->context());
2951 Register value = ToRegister(instr->value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002952
2953 Label skip_assignment;
2954
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002955 Operand target = ContextOperand(context, instr->slot_index());
2956 if (instr->hydrogen()->RequiresHoleCheck()) {
2957 __ cmp(target, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002958 if (instr->hydrogen()->DeoptimizesOnHole()) {
2959 DeoptimizeIf(equal, instr->environment());
2960 } else {
2961 __ j(not_equal, &skip_assignment, Label::kNear);
2962 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002963 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002964
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002965 __ mov(target, value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002966 if (instr->hydrogen()->NeedsWriteBarrier()) {
2967 HType type = instr->hydrogen()->value()->type();
2968 SmiCheck check_needed =
2969 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002970 Register temp = ToRegister(instr->temp());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002971 int offset = Context::SlotOffset(instr->slot_index());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002972 __ RecordWriteContextSlot(context,
2973 offset,
2974 value,
2975 temp,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002976 GetSaveFPRegsMode(),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002977 EMIT_REMEMBERED_SET,
2978 check_needed);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002979 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002980
2981 __ bind(&skip_assignment);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002982}
2983
2984
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002985void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00002986 HObjectAccess access = instr->hydrogen()->access();
2987 int offset = access.offset();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002988 Register object = ToRegister(instr->object());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002989 if (FLAG_track_double_fields &&
2990 instr->hydrogen()->representation().IsDouble()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00002991 if (CpuFeatures::IsSupported(SSE2)) {
2992 CpuFeatureScope scope(masm(), SSE2);
2993 XMMRegister result = ToDoubleRegister(instr->result());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002994 __ movdbl(result, FieldOperand(object, offset));
danno@chromium.orgf005df62013-04-30 16:36:45 +00002995 } else {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002996 PushX87DoubleOperand(FieldOperand(object, offset));
danno@chromium.orgf005df62013-04-30 16:36:45 +00002997 CurrentInstructionReturnsX87Result();
2998 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002999 return;
3000 }
3001
3002 Register result = ToRegister(instr->result());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003003 if (access.IsInobject()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003004 __ mov(result, FieldOperand(object, offset));
3005 } else {
3006 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
3007 __ mov(result, FieldOperand(result, offset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003008 }
3009}
3010
3011
lrn@chromium.org1c092762011-05-09 09:42:16 +00003012void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
3013 Register object,
3014 Handle<Map> type,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003015 Handle<String> name,
3016 LEnvironment* env) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003017 LookupResult lookup(isolate());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003018 type->LookupDescriptor(NULL, *name, &lookup);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003019 ASSERT(lookup.IsFound() || lookup.IsCacheable());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00003020 if (lookup.IsField()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00003021 int index = lookup.GetLocalFieldIndexFromMap(*type);
3022 int offset = index * kPointerSize;
3023 if (index < 0) {
3024 // Negative property indices are in-object properties, indexed
3025 // from the end of the fixed part of the object.
3026 __ mov(result, FieldOperand(object, offset + type->instance_size()));
3027 } else {
3028 // Non-negative property indices are in the properties array.
3029 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
3030 __ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
3031 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00003032 } else if (lookup.IsConstantFunction()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00003033 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003034 __ LoadHeapObject(result, function);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003035 } else {
3036 // Negative lookup.
3037 // Check prototypes.
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00003038 Handle<HeapObject> current(HeapObject::cast((*type)->prototype()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003039 Heap* heap = type->GetHeap();
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00003040 while (*current != heap->null_value()) {
3041 __ LoadHeapObject(result, current);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003042 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00003043 Handle<Map>(current->map()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003044 DeoptimizeIf(not_equal, env);
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00003045 current =
3046 Handle<HeapObject>(HeapObject::cast(current->map()->prototype()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003047 }
3048 __ mov(result, factory()->undefined_value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003049 }
3050}
3051
3052
3053void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
3054 ASSERT(!operand->IsDoubleRegister());
3055 if (operand->IsConstantOperand()) {
3056 Handle<Object> object = ToHandle(LConstantOperand::cast(operand));
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003057 AllowDeferredHandleDereference smi_check;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003058 if (object->IsSmi()) {
3059 __ Push(Handle<Smi>::cast(object));
3060 } else {
3061 __ PushHeapObject(Handle<HeapObject>::cast(object));
3062 }
3063 } else if (operand->IsRegister()) {
3064 __ push(ToRegister(operand));
3065 } else {
3066 __ push(ToOperand(operand));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003067 }
3068}
3069
3070
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003071// Check for cases where EmitLoadFieldOrConstantFunction needs to walk the
3072// prototype chain, which causes unbounded code generation.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00003073static bool CompactEmit(SmallMapList* list,
3074 Handle<String> name,
3075 int i,
3076 Isolate* isolate) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003077 Handle<Map> map = list->at(i);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00003078 // If the map has ElementsKind transitions, we will generate map checks
3079 // for each kind in __ CompareMap(..., ALLOW_ELEMENTS_TRANSITION_MAPS).
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003080 if (map->HasElementsTransition()) return false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00003081 LookupResult lookup(isolate);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003082 map->LookupDescriptor(NULL, *name, &lookup);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00003083 return lookup.IsField() || lookup.IsConstantFunction();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003084}
3085
3086
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003087void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
3088 Register object = ToRegister(instr->object());
3089 Register result = ToRegister(instr->result());
3090
3091 int map_count = instr->hydrogen()->types()->length();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003092 bool need_generic = instr->hydrogen()->need_generic();
3093
3094 if (map_count == 0 && !need_generic) {
3095 DeoptimizeIf(no_condition, instr->environment());
3096 return;
3097 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003098 Handle<String> name = instr->hydrogen()->name();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003099 Label done;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003100 bool all_are_compact = true;
3101 for (int i = 0; i < map_count; ++i) {
3102 if (!CompactEmit(instr->hydrogen()->types(), name, i, isolate())) {
3103 all_are_compact = false;
3104 break;
3105 }
3106 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003107 for (int i = 0; i < map_count; ++i) {
3108 bool last = (i == map_count - 1);
3109 Handle<Map> map = instr->hydrogen()->types()->at(i);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003110 Label check_passed;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003111 __ CompareMap(object, map, &check_passed);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003112 if (last && !need_generic) {
3113 DeoptimizeIf(not_equal, instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003114 __ bind(&check_passed);
3115 EmitLoadFieldOrConstantFunction(
3116 result, object, map, name, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003117 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003118 Label next;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003119 bool compact = all_are_compact ? true :
3120 CompactEmit(instr->hydrogen()->types(), name, i, isolate());
3121 __ j(not_equal, &next, compact ? Label::kNear : Label::kFar);
3122 __ bind(&check_passed);
3123 EmitLoadFieldOrConstantFunction(
3124 result, object, map, name, instr->environment());
3125 __ jmp(&done, all_are_compact ? Label::kNear : Label::kFar);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003126 __ bind(&next);
3127 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003128 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003129 if (need_generic) {
3130 __ mov(ecx, name);
3131 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
3132 CallCode(ic, RelocInfo::CODE_TARGET, instr);
3133 }
3134 __ bind(&done);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003135}
3136
3137
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003138void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003139 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003140 ASSERT(ToRegister(instr->object()).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003141 ASSERT(ToRegister(instr->result()).is(eax));
3142
3143 __ mov(ecx, instr->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003144 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003145 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003146}
3147
3148
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003149void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
3150 Register function = ToRegister(instr->function());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003151 Register temp = ToRegister(instr->temp());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003152 Register result = ToRegister(instr->result());
3153
3154 // Check that the function really is a function.
3155 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
3156 DeoptimizeIf(not_equal, instr->environment());
3157
3158 // Check whether the function has an instance prototype.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003159 Label non_instance;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003160 __ test_b(FieldOperand(result, Map::kBitFieldOffset),
3161 1 << Map::kHasNonInstancePrototype);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003162 __ j(not_zero, &non_instance, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003163
3164 // Get the prototype or initial map from the function.
3165 __ mov(result,
3166 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
3167
3168 // Check that the function has a prototype or an initial map.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003169 __ cmp(Operand(result), Immediate(factory()->the_hole_value()));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003170 DeoptimizeIf(equal, instr->environment());
3171
3172 // If the function does not have an initial map, we're done.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003173 Label done;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003174 __ CmpObjectType(result, MAP_TYPE, temp);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003175 __ j(not_equal, &done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003176
3177 // Get the prototype from the initial map.
3178 __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003179 __ jmp(&done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003180
3181 // Non-instance prototype: Fetch prototype from constructor field
3182 // in the function's map.
3183 __ bind(&non_instance);
3184 __ mov(result, FieldOperand(result, Map::kConstructorOffset));
3185
3186 // All done.
3187 __ bind(&done);
3188}
3189
3190
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003191void LCodeGen::DoLoadExternalArrayPointer(
3192 LLoadExternalArrayPointer* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003193 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003194 Register input = ToRegister(instr->object());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003195 __ mov(result, FieldOperand(input,
3196 ExternalArray::kExternalPointerOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003197}
3198
3199
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003200void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
3201 Register arguments = ToRegister(instr->arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003202 Register result = ToRegister(instr->result());
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003203 if (instr->length()->IsConstantOperand() &&
3204 instr->index()->IsConstantOperand()) {
3205 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3206 int const_length = ToInteger32(LConstantOperand::cast(instr->length()));
3207 int index = (const_length - const_index) + 1;
3208 __ mov(result, Operand(arguments, index * kPointerSize));
3209 } else {
3210 Register length = ToRegister(instr->length());
3211 Operand index = ToOperand(instr->index());
3212 // There are two words between the frame pointer and the last argument.
3213 // Subtracting from length accounts for one of them add one more.
3214 __ sub(length, index);
3215 __ mov(result, Operand(arguments, length, times_4, kPointerSize));
3216 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003217}
3218
3219
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003220void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003221 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003222 LOperand* key = instr->key();
3223 if (!key->IsConstantOperand() &&
3224 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
3225 elements_kind)) {
3226 __ SmiUntag(ToRegister(key));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003227 }
3228 Operand operand(BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003229 instr->elements(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003230 key,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003231 instr->hydrogen()->key()->representation(),
3232 elements_kind,
3233 0,
3234 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003235 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003236 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003237 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003238 XMMRegister result(ToDoubleRegister(instr->result()));
3239 __ movss(result, operand);
3240 __ cvtss2sd(result, result);
3241 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003242 PushX87FloatOperand(operand);
3243 CurrentInstructionReturnsX87Result();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003244 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003245 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003246 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003247 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003248 __ movdbl(ToDoubleRegister(instr->result()), operand);
3249 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003250 PushX87DoubleOperand(operand);
3251 CurrentInstructionReturnsX87Result();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003252 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003253 } else {
3254 Register result(ToRegister(instr->result()));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003255 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003256 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003257 __ movsx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003258 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003259 case EXTERNAL_PIXEL_ELEMENTS:
3260 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003261 __ movzx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003262 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003263 case EXTERNAL_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003264 __ movsx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003265 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003266 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003267 __ movzx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003268 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003269 case EXTERNAL_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003270 __ mov(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003271 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003272 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003273 __ mov(result, operand);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003274 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
3275 __ test(result, Operand(result));
3276 DeoptimizeIf(negative, instr->environment());
3277 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003278 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003279 case EXTERNAL_FLOAT_ELEMENTS:
3280 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003281 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003282 case FAST_ELEMENTS:
3283 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003284 case FAST_HOLEY_SMI_ELEMENTS:
3285 case FAST_HOLEY_ELEMENTS:
3286 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003287 case DICTIONARY_ELEMENTS:
3288 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003289 UNREACHABLE();
3290 break;
3291 }
3292 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003293}
3294
3295
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003296void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003297 if (instr->hydrogen()->RequiresHoleCheck()) {
3298 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
3299 sizeof(kHoleNanLower32);
3300 Operand hole_check_operand = BuildFastArrayOperand(
3301 instr->elements(), instr->key(),
3302 instr->hydrogen()->key()->representation(),
3303 FAST_DOUBLE_ELEMENTS,
3304 offset,
3305 instr->additional_index());
3306 __ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
3307 DeoptimizeIf(equal, instr->environment());
3308 }
3309
3310 Operand double_load_operand = BuildFastArrayOperand(
3311 instr->elements(),
3312 instr->key(),
3313 instr->hydrogen()->key()->representation(),
3314 FAST_DOUBLE_ELEMENTS,
3315 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
3316 instr->additional_index());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003317 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003318 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003319 XMMRegister result = ToDoubleRegister(instr->result());
3320 __ movdbl(result, double_load_operand);
3321 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003322 PushX87DoubleOperand(double_load_operand);
3323 CurrentInstructionReturnsX87Result();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003324 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003325}
3326
3327
3328void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
3329 Register result = ToRegister(instr->result());
3330
3331 // Load the result.
3332 __ mov(result,
3333 BuildFastArrayOperand(instr->elements(),
3334 instr->key(),
3335 instr->hydrogen()->key()->representation(),
3336 FAST_ELEMENTS,
3337 FixedArray::kHeaderSize - kHeapObjectTag,
3338 instr->additional_index()));
3339
3340 // Check for the hole value.
3341 if (instr->hydrogen()->RequiresHoleCheck()) {
3342 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
3343 __ test(result, Immediate(kSmiTagMask));
3344 DeoptimizeIf(not_equal, instr->environment());
3345 } else {
3346 __ cmp(result, factory()->the_hole_value());
3347 DeoptimizeIf(equal, instr->environment());
3348 }
3349 }
3350}
3351
3352
3353void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
3354 if (instr->is_external()) {
3355 DoLoadKeyedExternalArray(instr);
3356 } else if (instr->hydrogen()->representation().IsDouble()) {
3357 DoLoadKeyedFixedDoubleArray(instr);
3358 } else {
3359 DoLoadKeyedFixedArray(instr);
3360 }
3361}
3362
3363
3364Operand LCodeGen::BuildFastArrayOperand(
3365 LOperand* elements_pointer,
3366 LOperand* key,
3367 Representation key_representation,
3368 ElementsKind elements_kind,
3369 uint32_t offset,
3370 uint32_t additional_index) {
3371 Register elements_pointer_reg = ToRegister(elements_pointer);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003372 int element_shift_size = ElementsKindToShiftSize(elements_kind);
3373 int shift_size = element_shift_size;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003374 if (key->IsConstantOperand()) {
3375 int constant_value = ToInteger32(LConstantOperand::cast(key));
3376 if (constant_value & 0xF0000000) {
3377 Abort("array index constant value too big");
3378 }
3379 return Operand(elements_pointer_reg,
3380 ((constant_value + additional_index) << shift_size)
3381 + offset);
3382 } else {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00003383 // Take the tag bit into account while computing the shift size.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003384 if (key_representation.IsSmi() && (shift_size >= 1)) {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00003385 shift_size -= kSmiTagSize;
3386 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003387 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
3388 return Operand(elements_pointer_reg,
3389 ToRegister(key),
3390 scale_factor,
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003391 offset + (additional_index << element_shift_size));
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003392 }
3393}
3394
3395
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003396void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003397 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003398 ASSERT(ToRegister(instr->object()).is(edx));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003399 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003400
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003401 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003402 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003403}
3404
3405
3406void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
3407 Register result = ToRegister(instr->result());
3408
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003409 if (instr->hydrogen()->from_inlined()) {
3410 __ lea(result, Operand(esp, -2 * kPointerSize));
3411 } else {
3412 // Check for arguments adapter frame.
3413 Label done, adapted;
3414 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3415 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
3416 __ cmp(Operand(result),
3417 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3418 __ j(equal, &adapted, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003419
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003420 // No arguments adaptor frame.
3421 __ mov(result, Operand(ebp));
3422 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003423
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003424 // Arguments adaptor frame present.
3425 __ bind(&adapted);
3426 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003427
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003428 // Result is the frame pointer for the frame if not adapted and for the real
3429 // frame below the adaptor frame if adapted.
3430 __ bind(&done);
3431 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003432}
3433
3434
3435void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003436 Operand elem = ToOperand(instr->elements());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003437 Register result = ToRegister(instr->result());
3438
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003439 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003440
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003441 // If no arguments adaptor frame the number of arguments is fixed.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003442 __ cmp(ebp, elem);
3443 __ mov(result, Immediate(scope()->num_parameters()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003444 __ j(equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003445
3446 // Arguments adaptor frame present. Get argument length from there.
3447 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3448 __ mov(result, Operand(result,
3449 ArgumentsAdaptorFrameConstants::kLengthOffset));
3450 __ SmiUntag(result);
3451
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003452 // Argument length is in result register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003453 __ bind(&done);
3454}
3455
3456
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003457void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003458 Register receiver = ToRegister(instr->receiver());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003459 Register function = ToRegister(instr->function());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003460 Register scratch = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003461
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003462 // If the receiver is null or undefined, we have to pass the global
3463 // object as a receiver to normal functions. Values have to be
3464 // passed unchanged to builtins and strict-mode functions.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003465 Label global_object, receiver_ok;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003466
3467 // Do not transform the receiver to object for strict mode
3468 // functions.
3469 __ mov(scratch,
3470 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
3471 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset),
3472 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
danno@chromium.org412fa512012-09-14 13:28:26 +00003473 __ j(not_equal, &receiver_ok); // A near jump is not sufficient here!
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003474
3475 // Do not transform the receiver to object for builtins.
3476 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset),
3477 1 << SharedFunctionInfo::kNativeBitWithinByte);
danno@chromium.org412fa512012-09-14 13:28:26 +00003478 __ j(not_equal, &receiver_ok);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003479
3480 // Normal function. Replace undefined or null with global receiver.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003481 __ cmp(receiver, factory()->null_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003482 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003483 __ cmp(receiver, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003484 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003485
3486 // The receiver should be a JS object.
3487 __ test(receiver, Immediate(kSmiTagMask));
3488 DeoptimizeIf(equal, instr->environment());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003489 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, scratch);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003490 DeoptimizeIf(below, instr->environment());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003491 __ jmp(&receiver_ok, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003492
3493 __ bind(&global_object);
3494 // TODO(kmillikin): We have a hydrogen value for the global object. See
3495 // if it's better to use it than to explicitly fetch it from the context
3496 // here.
3497 __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003498 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_OBJECT_INDEX));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003499 __ mov(receiver,
3500 FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003501 __ bind(&receiver_ok);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003502}
3503
3504
3505void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
3506 Register receiver = ToRegister(instr->receiver());
3507 Register function = ToRegister(instr->function());
3508 Register length = ToRegister(instr->length());
3509 Register elements = ToRegister(instr->elements());
3510 ASSERT(receiver.is(eax)); // Used for parameter count.
3511 ASSERT(function.is(edi)); // Required by InvokeFunction.
3512 ASSERT(ToRegister(instr->result()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003513
3514 // Copy the arguments to this function possibly from the
3515 // adaptor frame below it.
3516 const uint32_t kArgumentsLimit = 1 * KB;
3517 __ cmp(length, kArgumentsLimit);
3518 DeoptimizeIf(above, instr->environment());
3519
3520 __ push(receiver);
3521 __ mov(receiver, length);
3522
3523 // Loop through the arguments pushing them onto the execution
3524 // stack.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003525 Label invoke, loop;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003526 // length is a small non-negative integer, due to the test above.
3527 __ test(length, Operand(length));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003528 __ j(zero, &invoke, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003529 __ bind(&loop);
3530 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
3531 __ dec(length);
3532 __ j(not_zero, &loop);
3533
3534 // Invoke the function.
3535 __ bind(&invoke);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003536 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003537 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003538 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003539 SafepointGenerator safepoint_generator(
3540 this, pointers, Safepoint::kLazyDeopt);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003541 ParameterCount actual(eax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003542 __ InvokeFunction(function, actual, CALL_FUNCTION,
3543 safepoint_generator, CALL_AS_METHOD);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003544}
3545
3546
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003547void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
3548 __ int3();
3549}
3550
3551
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003552void LCodeGen::DoPushArgument(LPushArgument* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003553 LOperand* argument = instr->value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003554 EmitPushTaggedOperand(argument);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003555}
3556
3557
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003558void LCodeGen::DoDrop(LDrop* instr) {
3559 __ Drop(instr->count());
3560}
3561
3562
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003563void LCodeGen::DoThisFunction(LThisFunction* instr) {
3564 Register result = ToRegister(instr->result());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003565 __ mov(result, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003566}
3567
3568
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003569void LCodeGen::DoContext(LContext* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003570 Register result = ToRegister(instr->result());
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00003571 if (info()->IsOptimizing()) {
3572 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
3573 } else {
3574 // If there is no frame, the context must be in esi.
3575 ASSERT(result.is(esi));
3576 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003577}
3578
3579
3580void LCodeGen::DoOuterContext(LOuterContext* instr) {
3581 Register context = ToRegister(instr->context());
3582 Register result = ToRegister(instr->result());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003583 __ mov(result,
3584 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003585}
3586
3587
yangguo@chromium.org56454712012-02-16 15:33:53 +00003588void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003589 ASSERT(ToRegister(instr->context()).is(esi));
yangguo@chromium.org56454712012-02-16 15:33:53 +00003590 __ push(esi); // The context is the first argument.
3591 __ push(Immediate(instr->hydrogen()->pairs()));
3592 __ push(Immediate(Smi::FromInt(instr->hydrogen()->flags())));
3593 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
3594}
3595
3596
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003597void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
3598 Register context = ToRegister(instr->context());
3599 Register result = ToRegister(instr->result());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003600 __ mov(result,
3601 Operand(context, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003602}
3603
3604
3605void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003606 Register global = ToRegister(instr->global());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003607 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003608 __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003609}
3610
3611
3612void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003613 int formal_parameter_count,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003614 int arity,
danno@chromium.org40cb8782011-05-25 07:58:50 +00003615 LInstruction* instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003616 CallKind call_kind,
3617 EDIState edi_state) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003618 bool dont_adapt_arguments =
3619 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel;
3620 bool can_invoke_directly =
3621 dont_adapt_arguments || formal_parameter_count == arity;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003622
3623 LPointerMap* pointers = instr->pointer_map();
3624 RecordPosition(pointers->position());
3625
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003626 if (can_invoke_directly) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003627 if (edi_state == EDI_UNINITIALIZED) {
3628 __ LoadHeapObject(edi, function);
3629 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003630
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00003631 // Change context.
3632 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003633
3634 // Set eax to arguments count if adaption is not needed. Assumes that eax
3635 // is available to write to at this point.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003636 if (dont_adapt_arguments) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003637 __ mov(eax, arity);
3638 }
3639
3640 // Invoke function directly.
3641 __ SetCallKind(ecx, call_kind);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003642 if (function.is_identical_to(info()->closure())) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003643 __ CallSelf();
3644 } else {
3645 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
3646 }
3647 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
3648 } else {
3649 // We need to adapt arguments.
3650 SafepointGenerator generator(
3651 this, pointers, Safepoint::kLazyDeopt);
3652 ParameterCount count(arity);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003653 ParameterCount expected(formal_parameter_count);
3654 __ InvokeFunction(
3655 function, expected, count, CALL_FUNCTION, generator, call_kind);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003656 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003657}
3658
3659
3660void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
3661 ASSERT(ToRegister(instr->result()).is(eax));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003662 CallKnownFunction(instr->hydrogen()->function(),
3663 instr->hydrogen()->formal_parameter_count(),
danno@chromium.org40cb8782011-05-25 07:58:50 +00003664 instr->arity(),
3665 instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003666 CALL_AS_METHOD,
3667 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003668}
3669
3670
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003671void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003672 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003673 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003674 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003675 DeoptimizeIf(not_equal, instr->environment());
3676
3677 Label done;
3678 Register tmp = input_reg.is(eax) ? ecx : eax;
3679 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx;
3680
3681 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003682 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003683
3684 Label negative;
3685 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003686 // Check the sign of the argument. If the argument is positive, just
3687 // return it. We do not need to patch the stack since |input| and
3688 // |result| are the same register and |input| will be restored
3689 // unchanged by popping safepoint registers.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003690 __ test(tmp, Immediate(HeapNumber::kSignMask));
3691 __ j(not_zero, &negative);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003692 __ jmp(&done);
3693
3694 __ bind(&negative);
3695
3696 Label allocated, slow;
3697 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow);
3698 __ jmp(&allocated);
3699
3700 // Slow case: Call the runtime system to do the number allocation.
3701 __ bind(&slow);
3702
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003703 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0,
3704 instr, instr->context());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003705
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003706 // Set the pointer to the new heap number in tmp.
3707 if (!tmp.is(eax)) __ mov(tmp, eax);
3708
3709 // Restore input_reg after call to runtime.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003710 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003711
3712 __ bind(&allocated);
3713 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3714 __ and_(tmp2, ~HeapNumber::kSignMask);
3715 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
3716 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
3717 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003718 __ StoreToSafepointRegisterSlot(input_reg, tmp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003719
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003720 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003721}
3722
3723
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003724void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003725 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003726 __ test(input_reg, Operand(input_reg));
3727 Label is_positive;
3728 __ j(not_sign, &is_positive);
3729 __ neg(input_reg);
3730 __ test(input_reg, Operand(input_reg));
3731 DeoptimizeIf(negative, instr->environment());
3732 __ bind(&is_positive);
3733}
3734
3735
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003736void LCodeGen::DoMathAbs(LMathAbs* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003737 // Class for deferred case.
3738 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
3739 public:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003740 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003741 : LDeferredCode(codegen), instr_(instr) { }
3742 virtual void Generate() {
3743 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3744 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003745 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003746 private:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003747 LMathAbs* instr_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003748 };
3749
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003750 ASSERT(instr->value()->Equals(instr->result()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003751 Representation r = instr->hydrogen()->value()->representation();
3752
ulan@chromium.org750145a2013-03-07 15:14:13 +00003753 CpuFeatureScope scope(masm(), SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003754 if (r.IsDouble()) {
3755 XMMRegister scratch = xmm0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003756 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003757 __ xorps(scratch, scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003758 __ subsd(scratch, input_reg);
3759 __ pand(input_reg, scratch);
3760 } else if (r.IsInteger32()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003761 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003762 } else { // Tagged case.
3763 DeferredMathAbsTaggedHeapNumber* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003764 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003765 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003766 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003767 __ JumpIfNotSmi(input_reg, deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003768 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003769 __ bind(deferred->exit());
3770 }
3771}
3772
3773
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003774void LCodeGen::DoMathFloor(LMathFloor* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003775 CpuFeatureScope scope(masm(), SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003776 XMMRegister xmm_scratch = xmm0;
3777 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003778 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003779
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003780 if (CpuFeatures::IsSupported(SSE4_1)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003781 CpuFeatureScope scope(masm(), SSE4_1);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003782 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3783 // Deoptimize on negative zero.
3784 Label non_zero;
3785 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3786 __ ucomisd(input_reg, xmm_scratch);
3787 __ j(not_equal, &non_zero, Label::kNear);
3788 __ movmskpd(output_reg, input_reg);
3789 __ test(output_reg, Immediate(1));
3790 DeoptimizeIf(not_zero, instr->environment());
3791 __ bind(&non_zero);
3792 }
3793 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
3794 __ cvttsd2si(output_reg, Operand(xmm_scratch));
3795 // Overflow is signalled with minint.
3796 __ cmp(output_reg, 0x80000000u);
3797 DeoptimizeIf(equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003798 } else {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003799 Label negative_sign, done;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003800 // Deoptimize on unordered.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003801 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3802 __ ucomisd(input_reg, xmm_scratch);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003803 DeoptimizeIf(parity_even, instr->environment());
3804 __ j(below, &negative_sign, Label::kNear);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003805
3806 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3807 // Check for negative zero.
3808 Label positive_sign;
3809 __ j(above, &positive_sign, Label::kNear);
3810 __ movmskpd(output_reg, input_reg);
3811 __ test(output_reg, Immediate(1));
3812 DeoptimizeIf(not_zero, instr->environment());
3813 __ Set(output_reg, Immediate(0));
3814 __ jmp(&done, Label::kNear);
3815 __ bind(&positive_sign);
3816 }
3817
3818 // Use truncating instruction (OK because input is positive).
3819 __ cvttsd2si(output_reg, Operand(input_reg));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003820 // Overflow is signalled with minint.
3821 __ cmp(output_reg, 0x80000000u);
3822 DeoptimizeIf(equal, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003823 __ jmp(&done, Label::kNear);
3824
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003825 // Non-zero negative reaches here.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003826 __ bind(&negative_sign);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003827 // Truncate, then compare and compensate.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003828 __ cvttsd2si(output_reg, Operand(input_reg));
3829 __ cvtsi2sd(xmm_scratch, output_reg);
3830 __ ucomisd(input_reg, xmm_scratch);
3831 __ j(equal, &done, Label::kNear);
3832 __ sub(output_reg, Immediate(1));
3833 DeoptimizeIf(overflow, instr->environment());
3834
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003835 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003836 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003837}
3838
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003839void LCodeGen::DoMathRound(LMathRound* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003840 CpuFeatureScope scope(masm(), SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003841 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003842 XMMRegister input_reg = ToDoubleRegister(instr->value());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003843 XMMRegister xmm_scratch = xmm0;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003844 XMMRegister input_temp = ToDoubleRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003845 ExternalReference one_half = ExternalReference::address_of_one_half();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003846 ExternalReference minus_one_half =
3847 ExternalReference::address_of_minus_one_half();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003848
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003849 Label done, round_to_zero, below_one_half, do_not_compensate;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003850 __ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003851 __ ucomisd(xmm_scratch, input_reg);
3852 __ j(above, &below_one_half);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003853
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003854 // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x).
3855 __ addsd(xmm_scratch, input_reg);
3856 __ cvttsd2si(output_reg, Operand(xmm_scratch));
3857 // Overflow is signalled with minint.
3858 __ cmp(output_reg, 0x80000000u);
3859 __ RecordComment("D2I conversion overflow");
3860 DeoptimizeIf(equal, instr->environment());
3861 __ jmp(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003862
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003863 __ bind(&below_one_half);
3864 __ movdbl(xmm_scratch, Operand::StaticVariable(minus_one_half));
3865 __ ucomisd(xmm_scratch, input_reg);
3866 __ j(below_equal, &round_to_zero);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003867
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003868 // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then
3869 // compare and compensate.
3870 __ movsd(input_temp, input_reg); // Do not alter input_reg.
3871 __ subsd(input_temp, xmm_scratch);
3872 __ cvttsd2si(output_reg, Operand(input_temp));
3873 // Catch minint due to overflow, and to prevent overflow when compensating.
3874 __ cmp(output_reg, 0x80000000u);
3875 __ RecordComment("D2I conversion overflow");
3876 DeoptimizeIf(equal, instr->environment());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003877
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003878 __ cvtsi2sd(xmm_scratch, output_reg);
3879 __ ucomisd(xmm_scratch, input_temp);
3880 __ j(equal, &done);
3881 __ sub(output_reg, Immediate(1));
3882 // No overflow because we already ruled out minint.
3883 __ jmp(&done);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003884
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003885 __ bind(&round_to_zero);
3886 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
3887 // we can ignore the difference between a result of -0 and +0.
3888 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3889 // If the sign is positive, we return +0.
3890 __ movmskpd(output_reg, input_reg);
3891 __ test(output_reg, Immediate(1));
3892 __ RecordComment("Minus zero");
3893 DeoptimizeIf(not_zero, instr->environment());
danno@chromium.org160a7b02011-04-18 15:51:38 +00003894 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003895 __ Set(output_reg, Immediate(0));
3896 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003897}
3898
3899
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003900void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003901 CpuFeatureScope scope(masm(), SSE2);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003902 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003903 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
3904 __ sqrtsd(input_reg, input_reg);
3905}
3906
3907
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003908void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003909 CpuFeatureScope scope(masm(), SSE2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003910 XMMRegister xmm_scratch = xmm0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003911 XMMRegister input_reg = ToDoubleRegister(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003912 Register scratch = ToRegister(instr->temp());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003913 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003914
3915 // Note that according to ECMA-262 15.8.2.13:
3916 // Math.pow(-Infinity, 0.5) == Infinity
3917 // Math.sqrt(-Infinity) == NaN
3918 Label done, sqrt;
3919 // Check base for -Infinity. According to IEEE-754, single-precision
3920 // -Infinity has the highest 9 bits set and the lowest 23 bits cleared.
3921 __ mov(scratch, 0xFF800000);
3922 __ movd(xmm_scratch, scratch);
3923 __ cvtss2sd(xmm_scratch, xmm_scratch);
3924 __ ucomisd(input_reg, xmm_scratch);
3925 // Comparing -Infinity with NaN results in "unordered", which sets the
3926 // zero flag as if both were equal. However, it also sets the carry flag.
3927 __ j(not_equal, &sqrt, Label::kNear);
3928 __ j(carry, &sqrt, Label::kNear);
3929 // If input is -Infinity, return Infinity.
3930 __ xorps(input_reg, input_reg);
3931 __ subsd(input_reg, xmm_scratch);
3932 __ jmp(&done, Label::kNear);
3933
3934 // Square root.
3935 __ bind(&sqrt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003936 __ xorps(xmm_scratch, xmm_scratch);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003937 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003938 __ sqrtsd(input_reg, input_reg);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003939 __ bind(&done);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003940}
3941
3942
3943void LCodeGen::DoPower(LPower* instr) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003944 Representation exponent_type = instr->hydrogen()->right()->representation();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003945 // Having marked this as a call, we can use any registers.
3946 // Just make sure that the input/output registers are the expected ones.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003947 ASSERT(!instr->right()->IsDoubleRegister() ||
3948 ToDoubleRegister(instr->right()).is(xmm1));
3949 ASSERT(!instr->right()->IsRegister() ||
3950 ToRegister(instr->right()).is(eax));
3951 ASSERT(ToDoubleRegister(instr->left()).is(xmm2));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003952 ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003953
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003954 if (exponent_type.IsSmi()) {
3955 MathPowStub stub(MathPowStub::TAGGED);
3956 __ CallStub(&stub);
3957 } else if (exponent_type.IsTagged()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003958 Label no_deopt;
3959 __ JumpIfSmi(eax, &no_deopt);
3960 __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003961 DeoptimizeIf(not_equal, instr->environment());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003962 __ bind(&no_deopt);
3963 MathPowStub stub(MathPowStub::TAGGED);
3964 __ CallStub(&stub);
3965 } else if (exponent_type.IsInteger32()) {
3966 MathPowStub stub(MathPowStub::INTEGER);
3967 __ CallStub(&stub);
3968 } else {
3969 ASSERT(exponent_type.IsDouble());
3970 MathPowStub stub(MathPowStub::DOUBLE);
3971 __ CallStub(&stub);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003972 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003973}
3974
3975
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003976void LCodeGen::DoRandom(LRandom* instr) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003977 class DeferredDoRandom: public LDeferredCode {
3978 public:
3979 DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
3980 : LDeferredCode(codegen), instr_(instr) { }
3981 virtual void Generate() { codegen()->DoDeferredRandom(instr_); }
3982 virtual LInstruction* instr() { return instr_; }
3983 private:
3984 LRandom* instr_;
3985 };
3986
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003987 DeferredDoRandom* deferred = new(zone()) DeferredDoRandom(this, instr);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003988
ulan@chromium.org750145a2013-03-07 15:14:13 +00003989 CpuFeatureScope scope(masm(), SSE2);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003990 // Having marked this instruction as a call we can use any
3991 // registers.
3992 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003993 ASSERT(ToRegister(instr->global_object()).is(eax));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003994 // Assert that the register size is indeed the size of each seed.
3995 static const int kSeedSize = sizeof(uint32_t);
3996 STATIC_ASSERT(kPointerSize == kSeedSize);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003997
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003998 __ mov(eax, FieldOperand(eax, GlobalObject::kNativeContextOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003999 static const int kRandomSeedOffset =
4000 FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
4001 __ mov(ebx, FieldOperand(eax, kRandomSeedOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004002 // ebx: FixedArray of the native context's random seeds
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004003
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004004 // Load state[0].
4005 __ mov(ecx, FieldOperand(ebx, ByteArray::kHeaderSize));
4006 // If state[0] == 0, call runtime to initialize seeds.
4007 __ test(ecx, ecx);
4008 __ j(zero, deferred->entry());
4009 // Load state[1].
4010 __ mov(eax, FieldOperand(ebx, ByteArray::kHeaderSize + kSeedSize));
4011 // ecx: state[0]
4012 // eax: state[1]
4013
4014 // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
4015 __ movzx_w(edx, ecx);
4016 __ imul(edx, edx, 18273);
4017 __ shr(ecx, 16);
4018 __ add(ecx, edx);
4019 // Save state[0].
4020 __ mov(FieldOperand(ebx, ByteArray::kHeaderSize), ecx);
4021
4022 // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
4023 __ movzx_w(edx, eax);
4024 __ imul(edx, edx, 36969);
4025 __ shr(eax, 16);
4026 __ add(eax, edx);
4027 // Save state[1].
4028 __ mov(FieldOperand(ebx, ByteArray::kHeaderSize + kSeedSize), eax);
4029
4030 // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
4031 __ shl(ecx, 14);
4032 __ and_(eax, Immediate(0x3FFFF));
4033 __ add(eax, ecx);
4034
4035 __ bind(deferred->exit());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004036 // Convert 32 random bits in eax to 0.(32 random bits) in a double
4037 // by computing:
4038 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
4039 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
4040 __ movd(xmm2, ebx);
4041 __ movd(xmm1, eax);
4042 __ cvtss2sd(xmm2, xmm2);
4043 __ xorps(xmm1, xmm2);
4044 __ subsd(xmm1, xmm2);
4045}
4046
4047
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004048void LCodeGen::DoDeferredRandom(LRandom* instr) {
4049 __ PrepareCallCFunction(1, ebx);
4050 __ mov(Operand(esp, 0), eax);
4051 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
4052 // Return value is in eax.
4053}
4054
4055
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004056void LCodeGen::DoMathLog(LMathLog* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004057 CpuFeatureScope scope(masm(), SSE2);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004058 ASSERT(instr->value()->Equals(instr->result()));
4059 XMMRegister input_reg = ToDoubleRegister(instr->value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004060 Label positive, done, zero;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00004061 __ xorps(xmm0, xmm0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004062 __ ucomisd(input_reg, xmm0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004063 __ j(above, &positive, Label::kNear);
4064 __ j(equal, &zero, Label::kNear);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004065 ExternalReference nan =
4066 ExternalReference::address_of_canonical_non_hole_nan();
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004067 __ movdbl(input_reg, Operand::StaticVariable(nan));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004068 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004069 __ bind(&zero);
4070 __ push(Immediate(0xFFF00000));
4071 __ push(Immediate(0));
4072 __ movdbl(input_reg, Operand(esp, 0));
4073 __ add(Operand(esp), Immediate(kDoubleSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004074 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004075 __ bind(&positive);
4076 __ fldln2();
4077 __ sub(Operand(esp), Immediate(kDoubleSize));
4078 __ movdbl(Operand(esp, 0), input_reg);
4079 __ fld_d(Operand(esp, 0));
4080 __ fyl2x();
4081 __ fstp_d(Operand(esp, 0));
4082 __ movdbl(input_reg, Operand(esp, 0));
4083 __ add(Operand(esp), Immediate(kDoubleSize));
4084 __ bind(&done);
whesse@chromium.org023421e2010-12-21 12:19:12 +00004085}
4086
4087
danno@chromium.org1f34ad32012-11-26 14:53:56 +00004088void LCodeGen::DoMathExp(LMathExp* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004089 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00004090 XMMRegister input = ToDoubleRegister(instr->value());
4091 XMMRegister result = ToDoubleRegister(instr->result());
4092 Register temp1 = ToRegister(instr->temp1());
4093 Register temp2 = ToRegister(instr->temp2());
4094
4095 MathExpGenerator::EmitMathExp(masm(), input, result, xmm0, temp1, temp2);
4096}
4097
4098
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004099void LCodeGen::DoMathTan(LMathTan* instr) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004100 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
4101 TranscendentalCacheStub stub(TranscendentalCache::TAN,
4102 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004103 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004104}
4105
4106
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004107void LCodeGen::DoMathCos(LMathCos* instr) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00004108 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
4109 TranscendentalCacheStub stub(TranscendentalCache::COS,
4110 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004111 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org023421e2010-12-21 12:19:12 +00004112}
4113
4114
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004115void LCodeGen::DoMathSin(LMathSin* instr) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00004116 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
4117 TranscendentalCacheStub stub(TranscendentalCache::SIN,
4118 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004119 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004120}
4121
4122
danno@chromium.org160a7b02011-04-18 15:51:38 +00004123void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
4124 ASSERT(ToRegister(instr->context()).is(esi));
4125 ASSERT(ToRegister(instr->function()).is(edi));
4126 ASSERT(instr->HasPointerMap());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004127
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004128 Handle<JSFunction> known_function = instr->hydrogen()->known_function();
4129 if (known_function.is_null()) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004130 LPointerMap* pointers = instr->pointer_map();
4131 RecordPosition(pointers->position());
4132 SafepointGenerator generator(
4133 this, pointers, Safepoint::kLazyDeopt);
4134 ParameterCount count(instr->arity());
4135 __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
4136 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004137 CallKnownFunction(known_function,
4138 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004139 instr->arity(),
4140 instr,
4141 CALL_AS_METHOD,
4142 EDI_CONTAINS_TARGET);
4143 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00004144}
4145
4146
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004147void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004148 ASSERT(ToRegister(instr->context()).is(esi));
4149 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004150 ASSERT(ToRegister(instr->result()).is(eax));
4151
4152 int arity = instr->arity();
lrn@chromium.org34e60782011-09-15 07:25:40 +00004153 Handle<Code> ic =
4154 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004155 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004156}
4157
4158
4159void LCodeGen::DoCallNamed(LCallNamed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004160 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004161 ASSERT(ToRegister(instr->result()).is(eax));
4162
4163 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00004164 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
4165 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00004166 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004167 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004168 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004169}
4170
4171
4172void LCodeGen::DoCallFunction(LCallFunction* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004173 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.orgc612e022011-11-10 11:38:15 +00004174 ASSERT(ToRegister(instr->function()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004175 ASSERT(ToRegister(instr->result()).is(eax));
4176
4177 int arity = instr->arity();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004178 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004179 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004180}
4181
4182
4183void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004184 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004185 ASSERT(ToRegister(instr->result()).is(eax));
4186
4187 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00004188 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
4189 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00004190 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004191 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004192 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004193}
4194
4195
4196void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
4197 ASSERT(ToRegister(instr->result()).is(eax));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004198 CallKnownFunction(instr->hydrogen()->target(),
4199 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004200 instr->arity(),
4201 instr,
4202 CALL_AS_FUNCTION,
4203 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004204}
4205
4206
4207void LCodeGen::DoCallNew(LCallNew* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004208 ASSERT(ToRegister(instr->context()).is(esi));
4209 ASSERT(ToRegister(instr->constructor()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004210 ASSERT(ToRegister(instr->result()).is(eax));
4211
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004212 if (FLAG_optimize_constructed_arrays) {
4213 // No cell in ebx for construct type feedback in optimized code
4214 Handle<Object> undefined_value(isolate()->heap()->undefined_value(),
4215 isolate());
4216 __ mov(ebx, Immediate(undefined_value));
4217 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004218 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004219 __ Set(eax, Immediate(instr->arity()));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004220 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004221}
4222
4223
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004224void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
4225 ASSERT(ToRegister(instr->context()).is(esi));
4226 ASSERT(ToRegister(instr->constructor()).is(edi));
4227 ASSERT(ToRegister(instr->result()).is(eax));
4228 ASSERT(FLAG_optimize_constructed_arrays);
4229
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004230 __ Set(eax, Immediate(instr->arity()));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004231 __ mov(ebx, instr->hydrogen()->property_cell());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004232 ElementsKind kind = instr->hydrogen()->elements_kind();
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00004233 bool disable_allocation_sites =
4234 (AllocationSiteInfo::GetMode(kind) == TRACK_ALLOCATION_SITE);
4235
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004236 if (instr->arity() == 0) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00004237 ArrayNoArgumentConstructorStub stub(kind, disable_allocation_sites);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004238 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
4239 } else if (instr->arity() == 1) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00004240 ArraySingleArgumentConstructorStub stub(kind, disable_allocation_sites);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004241 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
4242 } else {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00004243 ArrayNArgumentsConstructorStub stub(kind, disable_allocation_sites);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004244 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
4245 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004246}
4247
4248
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004249void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004250 CallRuntime(instr->function(), instr->arity(), instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004251}
4252
4253
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004254void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
4255 Register result = ToRegister(instr->result());
4256 Register base = ToRegister(instr->base_object());
4257 __ lea(result, Operand(base, instr->offset()));
4258}
4259
4260
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004261void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00004262 Representation representation = instr->representation();
4263
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004264 Register object = ToRegister(instr->object());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004265 HObjectAccess access = instr->hydrogen()->access();
4266 int offset = access.offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004267
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004268 Handle<Map> transition = instr->transition();
4269
danno@chromium.orgf005df62013-04-30 16:36:45 +00004270 if (FLAG_track_fields && representation.IsSmi()) {
4271 if (instr->value()->IsConstantOperand()) {
4272 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004273 if (!IsSmi(operand_value)) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00004274 DeoptimizeIf(no_condition, instr->environment());
4275 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00004276 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00004277 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
4278 if (instr->value()->IsConstantOperand()) {
4279 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
4280 if (IsInteger32(operand_value)) {
4281 DeoptimizeIf(no_condition, instr->environment());
4282 }
4283 } else {
4284 if (!instr->hydrogen()->value()->type().IsHeapObject()) {
4285 Register value = ToRegister(instr->value());
4286 __ test(value, Immediate(kSmiTagMask));
4287 DeoptimizeIf(zero, instr->environment());
4288 }
4289 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004290 } else if (FLAG_track_double_fields && representation.IsDouble()) {
4291 ASSERT(transition.is_null());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004292 ASSERT(access.IsInobject());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004293 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
4294 if (CpuFeatures::IsSupported(SSE2)) {
4295 CpuFeatureScope scope(masm(), SSE2);
4296 XMMRegister value = ToDoubleRegister(instr->value());
4297 __ movdbl(FieldOperand(object, offset), value);
4298 } else {
4299 __ fstp_d(FieldOperand(object, offset));
4300 }
4301 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00004302 }
4303
danno@chromium.orgf005df62013-04-30 16:36:45 +00004304 if (!transition.is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +00004305 if (!instr->hydrogen()->NeedsWriteBarrierForMap()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00004306 __ mov(FieldOperand(object, HeapObject::kMapOffset), transition);
verwaest@chromium.org37141392012-05-31 13:27:02 +00004307 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004308 Register temp = ToRegister(instr->temp());
4309 Register temp_map = ToRegister(instr->temp_map());
danno@chromium.orgf005df62013-04-30 16:36:45 +00004310 __ mov(temp_map, transition);
verwaest@chromium.org37141392012-05-31 13:27:02 +00004311 __ mov(FieldOperand(object, HeapObject::kMapOffset), temp_map);
4312 // Update the write barrier for the map field.
4313 __ RecordWriteField(object,
4314 HeapObject::kMapOffset,
4315 temp_map,
4316 temp,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004317 GetSaveFPRegsMode(),
verwaest@chromium.org37141392012-05-31 13:27:02 +00004318 OMIT_REMEMBERED_SET,
4319 OMIT_SMI_CHECK);
4320 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004321 }
4322
4323 // Do the store.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004324 HType type = instr->hydrogen()->value()->type();
4325 SmiCheck check_needed =
4326 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004327
4328 Register write_register = object;
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004329 if (!access.IsInobject()) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004330 write_register = ToRegister(instr->temp());
4331 __ mov(write_register,
4332 FieldOperand(object, JSObject::kPropertiesOffset));
4333 }
4334
4335 if (instr->value()->IsConstantOperand()) {
4336 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004337 if (operand_value->IsRegister()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004338 __ mov(FieldOperand(write_register, offset), ToRegister(operand_value));
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004339 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004340 Handle<Object> handle_value = ToHandle(operand_value);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004341 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004342 __ mov(FieldOperand(write_register, offset), handle_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004343 }
4344 } else {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004345 __ mov(FieldOperand(write_register, offset), ToRegister(instr->value()));
4346 }
4347
4348 if (instr->hydrogen()->NeedsWriteBarrier()) {
4349 Register value = ToRegister(instr->value());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004350 Register temp = access.IsInobject() ? ToRegister(instr->temp()) : object;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004351 // Update the write barrier for the object for in-object properties.
4352 __ RecordWriteField(write_register,
4353 offset,
4354 value,
4355 temp,
4356 GetSaveFPRegsMode(),
4357 EMIT_REMEMBERED_SET,
4358 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004359 }
4360}
4361
4362
4363void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004364 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004365 ASSERT(ToRegister(instr->object()).is(edx));
4366 ASSERT(ToRegister(instr->value()).is(eax));
4367
4368 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004369 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004370 ? isolate()->builtins()->StoreIC_Initialize_Strict()
4371 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004372 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004373}
4374
4375
4376void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004377 if (instr->hydrogen()->skip_check()) return;
4378
danno@chromium.orgb6451162011-08-17 14:33:23 +00004379 if (instr->index()->IsConstantOperand()) {
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004380 int constant_index =
4381 ToInteger32(LConstantOperand::cast(instr->index()));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004382 if (instr->hydrogen()->length()->representation().IsSmi()) {
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004383 __ cmp(ToOperand(instr->length()),
4384 Immediate(Smi::FromInt(constant_index)));
4385 } else {
4386 __ cmp(ToOperand(instr->length()), Immediate(constant_index));
4387 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00004388 DeoptimizeIf(below_equal, instr->environment());
4389 } else {
4390 __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
4391 DeoptimizeIf(above_equal, instr->environment());
4392 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004393}
4394
4395
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004396void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004397 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004398 LOperand* key = instr->key();
4399 if (!key->IsConstantOperand() &&
4400 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
4401 elements_kind)) {
4402 __ SmiUntag(ToRegister(key));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004403 }
4404 Operand operand(BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004405 instr->elements(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004406 key,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004407 instr->hydrogen()->key()->representation(),
4408 elements_kind,
4409 0,
4410 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004411 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004412 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
4413 CpuFeatureScope scope(masm(), SSE2);
4414 __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
4415 __ movss(operand, xmm0);
4416 } else {
4417 __ fld(0);
4418 __ fstp_s(operand);
4419 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004420 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004421 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
4422 CpuFeatureScope scope(masm(), SSE2);
4423 __ movdbl(operand, ToDoubleRegister(instr->value()));
4424 } else {
4425 __ fst_d(operand);
4426 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004427 } else {
4428 Register value = ToRegister(instr->value());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004429 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004430 case EXTERNAL_PIXEL_ELEMENTS:
4431 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4432 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004433 __ mov_b(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004434 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004435 case EXTERNAL_SHORT_ELEMENTS:
4436 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004437 __ mov_w(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004438 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004439 case EXTERNAL_INT_ELEMENTS:
4440 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004441 __ mov(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004442 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004443 case EXTERNAL_FLOAT_ELEMENTS:
4444 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004445 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004446 case FAST_ELEMENTS:
4447 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004448 case FAST_HOLEY_SMI_ELEMENTS:
4449 case FAST_HOLEY_ELEMENTS:
4450 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004451 case DICTIONARY_ELEMENTS:
4452 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004453 UNREACHABLE();
4454 break;
4455 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004456 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004457}
4458
4459
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004460void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004461 ExternalReference canonical_nan_reference =
4462 ExternalReference::address_of_canonical_non_hole_nan();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004463 Operand double_store_operand = BuildFastArrayOperand(
4464 instr->elements(),
4465 instr->key(),
4466 instr->hydrogen()->key()->representation(),
4467 FAST_DOUBLE_ELEMENTS,
4468 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
4469 instr->additional_index());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004470
4471 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
4472 CpuFeatureScope scope(masm(), SSE2);
4473 XMMRegister value = ToDoubleRegister(instr->value());
4474
4475 if (instr->NeedsCanonicalization()) {
4476 Label have_value;
4477
4478 __ ucomisd(value, value);
4479 __ j(parity_odd, &have_value); // NaN.
4480
4481 __ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
4482 __ bind(&have_value);
4483 }
4484
4485 __ movdbl(double_store_operand, value);
4486 } else {
4487 // Can't use SSE2 in the serializer
4488 if (instr->hydrogen()->IsConstantHoleStore()) {
4489 // This means we should store the (double) hole. No floating point
4490 // registers required.
4491 double nan_double = FixedDoubleArray::hole_nan_as_double();
4492 uint64_t int_val = BitCast<uint64_t, double>(nan_double);
4493 int32_t lower = static_cast<int32_t>(int_val);
4494 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
4495
4496 __ mov(double_store_operand, Immediate(lower));
4497 Operand double_store_operand2 = BuildFastArrayOperand(
4498 instr->elements(),
4499 instr->key(),
4500 instr->hydrogen()->key()->representation(),
4501 FAST_DOUBLE_ELEMENTS,
4502 FixedDoubleArray::kHeaderSize - kHeapObjectTag + kPointerSize,
4503 instr->additional_index());
4504 __ mov(double_store_operand2, Immediate(upper));
4505 } else {
4506 Label no_special_nan_handling;
4507 ASSERT(x87_stack_depth_ > 0);
4508
4509 if (instr->NeedsCanonicalization()) {
4510 __ fld(0);
4511 __ fld(0);
4512 __ FCmp();
4513
4514 __ j(parity_odd, &no_special_nan_handling);
4515 __ sub(esp, Immediate(kDoubleSize));
4516 __ fst_d(MemOperand(esp, 0));
4517 __ cmp(MemOperand(esp, sizeof(kHoleNanLower32)),
4518 Immediate(kHoleNanUpper32));
4519 __ add(esp, Immediate(kDoubleSize));
4520 Label canonicalize;
4521 __ j(not_equal, &canonicalize);
4522 __ jmp(&no_special_nan_handling);
4523 __ bind(&canonicalize);
4524 __ fstp(0);
4525 __ fld_d(Operand::StaticVariable(canonical_nan_reference));
4526 }
4527
4528 __ bind(&no_special_nan_handling);
4529 __ fst_d(double_store_operand);
4530 }
4531 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004532}
4533
4534
4535void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004536 Register elements = ToRegister(instr->elements());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004537 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
4538
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004539 Operand operand = BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004540 instr->elements(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004541 instr->key(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004542 instr->hydrogen()->key()->representation(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004543 FAST_ELEMENTS,
4544 FixedArray::kHeaderSize - kHeapObjectTag,
4545 instr->additional_index());
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004546 if (instr->value()->IsRegister()) {
4547 __ mov(operand, ToRegister(instr->value()));
4548 } else {
4549 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
4550 if (IsInteger32(operand_value)) {
4551 Smi* smi_value = Smi::FromInt(ToInteger32(operand_value));
4552 __ mov(operand, Immediate(smi_value));
4553 } else {
4554 Handle<Object> handle_value = ToHandle(operand_value);
4555 __ mov(operand, handle_value);
4556 }
4557 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004558
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004559 if (instr->hydrogen()->NeedsWriteBarrier()) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004560 ASSERT(instr->value()->IsRegister());
4561 Register value = ToRegister(instr->value());
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004562 ASSERT(!instr->key()->IsConstantOperand());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004563 HType type = instr->hydrogen()->value()->type();
4564 SmiCheck check_needed =
4565 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004566 // Compute address of modified element and store it into key register.
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004567 __ lea(key, operand);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004568 __ RecordWrite(elements,
4569 key,
4570 value,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004571 GetSaveFPRegsMode(),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004572 EMIT_REMEMBERED_SET,
4573 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004574 }
4575}
4576
4577
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004578void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
4579 // By cases...external, fast-double, fast
4580 if (instr->is_external()) {
4581 DoStoreKeyedExternalArray(instr);
4582 } else if (instr->hydrogen()->value()->representation().IsDouble()) {
4583 DoStoreKeyedFixedDoubleArray(instr);
4584 } else {
4585 DoStoreKeyedFixedArray(instr);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004586 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004587}
4588
4589
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004590void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004591 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004592 ASSERT(ToRegister(instr->object()).is(edx));
4593 ASSERT(ToRegister(instr->key()).is(ecx));
4594 ASSERT(ToRegister(instr->value()).is(eax));
4595
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004596 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004597 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
4598 : isolate()->builtins()->KeyedStoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004599 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004600}
4601
4602
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004603void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
4604 Register object = ToRegister(instr->object());
4605 Register temp = ToRegister(instr->temp());
4606 __ TestJSArrayForAllocationSiteInfo(object, temp);
4607 DeoptimizeIf(equal, instr->environment());
4608}
4609
4610
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004611void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
4612 Register object_reg = ToRegister(instr->object());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004613
4614 Handle<Map> from_map = instr->original_map();
4615 Handle<Map> to_map = instr->transitioned_map();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00004616 ElementsKind from_kind = instr->from_kind();
4617 ElementsKind to_kind = instr->to_kind();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004618
4619 Label not_applicable;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004620 bool is_simple_map_transition =
4621 IsSimpleMapChangeTransition(from_kind, to_kind);
4622 Label::Distance branch_distance =
4623 is_simple_map_transition ? Label::kNear : Label::kFar;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004624 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004625 __ j(not_equal, &not_applicable, branch_distance);
4626 if (is_simple_map_transition) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004627 Register new_map_reg = ToRegister(instr->new_map_temp());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004628 Handle<Map> map = instr->hydrogen()->transitioned_map();
4629 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset),
4630 Immediate(map));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004631 // Write barrier.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004632 ASSERT_NE(instr->temp(), NULL);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004633 __ RecordWriteForMap(object_reg, to_map, new_map_reg,
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004634 ToRegister(instr->temp()),
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004635 kDontSaveFPRegs);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004636 } else if (FLAG_compiled_transitions) {
4637 PushSafepointRegistersScope scope(this);
4638 if (!object_reg.is(eax)) {
4639 __ push(object_reg);
4640 }
4641 LoadContextFromDeferred(instr->context());
4642 if (!object_reg.is(eax)) {
4643 __ pop(eax);
4644 }
4645 __ mov(ebx, to_map);
4646 TransitionElementsKindStub stub(from_kind, to_kind);
4647 __ CallStub(&stub);
4648 RecordSafepointWithRegisters(
4649 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004650 } else if (IsFastSmiElementsKind(from_kind) &&
4651 IsFastDoubleElementsKind(to_kind)) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004652 Register new_map_reg = ToRegister(instr->new_map_temp());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004653 __ mov(new_map_reg, to_map);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004654 Register fixed_object_reg = ToRegister(instr->temp());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004655 ASSERT(fixed_object_reg.is(edx));
4656 ASSERT(new_map_reg.is(ebx));
4657 __ mov(fixed_object_reg, object_reg);
4658 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
4659 RelocInfo::CODE_TARGET, instr);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004660 } else if (IsFastDoubleElementsKind(from_kind) &&
4661 IsFastObjectElementsKind(to_kind)) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004662 Register new_map_reg = ToRegister(instr->new_map_temp());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004663 __ mov(new_map_reg, to_map);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004664 Register fixed_object_reg = ToRegister(instr->temp());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004665 ASSERT(fixed_object_reg.is(edx));
4666 ASSERT(new_map_reg.is(ebx));
4667 __ mov(fixed_object_reg, object_reg);
4668 CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
4669 RelocInfo::CODE_TARGET, instr);
4670 } else {
4671 UNREACHABLE();
4672 }
4673 __ bind(&not_applicable);
4674}
4675
4676
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004677void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
4678 class DeferredStringCharCodeAt: public LDeferredCode {
4679 public:
4680 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
4681 : LDeferredCode(codegen), instr_(instr) { }
4682 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004683 virtual LInstruction* instr() { return instr_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004684 private:
4685 LStringCharCodeAt* instr_;
4686 };
4687
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004688 DeferredStringCharCodeAt* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004689 new(zone()) DeferredStringCharCodeAt(this, instr);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004690
erikcorry0ad885c2011-11-21 13:51:57 +00004691 StringCharLoadGenerator::Generate(masm(),
4692 factory(),
4693 ToRegister(instr->string()),
4694 ToRegister(instr->index()),
4695 ToRegister(instr->result()),
4696 deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004697 __ bind(deferred->exit());
4698}
4699
4700
4701void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
4702 Register string = ToRegister(instr->string());
4703 Register result = ToRegister(instr->result());
4704
4705 // TODO(3095996): Get rid of this. For now, we need to make the
4706 // result register contain a valid pointer because it is already
4707 // contained in the register pointer map.
4708 __ Set(result, Immediate(0));
4709
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004710 PushSafepointRegistersScope scope(this);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004711 __ push(string);
4712 // Push the index as a smi. This is safe because of the checks in
4713 // DoStringCharCodeAt above.
4714 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
4715 if (instr->index()->IsConstantOperand()) {
4716 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
4717 __ push(Immediate(Smi::FromInt(const_index)));
4718 } else {
4719 Register index = ToRegister(instr->index());
4720 __ SmiTag(index);
4721 __ push(index);
4722 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004723 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2,
4724 instr, instr->context());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004725 __ AssertSmi(eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004726 __ SmiUntag(eax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004727 __ StoreToSafepointRegisterSlot(result, eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004728}
4729
4730
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004731void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
4732 class DeferredStringCharFromCode: public LDeferredCode {
4733 public:
4734 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
4735 : LDeferredCode(codegen), instr_(instr) { }
4736 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004737 virtual LInstruction* instr() { return instr_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004738 private:
4739 LStringCharFromCode* instr_;
4740 };
4741
4742 DeferredStringCharFromCode* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004743 new(zone()) DeferredStringCharFromCode(this, instr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004744
4745 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
4746 Register char_code = ToRegister(instr->char_code());
4747 Register result = ToRegister(instr->result());
4748 ASSERT(!char_code.is(result));
4749
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004750 __ cmp(char_code, String::kMaxOneByteCharCode);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004751 __ j(above, deferred->entry());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004752 __ Set(result, Immediate(factory()->single_character_string_cache()));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004753 __ mov(result, FieldOperand(result,
4754 char_code, times_pointer_size,
4755 FixedArray::kHeaderSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004756 __ cmp(result, factory()->undefined_value());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004757 __ j(equal, deferred->entry());
4758 __ bind(deferred->exit());
4759}
4760
4761
4762void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4763 Register char_code = ToRegister(instr->char_code());
4764 Register result = ToRegister(instr->result());
4765
4766 // TODO(3095996): Get rid of this. For now, we need to make the
4767 // result register contain a valid pointer because it is already
4768 // contained in the register pointer map.
4769 __ Set(result, Immediate(0));
4770
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004771 PushSafepointRegistersScope scope(this);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004772 __ SmiTag(char_code);
4773 __ push(char_code);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004774 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004775 __ StoreToSafepointRegisterSlot(result, eax);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004776}
4777
4778
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004779void LCodeGen::DoStringLength(LStringLength* instr) {
4780 Register string = ToRegister(instr->string());
4781 Register result = ToRegister(instr->result());
4782 __ mov(result, FieldOperand(string, String::kLengthOffset));
4783}
4784
4785
danno@chromium.org160a7b02011-04-18 15:51:38 +00004786void LCodeGen::DoStringAdd(LStringAdd* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004787 EmitPushTaggedOperand(instr->left());
4788 EmitPushTaggedOperand(instr->right());
danno@chromium.org160a7b02011-04-18 15:51:38 +00004789 StringAddStub stub(NO_STRING_CHECK_IN_STUB);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004790 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
danno@chromium.org160a7b02011-04-18 15:51:38 +00004791}
4792
4793
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004794void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004795 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004796 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004797 LOperand* input = instr->value();
4798 ASSERT(input->IsRegister() || input->IsStackSlot());
4799 LOperand* output = instr->result();
4800 ASSERT(output->IsDoubleRegister());
4801 __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
4802 } else {
4803 UNREACHABLE();
4804 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004805}
4806
4807
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004808void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) {
4809 Register input = ToRegister(instr->value());
4810 __ SmiTag(input);
4811 if (!instr->hydrogen()->value()->HasRange() ||
4812 !instr->hydrogen()->value()->range()->IsInSmiRange()) {
4813 DeoptimizeIf(overflow, instr->environment());
4814 }
4815}
4816
4817
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004818void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004819 CpuFeatureScope scope(masm(), SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004820 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004821 LOperand* output = instr->result();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004822 LOperand* temp = instr->temp();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004823
4824 __ LoadUint32(ToDoubleRegister(output),
4825 ToRegister(input),
4826 ToDoubleRegister(temp));
4827}
4828
4829
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004830void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
4831 class DeferredNumberTagI: public LDeferredCode {
4832 public:
4833 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
4834 : LDeferredCode(codegen), instr_(instr) { }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004835 virtual void Generate() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004836 codegen()->DoDeferredNumberTagI(instr_, instr_->value(), SIGNED_INT32);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004837 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004838 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004839 private:
4840 LNumberTagI* instr_;
4841 };
4842
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004843 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004844 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4845 Register reg = ToRegister(input);
4846
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004847 DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004848 __ SmiTag(reg);
4849 __ j(overflow, deferred->entry());
4850 __ bind(deferred->exit());
4851}
4852
4853
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004854void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
4855 class DeferredNumberTagU: public LDeferredCode {
4856 public:
4857 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
4858 : LDeferredCode(codegen), instr_(instr) { }
4859 virtual void Generate() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004860 codegen()->DoDeferredNumberTagI(instr_, instr_->value(), UNSIGNED_INT32);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004861 }
4862 virtual LInstruction* instr() { return instr_; }
4863 private:
4864 LNumberTagU* instr_;
4865 };
4866
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004867 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004868 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4869 Register reg = ToRegister(input);
4870
4871 DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
4872 __ cmp(reg, Immediate(Smi::kMaxValue));
4873 __ j(above, deferred->entry());
4874 __ SmiTag(reg);
4875 __ bind(deferred->exit());
4876}
4877
4878
4879void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
4880 LOperand* value,
4881 IntegerSignedness signedness) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004882 Label slow;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004883 Register reg = ToRegister(value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004884 Register tmp = reg.is(eax) ? ecx : eax;
4885
4886 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004887 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004888
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004889 Label done;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004890
4891 if (signedness == SIGNED_INT32) {
4892 // There was overflow, so bits 30 and 31 of the original integer
4893 // disagree. Try to allocate a heap number in new space and store
4894 // the value in there. If that fails, call the runtime system.
4895 __ SmiUntag(reg);
4896 __ xor_(reg, 0x80000000);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004897 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004898 CpuFeatureScope feature_scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004899 __ cvtsi2sd(xmm0, Operand(reg));
4900 } else {
4901 __ push(reg);
4902 __ fild_s(Operand(esp, 0));
4903 __ pop(reg);
4904 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004905 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004906 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004907 CpuFeatureScope feature_scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004908 __ LoadUint32(xmm0, reg, xmm1);
4909 } else {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00004910 // There's no fild variant for unsigned values, so zero-extend to a 64-bit
4911 // int manually.
4912 __ push(Immediate(0));
4913 __ push(reg);
4914 __ fild_d(Operand(esp, 0));
4915 __ pop(reg);
4916 __ pop(reg);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004917 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004918 }
4919
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004920 if (FLAG_inline_new) {
4921 __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004922 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004923 }
4924
4925 // Slow case: Call the runtime system to do the number allocation.
4926 __ bind(&slow);
4927
4928 // TODO(3095996): Put a valid pointer value in the stack slot where the result
4929 // register is stored, as this register is in the pointer map, but contains an
4930 // integer value.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004931 __ StoreToSafepointRegisterSlot(reg, Immediate(0));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004932 // NumberTagI and NumberTagD use the context from the frame, rather than
4933 // the environment's HContext or HInlinedContext value.
4934 // They only call Runtime::kAllocateHeapNumber.
4935 // The corresponding HChange instructions are added in a phase that does
4936 // not have easy access to the local context.
4937 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4938 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4939 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004940 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004941 if (!reg.is(eax)) __ mov(reg, eax);
4942
4943 // Done. Put the value in xmm0 into the value of the allocated heap
4944 // number.
4945 __ bind(&done);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004946 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004947 CpuFeatureScope feature_scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004948 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0);
4949 } else {
4950 __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
4951 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004952 __ StoreToSafepointRegisterSlot(reg, reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004953}
4954
4955
4956void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
4957 class DeferredNumberTagD: public LDeferredCode {
4958 public:
4959 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
4960 : LDeferredCode(codegen), instr_(instr) { }
4961 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004962 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004963 private:
4964 LNumberTagD* instr_;
4965 };
4966
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004967 Register reg = ToRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004968
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004969 bool convert_hole = false;
4970 HValue* change_input = instr->hydrogen()->value();
4971 if (change_input->IsLoadKeyed()) {
4972 HLoadKeyed* load = HLoadKeyed::cast(change_input);
4973 convert_hole = load->UsesMustHandleHole();
4974 }
4975
4976 Label no_special_nan_handling;
4977 Label done;
4978 if (convert_hole) {
4979 bool use_sse2 = CpuFeatures::IsSupported(SSE2);
4980 if (use_sse2) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004981 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004982 XMMRegister input_reg = ToDoubleRegister(instr->value());
4983 __ ucomisd(input_reg, input_reg);
4984 } else {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004985 __ fld(0);
4986 __ fld(0);
4987 __ FCmp();
4988 }
4989
4990 __ j(parity_odd, &no_special_nan_handling);
4991 __ sub(esp, Immediate(kDoubleSize));
4992 if (use_sse2) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004993 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004994 XMMRegister input_reg = ToDoubleRegister(instr->value());
4995 __ movdbl(MemOperand(esp, 0), input_reg);
4996 } else {
4997 __ fld(0);
4998 __ fstp_d(MemOperand(esp, 0));
4999 }
5000 __ cmp(MemOperand(esp, sizeof(kHoleNanLower32)),
5001 Immediate(kHoleNanUpper32));
5002 Label canonicalize;
5003 __ j(not_equal, &canonicalize);
5004 __ add(esp, Immediate(kDoubleSize));
5005 __ mov(reg, factory()->the_hole_value());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005006 if (!use_sse2) {
5007 __ fstp(0);
5008 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005009 __ jmp(&done);
5010 __ bind(&canonicalize);
5011 __ add(esp, Immediate(kDoubleSize));
5012 ExternalReference nan =
5013 ExternalReference::address_of_canonical_non_hole_nan();
5014 if (use_sse2) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005015 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005016 XMMRegister input_reg = ToDoubleRegister(instr->value());
5017 __ movdbl(input_reg, Operand::StaticVariable(nan));
5018 } else {
5019 __ fstp(0);
5020 __ fld_d(Operand::StaticVariable(nan));
5021 }
5022 }
5023
5024 __ bind(&no_special_nan_handling);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005025 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005026 if (FLAG_inline_new) {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00005027 Register tmp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005028 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
5029 } else {
5030 __ jmp(deferred->entry());
5031 }
5032 __ bind(deferred->exit());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005033 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005034 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005035 XMMRegister input_reg = ToDoubleRegister(instr->value());
5036 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
5037 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005038 __ fst_d(FieldOperand(reg, HeapNumber::kValueOffset));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005039 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005040 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005041}
5042
5043
5044void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
5045 // TODO(3095996): Get rid of this. For now, we need to make the
5046 // result register contain a valid pointer because it is already
5047 // contained in the register pointer map.
5048 Register reg = ToRegister(instr->result());
5049 __ Set(reg, Immediate(0));
5050
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00005051 PushSafepointRegistersScope scope(this);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005052 // NumberTagI and NumberTagD use the context from the frame, rather than
5053 // the environment's HContext or HInlinedContext value.
5054 // They only call Runtime::kAllocateHeapNumber.
5055 // The corresponding HChange instructions are added in a phase that does
5056 // not have easy access to the local context.
5057 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
5058 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005059 RecordSafepointWithRegisters(
5060 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005061 __ StoreToSafepointRegisterSlot(reg, eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005062}
5063
5064
5065void LCodeGen::DoSmiTag(LSmiTag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005066 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005067 ASSERT(input->IsRegister() && input->Equals(instr->result()));
5068 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
5069 __ SmiTag(ToRegister(input));
5070}
5071
5072
5073void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005074 LOperand* input = instr->value();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005075 Register result = ToRegister(input);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005076 ASSERT(input->IsRegister() && input->Equals(instr->result()));
5077 if (instr->needs_check()) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005078 __ test(result, Immediate(kSmiTagMask));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005079 DeoptimizeIf(not_zero, instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005080 } else {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005081 __ AssertSmi(result);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005082 }
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005083 __ SmiUntag(result);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005084}
5085
5086
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005087void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg,
5088 Register temp_reg,
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00005089 bool allow_undefined_as_nan,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005090 bool deoptimize_on_minus_zero,
5091 LEnvironment* env,
5092 NumberUntagDMode mode) {
5093 Label load_smi, done;
5094
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005095 STATIC_ASSERT(NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE >
5096 NUMBER_CANDIDATE_IS_ANY_TAGGED);
5097 if (mode >= NUMBER_CANDIDATE_IS_ANY_TAGGED) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005098 // Smi check.
5099 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
5100
5101 // Heap number map check.
5102 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5103 factory()->heap_number_map());
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00005104 if (!allow_undefined_as_nan) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005105 DeoptimizeIf(not_equal, env);
5106 } else {
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005107 Label heap_number, convert;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005108 __ j(equal, &heap_number, Label::kNear);
5109
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005110 // Convert undefined (or hole) to NaN.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005111 __ cmp(input_reg, factory()->undefined_value());
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005112 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE) {
5113 __ j(equal, &convert, Label::kNear);
5114 __ cmp(input_reg, factory()->the_hole_value());
5115 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005116 DeoptimizeIf(not_equal, env);
5117
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005118 __ bind(&convert);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005119 ExternalReference nan =
5120 ExternalReference::address_of_canonical_non_hole_nan();
5121 __ fld_d(Operand::StaticVariable(nan));
5122 __ jmp(&done, Label::kNear);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005123
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005124 __ bind(&heap_number);
5125 }
5126 // Heap number to x87 conversion.
5127 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
5128 if (deoptimize_on_minus_zero) {
5129 __ fldz();
5130 __ FCmp();
5131 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
5132 __ j(not_zero, &done, Label::kNear);
5133
5134 // Use general purpose registers to check if we have -0.0
5135 __ mov(temp_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
5136 __ test(temp_reg, Immediate(HeapNumber::kSignMask));
5137 __ j(zero, &done, Label::kNear);
5138
5139 // Pop FPU stack before deoptimizing.
5140 __ fstp(0);
5141 DeoptimizeIf(not_zero, env);
5142 }
5143 __ jmp(&done, Label::kNear);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005144 } else {
5145 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
5146 }
5147
5148 __ bind(&load_smi);
5149 __ SmiUntag(input_reg); // Untag smi before converting to float.
5150 __ push(input_reg);
5151 __ fild_s(Operand(esp, 0));
5152 __ pop(input_reg);
5153 __ SmiTag(input_reg); // Retag smi.
5154 __ bind(&done);
5155}
5156
5157
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005158void LCodeGen::EmitNumberUntagD(Register input_reg,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005159 Register temp_reg,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005160 XMMRegister result_reg,
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00005161 bool allow_undefined_as_nan,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005162 bool deoptimize_on_minus_zero,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005163 LEnvironment* env,
5164 NumberUntagDMode mode) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005165 Label load_smi, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005166
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005167 STATIC_ASSERT(NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE >
5168 NUMBER_CANDIDATE_IS_ANY_TAGGED);
5169 if (mode >= NUMBER_CANDIDATE_IS_ANY_TAGGED) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005170 // Smi check.
5171 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005172
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005173 // Heap number map check.
5174 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5175 factory()->heap_number_map());
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00005176 if (!allow_undefined_as_nan) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005177 DeoptimizeIf(not_equal, env);
5178 } else {
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005179 Label heap_number, convert;
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005180 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005181
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005182 // Convert undefined (and hole) to NaN.
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005183 __ cmp(input_reg, factory()->undefined_value());
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005184 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE) {
5185 __ j(equal, &convert, Label::kNear);
5186 __ cmp(input_reg, factory()->the_hole_value());
5187 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005188 DeoptimizeIf(not_equal, env);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005189
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005190 __ bind(&convert);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005191 ExternalReference nan =
5192 ExternalReference::address_of_canonical_non_hole_nan();
5193 __ movdbl(result_reg, Operand::StaticVariable(nan));
5194 __ jmp(&done, Label::kNear);
5195
5196 __ bind(&heap_number);
5197 }
5198 // Heap number to XMM conversion.
5199 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
5200 if (deoptimize_on_minus_zero) {
5201 XMMRegister xmm_scratch = xmm0;
5202 __ xorps(xmm_scratch, xmm_scratch);
5203 __ ucomisd(result_reg, xmm_scratch);
5204 __ j(not_zero, &done, Label::kNear);
5205 __ movmskpd(temp_reg, result_reg);
5206 __ test_b(temp_reg, 1);
5207 DeoptimizeIf(not_zero, env);
5208 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005209 __ jmp(&done, Label::kNear);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005210 } else {
5211 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005212 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005213
5214 // Smi to XMM conversion
5215 __ bind(&load_smi);
5216 __ SmiUntag(input_reg); // Untag smi before converting to float.
5217 __ cvtsi2sd(result_reg, Operand(input_reg));
5218 __ SmiTag(input_reg); // Retag smi.
5219 __ bind(&done);
5220}
5221
5222
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005223void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005224 Label done, heap_number;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005225 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005226
5227 // Heap number map check.
5228 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005229 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005230
5231 if (instr->truncating()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005232 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005233 // Check for undefined. Undefined is converted to zero for truncating
5234 // conversions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005235 __ cmp(input_reg, factory()->undefined_value());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005236 __ RecordComment("Deferred TaggedToI: cannot truncate");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005237 DeoptimizeIf(not_equal, instr->environment());
5238 __ mov(input_reg, 0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005239 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005240
5241 __ bind(&heap_number);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005242 if (CpuFeatures::IsSupported(SSE3)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005243 CpuFeatureScope scope(masm(), SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005244 Label convert;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005245 // Use more powerful conversion when sse3 is available.
5246 // Load x87 register with heap number.
5247 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
5248 // Get exponent alone and check for too-big exponent.
5249 __ mov(input_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
5250 __ and_(input_reg, HeapNumber::kExponentMask);
5251 const uint32_t kTooBigExponent =
5252 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
5253 __ cmp(Operand(input_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005254 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005255 // Pop FPU stack before deoptimizing.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005256 __ fstp(0);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005257 __ RecordComment("Deferred TaggedToI: exponent too big");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005258 DeoptimizeIf(no_condition, instr->environment());
5259
5260 // Reserve space for 64 bit answer.
5261 __ bind(&convert);
5262 __ sub(Operand(esp), Immediate(kDoubleSize));
5263 // Do conversion, which cannot fail because we checked the exponent.
5264 __ fisttp_d(Operand(esp, 0));
5265 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result.
5266 __ add(Operand(esp), Immediate(kDoubleSize));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005267 } else if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005268 CpuFeatureScope scope(masm(), SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005269 XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005270 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
5271 __ cvttsd2si(input_reg, Operand(xmm0));
5272 __ cmp(input_reg, 0x80000000u);
5273 __ j(not_equal, &done);
5274 // Check if the input was 0x8000000 (kMinInt).
5275 // If no, then we got an overflow and we deoptimize.
5276 ExternalReference min_int = ExternalReference::address_of_min_int();
5277 __ movdbl(xmm_temp, Operand::StaticVariable(min_int));
5278 __ ucomisd(xmm_temp, xmm0);
5279 DeoptimizeIf(not_equal, instr->environment());
5280 DeoptimizeIf(parity_even, instr->environment()); // NaN.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005281 } else {
5282 UNREACHABLE();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005283 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005284 } else if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005285 CpuFeatureScope scope(masm(), SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005286 // Deoptimize if we don't have a heap number.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005287 __ RecordComment("Deferred TaggedToI: not a heap number");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005288 DeoptimizeIf(not_equal, instr->environment());
5289
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005290 XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005291 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
5292 __ cvttsd2si(input_reg, Operand(xmm0));
5293 __ cvtsi2sd(xmm_temp, Operand(input_reg));
5294 __ ucomisd(xmm0, xmm_temp);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005295 __ RecordComment("Deferred TaggedToI: lost precision");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005296 DeoptimizeIf(not_equal, instr->environment());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005297 __ RecordComment("Deferred TaggedToI: NaN");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005298 DeoptimizeIf(parity_even, instr->environment()); // NaN.
5299 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
5300 __ test(input_reg, Operand(input_reg));
5301 __ j(not_zero, &done);
5302 __ movmskpd(input_reg, xmm0);
5303 __ and_(input_reg, 1);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005304 __ RecordComment("Deferred TaggedToI: minus zero");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005305 DeoptimizeIf(not_zero, instr->environment());
5306 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005307 } else {
5308 UNREACHABLE();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005309 }
5310 __ bind(&done);
5311}
5312
5313
5314void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005315 class DeferredTaggedToI: public LDeferredCode {
5316 public:
5317 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
5318 : LDeferredCode(codegen), instr_(instr) { }
5319 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
5320 virtual LInstruction* instr() { return instr_; }
5321 private:
5322 LTaggedToI* instr_;
5323 };
5324
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005325 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005326 ASSERT(input->IsRegister());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005327 Register input_reg = ToRegister(input);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005328 ASSERT(input_reg.is(ToRegister(instr->result())));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005329
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005330 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005331
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005332 __ JumpIfNotSmi(input_reg, deferred->entry());
5333 __ SmiUntag(input_reg);
5334 __ bind(deferred->exit());
5335}
5336
5337
5338void LCodeGen::DoDeferredTaggedToINoSSE2(LTaggedToINoSSE2* instr) {
5339 Label done, heap_number;
5340 Register result_reg = ToRegister(instr->result());
5341 Register input_reg = ToRegister(instr->value());
5342
5343 // Heap number map check.
5344 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5345 factory()->heap_number_map());
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00005346 if (instr->truncating()) {
5347 __ j(equal, &heap_number, Label::kNear);
5348 // Check for undefined. Undefined is converted to zero for truncating
5349 // conversions.
5350 __ cmp(input_reg, factory()->undefined_value());
5351 __ RecordComment("Deferred TaggedToI: cannot truncate");
5352 DeoptimizeIf(not_equal, instr->environment());
5353 __ xor_(result_reg, result_reg);
5354 __ jmp(&done, Label::kFar);
5355 __ bind(&heap_number);
5356 } else {
5357 // Deoptimize if we don't have a heap number.
5358 DeoptimizeIf(not_equal, instr->environment());
5359 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005360
5361 // Surprisingly, all of this crazy bit manipulation is considerably
5362 // faster than using the built-in x86 CPU conversion functions (about 6x).
5363 Label right_exponent, adjust_bias, zero_result;
5364 Register scratch = ToRegister(instr->scratch());
5365 Register scratch2 = ToRegister(instr->scratch2());
5366 // Get exponent word.
5367 __ mov(scratch, FieldOperand(input_reg, HeapNumber::kExponentOffset));
5368 // Get exponent alone in scratch2.
5369 __ mov(scratch2, scratch);
5370 __ and_(scratch2, HeapNumber::kExponentMask);
5371 __ shr(scratch2, HeapNumber::kExponentShift);
5372 if (instr->truncating()) {
5373 __ j(zero, &zero_result);
5374 } else {
5375 __ j(not_zero, &adjust_bias);
5376 __ test(scratch, Immediate(HeapNumber::kMantissaMask));
5377 DeoptimizeIf(not_zero, instr->environment());
5378 __ cmp(FieldOperand(input_reg, HeapNumber::kMantissaOffset), Immediate(0));
5379 DeoptimizeIf(not_equal, instr->environment());
5380 __ bind(&adjust_bias);
5381 }
5382 __ sub(scratch2, Immediate(HeapNumber::kExponentBias));
5383 if (!instr->truncating()) {
5384 DeoptimizeIf(negative, instr->environment());
5385 } else {
5386 __ j(negative, &zero_result);
5387 }
5388
5389 // Get the second half of the double. For some exponents we don't
5390 // actually need this because the bits get shifted out again, but
5391 // it's probably slower to test than just to do it.
5392 Register scratch3 = ToRegister(instr->scratch3());
5393 __ mov(scratch3, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
5394 __ xor_(result_reg, result_reg);
5395
5396 const uint32_t non_int32_exponent = 31;
5397 __ cmp(scratch2, Immediate(non_int32_exponent));
5398 // If we have a match of the int32 exponent then skip some logic.
5399 __ j(equal, &right_exponent, Label::kNear);
5400 // If the number doesn't find in an int32, deopt.
5401 DeoptimizeIf(greater, instr->environment());
5402
5403 // Exponent word in scratch, exponent in scratch2. We know that 0 <= exponent
5404 // < 31.
5405 __ mov(result_reg, Immediate(31));
5406 __ sub(result_reg, scratch2);
5407
5408 __ bind(&right_exponent);
5409
5410 // Save off exponent for negative check later.
5411 __ mov(scratch2, scratch);
5412
5413 // Here result_reg is the shift, scratch is the exponent word.
5414 // Get the top bits of the mantissa.
5415 __ and_(scratch, HeapNumber::kMantissaMask);
5416 // Put back the implicit 1.
5417 __ or_(scratch, 1 << HeapNumber::kExponentShift);
5418 // Shift up the mantissa bits to take up the space the exponent used to
5419 // take. We have kExponentShift + 1 significant bits int he low end of the
5420 // word. Shift them to the top bits.
5421 const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1;
5422 __ shl(scratch, shift_distance);
5423 if (!instr->truncating()) {
5424 // If not truncating, a non-zero value in the bottom 22 bits means a
5425 // non-integral value --> trigger a deopt.
5426 __ test(scratch3, Immediate((1 << (32 - shift_distance)) - 1));
5427 DeoptimizeIf(not_equal, instr->environment());
5428 }
5429 // Shift down 22 bits to get the most significant 10 bits or the low
5430 // mantissa word.
5431 __ shr(scratch3, 32 - shift_distance);
5432 __ or_(scratch3, scratch);
5433 if (!instr->truncating()) {
5434 // If truncating, a non-zero value in the bits that will be shifted away
5435 // when adjusting the exponent means rounding --> deopt.
5436 __ mov(scratch, 0x1);
5437 ASSERT(result_reg.is(ecx));
5438 __ shl_cl(scratch);
5439 __ dec(scratch);
5440 __ test(scratch3, scratch);
5441 DeoptimizeIf(not_equal, instr->environment());
5442 }
5443 // Move down according to the exponent.
5444 ASSERT(result_reg.is(ecx));
5445 __ shr_cl(scratch3);
5446 // Now the unsigned 32-bit answer is in scratch3. We need to move it to
5447 // result_reg and we may need to fix the sign.
5448 Label negative_result;
5449 __ xor_(result_reg, result_reg);
5450 __ cmp(scratch2, result_reg);
5451 __ j(less, &negative_result, Label::kNear);
5452 __ cmp(scratch3, result_reg);
5453 __ mov(result_reg, scratch3);
5454 // If the result is > MAX_INT, result doesn't fit in signed 32-bit --> deopt.
5455 DeoptimizeIf(less, instr->environment());
5456 __ jmp(&done, Label::kNear);
5457 __ bind(&zero_result);
5458 __ xor_(result_reg, result_reg);
5459 __ jmp(&done, Label::kNear);
5460 __ bind(&negative_result);
5461 __ sub(result_reg, scratch3);
5462 if (!instr->truncating()) {
5463 // -0.0 triggers a deopt.
5464 DeoptimizeIf(zero, instr->environment());
5465 }
5466 // If the negative subtraction overflows into a positive number, there was an
5467 // overflow --> deopt.
5468 DeoptimizeIf(positive, instr->environment());
5469 __ bind(&done);
5470}
5471
5472
5473void LCodeGen::DoTaggedToINoSSE2(LTaggedToINoSSE2* instr) {
5474 class DeferredTaggedToINoSSE2: public LDeferredCode {
5475 public:
5476 DeferredTaggedToINoSSE2(LCodeGen* codegen, LTaggedToINoSSE2* instr)
5477 : LDeferredCode(codegen), instr_(instr) { }
5478 virtual void Generate() { codegen()->DoDeferredTaggedToINoSSE2(instr_); }
5479 virtual LInstruction* instr() { return instr_; }
5480 private:
5481 LTaggedToINoSSE2* instr_;
5482 };
5483
5484 LOperand* input = instr->value();
5485 ASSERT(input->IsRegister());
5486 Register input_reg = ToRegister(input);
5487 ASSERT(input_reg.is(ToRegister(instr->result())));
5488
5489 DeferredTaggedToINoSSE2* deferred =
5490 new(zone()) DeferredTaggedToINoSSE2(this, instr);
5491
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005492 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00005493 __ JumpIfNotSmi(input_reg, deferred->entry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005494 __ SmiUntag(input_reg); // Untag smi.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005495 __ bind(deferred->exit());
5496}
5497
5498
5499void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005500 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005501 ASSERT(input->IsRegister());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005502 LOperand* temp = instr->temp();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005503 ASSERT(temp == NULL || temp->IsRegister());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005504 LOperand* result = instr->result();
5505 ASSERT(result->IsDoubleRegister());
5506
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005507 Register input_reg = ToRegister(input);
5508 bool deoptimize_on_minus_zero =
5509 instr->hydrogen()->deoptimize_on_minus_zero();
5510 Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005511
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005512 NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED;
5513 HValue* value = instr->hydrogen()->value();
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005514 if (value->representation().IsSmi()) {
5515 mode = NUMBER_CANDIDATE_IS_SMI;
5516 } else if (value->IsLoadKeyed()) {
5517 HLoadKeyed* load = HLoadKeyed::cast(value);
5518 if (load->UsesMustHandleHole()) {
5519 mode = NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE;
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005520 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005521 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005522
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005523 if (CpuFeatures::IsSupported(SSE2)) {
5524 CpuFeatureScope scope(masm(), SSE2);
5525 XMMRegister result_reg = ToDoubleRegister(result);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005526 EmitNumberUntagD(input_reg,
5527 temp_reg,
5528 result_reg,
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00005529 instr->hydrogen()->allow_undefined_as_nan(),
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005530 deoptimize_on_minus_zero,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005531 instr->environment(),
5532 mode);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005533 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005534 EmitNumberUntagDNoSSE2(input_reg,
5535 temp_reg,
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00005536 instr->hydrogen()->allow_undefined_as_nan(),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005537 deoptimize_on_minus_zero,
5538 instr->environment(),
5539 mode);
5540 CurrentInstructionReturnsX87Result();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005541 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005542}
5543
5544
5545void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005546 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005547 ASSERT(input->IsDoubleRegister());
5548 LOperand* result = instr->result();
5549 ASSERT(result->IsRegister());
ulan@chromium.org750145a2013-03-07 15:14:13 +00005550 CpuFeatureScope scope(masm(), SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005551
5552 XMMRegister input_reg = ToDoubleRegister(input);
5553 Register result_reg = ToRegister(result);
5554
5555 if (instr->truncating()) {
5556 // Performs a truncating conversion of a floating point number as used by
5557 // the JS bitwise operations.
5558 __ cvttsd2si(result_reg, Operand(input_reg));
5559 __ cmp(result_reg, 0x80000000u);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005560 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005561 // This will deoptimize if the exponent of the input in out of range.
ulan@chromium.org750145a2013-03-07 15:14:13 +00005562 CpuFeatureScope scope(masm(), SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005563 Label convert, done;
5564 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005565 __ sub(Operand(esp), Immediate(kDoubleSize));
5566 __ movdbl(Operand(esp, 0), input_reg);
5567 // Get exponent alone and check for too-big exponent.
5568 __ mov(result_reg, Operand(esp, sizeof(int32_t)));
5569 __ and_(result_reg, HeapNumber::kExponentMask);
5570 const uint32_t kTooBigExponent =
5571 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
5572 __ cmp(Operand(result_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005573 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005574 __ add(Operand(esp), Immediate(kDoubleSize));
5575 DeoptimizeIf(no_condition, instr->environment());
5576 __ bind(&convert);
5577 // Do conversion, which cannot fail because we checked the exponent.
5578 __ fld_d(Operand(esp, 0));
5579 __ fisttp_d(Operand(esp, 0));
5580 __ mov(result_reg, Operand(esp, 0)); // Low word of answer is the result.
5581 __ add(Operand(esp), Immediate(kDoubleSize));
5582 __ bind(&done);
5583 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005584 Label done;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005585 Register temp_reg = ToRegister(instr->temp());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005586 XMMRegister xmm_scratch = xmm0;
5587
5588 // If cvttsd2si succeeded, we're done. Otherwise, we attempt
5589 // manual conversion.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005590 __ j(not_equal, &done, Label::kNear);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005591
5592 // Get high 32 bits of the input in result_reg and temp_reg.
5593 __ pshufd(xmm_scratch, input_reg, 1);
5594 __ movd(Operand(temp_reg), xmm_scratch);
5595 __ mov(result_reg, temp_reg);
5596
5597 // Prepare negation mask in temp_reg.
5598 __ sar(temp_reg, kBitsPerInt - 1);
5599
5600 // Extract the exponent from result_reg and subtract adjusted
5601 // bias from it. The adjustment is selected in a way such that
5602 // when the difference is zero, the answer is in the low 32 bits
5603 // of the input, otherwise a shift has to be performed.
5604 __ shr(result_reg, HeapNumber::kExponentShift);
5605 __ and_(result_reg,
5606 HeapNumber::kExponentMask >> HeapNumber::kExponentShift);
5607 __ sub(Operand(result_reg),
5608 Immediate(HeapNumber::kExponentBias +
5609 HeapNumber::kExponentBits +
5610 HeapNumber::kMantissaBits));
5611 // Don't handle big (> kMantissaBits + kExponentBits == 63) or
5612 // special exponents.
5613 DeoptimizeIf(greater, instr->environment());
5614
5615 // Zero out the sign and the exponent in the input (by shifting
5616 // it to the left) and restore the implicit mantissa bit,
5617 // i.e. convert the input to unsigned int64 shifted left by
5618 // kExponentBits.
5619 ExternalReference minus_zero = ExternalReference::address_of_minus_zero();
5620 // Minus zero has the most significant bit set and the other
5621 // bits cleared.
5622 __ movdbl(xmm_scratch, Operand::StaticVariable(minus_zero));
5623 __ psllq(input_reg, HeapNumber::kExponentBits);
5624 __ por(input_reg, xmm_scratch);
5625
5626 // Get the amount to shift the input right in xmm_scratch.
5627 __ neg(result_reg);
5628 __ movd(xmm_scratch, Operand(result_reg));
5629
5630 // Shift the input right and extract low 32 bits.
5631 __ psrlq(input_reg, xmm_scratch);
5632 __ movd(Operand(result_reg), input_reg);
5633
5634 // Use the prepared mask in temp_reg to negate the result if necessary.
5635 __ xor_(result_reg, Operand(temp_reg));
5636 __ sub(result_reg, Operand(temp_reg));
5637 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005638 }
5639 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005640 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005641 __ cvttsd2si(result_reg, Operand(input_reg));
5642 __ cvtsi2sd(xmm0, Operand(result_reg));
5643 __ ucomisd(xmm0, input_reg);
5644 DeoptimizeIf(not_equal, instr->environment());
5645 DeoptimizeIf(parity_even, instr->environment()); // NaN.
5646 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
5647 // The integer converted back is equal to the original. We
5648 // only have to test if we got -0 as an input.
5649 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005650 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005651 __ movmskpd(result_reg, input_reg);
5652 // Bit 0 contains the sign of the double in input_reg.
5653 // If input was positive, we are ok and return 0, otherwise
5654 // deoptimize.
5655 __ and_(result_reg, 1);
5656 DeoptimizeIf(not_zero, instr->environment());
5657 }
5658 __ bind(&done);
5659 }
5660}
5661
5662
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005663void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
5664 LOperand* input = instr->value();
5665 ASSERT(input->IsDoubleRegister());
5666 LOperand* result = instr->result();
5667 ASSERT(result->IsRegister());
5668 CpuFeatureScope scope(masm(), SSE2);
5669
5670 XMMRegister input_reg = ToDoubleRegister(input);
5671 Register result_reg = ToRegister(result);
5672
5673 Label done;
5674 __ cvttsd2si(result_reg, Operand(input_reg));
5675 __ cvtsi2sd(xmm0, Operand(result_reg));
5676 __ ucomisd(xmm0, input_reg);
5677 DeoptimizeIf(not_equal, instr->environment());
5678 DeoptimizeIf(parity_even, instr->environment()); // NaN.
5679
5680 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
5681 // The integer converted back is equal to the original. We
5682 // only have to test if we got -0 as an input.
5683 __ test(result_reg, Operand(result_reg));
5684 __ j(not_zero, &done, Label::kNear);
5685 __ movmskpd(result_reg, input_reg);
5686 // Bit 0 contains the sign of the double in input_reg.
5687 // If input was positive, we are ok and return 0, otherwise
5688 // deoptimize.
5689 __ and_(result_reg, 1);
5690 DeoptimizeIf(not_zero, instr->environment());
5691 __ bind(&done);
5692 }
5693 __ SmiTag(result_reg);
5694 DeoptimizeIf(overflow, instr->environment());
5695}
5696
5697
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005698void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005699 LOperand* input = instr->value();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005700 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005701 DeoptimizeIf(not_zero, instr->environment());
5702}
5703
5704
5705void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005706 LOperand* input = instr->value();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005707 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005708 DeoptimizeIf(zero, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005709}
5710
5711
5712void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005713 Register input = ToRegister(instr->value());
5714 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005715
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005716 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005717
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005718 if (instr->hydrogen()->is_interval_check()) {
5719 InstanceType first;
5720 InstanceType last;
5721 instr->hydrogen()->GetCheckInterval(&first, &last);
5722
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005723 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
5724 static_cast<int8_t>(first));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005725
5726 // If there is only one type in the interval check for equality.
5727 if (first == last) {
5728 DeoptimizeIf(not_equal, instr->environment());
5729 } else {
5730 DeoptimizeIf(below, instr->environment());
5731 // Omit check for the last type.
5732 if (last != LAST_TYPE) {
5733 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
5734 static_cast<int8_t>(last));
5735 DeoptimizeIf(above, instr->environment());
5736 }
5737 }
5738 } else {
5739 uint8_t mask;
5740 uint8_t tag;
5741 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
5742
5743 if (IsPowerOf2(mask)) {
5744 ASSERT(tag == 0 || IsPowerOf2(tag));
5745 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), mask);
5746 DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
5747 } else {
5748 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
5749 __ and_(temp, mask);
yangguo@chromium.org56454712012-02-16 15:33:53 +00005750 __ cmp(temp, tag);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005751 DeoptimizeIf(not_equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005752 }
5753 }
5754}
5755
5756
5757void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005758 Handle<JSFunction> target = instr->hydrogen()->target();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00005759 if (instr->hydrogen()->target_in_new_space()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005760 Register reg = ToRegister(instr->value());
5761 Handle<JSGlobalPropertyCell> cell =
5762 isolate()->factory()->NewJSGlobalPropertyCell(target);
5763 __ cmp(reg, Operand::Cell(cell));
5764 } else {
5765 Operand operand = ToOperand(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005766 __ cmp(operand, target);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005767 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005768 DeoptimizeIf(not_equal, instr->environment());
5769}
5770
5771
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005772void LCodeGen::DoCheckMapCommon(Register reg,
5773 Handle<Map> map,
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005774 LInstruction* instr) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005775 Label success;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005776 __ CompareMap(reg, map, &success);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005777 DeoptimizeIf(not_equal, instr->environment());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005778 __ bind(&success);
5779}
5780
5781
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005782void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005783 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005784 ASSERT(input->IsRegister());
5785 Register reg = ToRegister(input);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005786
5787 Label success;
5788 SmallMapList* map_set = instr->hydrogen()->map_set();
5789 for (int i = 0; i < map_set->length() - 1; i++) {
5790 Handle<Map> map = map_set->at(i);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005791 __ CompareMap(reg, map, &success);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005792 __ j(equal, &success);
5793 }
5794 Handle<Map> map = map_set->last();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005795 DoCheckMapCommon(reg, map, instr);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005796 __ bind(&success);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005797}
5798
5799
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005800void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005801 CpuFeatureScope scope(masm(), SSE2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005802 XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
5803 Register result_reg = ToRegister(instr->result());
5804 __ ClampDoubleToUint8(value_reg, xmm0, result_reg);
5805}
5806
5807
5808void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
5809 ASSERT(instr->unclamped()->Equals(instr->result()));
5810 Register value_reg = ToRegister(instr->result());
5811 __ ClampUint8(value_reg);
5812}
5813
5814
5815void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005816 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005817
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005818 ASSERT(instr->unclamped()->Equals(instr->result()));
5819 Register input_reg = ToRegister(instr->unclamped());
5820 Label is_smi, done, heap_number;
5821
5822 __ JumpIfSmi(input_reg, &is_smi);
5823
5824 // Check for heap number
5825 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5826 factory()->heap_number_map());
5827 __ j(equal, &heap_number, Label::kNear);
5828
5829 // Check for undefined. Undefined is converted to zero for clamping
5830 // conversions.
5831 __ cmp(input_reg, factory()->undefined_value());
5832 DeoptimizeIf(not_equal, instr->environment());
5833 __ mov(input_reg, 0);
5834 __ jmp(&done, Label::kNear);
5835
5836 // Heap number
5837 __ bind(&heap_number);
5838 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
5839 __ ClampDoubleToUint8(xmm0, xmm1, input_reg);
5840 __ jmp(&done, Label::kNear);
5841
5842 // smi
5843 __ bind(&is_smi);
5844 __ SmiUntag(input_reg);
5845 __ ClampUint8(input_reg);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005846 __ bind(&done);
5847}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005848
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005849
5850void LCodeGen::DoClampTToUint8NoSSE2(LClampTToUint8NoSSE2* instr) {
5851 Register input_reg = ToRegister(instr->unclamped());
5852 Register result_reg = ToRegister(instr->result());
5853 Register scratch = ToRegister(instr->scratch());
5854 Register scratch2 = ToRegister(instr->scratch2());
5855 Register scratch3 = ToRegister(instr->scratch3());
5856 Label is_smi, done, heap_number, valid_exponent,
5857 largest_value, zero_result, maybe_nan_or_infinity;
5858
5859 __ JumpIfSmi(input_reg, &is_smi);
5860
5861 // Check for heap number
5862 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5863 factory()->heap_number_map());
5864 __ j(equal, &heap_number, Label::kFar);
5865
5866 // Check for undefined. Undefined is converted to zero for clamping
5867 // conversions.
5868 __ cmp(input_reg, factory()->undefined_value());
5869 DeoptimizeIf(not_equal, instr->environment());
5870 __ jmp(&zero_result);
5871
5872 // Heap number
5873 __ bind(&heap_number);
5874
5875 // Surprisingly, all of the hand-crafted bit-manipulations below are much
5876 // faster than the x86 FPU built-in instruction, especially since "banker's
5877 // rounding" would be additionally very expensive
5878
5879 // Get exponent word.
5880 __ mov(scratch, FieldOperand(input_reg, HeapNumber::kExponentOffset));
5881 __ mov(scratch3, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
5882
5883 // Test for negative values --> clamp to zero
5884 __ test(scratch, scratch);
5885 __ j(negative, &zero_result);
5886
5887 // Get exponent alone in scratch2.
5888 __ mov(scratch2, scratch);
5889 __ and_(scratch2, HeapNumber::kExponentMask);
5890 __ shr(scratch2, HeapNumber::kExponentShift);
5891 __ j(zero, &zero_result);
5892 __ sub(scratch2, Immediate(HeapNumber::kExponentBias - 1));
5893 __ j(negative, &zero_result);
5894
5895 const uint32_t non_int8_exponent = 7;
5896 __ cmp(scratch2, Immediate(non_int8_exponent + 1));
5897 // If the exponent is too big, check for special values.
5898 __ j(greater, &maybe_nan_or_infinity, Label::kNear);
5899
5900 __ bind(&valid_exponent);
5901 // Exponent word in scratch, exponent in scratch2. We know that 0 <= exponent
5902 // < 7. The shift bias is the number of bits to shift the mantissa such that
5903 // with an exponent of 7 such the that top-most one is in bit 30, allowing
5904 // detection the rounding overflow of a 255.5 to 256 (bit 31 goes from 0 to
5905 // 1).
5906 int shift_bias = (30 - HeapNumber::kExponentShift) - 7 - 1;
5907 __ lea(result_reg, MemOperand(scratch2, shift_bias));
5908 // Here result_reg (ecx) is the shift, scratch is the exponent word. Get the
5909 // top bits of the mantissa.
5910 __ and_(scratch, HeapNumber::kMantissaMask);
5911 // Put back the implicit 1 of the mantissa
5912 __ or_(scratch, 1 << HeapNumber::kExponentShift);
5913 // Shift up to round
5914 __ shl_cl(scratch);
5915 // Use "banker's rounding" to spec: If fractional part of number is 0.5, then
5916 // use the bit in the "ones" place and add it to the "halves" place, which has
5917 // the effect of rounding to even.
5918 __ mov(scratch2, scratch);
5919 const uint32_t one_half_bit_shift = 30 - sizeof(uint8_t) * 8;
5920 const uint32_t one_bit_shift = one_half_bit_shift + 1;
5921 __ and_(scratch2, Immediate((1 << one_bit_shift) - 1));
5922 __ cmp(scratch2, Immediate(1 << one_half_bit_shift));
5923 Label no_round;
5924 __ j(less, &no_round);
5925 Label round_up;
5926 __ mov(scratch2, Immediate(1 << one_half_bit_shift));
5927 __ j(greater, &round_up);
5928 __ test(scratch3, scratch3);
5929 __ j(not_zero, &round_up);
5930 __ mov(scratch2, scratch);
5931 __ and_(scratch2, Immediate(1 << one_bit_shift));
5932 __ shr(scratch2, 1);
5933 __ bind(&round_up);
5934 __ add(scratch, scratch2);
5935 __ j(overflow, &largest_value);
5936 __ bind(&no_round);
5937 __ shr(scratch, 23);
5938 __ mov(result_reg, scratch);
5939 __ jmp(&done, Label::kNear);
5940
5941 __ bind(&maybe_nan_or_infinity);
5942 // Check for NaN/Infinity, all other values map to 255
5943 __ cmp(scratch2, Immediate(HeapNumber::kInfinityOrNanExponent + 1));
5944 __ j(not_equal, &largest_value, Label::kNear);
5945
5946 // Check for NaN, which differs from Infinity in that at least one mantissa
5947 // bit is set.
5948 __ and_(scratch, HeapNumber::kMantissaMask);
5949 __ or_(scratch, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
5950 __ j(not_zero, &zero_result); // M!=0 --> NaN
5951 // Infinity -> Fall through to map to 255.
5952
5953 __ bind(&largest_value);
5954 __ mov(result_reg, Immediate(255));
5955 __ jmp(&done, Label::kNear);
5956
5957 __ bind(&zero_result);
5958 __ xor_(result_reg, result_reg);
5959 __ jmp(&done);
5960
5961 // smi
5962 __ bind(&is_smi);
5963 if (!input_reg.is(result_reg)) {
5964 __ mov(result_reg, input_reg);
5965 }
5966 __ SmiUntag(result_reg);
5967 __ ClampUint8(result_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005968 __ bind(&done);
5969}
5970
5971
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005972void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005973 Register reg = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005974
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00005975 ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
5976 ZoneList<Handle<Map> >* maps = instr->maps();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005977
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00005978 ASSERT(prototypes->length() == maps->length());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005979
danno@chromium.org1fd77d52013-06-07 16:01:45 +00005980 if (!instr->hydrogen()->CanOmitPrototypeChecks()) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +00005981 for (int i = 0; i < prototypes->length(); i++) {
5982 __ LoadHeapObject(reg, prototypes->at(i));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005983 DoCheckMapCommon(reg, maps->at(i), instr);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00005984 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005985 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005986}
5987
5988
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005989void LCodeGen::DoAllocate(LAllocate* instr) {
5990 class DeferredAllocate: public LDeferredCode {
5991 public:
5992 DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
5993 : LDeferredCode(codegen), instr_(instr) { }
5994 virtual void Generate() { codegen()->DoDeferredAllocate(instr_); }
5995 virtual LInstruction* instr() { return instr_; }
5996 private:
5997 LAllocate* instr_;
5998 };
5999
6000 DeferredAllocate* deferred =
6001 new(zone()) DeferredAllocate(this, instr);
6002
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00006003 Register result = ToRegister(instr->result());
6004 Register temp = ToRegister(instr->temp());
6005
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00006006 // Allocate memory for the object.
6007 AllocationFlags flags = TAG_OBJECT;
6008 if (instr->hydrogen()->MustAllocateDoubleAligned()) {
6009 flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
6010 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00006011 if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00006012 ASSERT(!instr->hydrogen()->CanAllocateInOldDataSpace());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00006013 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00006014 } else if (instr->hydrogen()->CanAllocateInOldDataSpace()) {
6015 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_DATA_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00006016 }
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00006017
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00006018 if (instr->size()->IsConstantOperand()) {
6019 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006020 __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00006021 } else {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00006022 Register size = ToRegister(instr->size());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006023 __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00006024 }
6025
6026 __ bind(deferred->exit());
6027}
6028
6029
6030void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00006031 Register result = ToRegister(instr->result());
6032
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00006033 // TODO(3095996): Get rid of this. For now, we need to make the
6034 // result register contain a valid pointer because it is already
6035 // contained in the register pointer map.
danno@chromium.orgf005df62013-04-30 16:36:45 +00006036 __ mov(result, Immediate(Smi::FromInt(0)));
6037
6038 PushSafepointRegistersScope scope(this);
6039 if (instr->size()->IsRegister()) {
6040 Register size = ToRegister(instr->size());
6041 ASSERT(!size.is(result));
6042 __ SmiTag(ToRegister(instr->size()));
6043 __ push(size);
6044 } else {
6045 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
6046 __ push(Immediate(Smi::FromInt(size)));
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00006047 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00006048
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00006049 if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00006050 ASSERT(!instr->hydrogen()->CanAllocateInOldDataSpace());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00006051 CallRuntimeFromDeferred(
6052 Runtime::kAllocateInOldPointerSpace, 1, instr, instr->context());
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00006053 } else if (instr->hydrogen()->CanAllocateInOldDataSpace()) {
6054 CallRuntimeFromDeferred(
6055 Runtime::kAllocateInOldDataSpace, 1, instr, instr->context());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00006056 } else {
6057 CallRuntimeFromDeferred(
6058 Runtime::kAllocateInNewSpace, 1, instr, instr->context());
6059 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00006060 __ StoreToSafepointRegisterSlot(result, eax);
6061}
6062
6063
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006064void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00006065 ASSERT(ToRegister(instr->value()).is(eax));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006066 __ push(eax);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006067 CallRuntime(Runtime::kToFastProperties, 1, instr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006068}
6069
6070
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006071void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006072 ASSERT(ToRegister(instr->context()).is(esi));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00006073 Label materialized;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006074 // Registers will be used as follows:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006075 // ecx = literals array.
6076 // ebx = regexp literal.
6077 // eax = regexp literal clone.
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006078 // esi = context.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00006079 int literal_offset =
6080 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
6081 __ LoadHeapObject(ecx, instr->hydrogen()->literals());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006082 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006083 __ cmp(ebx, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00006084 __ j(not_equal, &materialized, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006085
6086 // Create regexp literal using runtime function
6087 // Result will be in eax.
6088 __ push(ecx);
6089 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
6090 __ push(Immediate(instr->hydrogen()->pattern()));
6091 __ push(Immediate(instr->hydrogen()->flags()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006092 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006093 __ mov(ebx, eax);
6094
6095 __ bind(&materialized);
6096 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
6097 Label allocated, runtime_allocate;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006098 __ Allocate(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006099 __ jmp(&allocated);
6100
6101 __ bind(&runtime_allocate);
6102 __ push(ebx);
6103 __ push(Immediate(Smi::FromInt(size)));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006104 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006105 __ pop(ebx);
6106
6107 __ bind(&allocated);
6108 // Copy the content into the newly allocated memory.
6109 // (Unroll copy loop once for better throughput).
6110 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
6111 __ mov(edx, FieldOperand(ebx, i));
6112 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
6113 __ mov(FieldOperand(eax, i), edx);
6114 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
6115 }
6116 if ((size % (2 * kPointerSize)) != 0) {
6117 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
6118 __ mov(FieldOperand(eax, size - kPointerSize), edx);
6119 }
6120}
6121
6122
6123void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006124 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006125 // Use the fast case closure allocation code that allocates in new
6126 // space for nested functions that don't need literals cloning.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006127 bool pretenure = instr->hydrogen()->pretenure();
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00006128 if (!pretenure && instr->hydrogen()->has_no_literals()) {
6129 FastNewClosureStub stub(instr->hydrogen()->language_mode(),
6130 instr->hydrogen()->is_generator());
6131 __ push(Immediate(instr->hydrogen()->shared_info()));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00006132 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006133 } else {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006134 __ push(esi);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00006135 __ push(Immediate(instr->hydrogen()->shared_info()));
6136 __ push(Immediate(pretenure ? factory()->true_value()
6137 : factory()->false_value()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006138 CallRuntime(Runtime::kNewClosure, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006139 }
6140}
6141
6142
6143void LCodeGen::DoTypeof(LTypeof* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00006144 LOperand* input = instr->value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006145 EmitPushTaggedOperand(input);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006146 CallRuntime(Runtime::kTypeof, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006147}
6148
6149
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006150void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00006151 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006152 int true_block = chunk_->LookupDestination(instr->true_block_id());
6153 int false_block = chunk_->LookupDestination(instr->false_block_id());
6154 Label* true_label = chunk_->GetAssemblyLabel(true_block);
6155 Label* false_label = chunk_->GetAssemblyLabel(false_block);
6156
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006157 Condition final_branch_condition =
6158 EmitTypeofIs(true_label, false_label, input, instr->type_literal());
6159 if (final_branch_condition != no_condition) {
6160 EmitBranch(true_block, false_block, final_branch_condition);
6161 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006162}
6163
6164
6165Condition LCodeGen::EmitTypeofIs(Label* true_label,
6166 Label* false_label,
6167 Register input,
6168 Handle<String> type_name) {
6169 Condition final_branch_condition = no_condition;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006170 if (type_name->Equals(heap()->number_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006171 __ JumpIfSmi(input, true_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006172 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006173 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006174 final_branch_condition = equal;
6175
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006176 } else if (type_name->Equals(heap()->string_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006177 __ JumpIfSmi(input, false_label);
6178 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
6179 __ j(above_equal, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006180 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
6181 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006182 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006183
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006184 } else if (type_name->Equals(heap()->symbol_string())) {
6185 __ JumpIfSmi(input, false_label);
6186 __ CmpObjectType(input, SYMBOL_TYPE, input);
6187 final_branch_condition = equal;
6188
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006189 } else if (type_name->Equals(heap()->boolean_string())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006190 __ cmp(input, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006191 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006192 __ cmp(input, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006193 final_branch_condition = equal;
6194
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006195 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00006196 __ cmp(input, factory()->null_value());
6197 final_branch_condition = equal;
6198
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006199 } else if (type_name->Equals(heap()->undefined_string())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006200 __ cmp(input, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006201 __ j(equal, true_label);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006202 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006203 // Check for undetectable objects => true.
6204 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
6205 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
6206 1 << Map::kIsUndetectable);
6207 final_branch_condition = not_zero;
6208
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006209 } else if (type_name->Equals(heap()->function_string())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006210 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006211 __ JumpIfSmi(input, false_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006212 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
6213 __ j(equal, true_label);
6214 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
6215 final_branch_condition = equal;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006216
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006217 } else if (type_name->Equals(heap()->object_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006218 __ JumpIfSmi(input, false_label);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00006219 if (!FLAG_harmony_typeof) {
6220 __ cmp(input, factory()->null_value());
6221 __ j(equal, true_label);
6222 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006223 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006224 __ j(below, false_label);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00006225 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
6226 __ j(above, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006227 // Check for undetectable objects => false.
6228 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
6229 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006230 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006231
6232 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006233 __ jmp(false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006234 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006235 return final_branch_condition;
6236}
6237
6238
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006239void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00006240 Register temp = ToRegister(instr->temp());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006241 int true_block = chunk_->LookupDestination(instr->true_block_id());
6242 int false_block = chunk_->LookupDestination(instr->false_block_id());
6243
6244 EmitIsConstructCall(temp);
6245 EmitBranch(true_block, false_block, equal);
6246}
6247
6248
6249void LCodeGen::EmitIsConstructCall(Register temp) {
6250 // Get the frame pointer for the calling frame.
6251 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
6252
6253 // Skip the arguments adaptor frame if it exists.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00006254 Label check_frame_marker;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006255 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
6256 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00006257 __ j(not_equal, &check_frame_marker, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006258 __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
6259
6260 // Check the marker in the calling frame.
6261 __ bind(&check_frame_marker);
6262 __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
6263 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
6264}
6265
6266
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006267void LCodeGen::EnsureSpaceForLazyDeopt() {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00006268 if (!info()->IsStub()) {
6269 // Ensure that we have enough space after the previous lazy-bailout
6270 // instruction for patching the code here.
6271 int current_pc = masm()->pc_offset();
6272 int patch_size = Deoptimizer::patch_size();
6273 if (current_pc < last_lazy_deopt_pc_ + patch_size) {
6274 int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc;
6275 __ Nop(padding_size);
6276 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006277 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00006278 last_lazy_deopt_pc_ = masm()->pc_offset();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006279}
6280
6281
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006282void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006283 EnsureSpaceForLazyDeopt();
6284 ASSERT(instr->HasEnvironment());
6285 LEnvironment* env = instr->environment();
6286 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
6287 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006288}
6289
6290
6291void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
danno@chromium.orgaefd6072013-05-14 14:11:47 +00006292 if (instr->hydrogen_value()->IsSoftDeoptimize()) {
6293 SoftDeoptimize(instr->environment());
6294 } else {
6295 DeoptimizeIf(no_condition, instr->environment());
6296 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006297}
6298
6299
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006300void LCodeGen::DoDummyUse(LDummyUse* instr) {
6301 // Nothing to see here, move on!
6302}
6303
6304
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006305void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
6306 LOperand* obj = instr->object();
6307 LOperand* key = instr->key();
6308 __ push(ToOperand(obj));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006309 EmitPushTaggedOperand(key);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00006310 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00006311 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00006312 RecordPosition(pointers->position());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006313 // Create safepoint generator that will also ensure enough space in the
6314 // reloc info for patching in deoptimization (since this is invoking a
6315 // builtin)
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006316 SafepointGenerator safepoint_generator(
6317 this, pointers, Safepoint::kLazyDeopt);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006318 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00006319 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006320}
6321
6322
ager@chromium.org04921a82011-06-27 13:21:41 +00006323void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006324 PushSafepointRegistersScope scope(this);
6325 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
6326 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
6327 RecordSafepointWithLazyDeopt(
6328 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
6329 ASSERT(instr->HasEnvironment());
6330 LEnvironment* env = instr->environment();
6331 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00006332}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006333
ager@chromium.org04921a82011-06-27 13:21:41 +00006334
6335void LCodeGen::DoStackCheck(LStackCheck* instr) {
6336 class DeferredStackCheck: public LDeferredCode {
6337 public:
6338 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
6339 : LDeferredCode(codegen), instr_(instr) { }
6340 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006341 virtual LInstruction* instr() { return instr_; }
ager@chromium.org04921a82011-06-27 13:21:41 +00006342 private:
6343 LStackCheck* instr_;
6344 };
6345
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006346 ASSERT(instr->HasEnvironment());
6347 LEnvironment* env = instr->environment();
6348 // There is no LLazyBailout instruction for stack-checks. We have to
6349 // prepare for lazy deoptimization explicitly here.
ager@chromium.org04921a82011-06-27 13:21:41 +00006350 if (instr->hydrogen()->is_function_entry()) {
6351 // Perform stack overflow check.
6352 Label done;
6353 ExternalReference stack_limit =
6354 ExternalReference::address_of_stack_limit(isolate());
6355 __ cmp(esp, Operand::StaticVariable(stack_limit));
6356 __ j(above_equal, &done, Label::kNear);
6357
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006358 ASSERT(instr->context()->IsRegister());
6359 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org04921a82011-06-27 13:21:41 +00006360 StackCheckStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00006361 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006362 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00006363 __ bind(&done);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006364 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
6365 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00006366 } else {
6367 ASSERT(instr->hydrogen()->is_backwards_branch());
6368 // Perform stack overflow check if this goto needs it before jumping.
6369 DeferredStackCheck* deferred_stack_check =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00006370 new(zone()) DeferredStackCheck(this, instr);
ager@chromium.org04921a82011-06-27 13:21:41 +00006371 ExternalReference stack_limit =
6372 ExternalReference::address_of_stack_limit(isolate());
6373 __ cmp(esp, Operand::StaticVariable(stack_limit));
6374 __ j(below, deferred_stack_check->entry());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006375 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00006376 __ bind(instr->done_label());
6377 deferred_stack_check->SetExit(instr->done_label());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006378 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
6379 // Don't record a deoptimization index for the safepoint here.
6380 // This will be done explicitly when emitting call and the safepoint in
6381 // the deferred code.
ager@chromium.org04921a82011-06-27 13:21:41 +00006382 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006383}
6384
6385
6386void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
6387 // This is a pseudo-instruction that ensures that the environment here is
6388 // properly registered for deoptimization and records the assembler's PC
6389 // offset.
6390 LEnvironment* environment = instr->environment();
6391 environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
6392 instr->SpilledDoubleRegisterArray());
6393
6394 // If the environment were already registered, we would have no way of
6395 // backpatching it with the spill slot operands.
6396 ASSERT(!environment->HasBeenRegistered());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006397 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006398 ASSERT(osr_pc_offset_ == -1);
6399 osr_pc_offset_ = masm()->pc_offset();
6400}
6401
6402
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006403void LCodeGen::DoIn(LIn* instr) {
6404 LOperand* obj = instr->object();
6405 LOperand* key = instr->key();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006406 EmitPushTaggedOperand(key);
6407 EmitPushTaggedOperand(obj);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00006408 ASSERT(instr->HasPointerMap());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006409 LPointerMap* pointers = instr->pointer_map();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006410 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006411 SafepointGenerator safepoint_generator(
6412 this, pointers, Safepoint::kLazyDeopt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00006413 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006414}
6415
6416
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006417void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
6418 __ cmp(eax, isolate()->factory()->undefined_value());
6419 DeoptimizeIf(equal, instr->environment());
6420
6421 __ cmp(eax, isolate()->factory()->null_value());
6422 DeoptimizeIf(equal, instr->environment());
6423
6424 __ test(eax, Immediate(kSmiTagMask));
6425 DeoptimizeIf(zero, instr->environment());
6426
6427 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
6428 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
6429 DeoptimizeIf(below_equal, instr->environment());
6430
6431 Label use_cache, call_runtime;
6432 __ CheckEnumCache(&call_runtime);
6433
6434 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
6435 __ jmp(&use_cache, Label::kNear);
6436
6437 // Get the set of properties to enumerate.
6438 __ bind(&call_runtime);
6439 __ push(eax);
6440 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
6441
6442 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
6443 isolate()->factory()->meta_map());
6444 DeoptimizeIf(not_equal, instr->environment());
6445 __ bind(&use_cache);
6446}
6447
6448
6449void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
6450 Register map = ToRegister(instr->map());
6451 Register result = ToRegister(instr->result());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00006452 Label load_cache, done;
6453 __ EnumLength(result, map);
6454 __ cmp(result, Immediate(Smi::FromInt(0)));
6455 __ j(not_equal, &load_cache);
6456 __ mov(result, isolate()->factory()->empty_fixed_array());
6457 __ jmp(&done);
6458
6459 __ bind(&load_cache);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006460 __ LoadInstanceDescriptors(map, result);
6461 __ mov(result,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006462 FieldOperand(result, DescriptorArray::kEnumCacheOffset));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006463 __ mov(result,
6464 FieldOperand(result, FixedArray::SizeFor(instr->idx())));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00006465 __ bind(&done);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006466 __ test(result, result);
6467 DeoptimizeIf(equal, instr->environment());
6468}
6469
6470
6471void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
6472 Register object = ToRegister(instr->value());
6473 __ cmp(ToRegister(instr->map()),
6474 FieldOperand(object, HeapObject::kMapOffset));
6475 DeoptimizeIf(not_equal, instr->environment());
6476}
6477
6478
6479void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
6480 Register object = ToRegister(instr->object());
6481 Register index = ToRegister(instr->index());
6482
6483 Label out_of_object, done;
6484 __ cmp(index, Immediate(0));
6485 __ j(less, &out_of_object);
6486 __ mov(object, FieldOperand(object,
6487 index,
6488 times_half_pointer_size,
6489 JSObject::kHeaderSize));
6490 __ jmp(&done, Label::kNear);
6491
6492 __ bind(&out_of_object);
6493 __ mov(object, FieldOperand(object, JSObject::kPropertiesOffset));
6494 __ neg(index);
6495 // Index is now equal to out of object property index plus 1.
6496 __ mov(object, FieldOperand(object,
6497 index,
6498 times_half_pointer_size,
6499 FixedArray::kHeaderSize - kPointerSize));
6500 __ bind(&done);
6501}
6502
6503
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006504#undef __
6505
6506} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006507
6508#endif // V8_TARGET_ARCH_IA32