blob: e2b54cd6ec8c9a982d45c9a84eff9bdd19325de6 [file] [log] [blame]
ager@chromium.org5ec48922009-05-05 07:25:34 +00001// Copyright 2009 the V8 project authors. All rights reserved.
2// 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
kasperl@chromium.org71affb52009-05-26 05:44:31 +000028#include "v8.h"
29
30#include "bootstrapper.h"
31#include "codegen-inl.h"
ager@chromium.orgeadaf222009-06-16 09:43:10 +000032#include "assembler-x64.h"
ager@chromium.orge2902be2009-06-08 12:21:35 +000033#include "macro-assembler-x64.h"
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +000034#include "serialize.h"
ager@chromium.orgeadaf222009-06-16 09:43:10 +000035#include "debug.h"
kasperl@chromium.org71affb52009-05-26 05:44:31 +000036
37namespace v8 {
38namespace internal {
39
40MacroAssembler::MacroAssembler(void* buffer, int size)
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000041 : Assembler(buffer, size),
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000042 generating_stub_(false),
43 allow_stub_calls_(true),
44 code_object_(Heap::undefined_value()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000045}
46
ager@chromium.orge2902be2009-06-08 12:21:35 +000047
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000048void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000049 movq(destination, Operand(kRootRegister, index << kPointerSizeLog2));
ager@chromium.org18ad94b2009-09-02 08:22:29 +000050}
51
52
53void MacroAssembler::PushRoot(Heap::RootListIndex index) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000054 push(Operand(kRootRegister, index << kPointerSizeLog2));
ager@chromium.org18ad94b2009-09-02 08:22:29 +000055}
56
57
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000058void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000059 cmpq(with, Operand(kRootRegister, index << kPointerSizeLog2));
ager@chromium.org18ad94b2009-09-02 08:22:29 +000060}
61
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +000062
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000063void MacroAssembler::CompareRoot(Operand with, Heap::RootListIndex index) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000064 LoadRoot(kScratchRegister, index);
65 cmpq(with, kScratchRegister);
66}
67
68
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000069void MacroAssembler::StackLimitCheck(Label* on_stack_overflow) {
70 CompareRoot(rsp, Heap::kStackLimitRootIndex);
71 j(below, on_stack_overflow);
72}
73
74
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +000075static void RecordWriteHelper(MacroAssembler* masm,
76 Register object,
77 Register addr,
78 Register scratch) {
79 Label fast;
80
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +000081 // Compute the page start address from the heap object pointer, and reuse
82 // the 'object' register for it.
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +000083 ASSERT(is_int32(~Page::kPageAlignmentMask));
84 masm->and_(object,
85 Immediate(static_cast<int32_t>(~Page::kPageAlignmentMask)));
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +000086 Register page_start = object;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +000087
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +000088 // Compute the bit addr in the remembered set/index of the pointer in the
89 // page. Reuse 'addr' as pointer_offset.
90 masm->subq(addr, page_start);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +000091 masm->shr(addr, Immediate(kPointerSizeLog2));
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +000092 Register pointer_offset = addr;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +000093
94 // If the bit offset lies beyond the normal remembered set range, it is in
95 // the extra remembered set area of a large object.
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +000096 masm->cmpq(pointer_offset, Immediate(Page::kPageSize / kPointerSize));
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +000097 masm->j(less, &fast);
98
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +000099 // Adjust 'page_start' so that addressing using 'pointer_offset' hits the
100 // extra remembered set after the large object.
101
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000102 // Load the array length into 'scratch'.
103 masm->movl(scratch,
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000104 Operand(page_start,
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000105 Page::kObjectStartOffset + FixedArray::kLengthOffset));
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000106 Register array_length = scratch;
107
108 // Extra remembered set starts right after the large object (a FixedArray), at
109 // page_start + kObjectStartOffset + objectSize
110 // where objectSize is FixedArray::kHeaderSize + kPointerSize * array_length.
111 // Add the delta between the end of the normal RSet and the start of the
112 // extra RSet to 'page_start', so that addressing the bit using
113 // 'pointer_offset' hits the extra RSet words.
114 masm->lea(page_start,
115 Operand(page_start, array_length, times_pointer_size,
116 Page::kObjectStartOffset + FixedArray::kHeaderSize
117 - Page::kRSetEndOffset));
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000118
119 // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction
120 // to limit code size. We should probably evaluate this decision by
121 // measuring the performance of an equivalent implementation using
122 // "simpler" instructions
123 masm->bind(&fast);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000124 masm->bts(Operand(page_start, Page::kRSetOffset), pointer_offset);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000125}
126
127
128class RecordWriteStub : public CodeStub {
129 public:
130 RecordWriteStub(Register object, Register addr, Register scratch)
131 : object_(object), addr_(addr), scratch_(scratch) { }
132
133 void Generate(MacroAssembler* masm);
134
135 private:
136 Register object_;
137 Register addr_;
138 Register scratch_;
139
140#ifdef DEBUG
141 void Print() {
142 PrintF("RecordWriteStub (object reg %d), (addr reg %d), (scratch reg %d)\n",
143 object_.code(), addr_.code(), scratch_.code());
144 }
145#endif
146
147 // Minor key encoding in 12 bits of three registers (object, address and
148 // scratch) OOOOAAAASSSS.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000149 class ScratchBits : public BitField<uint32_t, 0, 4> {};
150 class AddressBits : public BitField<uint32_t, 4, 4> {};
151 class ObjectBits : public BitField<uint32_t, 8, 4> {};
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000152
153 Major MajorKey() { return RecordWrite; }
154
155 int MinorKey() {
156 // Encode the registers.
157 return ObjectBits::encode(object_.code()) |
158 AddressBits::encode(addr_.code()) |
159 ScratchBits::encode(scratch_.code());
160 }
161};
162
163
164void RecordWriteStub::Generate(MacroAssembler* masm) {
165 RecordWriteHelper(masm, object_, addr_, scratch_);
166 masm->ret(0);
167}
168
169
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000170void MacroAssembler::InNewSpace(Register object,
171 Register scratch,
172 Condition cc,
173 Label* branch) {
174 ASSERT(cc == equal || cc == not_equal);
175 if (!scratch.is(object)) {
176 movq(scratch, object);
177 }
178 ASSERT(is_int32(static_cast<int64_t>(Heap::NewSpaceMask())));
179 and_(scratch, Immediate(static_cast<int32_t>(Heap::NewSpaceMask())));
180 movq(kScratchRegister, ExternalReference::new_space_start());
181 cmpq(scratch, kScratchRegister);
182 j(cc, branch);
183}
184
185
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000186// Set the remembered set bit for [object+offset].
187// object is the object being stored into, value is the object being stored.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000188// If offset is zero, then the smi_index register contains the array index into
189// the elements array represented as a smi. Otherwise it can be used as a
190// scratch register.
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000191// All registers are clobbered by the operation.
192void MacroAssembler::RecordWrite(Register object,
193 int offset,
194 Register value,
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000195 Register smi_index) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000196 // The compiled code assumes that record write doesn't change the
197 // context register, so we check that none of the clobbered
198 // registers are rsi.
199 ASSERT(!object.is(rsi) && !value.is(rsi) && !smi_index.is(rsi));
200
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000201 // First, check if a remembered set write is even needed. The tests below
202 // catch stores of Smis and stores into young gen (which does not have space
203 // for the remembered set bits.
204 Label done;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000205 JumpIfSmi(value, &done);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000206
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000207 RecordWriteNonSmi(object, offset, value, smi_index);
208 bind(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000209
210 // Clobber all input registers when running with the debug-code flag
211 // turned on to provoke errors. This clobbering repeats the
212 // clobbering done inside RecordWriteNonSmi but it's necessary to
213 // avoid having the fast case for smis leave the registers
214 // unchanged.
215 if (FLAG_debug_code) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000216 movq(object, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
217 movq(value, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
218 movq(smi_index, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000219 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000220}
221
222
223void MacroAssembler::RecordWriteNonSmi(Register object,
224 int offset,
225 Register scratch,
226 Register smi_index) {
227 Label done;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000228
229 if (FLAG_debug_code) {
230 Label okay;
231 JumpIfNotSmi(object, &okay);
232 Abort("MacroAssembler::RecordWriteNonSmi cannot deal with smis");
233 bind(&okay);
234 }
235
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000236 // Test that the object address is not in the new space. We cannot
237 // set remembered set bits in the new space.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000238 InNewSpace(object, scratch, equal, &done);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000239
whesse@chromium.orge88a9ed2010-04-15 15:07:46 +0000240 // The offset is relative to a tagged or untagged HeapObject pointer,
241 // so either offset or offset + kHeapObjectTag must be a
242 // multiple of kPointerSize.
243 ASSERT(IsAligned(offset, kPointerSize) ||
244 IsAligned(offset + kHeapObjectTag, kPointerSize));
245
246 // We use optimized write barrier code if the word being written to is not in
247 // a large object page, or is in the first "page" of a large object page.
248 // We make sure that an offset is inside the right limits whether it is
249 // tagged or untagged.
250 if ((offset > 0) && (offset < Page::kMaxHeapObjectSize - kHeapObjectTag)) {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000251 // Compute the bit offset in the remembered set, leave it in 'value'.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000252 lea(scratch, Operand(object, offset));
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000253 ASSERT(is_int32(Page::kPageAlignmentMask));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000254 and_(scratch, Immediate(static_cast<int32_t>(Page::kPageAlignmentMask)));
255 shr(scratch, Immediate(kObjectAlignmentBits));
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000256
257 // Compute the page address from the heap object pointer, leave it in
258 // 'object' (immediate value is sign extended).
259 and_(object, Immediate(~Page::kPageAlignmentMask));
260
261 // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction
262 // to limit code size. We should probably evaluate this decision by
263 // measuring the performance of an equivalent implementation using
264 // "simpler" instructions
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000265 bts(Operand(object, Page::kRSetOffset), scratch);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000266 } else {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000267 Register dst = smi_index;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000268 if (offset != 0) {
269 lea(dst, Operand(object, offset));
270 } else {
271 // array access: calculate the destination address in the same manner as
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000272 // KeyedStoreIC::GenerateGeneric.
273 SmiIndex index = SmiToIndex(smi_index, smi_index, kPointerSizeLog2);
274 lea(dst, Operand(object,
275 index.reg,
276 index.scale,
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000277 FixedArray::kHeaderSize - kHeapObjectTag));
278 }
279 // If we are already generating a shared stub, not inlining the
280 // record write code isn't going to save us any memory.
281 if (generating_stub()) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000282 RecordWriteHelper(this, object, dst, scratch);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000283 } else {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000284 RecordWriteStub stub(object, dst, scratch);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000285 CallStub(&stub);
286 }
287 }
288
289 bind(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000290
291 // Clobber all input registers when running with the debug-code flag
292 // turned on to provoke errors.
293 if (FLAG_debug_code) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000294 movq(object, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
295 movq(scratch, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
296 movq(smi_index, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000297 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000298}
299
300
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000301void MacroAssembler::Assert(Condition cc, const char* msg) {
302 if (FLAG_debug_code) Check(cc, msg);
303}
304
305
306void MacroAssembler::Check(Condition cc, const char* msg) {
307 Label L;
308 j(cc, &L);
309 Abort(msg);
310 // will not return here
311 bind(&L);
312}
313
314
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000315void MacroAssembler::CheckStackAlignment() {
316 int frame_alignment = OS::ActivationFrameAlignment();
317 int frame_alignment_mask = frame_alignment - 1;
318 if (frame_alignment > kPointerSize) {
319 ASSERT(IsPowerOf2(frame_alignment));
320 Label alignment_as_expected;
321 testq(rsp, Immediate(frame_alignment_mask));
322 j(zero, &alignment_as_expected);
323 // Abort if stack is not aligned.
324 int3();
325 bind(&alignment_as_expected);
326 }
327}
328
329
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000330void MacroAssembler::NegativeZeroTest(Register result,
331 Register op,
332 Label* then_label) {
333 Label ok;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000334 testl(result, result);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000335 j(not_zero, &ok);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000336 testl(op, op);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000337 j(sign, then_label);
338 bind(&ok);
339}
340
341
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000342void MacroAssembler::Abort(const char* msg) {
343 // We want to pass the msg string like a smi to avoid GC
344 // problems, however msg is not guaranteed to be aligned
345 // properly. Instead, we pass an aligned pointer that is
346 // a proper v8 smi, but also pass the alignment difference
347 // from the real pointer as a smi.
348 intptr_t p1 = reinterpret_cast<intptr_t>(msg);
349 intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag;
350 // Note: p0 might not be a valid Smi *value*, but it has a valid Smi tag.
351 ASSERT(reinterpret_cast<Object*>(p0)->IsSmi());
352#ifdef DEBUG
353 if (msg != NULL) {
354 RecordComment("Abort message: ");
355 RecordComment(msg);
356 }
357#endif
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000358 // Disable stub call restrictions to always allow calls to abort.
359 set_allow_stub_calls(true);
360
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000361 push(rax);
362 movq(kScratchRegister, p0, RelocInfo::NONE);
363 push(kScratchRegister);
364 movq(kScratchRegister,
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000365 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(p1 - p0))),
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000366 RelocInfo::NONE);
367 push(kScratchRegister);
368 CallRuntime(Runtime::kAbort, 2);
369 // will not return here
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000370 int3();
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000371}
372
373
374void MacroAssembler::CallStub(CodeStub* stub) {
375 ASSERT(allow_stub_calls()); // calls are not allowed in some stubs
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000376 Call(stub->GetCode(), RelocInfo::CODE_TARGET);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000377}
378
379
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000380void MacroAssembler::TailCallStub(CodeStub* stub) {
381 ASSERT(allow_stub_calls()); // calls are not allowed in some stubs
382 Jump(stub->GetCode(), RelocInfo::CODE_TARGET);
383}
384
385
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000386void MacroAssembler::StubReturn(int argc) {
387 ASSERT(argc >= 1 && generating_stub());
388 ret((argc - 1) * kPointerSize);
389}
390
391
392void MacroAssembler::IllegalOperation(int num_arguments) {
393 if (num_arguments > 0) {
394 addq(rsp, Immediate(num_arguments * kPointerSize));
395 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000396 LoadRoot(rax, Heap::kUndefinedValueRootIndex);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000397}
398
399
400void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) {
401 CallRuntime(Runtime::FunctionForId(id), num_arguments);
402}
403
404
405void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
406 // If the expected number of arguments of the runtime function is
407 // constant, we check that the actual number of arguments match the
408 // expectation.
409 if (f->nargs >= 0 && f->nargs != num_arguments) {
410 IllegalOperation(num_arguments);
411 return;
412 }
413
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000414 // TODO(1236192): Most runtime routines don't need the number of
415 // arguments passed in because it is constant. At some point we
416 // should remove this need and make the runtime routine entry code
417 // smarter.
418 movq(rax, Immediate(num_arguments));
419 movq(rbx, ExternalReference(f));
420 CEntryStub ces(f->result_size);
421 CallStub(&ces);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000422}
423
424
ager@chromium.org5c838252010-02-19 08:53:10 +0000425void MacroAssembler::CallExternalReference(const ExternalReference& ext,
426 int num_arguments) {
427 movq(rax, Immediate(num_arguments));
428 movq(rbx, ext);
429
430 CEntryStub stub(1);
431 CallStub(&stub);
432}
433
434
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000435void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
436 int num_arguments,
437 int result_size) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000438 // ----------- S t a t e -------------
439 // -- rsp[0] : return address
440 // -- rsp[8] : argument num_arguments - 1
441 // ...
442 // -- rsp[8 * num_arguments] : argument 0 (receiver)
443 // -----------------------------------
444
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000445 // TODO(1236192): Most runtime routines don't need the number of
446 // arguments passed in because it is constant. At some point we
447 // should remove this need and make the runtime routine entry code
448 // smarter.
449 movq(rax, Immediate(num_arguments));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000450 JumpToExternalReference(ext, result_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000451}
452
453
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000454void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
455 int num_arguments,
456 int result_size) {
457 TailCallExternalReference(ExternalReference(fid), num_arguments, result_size);
458}
459
460
461void MacroAssembler::JumpToExternalReference(const ExternalReference& ext,
462 int result_size) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000463 // Set the entry point and jump to the C entry runtime stub.
464 movq(rbx, ext);
ager@chromium.orga1645e22009-09-09 19:27:10 +0000465 CEntryStub ces(result_size);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000466 jmp(ces.GetCode(), RelocInfo::CODE_TARGET);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000467}
468
ager@chromium.orge2902be2009-06-08 12:21:35 +0000469
ager@chromium.org5c838252010-02-19 08:53:10 +0000470void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
471 // Calls are not allowed in some stubs.
472 ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000473
ager@chromium.org5c838252010-02-19 08:53:10 +0000474 // Rely on the assertion to check that the number of provided
475 // arguments match the expected number of arguments. Fake a
476 // parameter count to avoid emitting code to do the check.
477 ParameterCount expected(0);
478 GetBuiltinEntry(rdx, id);
479 InvokeCode(rdx, expected, expected, flag);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000480}
481
ager@chromium.org5c838252010-02-19 08:53:10 +0000482
483void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000484 ASSERT(!target.is(rdi));
485
486 // Load the builtins object into target register.
487 movq(target, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
488 movq(target, FieldOperand(target, GlobalObject::kBuiltinsOffset));
489
ager@chromium.org5c838252010-02-19 08:53:10 +0000490 // Load the JavaScript builtin function from the builtins object.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000491 movq(rdi, FieldOperand(target, JSBuiltinsObject::OffsetOfFunctionWithId(id)));
492
493 // Load the code entry point from the builtins object.
494 movq(target, FieldOperand(target, JSBuiltinsObject::OffsetOfCodeWithId(id)));
495 if (FLAG_debug_code) {
496 // Make sure the code objects in the builtins object and in the
497 // builtin function are the same.
498 push(target);
499 movq(target, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
500 movq(target, FieldOperand(target, SharedFunctionInfo::kCodeOffset));
501 cmpq(target, Operand(rsp, 0));
502 Assert(equal, "Builtin code object changed");
503 pop(target);
504 }
505 lea(target, FieldOperand(target, Code::kHeaderSize));
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000506}
507
508
ager@chromium.orge2902be2009-06-08 12:21:35 +0000509void MacroAssembler::Set(Register dst, int64_t x) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000510 if (x == 0) {
511 xor_(dst, dst);
512 } else if (is_int32(x)) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000513 movq(dst, Immediate(static_cast<int32_t>(x)));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000514 } else if (is_uint32(x)) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000515 movl(dst, Immediate(static_cast<uint32_t>(x)));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000516 } else {
517 movq(dst, x, RelocInfo::NONE);
518 }
519}
520
521
522void MacroAssembler::Set(const Operand& dst, int64_t x) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000523 if (x == 0) {
524 xor_(kScratchRegister, kScratchRegister);
525 movq(dst, kScratchRegister);
526 } else if (is_int32(x)) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000527 movq(dst, Immediate(static_cast<int32_t>(x)));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000528 } else if (is_uint32(x)) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000529 movl(dst, Immediate(static_cast<uint32_t>(x)));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000530 } else {
531 movq(kScratchRegister, x, RelocInfo::NONE);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000532 movq(dst, kScratchRegister);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000533 }
ager@chromium.orge2902be2009-06-08 12:21:35 +0000534}
535
ager@chromium.org4af710e2009-09-15 12:20:11 +0000536// ----------------------------------------------------------------------------
537// Smi tagging, untagging and tag detection.
538
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000539static int kSmiShift = kSmiTagSize + kSmiShiftSize;
ager@chromium.org4af710e2009-09-15 12:20:11 +0000540
541void MacroAssembler::Integer32ToSmi(Register dst, Register src) {
ager@chromium.org4af710e2009-09-15 12:20:11 +0000542 ASSERT_EQ(0, kSmiTag);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000543 if (!dst.is(src)) {
544 movl(dst, src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000545 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000546 shl(dst, Immediate(kSmiShift));
ager@chromium.org4af710e2009-09-15 12:20:11 +0000547}
548
549
550void MacroAssembler::Integer32ToSmi(Register dst,
551 Register src,
552 Label* on_overflow) {
ager@chromium.org4af710e2009-09-15 12:20:11 +0000553 ASSERT_EQ(0, kSmiTag);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000554 // 32-bit integer always fits in a long smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000555 if (!dst.is(src)) {
556 movl(dst, src);
557 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000558 shl(dst, Immediate(kSmiShift));
ager@chromium.org4af710e2009-09-15 12:20:11 +0000559}
560
561
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000562void MacroAssembler::Integer64PlusConstantToSmi(Register dst,
563 Register src,
564 int constant) {
565 if (dst.is(src)) {
566 addq(dst, Immediate(constant));
567 } else {
568 lea(dst, Operand(src, constant));
569 }
570 shl(dst, Immediate(kSmiShift));
ager@chromium.org4af710e2009-09-15 12:20:11 +0000571}
572
573
574void MacroAssembler::SmiToInteger32(Register dst, Register src) {
ager@chromium.org4af710e2009-09-15 12:20:11 +0000575 ASSERT_EQ(0, kSmiTag);
576 if (!dst.is(src)) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000577 movq(dst, src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000578 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000579 shr(dst, Immediate(kSmiShift));
ager@chromium.org4af710e2009-09-15 12:20:11 +0000580}
581
582
583void MacroAssembler::SmiToInteger64(Register dst, Register src) {
ager@chromium.org4af710e2009-09-15 12:20:11 +0000584 ASSERT_EQ(0, kSmiTag);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000585 if (!dst.is(src)) {
586 movq(dst, src);
587 }
588 sar(dst, Immediate(kSmiShift));
589}
590
591
592void MacroAssembler::SmiTest(Register src) {
593 testq(src, src);
594}
595
596
597void MacroAssembler::SmiCompare(Register dst, Register src) {
598 cmpq(dst, src);
599}
600
601
602void MacroAssembler::SmiCompare(Register dst, Smi* src) {
603 ASSERT(!dst.is(kScratchRegister));
604 if (src->value() == 0) {
605 testq(dst, dst);
606 } else {
607 Move(kScratchRegister, src);
608 cmpq(dst, kScratchRegister);
609 }
610}
611
612
613void MacroAssembler::SmiCompare(const Operand& dst, Register src) {
614 cmpq(dst, src);
615}
616
617
618void MacroAssembler::SmiCompare(const Operand& dst, Smi* src) {
619 if (src->value() == 0) {
620 // Only tagged long smi to have 32-bit representation.
621 cmpq(dst, Immediate(0));
622 } else {
623 Move(kScratchRegister, src);
624 cmpq(dst, kScratchRegister);
625 }
ager@chromium.org4af710e2009-09-15 12:20:11 +0000626}
627
628
629void MacroAssembler::PositiveSmiTimesPowerOfTwoToInteger64(Register dst,
630 Register src,
631 int power) {
632 ASSERT(power >= 0);
633 ASSERT(power < 64);
634 if (power == 0) {
635 SmiToInteger64(dst, src);
636 return;
637 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000638 if (!dst.is(src)) {
639 movq(dst, src);
640 }
641 if (power < kSmiShift) {
642 sar(dst, Immediate(kSmiShift - power));
643 } else if (power > kSmiShift) {
644 shl(dst, Immediate(power - kSmiShift));
ager@chromium.org4af710e2009-09-15 12:20:11 +0000645 }
646}
647
648
ager@chromium.org4af710e2009-09-15 12:20:11 +0000649Condition MacroAssembler::CheckSmi(Register src) {
ager@chromium.org4af710e2009-09-15 12:20:11 +0000650 ASSERT_EQ(0, kSmiTag);
651 testb(src, Immediate(kSmiTagMask));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000652 return zero;
ager@chromium.org4af710e2009-09-15 12:20:11 +0000653}
654
655
656Condition MacroAssembler::CheckPositiveSmi(Register src) {
657 ASSERT_EQ(0, kSmiTag);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000658 movq(kScratchRegister, src);
659 rol(kScratchRegister, Immediate(1));
660 testl(kScratchRegister, Immediate(0x03));
ager@chromium.org4af710e2009-09-15 12:20:11 +0000661 return zero;
662}
663
664
ager@chromium.org4af710e2009-09-15 12:20:11 +0000665Condition MacroAssembler::CheckBothSmi(Register first, Register second) {
666 if (first.is(second)) {
667 return CheckSmi(first);
668 }
669 movl(kScratchRegister, first);
670 orl(kScratchRegister, second);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000671 testb(kScratchRegister, Immediate(kSmiTagMask));
672 return zero;
ager@chromium.org4af710e2009-09-15 12:20:11 +0000673}
674
675
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000676Condition MacroAssembler::CheckBothPositiveSmi(Register first,
677 Register second) {
678 if (first.is(second)) {
679 return CheckPositiveSmi(first);
680 }
681 movl(kScratchRegister, first);
682 orl(kScratchRegister, second);
683 rol(kScratchRegister, Immediate(1));
684 testl(kScratchRegister, Immediate(0x03));
685 return zero;
686}
687
688
689
690Condition MacroAssembler::CheckEitherSmi(Register first, Register second) {
691 if (first.is(second)) {
692 return CheckSmi(first);
693 }
694 movl(kScratchRegister, first);
695 andl(kScratchRegister, second);
696 testb(kScratchRegister, Immediate(kSmiTagMask));
697 return zero;
698}
699
700
ager@chromium.org4af710e2009-09-15 12:20:11 +0000701Condition MacroAssembler::CheckIsMinSmi(Register src) {
702 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000703 movq(kScratchRegister, src);
704 rol(kScratchRegister, Immediate(1));
705 cmpq(kScratchRegister, Immediate(1));
ager@chromium.org4af710e2009-09-15 12:20:11 +0000706 return equal;
707}
708
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000709
ager@chromium.org4af710e2009-09-15 12:20:11 +0000710Condition MacroAssembler::CheckInteger32ValidSmiValue(Register src) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000711 // A 32-bit integer value can always be converted to a smi.
712 return always;
ager@chromium.org4af710e2009-09-15 12:20:11 +0000713}
714
715
ager@chromium.org3811b432009-10-28 14:53:37 +0000716Condition MacroAssembler::CheckUInteger32ValidSmiValue(Register src) {
717 // An unsigned 32-bit integer value is valid as long as the high bit
718 // is not set.
719 testq(src, Immediate(0x80000000));
720 return zero;
721}
722
723
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000724void MacroAssembler::SmiNeg(Register dst, Register src, Label* on_smi_result) {
725 if (dst.is(src)) {
726 ASSERT(!dst.is(kScratchRegister));
727 movq(kScratchRegister, src);
728 neg(dst); // Low 32 bits are retained as zero by negation.
729 // Test if result is zero or Smi::kMinValue.
730 cmpq(dst, kScratchRegister);
731 j(not_equal, on_smi_result);
732 movq(src, kScratchRegister);
733 } else {
734 movq(dst, src);
735 neg(dst);
736 cmpq(dst, src);
737 // If the result is zero or Smi::kMinValue, negation failed to create a smi.
738 j(not_equal, on_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000739 }
ager@chromium.org4af710e2009-09-15 12:20:11 +0000740}
741
742
743void MacroAssembler::SmiAdd(Register dst,
744 Register src1,
745 Register src2,
746 Label* on_not_smi_result) {
747 ASSERT(!dst.is(src2));
kmillikin@chromium.orgf8253d72010-05-03 09:56:08 +0000748 if (dst.is(src1)) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000749 addq(dst, src2);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000750 Label smi_result;
751 j(no_overflow, &smi_result);
752 // Restore src1.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000753 subq(src1, src2);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000754 jmp(on_not_smi_result);
755 bind(&smi_result);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000756 } else {
757 movq(dst, src1);
758 addq(dst, src2);
759 j(overflow, on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000760 }
761}
762
763
ager@chromium.org4af710e2009-09-15 12:20:11 +0000764void MacroAssembler::SmiSub(Register dst,
765 Register src1,
766 Register src2,
767 Label* on_not_smi_result) {
768 ASSERT(!dst.is(src2));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000769 if (on_not_smi_result == NULL) {
770 // No overflow checking. Use only when it's known that
771 // overflowing is impossible (e.g., subtracting two positive smis).
772 if (dst.is(src1)) {
773 subq(dst, src2);
774 } else {
775 movq(dst, src1);
776 subq(dst, src2);
777 }
778 Assert(no_overflow, "Smi substraction onverflow");
779 } else if (dst.is(src1)) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000780 subq(dst, src2);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000781 Label smi_result;
782 j(no_overflow, &smi_result);
783 // Restore src1.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000784 addq(src1, src2);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000785 jmp(on_not_smi_result);
786 bind(&smi_result);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000787 } else {
788 movq(dst, src1);
789 subq(dst, src2);
790 j(overflow, on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000791 }
792}
793
794
795void MacroAssembler::SmiMul(Register dst,
796 Register src1,
797 Register src2,
798 Label* on_not_smi_result) {
799 ASSERT(!dst.is(src2));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000800 ASSERT(!dst.is(kScratchRegister));
801 ASSERT(!src1.is(kScratchRegister));
802 ASSERT(!src2.is(kScratchRegister));
ager@chromium.org4af710e2009-09-15 12:20:11 +0000803
804 if (dst.is(src1)) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000805 Label failure, zero_correct_result;
806 movq(kScratchRegister, src1); // Create backup for later testing.
807 SmiToInteger64(dst, src1);
808 imul(dst, src2);
809 j(overflow, &failure);
810
811 // Check for negative zero result. If product is zero, and one
812 // argument is negative, go to slow case.
813 Label correct_result;
814 testq(dst, dst);
815 j(not_zero, &correct_result);
816
817 movq(dst, kScratchRegister);
818 xor_(dst, src2);
819 j(positive, &zero_correct_result); // Result was positive zero.
820
821 bind(&failure); // Reused failure exit, restores src1.
822 movq(src1, kScratchRegister);
823 jmp(on_not_smi_result);
824
825 bind(&zero_correct_result);
826 xor_(dst, dst);
827
828 bind(&correct_result);
829 } else {
830 SmiToInteger64(dst, src1);
831 imul(dst, src2);
832 j(overflow, on_not_smi_result);
833 // Check for negative zero result. If product is zero, and one
834 // argument is negative, go to slow case.
835 Label correct_result;
836 testq(dst, dst);
837 j(not_zero, &correct_result);
838 // One of src1 and src2 is zero, the check whether the other is
839 // negative.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000840 movq(kScratchRegister, src1);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000841 xor_(kScratchRegister, src2);
842 j(negative, on_not_smi_result);
843 bind(&correct_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000844 }
ager@chromium.org4af710e2009-09-15 12:20:11 +0000845}
846
847
848void MacroAssembler::SmiTryAddConstant(Register dst,
849 Register src,
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000850 Smi* constant,
ager@chromium.org4af710e2009-09-15 12:20:11 +0000851 Label* on_not_smi_result) {
852 // Does not assume that src is a smi.
ager@chromium.org3811b432009-10-28 14:53:37 +0000853 ASSERT_EQ(static_cast<int>(1), static_cast<int>(kSmiTagMask));
ager@chromium.org4af710e2009-09-15 12:20:11 +0000854 ASSERT_EQ(0, kSmiTag);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000855 ASSERT(!dst.is(kScratchRegister));
856 ASSERT(!src.is(kScratchRegister));
ager@chromium.org4af710e2009-09-15 12:20:11 +0000857
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000858 JumpIfNotSmi(src, on_not_smi_result);
859 Register tmp = (dst.is(src) ? kScratchRegister : dst);
860 Move(tmp, constant);
861 addq(tmp, src);
862 j(overflow, on_not_smi_result);
863 if (dst.is(src)) {
864 movq(dst, tmp);
865 }
866}
867
868
869void MacroAssembler::SmiAddConstant(Register dst, Register src, Smi* constant) {
870 if (constant->value() == 0) {
871 if (!dst.is(src)) {
872 movq(dst, src);
873 }
874 } else if (dst.is(src)) {
875 ASSERT(!dst.is(kScratchRegister));
876
877 Move(kScratchRegister, constant);
878 addq(dst, kScratchRegister);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000879 } else {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000880 Move(dst, constant);
881 addq(dst, src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000882 }
883}
884
885
886void MacroAssembler::SmiAddConstant(Register dst,
887 Register src,
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000888 Smi* constant,
ager@chromium.org4af710e2009-09-15 12:20:11 +0000889 Label* on_not_smi_result) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000890 if (constant->value() == 0) {
891 if (!dst.is(src)) {
892 movq(dst, src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000893 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000894 } else if (dst.is(src)) {
895 ASSERT(!dst.is(kScratchRegister));
896
897 Move(kScratchRegister, constant);
898 addq(dst, kScratchRegister);
899 Label result_ok;
900 j(no_overflow, &result_ok);
901 subq(dst, kScratchRegister);
902 jmp(on_not_smi_result);
903 bind(&result_ok);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000904 } else {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000905 Move(dst, constant);
906 addq(dst, src);
907 j(overflow, on_not_smi_result);
908 }
909}
910
911
912void MacroAssembler::SmiSubConstant(Register dst, Register src, Smi* constant) {
913 if (constant->value() == 0) {
ager@chromium.org4af710e2009-09-15 12:20:11 +0000914 if (!dst.is(src)) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000915 movq(dst, src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000916 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000917 } else if (dst.is(src)) {
918 ASSERT(!dst.is(kScratchRegister));
919
920 Move(kScratchRegister, constant);
921 subq(dst, kScratchRegister);
922 } else {
923 // Subtract by adding the negative, to do it in two operations.
924 if (constant->value() == Smi::kMinValue) {
925 Move(kScratchRegister, constant);
926 movq(dst, src);
927 subq(dst, kScratchRegister);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000928 } else {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000929 Move(dst, Smi::FromInt(-constant->value()));
930 addq(dst, src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000931 }
932 }
933}
934
935
936void MacroAssembler::SmiSubConstant(Register dst,
937 Register src,
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000938 Smi* constant,
ager@chromium.org4af710e2009-09-15 12:20:11 +0000939 Label* on_not_smi_result) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000940 if (constant->value() == 0) {
941 if (!dst.is(src)) {
942 movq(dst, src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000943 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000944 } else if (dst.is(src)) {
945 ASSERT(!dst.is(kScratchRegister));
946
947 Move(kScratchRegister, constant);
948 subq(dst, kScratchRegister);
949 Label sub_success;
950 j(no_overflow, &sub_success);
951 addq(src, kScratchRegister);
952 jmp(on_not_smi_result);
953 bind(&sub_success);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000954 } else {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000955 if (constant->value() == Smi::kMinValue) {
956 Move(kScratchRegister, constant);
957 movq(dst, src);
958 subq(dst, kScratchRegister);
959 j(overflow, on_not_smi_result);
960 } else {
961 Move(dst, Smi::FromInt(-(constant->value())));
962 addq(dst, src);
963 j(overflow, on_not_smi_result);
964 }
ager@chromium.org4af710e2009-09-15 12:20:11 +0000965 }
966}
967
968
969void MacroAssembler::SmiDiv(Register dst,
970 Register src1,
971 Register src2,
972 Label* on_not_smi_result) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000973 ASSERT(!src1.is(kScratchRegister));
974 ASSERT(!src2.is(kScratchRegister));
975 ASSERT(!dst.is(kScratchRegister));
ager@chromium.org4af710e2009-09-15 12:20:11 +0000976 ASSERT(!src2.is(rax));
977 ASSERT(!src2.is(rdx));
978 ASSERT(!src1.is(rdx));
979
980 // Check for 0 divisor (result is +/-Infinity).
981 Label positive_divisor;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000982 testq(src2, src2);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000983 j(zero, on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000984
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000985 if (src1.is(rax)) {
986 movq(kScratchRegister, src1);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000987 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000988 SmiToInteger32(rax, src1);
989 // We need to rule out dividing Smi::kMinValue by -1, since that would
990 // overflow in idiv and raise an exception.
991 // We combine this with negative zero test (negative zero only happens
992 // when dividing zero by a negative number).
ager@chromium.org4af710e2009-09-15 12:20:11 +0000993
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000994 // We overshoot a little and go to slow case if we divide min-value
995 // by any negative value, not just -1.
996 Label safe_div;
997 testl(rax, Immediate(0x7fffffff));
998 j(not_zero, &safe_div);
999 testq(src2, src2);
1000 if (src1.is(rax)) {
1001 j(positive, &safe_div);
1002 movq(src1, kScratchRegister);
1003 jmp(on_not_smi_result);
1004 } else {
1005 j(negative, on_not_smi_result);
1006 }
1007 bind(&safe_div);
1008
1009 SmiToInteger32(src2, src2);
1010 // Sign extend src1 into edx:eax.
1011 cdq();
ager@chromium.org4af710e2009-09-15 12:20:11 +00001012 idivl(src2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001013 Integer32ToSmi(src2, src2);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001014 // Check that the remainder is zero.
1015 testl(rdx, rdx);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001016 if (src1.is(rax)) {
1017 Label smi_result;
1018 j(zero, &smi_result);
1019 movq(src1, kScratchRegister);
1020 jmp(on_not_smi_result);
1021 bind(&smi_result);
1022 } else {
1023 j(not_zero, on_not_smi_result);
1024 }
1025 if (!dst.is(src1) && src1.is(rax)) {
1026 movq(src1, kScratchRegister);
1027 }
ager@chromium.org4af710e2009-09-15 12:20:11 +00001028 Integer32ToSmi(dst, rax);
1029}
1030
1031
1032void MacroAssembler::SmiMod(Register dst,
1033 Register src1,
1034 Register src2,
1035 Label* on_not_smi_result) {
1036 ASSERT(!dst.is(kScratchRegister));
1037 ASSERT(!src1.is(kScratchRegister));
1038 ASSERT(!src2.is(kScratchRegister));
1039 ASSERT(!src2.is(rax));
1040 ASSERT(!src2.is(rdx));
1041 ASSERT(!src1.is(rdx));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001042 ASSERT(!src1.is(src2));
ager@chromium.org4af710e2009-09-15 12:20:11 +00001043
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001044 testq(src2, src2);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001045 j(zero, on_not_smi_result);
1046
1047 if (src1.is(rax)) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001048 movq(kScratchRegister, src1);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001049 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001050 SmiToInteger32(rax, src1);
1051 SmiToInteger32(src2, src2);
1052
1053 // Test for the edge case of dividing Smi::kMinValue by -1 (will overflow).
1054 Label safe_div;
1055 cmpl(rax, Immediate(Smi::kMinValue));
1056 j(not_equal, &safe_div);
1057 cmpl(src2, Immediate(-1));
1058 j(not_equal, &safe_div);
1059 // Retag inputs and go slow case.
1060 Integer32ToSmi(src2, src2);
1061 if (src1.is(rax)) {
1062 movq(src1, kScratchRegister);
1063 }
1064 jmp(on_not_smi_result);
1065 bind(&safe_div);
1066
ager@chromium.org4af710e2009-09-15 12:20:11 +00001067 // Sign extend eax into edx:eax.
1068 cdq();
1069 idivl(src2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001070 // Restore smi tags on inputs.
1071 Integer32ToSmi(src2, src2);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001072 if (src1.is(rax)) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001073 movq(src1, kScratchRegister);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001074 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001075 // Check for a negative zero result. If the result is zero, and the
1076 // dividend is negative, go slow to return a floating point negative zero.
1077 Label smi_result;
1078 testl(rdx, rdx);
1079 j(not_zero, &smi_result);
1080 testq(src1, src1);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001081 j(negative, on_not_smi_result);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001082 bind(&smi_result);
1083 Integer32ToSmi(dst, rdx);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001084}
1085
1086
1087void MacroAssembler::SmiNot(Register dst, Register src) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001088 ASSERT(!dst.is(kScratchRegister));
1089 ASSERT(!src.is(kScratchRegister));
1090 // Set tag and padding bits before negating, so that they are zero afterwards.
1091 movl(kScratchRegister, Immediate(~0));
ager@chromium.org4af710e2009-09-15 12:20:11 +00001092 if (dst.is(src)) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001093 xor_(dst, kScratchRegister);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001094 } else {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001095 lea(dst, Operand(src, kScratchRegister, times_1, 0));
ager@chromium.org4af710e2009-09-15 12:20:11 +00001096 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001097 not_(dst);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001098}
1099
1100
1101void MacroAssembler::SmiAnd(Register dst, Register src1, Register src2) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001102 ASSERT(!dst.is(src2));
ager@chromium.org4af710e2009-09-15 12:20:11 +00001103 if (!dst.is(src1)) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001104 movq(dst, src1);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001105 }
1106 and_(dst, src2);
1107}
1108
1109
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001110void MacroAssembler::SmiAndConstant(Register dst, Register src, Smi* constant) {
1111 if (constant->value() == 0) {
1112 xor_(dst, dst);
1113 } else if (dst.is(src)) {
1114 ASSERT(!dst.is(kScratchRegister));
1115 Move(kScratchRegister, constant);
1116 and_(dst, kScratchRegister);
1117 } else {
1118 Move(dst, constant);
1119 and_(dst, src);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001120 }
ager@chromium.org4af710e2009-09-15 12:20:11 +00001121}
1122
1123
1124void MacroAssembler::SmiOr(Register dst, Register src1, Register src2) {
1125 if (!dst.is(src1)) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001126 movq(dst, src1);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001127 }
1128 or_(dst, src2);
1129}
1130
1131
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001132void MacroAssembler::SmiOrConstant(Register dst, Register src, Smi* constant) {
1133 if (dst.is(src)) {
1134 ASSERT(!dst.is(kScratchRegister));
1135 Move(kScratchRegister, constant);
1136 or_(dst, kScratchRegister);
1137 } else {
1138 Move(dst, constant);
1139 or_(dst, src);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001140 }
ager@chromium.org4af710e2009-09-15 12:20:11 +00001141}
1142
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001143
ager@chromium.org4af710e2009-09-15 12:20:11 +00001144void MacroAssembler::SmiXor(Register dst, Register src1, Register src2) {
1145 if (!dst.is(src1)) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001146 movq(dst, src1);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001147 }
1148 xor_(dst, src2);
1149}
1150
1151
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001152void MacroAssembler::SmiXorConstant(Register dst, Register src, Smi* constant) {
1153 if (dst.is(src)) {
1154 ASSERT(!dst.is(kScratchRegister));
1155 Move(kScratchRegister, constant);
1156 xor_(dst, kScratchRegister);
1157 } else {
1158 Move(dst, constant);
1159 xor_(dst, src);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001160 }
ager@chromium.org4af710e2009-09-15 12:20:11 +00001161}
1162
1163
ager@chromium.org4af710e2009-09-15 12:20:11 +00001164void MacroAssembler::SmiShiftArithmeticRightConstant(Register dst,
1165 Register src,
1166 int shift_value) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001167 ASSERT(is_uint5(shift_value));
ager@chromium.org4af710e2009-09-15 12:20:11 +00001168 if (shift_value > 0) {
1169 if (dst.is(src)) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001170 sar(dst, Immediate(shift_value + kSmiShift));
1171 shl(dst, Immediate(kSmiShift));
ager@chromium.org4af710e2009-09-15 12:20:11 +00001172 } else {
1173 UNIMPLEMENTED(); // Not used.
1174 }
1175 }
1176}
1177
1178
1179void MacroAssembler::SmiShiftLogicalRightConstant(Register dst,
1180 Register src,
1181 int shift_value,
1182 Label* on_not_smi_result) {
1183 // Logic right shift interprets its result as an *unsigned* number.
1184 if (dst.is(src)) {
1185 UNIMPLEMENTED(); // Not used.
1186 } else {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001187 movq(dst, src);
1188 if (shift_value == 0) {
1189 testq(dst, dst);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001190 j(negative, on_not_smi_result);
1191 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001192 shr(dst, Immediate(shift_value + kSmiShift));
1193 shl(dst, Immediate(kSmiShift));
ager@chromium.org4af710e2009-09-15 12:20:11 +00001194 }
1195}
1196
1197
1198void MacroAssembler::SmiShiftLeftConstant(Register dst,
1199 Register src,
1200 int shift_value,
1201 Label* on_not_smi_result) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001202 if (!dst.is(src)) {
1203 movq(dst, src);
1204 }
1205 if (shift_value > 0) {
1206 shl(dst, Immediate(shift_value));
ager@chromium.org4af710e2009-09-15 12:20:11 +00001207 }
1208}
1209
1210
1211void MacroAssembler::SmiShiftLeft(Register dst,
1212 Register src1,
1213 Register src2,
1214 Label* on_not_smi_result) {
1215 ASSERT(!dst.is(rcx));
1216 Label result_ok;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001217 // Untag shift amount.
1218 if (!dst.is(src1)) {
1219 movq(dst, src1);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001220 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001221 SmiToInteger32(rcx, src2);
1222 // Shift amount specified by lower 5 bits, not six as the shl opcode.
1223 and_(rcx, Immediate(0x1f));
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001224 shl_cl(dst);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001225}
1226
1227
1228void MacroAssembler::SmiShiftLogicalRight(Register dst,
1229 Register src1,
1230 Register src2,
1231 Label* on_not_smi_result) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001232 ASSERT(!dst.is(kScratchRegister));
1233 ASSERT(!src1.is(kScratchRegister));
1234 ASSERT(!src2.is(kScratchRegister));
ager@chromium.org4af710e2009-09-15 12:20:11 +00001235 ASSERT(!dst.is(rcx));
1236 Label result_ok;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001237 if (src1.is(rcx) || src2.is(rcx)) {
1238 movq(kScratchRegister, rcx);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001239 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001240 if (!dst.is(src1)) {
1241 movq(dst, src1);
1242 }
1243 SmiToInteger32(rcx, src2);
1244 orl(rcx, Immediate(kSmiShift));
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001245 shr_cl(dst); // Shift is rcx modulo 0x1f + 32.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001246 shl(dst, Immediate(kSmiShift));
1247 testq(dst, dst);
1248 if (src1.is(rcx) || src2.is(rcx)) {
1249 Label positive_result;
1250 j(positive, &positive_result);
1251 if (src1.is(rcx)) {
1252 movq(src1, kScratchRegister);
1253 } else {
1254 movq(src2, kScratchRegister);
1255 }
1256 jmp(on_not_smi_result);
1257 bind(&positive_result);
1258 } else {
1259 j(negative, on_not_smi_result); // src2 was zero and src1 negative.
1260 }
ager@chromium.org4af710e2009-09-15 12:20:11 +00001261}
1262
1263
1264void MacroAssembler::SmiShiftArithmeticRight(Register dst,
1265 Register src1,
1266 Register src2) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001267 ASSERT(!dst.is(kScratchRegister));
1268 ASSERT(!src1.is(kScratchRegister));
1269 ASSERT(!src2.is(kScratchRegister));
ager@chromium.org4af710e2009-09-15 12:20:11 +00001270 ASSERT(!dst.is(rcx));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001271 if (src1.is(rcx)) {
1272 movq(kScratchRegister, src1);
1273 } else if (src2.is(rcx)) {
1274 movq(kScratchRegister, src2);
1275 }
1276 if (!dst.is(src1)) {
1277 movq(dst, src1);
1278 }
ager@chromium.org4af710e2009-09-15 12:20:11 +00001279 SmiToInteger32(rcx, src2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001280 orl(rcx, Immediate(kSmiShift));
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001281 sar_cl(dst); // Shift 32 + original rcx & 0x1f.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001282 shl(dst, Immediate(kSmiShift));
1283 if (src1.is(rcx)) {
1284 movq(src1, kScratchRegister);
1285 } else if (src2.is(rcx)) {
1286 movq(src2, kScratchRegister);
1287 }
ager@chromium.org4af710e2009-09-15 12:20:11 +00001288}
1289
1290
1291void MacroAssembler::SelectNonSmi(Register dst,
1292 Register src1,
1293 Register src2,
1294 Label* on_not_smis) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001295 ASSERT(!dst.is(kScratchRegister));
1296 ASSERT(!src1.is(kScratchRegister));
1297 ASSERT(!src2.is(kScratchRegister));
ager@chromium.org4af710e2009-09-15 12:20:11 +00001298 ASSERT(!dst.is(src1));
1299 ASSERT(!dst.is(src2));
1300 // Both operands must not be smis.
1301#ifdef DEBUG
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001302 if (allow_stub_calls()) { // Check contains a stub call.
1303 Condition not_both_smis = NegateCondition(CheckBothSmi(src1, src2));
1304 Check(not_both_smis, "Both registers were smis in SelectNonSmi.");
1305 }
ager@chromium.org4af710e2009-09-15 12:20:11 +00001306#endif
1307 ASSERT_EQ(0, kSmiTag);
1308 ASSERT_EQ(0, Smi::FromInt(0));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001309 movl(kScratchRegister, Immediate(kSmiTagMask));
ager@chromium.org4af710e2009-09-15 12:20:11 +00001310 and_(kScratchRegister, src1);
1311 testl(kScratchRegister, src2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001312 // If non-zero then both are smis.
ager@chromium.org4af710e2009-09-15 12:20:11 +00001313 j(not_zero, on_not_smis);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001314
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001315 // Exactly one operand is a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +00001316 ASSERT_EQ(1, static_cast<int>(kSmiTagMask));
1317 // kScratchRegister still holds src1 & kSmiTag, which is either zero or one.
1318 subq(kScratchRegister, Immediate(1));
1319 // If src1 is a smi, then scratch register all 1s, else it is all 0s.
1320 movq(dst, src1);
1321 xor_(dst, src2);
1322 and_(dst, kScratchRegister);
1323 // If src1 is a smi, dst holds src1 ^ src2, else it is zero.
1324 xor_(dst, src1);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001325 // If src1 is a smi, dst is src2, else it is src1, i.e., the non-smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +00001326}
1327
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001328SmiIndex MacroAssembler::SmiToIndex(Register dst,
1329 Register src,
1330 int shift) {
ager@chromium.org4af710e2009-09-15 12:20:11 +00001331 ASSERT(is_uint6(shift));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001332 // There is a possible optimization if shift is in the range 60-63, but that
1333 // will (and must) never happen.
1334 if (!dst.is(src)) {
1335 movq(dst, src);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001336 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001337 if (shift < kSmiShift) {
1338 sar(dst, Immediate(kSmiShift - shift));
1339 } else {
1340 shl(dst, Immediate(shift - kSmiShift));
ager@chromium.org4af710e2009-09-15 12:20:11 +00001341 }
ager@chromium.org4af710e2009-09-15 12:20:11 +00001342 return SmiIndex(dst, times_1);
1343}
1344
ager@chromium.org4af710e2009-09-15 12:20:11 +00001345SmiIndex MacroAssembler::SmiToNegativeIndex(Register dst,
1346 Register src,
1347 int shift) {
1348 // Register src holds a positive smi.
1349 ASSERT(is_uint6(shift));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001350 if (!dst.is(src)) {
1351 movq(dst, src);
ager@chromium.org4af710e2009-09-15 12:20:11 +00001352 }
ager@chromium.org4af710e2009-09-15 12:20:11 +00001353 neg(dst);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001354 if (shift < kSmiShift) {
1355 sar(dst, Immediate(kSmiShift - shift));
1356 } else {
1357 shl(dst, Immediate(shift - kSmiShift));
1358 }
ager@chromium.org4af710e2009-09-15 12:20:11 +00001359 return SmiIndex(dst, times_1);
1360}
1361
1362
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001363void MacroAssembler::JumpIfSmi(Register src, Label* on_smi) {
1364 ASSERT_EQ(0, kSmiTag);
1365 Condition smi = CheckSmi(src);
1366 j(smi, on_smi);
1367}
1368
1369
1370void MacroAssembler::JumpIfNotSmi(Register src, Label* on_not_smi) {
1371 Condition smi = CheckSmi(src);
1372 j(NegateCondition(smi), on_not_smi);
1373}
1374
1375
1376void MacroAssembler::JumpIfNotPositiveSmi(Register src,
1377 Label* on_not_positive_smi) {
1378 Condition positive_smi = CheckPositiveSmi(src);
1379 j(NegateCondition(positive_smi), on_not_positive_smi);
1380}
1381
1382
1383void MacroAssembler::JumpIfSmiEqualsConstant(Register src,
1384 Smi* constant,
1385 Label* on_equals) {
1386 SmiCompare(src, constant);
1387 j(equal, on_equals);
1388}
1389
1390
1391void MacroAssembler::JumpIfNotValidSmiValue(Register src, Label* on_invalid) {
1392 Condition is_valid = CheckInteger32ValidSmiValue(src);
1393 j(NegateCondition(is_valid), on_invalid);
1394}
1395
1396
ager@chromium.org3811b432009-10-28 14:53:37 +00001397void MacroAssembler::JumpIfUIntNotValidSmiValue(Register src,
1398 Label* on_invalid) {
1399 Condition is_valid = CheckUInteger32ValidSmiValue(src);
1400 j(NegateCondition(is_valid), on_invalid);
1401}
1402
1403
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001404void MacroAssembler::JumpIfNotBothSmi(Register src1, Register src2,
1405 Label* on_not_both_smi) {
1406 Condition both_smi = CheckBothSmi(src1, src2);
1407 j(NegateCondition(both_smi), on_not_both_smi);
1408}
ager@chromium.org4af710e2009-09-15 12:20:11 +00001409
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001410
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001411void MacroAssembler::JumpIfNotBothPositiveSmi(Register src1, Register src2,
1412 Label* on_not_both_smi) {
1413 Condition both_smi = CheckBothPositiveSmi(src1, src2);
1414 j(NegateCondition(both_smi), on_not_both_smi);
1415}
1416
1417
1418
1419void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register first_object,
1420 Register second_object,
1421 Register scratch1,
1422 Register scratch2,
1423 Label* on_fail) {
1424 // Check that both objects are not smis.
1425 Condition either_smi = CheckEitherSmi(first_object, second_object);
1426 j(either_smi, on_fail);
1427
1428 // Load instance type for both strings.
1429 movq(scratch1, FieldOperand(first_object, HeapObject::kMapOffset));
1430 movq(scratch2, FieldOperand(second_object, HeapObject::kMapOffset));
1431 movzxbl(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset));
1432 movzxbl(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset));
1433
1434 // Check that both are flat ascii strings.
1435 ASSERT(kNotStringTag != 0);
1436 const int kFlatAsciiStringMask =
1437 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
1438 const int kFlatAsciiStringTag = ASCII_STRING_TYPE;
1439
1440 andl(scratch1, Immediate(kFlatAsciiStringMask));
1441 andl(scratch2, Immediate(kFlatAsciiStringMask));
1442 // Interleave the bits to check both scratch1 and scratch2 in one test.
1443 ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
1444 lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
1445 cmpl(scratch1,
1446 Immediate(kFlatAsciiStringTag + (kFlatAsciiStringTag << 3)));
1447 j(not_equal, on_fail);
1448}
1449
1450
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001451void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii(
1452 Register instance_type,
1453 Register scratch,
1454 Label *failure) {
1455 if (!scratch.is(instance_type)) {
1456 movl(scratch, instance_type);
1457 }
1458
1459 const int kFlatAsciiStringMask =
1460 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
1461
1462 andl(scratch, Immediate(kFlatAsciiStringMask));
1463 cmpl(scratch, Immediate(kStringTag | kSeqStringTag | kAsciiStringTag));
1464 j(not_equal, failure);
1465}
1466
1467
1468void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialAscii(
1469 Register first_object_instance_type,
1470 Register second_object_instance_type,
1471 Register scratch1,
1472 Register scratch2,
1473 Label* on_fail) {
1474 // Load instance type for both strings.
1475 movq(scratch1, first_object_instance_type);
1476 movq(scratch2, second_object_instance_type);
1477
1478 // Check that both are flat ascii strings.
1479 ASSERT(kNotStringTag != 0);
1480 const int kFlatAsciiStringMask =
1481 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
1482 const int kFlatAsciiStringTag = ASCII_STRING_TYPE;
1483
1484 andl(scratch1, Immediate(kFlatAsciiStringMask));
1485 andl(scratch2, Immediate(kFlatAsciiStringMask));
1486 // Interleave the bits to check both scratch1 and scratch2 in one test.
1487 ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
1488 lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
1489 cmpl(scratch1,
1490 Immediate(kFlatAsciiStringTag + (kFlatAsciiStringTag << 3)));
1491 j(not_equal, on_fail);
1492}
1493
1494
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001495void MacroAssembler::Move(Register dst, Handle<Object> source) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001496 ASSERT(!source->IsFailure());
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001497 if (source->IsSmi()) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001498 Move(dst, Smi::cast(*source));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001499 } else {
1500 movq(dst, source, RelocInfo::EMBEDDED_OBJECT);
1501 }
1502}
1503
1504
1505void MacroAssembler::Move(const Operand& dst, Handle<Object> source) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001506 ASSERT(!source->IsFailure());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001507 if (source->IsSmi()) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001508 Move(dst, Smi::cast(*source));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001509 } else {
1510 movq(kScratchRegister, source, RelocInfo::EMBEDDED_OBJECT);
1511 movq(dst, kScratchRegister);
1512 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001513}
1514
1515
1516void MacroAssembler::Cmp(Register dst, Handle<Object> source) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001517 if (source->IsSmi()) {
1518 SmiCompare(dst, Smi::cast(*source));
1519 } else {
1520 Move(kScratchRegister, source);
1521 cmpq(dst, kScratchRegister);
1522 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001523}
1524
1525
ager@chromium.org3e875802009-06-29 08:26:34 +00001526void MacroAssembler::Cmp(const Operand& dst, Handle<Object> source) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001527 if (source->IsSmi()) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001528 SmiCompare(dst, Smi::cast(*source));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001529 } else {
1530 ASSERT(source->IsHeapObject());
1531 movq(kScratchRegister, source, RelocInfo::EMBEDDED_OBJECT);
1532 cmpq(dst, kScratchRegister);
1533 }
ager@chromium.org3e875802009-06-29 08:26:34 +00001534}
1535
1536
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001537void MacroAssembler::Push(Handle<Object> source) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001538 if (source->IsSmi()) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001539 Push(Smi::cast(*source));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001540 } else {
1541 ASSERT(source->IsHeapObject());
1542 movq(kScratchRegister, source, RelocInfo::EMBEDDED_OBJECT);
1543 push(kScratchRegister);
1544 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001545}
1546
1547
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001548void MacroAssembler::Push(Smi* source) {
ager@chromium.org3811b432009-10-28 14:53:37 +00001549 intptr_t smi = reinterpret_cast<intptr_t>(source);
1550 if (is_int32(smi)) {
1551 push(Immediate(static_cast<int32_t>(smi)));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001552 } else {
ager@chromium.org3811b432009-10-28 14:53:37 +00001553 Set(kScratchRegister, smi);
1554 push(kScratchRegister);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001555 }
1556}
1557
1558
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001559void MacroAssembler::Drop(int stack_elements) {
1560 if (stack_elements > 0) {
1561 addq(rsp, Immediate(stack_elements * kPointerSize));
1562 }
1563}
1564
1565
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001566void MacroAssembler::Test(const Operand& src, Smi* source) {
ager@chromium.org3811b432009-10-28 14:53:37 +00001567 intptr_t smi = reinterpret_cast<intptr_t>(source);
1568 if (is_int32(smi)) {
1569 testl(src, Immediate(static_cast<int32_t>(smi)));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001570 } else {
ager@chromium.org3811b432009-10-28 14:53:37 +00001571 Move(kScratchRegister, source);
1572 testq(src, kScratchRegister);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001573 }
1574}
1575
1576
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001577void MacroAssembler::Jump(ExternalReference ext) {
1578 movq(kScratchRegister, ext);
1579 jmp(kScratchRegister);
1580}
1581
1582
1583void MacroAssembler::Jump(Address destination, RelocInfo::Mode rmode) {
1584 movq(kScratchRegister, destination, rmode);
1585 jmp(kScratchRegister);
1586}
1587
1588
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001589void MacroAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001590 // TODO(X64): Inline this
1591 jmp(code_object, rmode);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001592}
1593
1594
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001595void MacroAssembler::Call(ExternalReference ext) {
1596 movq(kScratchRegister, ext);
1597 call(kScratchRegister);
1598}
1599
1600
1601void MacroAssembler::Call(Address destination, RelocInfo::Mode rmode) {
1602 movq(kScratchRegister, destination, rmode);
1603 call(kScratchRegister);
1604}
1605
1606
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001607void MacroAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001608 ASSERT(RelocInfo::IsCodeTarget(rmode));
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001609 WriteRecordedPositions();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001610 call(code_object, rmode);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001611}
1612
1613
ager@chromium.orge2902be2009-06-08 12:21:35 +00001614void MacroAssembler::PushTryHandler(CodeLocation try_location,
1615 HandlerType type) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001616 // Adjust this code if not the case.
1617 ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
1618
1619 // The pc (return address) is already on TOS. This code pushes state,
1620 // frame pointer and current handler. Check that they are expected
1621 // next on the stack, in that order.
ager@chromium.orge2902be2009-06-08 12:21:35 +00001622 ASSERT_EQ(StackHandlerConstants::kStateOffset,
1623 StackHandlerConstants::kPCOffset - kPointerSize);
ager@chromium.orge2902be2009-06-08 12:21:35 +00001624 ASSERT_EQ(StackHandlerConstants::kFPOffset,
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001625 StackHandlerConstants::kStateOffset - kPointerSize);
1626 ASSERT_EQ(StackHandlerConstants::kNextOffset,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001627 StackHandlerConstants::kFPOffset - kPointerSize);
1628
1629 if (try_location == IN_JAVASCRIPT) {
1630 if (type == TRY_CATCH_HANDLER) {
1631 push(Immediate(StackHandler::TRY_CATCH));
1632 } else {
1633 push(Immediate(StackHandler::TRY_FINALLY));
1634 }
ager@chromium.orge2902be2009-06-08 12:21:35 +00001635 push(rbp);
ager@chromium.orge2902be2009-06-08 12:21:35 +00001636 } else {
1637 ASSERT(try_location == IN_JS_ENTRY);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001638 // The frame pointer does not point to a JS frame so we save NULL
1639 // for rbp. We expect the code throwing an exception to check rbp
1640 // before dereferencing it to restore the context.
ager@chromium.orge2902be2009-06-08 12:21:35 +00001641 push(Immediate(StackHandler::ENTRY));
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001642 push(Immediate(0)); // NULL frame pointer.
ager@chromium.orge2902be2009-06-08 12:21:35 +00001643 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001644 // Save the current handler.
ager@chromium.orge2902be2009-06-08 12:21:35 +00001645 movq(kScratchRegister, ExternalReference(Top::k_handler_address));
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001646 push(Operand(kScratchRegister, 0));
ager@chromium.orge2902be2009-06-08 12:21:35 +00001647 // Link this handler.
1648 movq(Operand(kScratchRegister, 0), rsp);
1649}
1650
1651
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001652void MacroAssembler::PopTryHandler() {
1653 ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
1654 // Unlink this handler.
1655 movq(kScratchRegister, ExternalReference(Top::k_handler_address));
1656 pop(Operand(kScratchRegister, 0));
1657 // Remove the remaining fields.
1658 addq(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize));
1659}
1660
1661
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001662void MacroAssembler::Ret() {
1663 ret(0);
1664}
1665
1666
ager@chromium.org3e875802009-06-29 08:26:34 +00001667void MacroAssembler::FCmp() {
ager@chromium.org3811b432009-10-28 14:53:37 +00001668 fucomip();
1669 ffree(0);
1670 fincstp();
ager@chromium.org3e875802009-06-29 08:26:34 +00001671}
1672
1673
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001674void MacroAssembler::CmpObjectType(Register heap_object,
1675 InstanceType type,
1676 Register map) {
1677 movq(map, FieldOperand(heap_object, HeapObject::kMapOffset));
1678 CmpInstanceType(map, type);
1679}
1680
1681
1682void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
1683 cmpb(FieldOperand(map, Map::kInstanceTypeOffset),
1684 Immediate(static_cast<int8_t>(type)));
1685}
1686
1687
ager@chromium.org5c838252010-02-19 08:53:10 +00001688void MacroAssembler::CheckMap(Register obj,
1689 Handle<Map> map,
1690 Label* fail,
1691 bool is_heap_object) {
1692 if (!is_heap_object) {
1693 JumpIfSmi(obj, fail);
1694 }
1695 Cmp(FieldOperand(obj, HeapObject::kMapOffset), map);
1696 j(not_equal, fail);
1697}
1698
1699
1700void MacroAssembler::AbortIfNotNumber(Register object, const char* msg) {
1701 Label ok;
1702 Condition is_smi = CheckSmi(object);
1703 j(is_smi, &ok);
1704 Cmp(FieldOperand(object, HeapObject::kMapOffset),
1705 Factory::heap_number_map());
1706 Assert(equal, msg);
1707 bind(&ok);
1708}
1709
1710
lrn@chromium.org25156de2010-04-06 13:10:27 +00001711void MacroAssembler::AbortIfNotSmi(Register object, const char* msg) {
1712 Label ok;
1713 Condition is_smi = CheckSmi(object);
1714 j(is_smi, &ok);
1715 Assert(equal, msg);
1716 bind(&ok);
1717}
1718
1719
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001720Condition MacroAssembler::IsObjectStringType(Register heap_object,
1721 Register map,
1722 Register instance_type) {
1723 movq(map, FieldOperand(heap_object, HeapObject::kMapOffset));
1724 movzxbl(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
1725 ASSERT(kNotStringTag != 0);
1726 testb(instance_type, Immediate(kIsNotStringMask));
1727 return zero;
1728}
1729
1730
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001731void MacroAssembler::TryGetFunctionPrototype(Register function,
1732 Register result,
1733 Label* miss) {
1734 // Check that the receiver isn't a smi.
1735 testl(function, Immediate(kSmiTagMask));
1736 j(zero, miss);
1737
1738 // Check that the function really is a function.
1739 CmpObjectType(function, JS_FUNCTION_TYPE, result);
1740 j(not_equal, miss);
1741
1742 // Make sure that the function has an instance prototype.
1743 Label non_instance;
1744 testb(FieldOperand(result, Map::kBitFieldOffset),
1745 Immediate(1 << Map::kHasNonInstancePrototype));
1746 j(not_zero, &non_instance);
1747
1748 // Get the prototype or initial map from the function.
1749 movq(result,
1750 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
1751
1752 // If the prototype or initial map is the hole, don't return it and
1753 // simply miss the cache instead. This will allow us to allocate a
1754 // prototype object on-demand in the runtime system.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001755 CompareRoot(result, Heap::kTheHoleValueRootIndex);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001756 j(equal, miss);
1757
1758 // If the function does not have an initial map, we're done.
1759 Label done;
1760 CmpObjectType(result, MAP_TYPE, kScratchRegister);
1761 j(not_equal, &done);
1762
1763 // Get the prototype from the initial map.
1764 movq(result, FieldOperand(result, Map::kPrototypeOffset));
1765 jmp(&done);
1766
1767 // Non-instance prototype: Fetch prototype from constructor field
1768 // in initial map.
1769 bind(&non_instance);
1770 movq(result, FieldOperand(result, Map::kConstructorOffset));
1771
1772 // All done.
1773 bind(&done);
1774}
1775
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001776
1777void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
1778 if (FLAG_native_code_counters && counter->Enabled()) {
1779 movq(kScratchRegister, ExternalReference(counter));
1780 movl(Operand(kScratchRegister, 0), Immediate(value));
1781 }
1782}
1783
1784
1785void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) {
1786 ASSERT(value > 0);
1787 if (FLAG_native_code_counters && counter->Enabled()) {
1788 movq(kScratchRegister, ExternalReference(counter));
1789 Operand operand(kScratchRegister, 0);
1790 if (value == 1) {
1791 incl(operand);
1792 } else {
1793 addl(operand, Immediate(value));
1794 }
1795 }
1796}
1797
1798
1799void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
1800 ASSERT(value > 0);
1801 if (FLAG_native_code_counters && counter->Enabled()) {
1802 movq(kScratchRegister, ExternalReference(counter));
1803 Operand operand(kScratchRegister, 0);
1804 if (value == 1) {
1805 decl(operand);
1806 } else {
1807 subl(operand, Immediate(value));
1808 }
1809 }
1810}
1811
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001812#ifdef ENABLE_DEBUGGER_SUPPORT
1813
1814void MacroAssembler::PushRegistersFromMemory(RegList regs) {
1815 ASSERT((regs & ~kJSCallerSaved) == 0);
1816 // Push the content of the memory location to the stack.
1817 for (int i = 0; i < kNumJSCallerSaved; i++) {
1818 int r = JSCallerSavedCode(i);
1819 if ((regs & (1 << r)) != 0) {
1820 ExternalReference reg_addr =
1821 ExternalReference(Debug_Address::Register(i));
1822 movq(kScratchRegister, reg_addr);
1823 push(Operand(kScratchRegister, 0));
1824 }
1825 }
1826}
1827
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001828
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001829void MacroAssembler::SaveRegistersToMemory(RegList regs) {
1830 ASSERT((regs & ~kJSCallerSaved) == 0);
1831 // Copy the content of registers to memory location.
1832 for (int i = 0; i < kNumJSCallerSaved; i++) {
1833 int r = JSCallerSavedCode(i);
1834 if ((regs & (1 << r)) != 0) {
1835 Register reg = { r };
1836 ExternalReference reg_addr =
1837 ExternalReference(Debug_Address::Register(i));
1838 movq(kScratchRegister, reg_addr);
1839 movq(Operand(kScratchRegister, 0), reg);
1840 }
1841 }
1842}
1843
1844
1845void MacroAssembler::RestoreRegistersFromMemory(RegList regs) {
1846 ASSERT((regs & ~kJSCallerSaved) == 0);
1847 // Copy the content of memory location to registers.
1848 for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
1849 int r = JSCallerSavedCode(i);
1850 if ((regs & (1 << r)) != 0) {
1851 Register reg = { r };
1852 ExternalReference reg_addr =
1853 ExternalReference(Debug_Address::Register(i));
1854 movq(kScratchRegister, reg_addr);
1855 movq(reg, Operand(kScratchRegister, 0));
1856 }
1857 }
1858}
1859
1860
1861void MacroAssembler::PopRegistersToMemory(RegList regs) {
1862 ASSERT((regs & ~kJSCallerSaved) == 0);
1863 // Pop the content from the stack to the memory location.
1864 for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
1865 int r = JSCallerSavedCode(i);
1866 if ((regs & (1 << r)) != 0) {
1867 ExternalReference reg_addr =
1868 ExternalReference(Debug_Address::Register(i));
1869 movq(kScratchRegister, reg_addr);
1870 pop(Operand(kScratchRegister, 0));
1871 }
1872 }
1873}
1874
1875
1876void MacroAssembler::CopyRegistersFromStackToMemory(Register base,
1877 Register scratch,
1878 RegList regs) {
1879 ASSERT(!scratch.is(kScratchRegister));
1880 ASSERT(!base.is(kScratchRegister));
1881 ASSERT(!base.is(scratch));
1882 ASSERT((regs & ~kJSCallerSaved) == 0);
1883 // Copy the content of the stack to the memory location and adjust base.
1884 for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
1885 int r = JSCallerSavedCode(i);
1886 if ((regs & (1 << r)) != 0) {
1887 movq(scratch, Operand(base, 0));
1888 ExternalReference reg_addr =
1889 ExternalReference(Debug_Address::Register(i));
1890 movq(kScratchRegister, reg_addr);
1891 movq(Operand(kScratchRegister, 0), scratch);
1892 lea(base, Operand(base, kPointerSize));
1893 }
1894 }
1895}
1896
ager@chromium.org5c838252010-02-19 08:53:10 +00001897void MacroAssembler::DebugBreak() {
1898 ASSERT(allow_stub_calls());
1899 xor_(rax, rax); // no arguments
1900 movq(rbx, ExternalReference(Runtime::kDebugBreak));
1901 CEntryStub ces(1);
1902 Call(ces.GetCode(), RelocInfo::DEBUG_BREAK);
ager@chromium.org3e875802009-06-29 08:26:34 +00001903}
ager@chromium.org5c838252010-02-19 08:53:10 +00001904#endif // ENABLE_DEBUGGER_SUPPORT
ager@chromium.org3e875802009-06-29 08:26:34 +00001905
1906
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001907void MacroAssembler::InvokePrologue(const ParameterCount& expected,
1908 const ParameterCount& actual,
1909 Handle<Code> code_constant,
1910 Register code_register,
1911 Label* done,
1912 InvokeFlag flag) {
1913 bool definitely_matches = false;
1914 Label invoke;
1915 if (expected.is_immediate()) {
1916 ASSERT(actual.is_immediate());
1917 if (expected.immediate() == actual.immediate()) {
1918 definitely_matches = true;
1919 } else {
1920 movq(rax, Immediate(actual.immediate()));
1921 if (expected.immediate() ==
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001922 SharedFunctionInfo::kDontAdaptArgumentsSentinel) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001923 // Don't worry about adapting arguments for built-ins that
1924 // don't want that done. Skip adaption code by making it look
1925 // like we have a match between expected and actual number of
1926 // arguments.
1927 definitely_matches = true;
1928 } else {
1929 movq(rbx, Immediate(expected.immediate()));
1930 }
1931 }
1932 } else {
1933 if (actual.is_immediate()) {
1934 // Expected is in register, actual is immediate. This is the
1935 // case when we invoke function values without going through the
1936 // IC mechanism.
1937 cmpq(expected.reg(), Immediate(actual.immediate()));
1938 j(equal, &invoke);
1939 ASSERT(expected.reg().is(rbx));
1940 movq(rax, Immediate(actual.immediate()));
1941 } else if (!expected.reg().is(actual.reg())) {
1942 // Both expected and actual are in (different) registers. This
1943 // is the case when we invoke functions using call and apply.
1944 cmpq(expected.reg(), actual.reg());
1945 j(equal, &invoke);
1946 ASSERT(actual.reg().is(rax));
1947 ASSERT(expected.reg().is(rbx));
1948 }
1949 }
1950
1951 if (!definitely_matches) {
1952 Handle<Code> adaptor =
1953 Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
1954 if (!code_constant.is_null()) {
1955 movq(rdx, code_constant, RelocInfo::EMBEDDED_OBJECT);
1956 addq(rdx, Immediate(Code::kHeaderSize - kHeapObjectTag));
1957 } else if (!code_register.is(rdx)) {
1958 movq(rdx, code_register);
1959 }
1960
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001961 if (flag == CALL_FUNCTION) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001962 Call(adaptor, RelocInfo::CODE_TARGET);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001963 jmp(done);
1964 } else {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001965 Jump(adaptor, RelocInfo::CODE_TARGET);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001966 }
1967 bind(&invoke);
1968 }
1969}
1970
1971
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001972void MacroAssembler::InvokeCode(Register code,
1973 const ParameterCount& expected,
1974 const ParameterCount& actual,
1975 InvokeFlag flag) {
1976 Label done;
1977 InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag);
1978 if (flag == CALL_FUNCTION) {
1979 call(code);
1980 } else {
1981 ASSERT(flag == JUMP_FUNCTION);
1982 jmp(code);
1983 }
1984 bind(&done);
1985}
1986
1987
1988void MacroAssembler::InvokeCode(Handle<Code> code,
1989 const ParameterCount& expected,
1990 const ParameterCount& actual,
1991 RelocInfo::Mode rmode,
1992 InvokeFlag flag) {
1993 Label done;
1994 Register dummy = rax;
1995 InvokePrologue(expected, actual, code, dummy, &done, flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001996 if (flag == CALL_FUNCTION) {
ager@chromium.org3e875802009-06-29 08:26:34 +00001997 Call(code, rmode);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001998 } else {
1999 ASSERT(flag == JUMP_FUNCTION);
ager@chromium.org3e875802009-06-29 08:26:34 +00002000 Jump(code, rmode);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002001 }
2002 bind(&done);
2003}
2004
2005
2006void MacroAssembler::InvokeFunction(Register function,
2007 const ParameterCount& actual,
2008 InvokeFlag flag) {
2009 ASSERT(function.is(rdi));
2010 movq(rdx, FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
2011 movq(rsi, FieldOperand(function, JSFunction::kContextOffset));
ager@chromium.org3e875802009-06-29 08:26:34 +00002012 movsxlq(rbx,
2013 FieldOperand(rdx, SharedFunctionInfo::kFormalParameterCountOffset));
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002014 movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002015 // Advances rdx to the end of the Code object header, to the start of
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002016 // the executable code.
2017 lea(rdx, FieldOperand(rdx, Code::kHeaderSize));
2018
2019 ParameterCount expected(rbx);
2020 InvokeCode(rdx, expected, actual, flag);
2021}
2022
2023
ager@chromium.org5c838252010-02-19 08:53:10 +00002024void MacroAssembler::InvokeFunction(JSFunction* function,
2025 const ParameterCount& actual,
2026 InvokeFlag flag) {
2027 ASSERT(function->is_compiled());
2028 // Get the function and setup the context.
2029 Move(rdi, Handle<JSFunction>(function));
2030 movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
2031
2032 // Invoke the cached code.
2033 Handle<Code> code(function->code());
2034 ParameterCount expected(function->shared()->formal_parameter_count());
2035 InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag);
2036}
2037
2038
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002039void MacroAssembler::EnterFrame(StackFrame::Type type) {
2040 push(rbp);
2041 movq(rbp, rsp);
2042 push(rsi); // Context.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002043 Push(Smi::FromInt(type));
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002044 movq(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT);
2045 push(kScratchRegister);
2046 if (FLAG_debug_code) {
2047 movq(kScratchRegister,
2048 Factory::undefined_value(),
2049 RelocInfo::EMBEDDED_OBJECT);
2050 cmpq(Operand(rsp, 0), kScratchRegister);
2051 Check(not_equal, "code object not properly patched");
2052 }
2053}
2054
2055
2056void MacroAssembler::LeaveFrame(StackFrame::Type type) {
2057 if (FLAG_debug_code) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002058 Move(kScratchRegister, Smi::FromInt(type));
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002059 cmpq(Operand(rbp, StandardFrameConstants::kMarkerOffset), kScratchRegister);
2060 Check(equal, "stack frame types must match");
2061 }
2062 movq(rsp, rbp);
2063 pop(rbp);
2064}
2065
2066
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002067void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002068 // Setup the frame structure on the stack.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002069 // All constants are relative to the frame pointer of the exit frame.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002070 ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize);
2071 ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize);
2072 ASSERT(ExitFrameConstants::kCallerFPOffset == 0 * kPointerSize);
2073 push(rbp);
2074 movq(rbp, rsp);
2075
2076 // Reserve room for entry stack pointer and push the debug marker.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002077 ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize);
ager@chromium.org5c838252010-02-19 08:53:10 +00002078 push(Immediate(0)); // Saved entry sp, patched before call.
2079 movq(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT);
2080 push(kScratchRegister); // Accessed from EditFrame::code_slot.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002081
2082 // Save the frame pointer and the context in top.
2083 ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
2084 ExternalReference context_address(Top::k_context_address);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002085 movq(r14, rax); // Backup rax before we use it.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002086
2087 movq(rax, rbp);
2088 store_rax(c_entry_fp_address);
2089 movq(rax, rsi);
2090 store_rax(context_address);
2091
2092 // Setup argv in callee-saved register r15. It is reused in LeaveExitFrame,
2093 // so it must be retained across the C-call.
2094 int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002095 lea(r15, Operand(rbp, r14, times_pointer_size, offset));
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002096
2097#ifdef ENABLE_DEBUGGER_SUPPORT
2098 // Save the state of all registers to the stack from the memory
2099 // location. This is needed to allow nested break points.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002100 if (mode == ExitFrame::MODE_DEBUG) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002101 // TODO(1243899): This should be symmetric to
2102 // CopyRegistersFromStackToMemory() but it isn't! esp is assumed
2103 // correct here, but computed for the other call. Very error
2104 // prone! FIX THIS. Actually there are deeper problems with
2105 // register saving than this asymmetry (see the bug report
2106 // associated with this issue).
2107 PushRegistersFromMemory(kJSCallerSaved);
2108 }
2109#endif
2110
ager@chromium.orga1645e22009-09-09 19:27:10 +00002111#ifdef _WIN64
2112 // Reserve space on stack for result and argument structures, if necessary.
2113 int result_stack_space = (result_size < 2) ? 0 : result_size * kPointerSize;
2114 // Reserve space for the Arguments object. The Windows 64-bit ABI
2115 // requires us to pass this structure as a pointer to its location on
2116 // the stack. The structure contains 2 values.
2117 int argument_stack_space = 2 * kPointerSize;
2118 // We also need backing space for 4 parameters, even though
2119 // we only pass one or two parameter, and it is in a register.
2120 int argument_mirror_space = 4 * kPointerSize;
2121 int total_stack_space =
2122 argument_mirror_space + argument_stack_space + result_stack_space;
2123 subq(rsp, Immediate(total_stack_space));
2124#endif
2125
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002126 // Get the required frame alignment for the OS.
2127 static const int kFrameAlignment = OS::ActivationFrameAlignment();
2128 if (kFrameAlignment > 0) {
2129 ASSERT(IsPowerOf2(kFrameAlignment));
2130 movq(kScratchRegister, Immediate(-kFrameAlignment));
2131 and_(rsp, kScratchRegister);
2132 }
2133
2134 // Patch the saved entry sp.
2135 movq(Operand(rbp, ExitFrameConstants::kSPOffset), rsp);
2136}
2137
2138
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002139void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode, int result_size) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002140 // Registers:
2141 // r15 : argv
2142#ifdef ENABLE_DEBUGGER_SUPPORT
2143 // Restore the memory copy of the registers by digging them out from
2144 // the stack. This is needed to allow nested break points.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002145 if (mode == ExitFrame::MODE_DEBUG) {
ager@chromium.orga1645e22009-09-09 19:27:10 +00002146 // It's okay to clobber register rbx below because we don't need
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002147 // the function pointer after this.
2148 const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002149 int kOffset = ExitFrameConstants::kCodeOffset - kCallerSavedSize;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002150 lea(rbx, Operand(rbp, kOffset));
2151 CopyRegistersFromStackToMemory(rbx, rcx, kJSCallerSaved);
2152 }
2153#endif
2154
2155 // Get the return address from the stack and restore the frame pointer.
2156 movq(rcx, Operand(rbp, 1 * kPointerSize));
2157 movq(rbp, Operand(rbp, 0 * kPointerSize));
2158
ager@chromium.orga1645e22009-09-09 19:27:10 +00002159 // Pop everything up to and including the arguments and the receiver
2160 // from the caller stack.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002161 lea(rsp, Operand(r15, 1 * kPointerSize));
2162
2163 // Restore current context from top and clear it in debug mode.
2164 ExternalReference context_address(Top::k_context_address);
2165 movq(kScratchRegister, context_address);
2166 movq(rsi, Operand(kScratchRegister, 0));
2167#ifdef DEBUG
2168 movq(Operand(kScratchRegister, 0), Immediate(0));
2169#endif
2170
2171 // Push the return address to get ready to return.
2172 push(rcx);
2173
2174 // Clear the top frame.
2175 ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
2176 movq(kScratchRegister, c_entry_fp_address);
2177 movq(Operand(kScratchRegister, 0), Immediate(0));
2178}
2179
2180
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002181Register MacroAssembler::CheckMaps(JSObject* object,
2182 Register object_reg,
2183 JSObject* holder,
2184 Register holder_reg,
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002185 Register scratch,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002186 int save_at_depth,
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002187 Label* miss) {
2188 // Make sure there's no overlap between scratch and the other
2189 // registers.
2190 ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg));
2191
2192 // Keep track of the current object in register reg. On the first
2193 // iteration, reg is an alias for object_reg, on later iterations,
2194 // it is an alias for holder_reg.
2195 Register reg = object_reg;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002196 int depth = 0;
2197
2198 if (save_at_depth == depth) {
2199 movq(Operand(rsp, kPointerSize), reg);
2200 }
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002201
2202 // Check the maps in the prototype chain.
2203 // Traverse the prototype chain from the object and do map checks.
2204 while (object != holder) {
2205 depth++;
2206
2207 // Only global objects and objects that do not require access
2208 // checks are allowed in stubs.
2209 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2210
2211 JSObject* prototype = JSObject::cast(object->GetPrototype());
2212 if (Heap::InNewSpace(prototype)) {
2213 // Get the map of the current object.
2214 movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
2215 Cmp(scratch, Handle<Map>(object->map()));
2216 // Branch on the result of the map check.
2217 j(not_equal, miss);
2218 // Check access rights to the global object. This has to happen
2219 // after the map check so that we know that the object is
2220 // actually a global object.
2221 if (object->IsJSGlobalProxy()) {
2222 CheckAccessGlobalProxy(reg, scratch, miss);
2223
2224 // Restore scratch register to be the map of the object.
2225 // We load the prototype from the map in the scratch register.
2226 movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
2227 }
2228 // The prototype is in new space; we cannot store a reference
2229 // to it in the code. Load it from the map.
2230 reg = holder_reg; // from now the object is in holder_reg
2231 movq(reg, FieldOperand(scratch, Map::kPrototypeOffset));
2232
2233 } else {
2234 // Check the map of the current object.
2235 Cmp(FieldOperand(reg, HeapObject::kMapOffset),
2236 Handle<Map>(object->map()));
2237 // Branch on the result of the map check.
2238 j(not_equal, miss);
2239 // Check access rights to the global object. This has to happen
2240 // after the map check so that we know that the object is
2241 // actually a global object.
2242 if (object->IsJSGlobalProxy()) {
2243 CheckAccessGlobalProxy(reg, scratch, miss);
2244 }
2245 // The prototype is in old space; load it directly.
2246 reg = holder_reg; // from now the object is in holder_reg
2247 Move(reg, Handle<JSObject>(prototype));
2248 }
2249
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002250 if (save_at_depth == depth) {
2251 movq(Operand(rsp, kPointerSize), reg);
2252 }
2253
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002254 // Go to the next object in the prototype chain.
2255 object = prototype;
2256 }
2257
2258 // Check the holder map.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002259 Cmp(FieldOperand(reg, HeapObject::kMapOffset), Handle<Map>(holder->map()));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002260 j(not_equal, miss);
2261
2262 // Log the check depth.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002263 LOG(IntEvent("check-maps-depth", depth + 1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002264
2265 // Perform security check for access to the global object and return
2266 // the holder register.
2267 ASSERT(object == holder);
2268 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2269 if (object->IsJSGlobalProxy()) {
2270 CheckAccessGlobalProxy(reg, scratch, miss);
2271 }
2272 return reg;
2273}
2274
2275
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002276void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
2277 Register scratch,
2278 Label* miss) {
2279 Label same_contexts;
2280
2281 ASSERT(!holder_reg.is(scratch));
2282 ASSERT(!scratch.is(kScratchRegister));
2283 // Load current lexical context from the stack frame.
2284 movq(scratch, Operand(rbp, StandardFrameConstants::kContextOffset));
2285
2286 // When generating debug code, make sure the lexical context is set.
2287 if (FLAG_debug_code) {
2288 cmpq(scratch, Immediate(0));
2289 Check(not_equal, "we should not have an empty lexical context");
2290 }
2291 // Load the global context of the current context.
2292 int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
2293 movq(scratch, FieldOperand(scratch, offset));
2294 movq(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
2295
2296 // Check the context is a global context.
2297 if (FLAG_debug_code) {
2298 Cmp(FieldOperand(scratch, HeapObject::kMapOffset),
2299 Factory::global_context_map());
2300 Check(equal, "JSGlobalObject::global_context should be a global context.");
2301 }
2302
2303 // Check if both contexts are the same.
2304 cmpq(scratch, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
2305 j(equal, &same_contexts);
2306
2307 // Compare security tokens.
2308 // Check that the security token in the calling global object is
2309 // compatible with the security token in the receiving global
2310 // object.
2311
2312 // Check the context is a global context.
2313 if (FLAG_debug_code) {
2314 // Preserve original value of holder_reg.
2315 push(holder_reg);
2316 movq(holder_reg, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002317 CompareRoot(holder_reg, Heap::kNullValueRootIndex);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002318 Check(not_equal, "JSGlobalProxy::context() should not be null.");
2319
2320 // Read the first word and compare to global_context_map(),
2321 movq(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002322 CompareRoot(holder_reg, Heap::kGlobalContextMapRootIndex);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002323 Check(equal, "JSGlobalObject::global_context should be a global context.");
2324 pop(holder_reg);
2325 }
2326
2327 movq(kScratchRegister,
2328 FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002329 int token_offset =
2330 Context::kHeaderSize + Context::SECURITY_TOKEN_INDEX * kPointerSize;
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002331 movq(scratch, FieldOperand(scratch, token_offset));
2332 cmpq(scratch, FieldOperand(kScratchRegister, token_offset));
2333 j(not_equal, miss);
2334
2335 bind(&same_contexts);
2336}
2337
2338
ager@chromium.orga1645e22009-09-09 19:27:10 +00002339void MacroAssembler::LoadAllocationTopHelper(Register result,
2340 Register result_end,
2341 Register scratch,
2342 AllocationFlags flags) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002343 ExternalReference new_space_allocation_top =
2344 ExternalReference::new_space_allocation_top_address();
2345
2346 // Just return if allocation top is already known.
ager@chromium.orga1645e22009-09-09 19:27:10 +00002347 if ((flags & RESULT_CONTAINS_TOP) != 0) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002348 // No use of scratch if allocation top is provided.
2349 ASSERT(scratch.is(no_reg));
ager@chromium.orga1645e22009-09-09 19:27:10 +00002350#ifdef DEBUG
2351 // Assert that result actually contains top on entry.
2352 movq(kScratchRegister, new_space_allocation_top);
2353 cmpq(result, Operand(kScratchRegister, 0));
2354 Check(equal, "Unexpected allocation top");
2355#endif
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002356 return;
2357 }
2358
2359 // Move address of new object to result. Use scratch register if available.
2360 if (scratch.is(no_reg)) {
2361 movq(kScratchRegister, new_space_allocation_top);
2362 movq(result, Operand(kScratchRegister, 0));
2363 } else {
2364 ASSERT(!scratch.is(result_end));
2365 movq(scratch, new_space_allocation_top);
2366 movq(result, Operand(scratch, 0));
2367 }
2368}
2369
2370
2371void MacroAssembler::UpdateAllocationTopHelper(Register result_end,
2372 Register scratch) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002373 if (FLAG_debug_code) {
2374 testq(result_end, Immediate(kObjectAlignmentMask));
2375 Check(zero, "Unaligned allocation in new space");
2376 }
2377
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002378 ExternalReference new_space_allocation_top =
2379 ExternalReference::new_space_allocation_top_address();
2380
2381 // Update new top.
2382 if (result_end.is(rax)) {
2383 // rax can be stored directly to a memory location.
2384 store_rax(new_space_allocation_top);
2385 } else {
2386 // Register required - use scratch provided if available.
2387 if (scratch.is(no_reg)) {
2388 movq(kScratchRegister, new_space_allocation_top);
2389 movq(Operand(kScratchRegister, 0), result_end);
2390 } else {
2391 movq(Operand(scratch, 0), result_end);
2392 }
2393 }
2394}
2395
2396
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002397void MacroAssembler::AllocateInNewSpace(int object_size,
2398 Register result,
2399 Register result_end,
2400 Register scratch,
2401 Label* gc_required,
2402 AllocationFlags flags) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002403 ASSERT(!result.is(result_end));
2404
2405 // Load address of new object into result.
ager@chromium.orga1645e22009-09-09 19:27:10 +00002406 LoadAllocationTopHelper(result, result_end, scratch, flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002407
2408 // Calculate new top and bail out if new space is exhausted.
2409 ExternalReference new_space_allocation_limit =
2410 ExternalReference::new_space_allocation_limit_address();
2411 lea(result_end, Operand(result, object_size));
2412 movq(kScratchRegister, new_space_allocation_limit);
2413 cmpq(result_end, Operand(kScratchRegister, 0));
2414 j(above, gc_required);
2415
2416 // Update allocation top.
2417 UpdateAllocationTopHelper(result_end, scratch);
ager@chromium.orga1645e22009-09-09 19:27:10 +00002418
2419 // Tag the result if requested.
2420 if ((flags & TAG_OBJECT) != 0) {
2421 addq(result, Immediate(kHeapObjectTag));
2422 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002423}
2424
2425
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002426void MacroAssembler::AllocateInNewSpace(int header_size,
2427 ScaleFactor element_size,
2428 Register element_count,
2429 Register result,
2430 Register result_end,
2431 Register scratch,
2432 Label* gc_required,
2433 AllocationFlags flags) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002434 ASSERT(!result.is(result_end));
2435
2436 // Load address of new object into result.
ager@chromium.orga1645e22009-09-09 19:27:10 +00002437 LoadAllocationTopHelper(result, result_end, scratch, flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002438
2439 // Calculate new top and bail out if new space is exhausted.
2440 ExternalReference new_space_allocation_limit =
2441 ExternalReference::new_space_allocation_limit_address();
2442 lea(result_end, Operand(result, element_count, element_size, header_size));
2443 movq(kScratchRegister, new_space_allocation_limit);
2444 cmpq(result_end, Operand(kScratchRegister, 0));
2445 j(above, gc_required);
2446
2447 // Update allocation top.
2448 UpdateAllocationTopHelper(result_end, scratch);
ager@chromium.orga1645e22009-09-09 19:27:10 +00002449
2450 // Tag the result if requested.
2451 if ((flags & TAG_OBJECT) != 0) {
2452 addq(result, Immediate(kHeapObjectTag));
2453 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002454}
2455
2456
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002457void MacroAssembler::AllocateInNewSpace(Register object_size,
2458 Register result,
2459 Register result_end,
2460 Register scratch,
2461 Label* gc_required,
2462 AllocationFlags flags) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002463 // Load address of new object into result.
ager@chromium.orga1645e22009-09-09 19:27:10 +00002464 LoadAllocationTopHelper(result, result_end, scratch, flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002465
2466 // Calculate new top and bail out if new space is exhausted.
2467 ExternalReference new_space_allocation_limit =
2468 ExternalReference::new_space_allocation_limit_address();
2469 if (!object_size.is(result_end)) {
2470 movq(result_end, object_size);
2471 }
2472 addq(result_end, result);
2473 movq(kScratchRegister, new_space_allocation_limit);
2474 cmpq(result_end, Operand(kScratchRegister, 0));
2475 j(above, gc_required);
2476
2477 // Update allocation top.
2478 UpdateAllocationTopHelper(result_end, scratch);
ager@chromium.orga1645e22009-09-09 19:27:10 +00002479
2480 // Tag the result if requested.
2481 if ((flags & TAG_OBJECT) != 0) {
2482 addq(result, Immediate(kHeapObjectTag));
2483 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002484}
2485
2486
2487void MacroAssembler::UndoAllocationInNewSpace(Register object) {
2488 ExternalReference new_space_allocation_top =
2489 ExternalReference::new_space_allocation_top_address();
2490
2491 // Make sure the object has no tag before resetting top.
2492 and_(object, Immediate(~kHeapObjectTagMask));
2493 movq(kScratchRegister, new_space_allocation_top);
2494#ifdef DEBUG
2495 cmpq(object, Operand(kScratchRegister, 0));
2496 Check(below, "Undo allocation of non allocated memory");
2497#endif
2498 movq(Operand(kScratchRegister, 0), object);
2499}
2500
2501
ager@chromium.org3811b432009-10-28 14:53:37 +00002502void MacroAssembler::AllocateHeapNumber(Register result,
2503 Register scratch,
2504 Label* gc_required) {
2505 // Allocate heap number in new space.
2506 AllocateInNewSpace(HeapNumber::kSize,
2507 result,
2508 scratch,
2509 no_reg,
2510 gc_required,
2511 TAG_OBJECT);
2512
2513 // Set the map.
2514 LoadRoot(kScratchRegister, Heap::kHeapNumberMapRootIndex);
2515 movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
2516}
2517
2518
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002519void MacroAssembler::AllocateTwoByteString(Register result,
2520 Register length,
2521 Register scratch1,
2522 Register scratch2,
2523 Register scratch3,
2524 Label* gc_required) {
2525 // Calculate the number of bytes needed for the characters in the string while
2526 // observing object alignment.
kmillikin@chromium.orgf8253d72010-05-03 09:56:08 +00002527 ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002528 ASSERT(kShortSize == 2);
2529 // scratch1 = length * 2 + kObjectAlignmentMask.
kmillikin@chromium.orgf8253d72010-05-03 09:56:08 +00002530 lea(scratch1, Operand(length, length, times_1, kObjectAlignmentMask));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002531 and_(scratch1, Immediate(~kObjectAlignmentMask));
2532
2533 // Allocate two byte string in new space.
2534 AllocateInNewSpace(SeqTwoByteString::kHeaderSize,
2535 times_1,
2536 scratch1,
2537 result,
2538 scratch2,
2539 scratch3,
2540 gc_required,
2541 TAG_OBJECT);
2542
2543 // Set the map, length and hash field.
2544 LoadRoot(kScratchRegister, Heap::kStringMapRootIndex);
2545 movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
kmillikin@chromium.orgf8253d72010-05-03 09:56:08 +00002546 movl(FieldOperand(result, String::kLengthOffset), length);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002547 movl(FieldOperand(result, String::kHashFieldOffset),
2548 Immediate(String::kEmptyHashField));
2549}
2550
2551
2552void MacroAssembler::AllocateAsciiString(Register result,
2553 Register length,
2554 Register scratch1,
2555 Register scratch2,
2556 Register scratch3,
2557 Label* gc_required) {
2558 // Calculate the number of bytes needed for the characters in the string while
2559 // observing object alignment.
kmillikin@chromium.orgf8253d72010-05-03 09:56:08 +00002560 ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002561 movl(scratch1, length);
2562 ASSERT(kCharSize == 1);
kmillikin@chromium.orgf8253d72010-05-03 09:56:08 +00002563 addq(scratch1, Immediate(kObjectAlignmentMask));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002564 and_(scratch1, Immediate(~kObjectAlignmentMask));
2565
2566 // Allocate ascii string in new space.
2567 AllocateInNewSpace(SeqAsciiString::kHeaderSize,
2568 times_1,
2569 scratch1,
2570 result,
2571 scratch2,
2572 scratch3,
2573 gc_required,
2574 TAG_OBJECT);
2575
2576 // Set the map, length and hash field.
2577 LoadRoot(kScratchRegister, Heap::kAsciiStringMapRootIndex);
2578 movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
kmillikin@chromium.orgf8253d72010-05-03 09:56:08 +00002579 movl(FieldOperand(result, String::kLengthOffset), length);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002580 movl(FieldOperand(result, String::kHashFieldOffset),
2581 Immediate(String::kEmptyHashField));
2582}
2583
2584
2585void MacroAssembler::AllocateConsString(Register result,
2586 Register scratch1,
2587 Register scratch2,
2588 Label* gc_required) {
2589 // Allocate heap number in new space.
2590 AllocateInNewSpace(ConsString::kSize,
2591 result,
2592 scratch1,
2593 scratch2,
2594 gc_required,
2595 TAG_OBJECT);
2596
2597 // Set the map. The other fields are left uninitialized.
2598 LoadRoot(kScratchRegister, Heap::kConsStringMapRootIndex);
2599 movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
2600}
2601
2602
2603void MacroAssembler::AllocateAsciiConsString(Register result,
2604 Register scratch1,
2605 Register scratch2,
2606 Label* gc_required) {
2607 // Allocate heap number in new space.
2608 AllocateInNewSpace(ConsString::kSize,
2609 result,
2610 scratch1,
2611 scratch2,
2612 gc_required,
2613 TAG_OBJECT);
2614
2615 // Set the map. The other fields are left uninitialized.
2616 LoadRoot(kScratchRegister, Heap::kConsAsciiStringMapRootIndex);
2617 movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
2618}
2619
2620
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002621void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
2622 if (context_chain_length > 0) {
2623 // Move up the chain of contexts to the context containing the slot.
2624 movq(dst, Operand(rsi, Context::SlotOffset(Context::CLOSURE_INDEX)));
2625 // Load the function context (which is the incoming, outer context).
lrn@chromium.orgd5649e32010-01-19 13:36:12 +00002626 movq(dst, FieldOperand(dst, JSFunction::kContextOffset));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002627 for (int i = 1; i < context_chain_length; i++) {
2628 movq(dst, Operand(dst, Context::SlotOffset(Context::CLOSURE_INDEX)));
2629 movq(dst, FieldOperand(dst, JSFunction::kContextOffset));
2630 }
2631 // The context may be an intermediate context, not a function context.
2632 movq(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
2633 } else { // context is the current function context.
2634 // The context may be an intermediate context, not a function context.
2635 movq(dst, Operand(rsi, Context::SlotOffset(Context::FCONTEXT_INDEX)));
2636 }
2637}
2638
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002639int MacroAssembler::ArgumentStackSlotsForCFunctionCall(int num_arguments) {
2640 // On Windows stack slots are reserved by the caller for all arguments
2641 // including the ones passed in registers. On Linux 6 arguments are passed in
2642 // registers and the caller does not reserve stack slots for them.
2643 ASSERT(num_arguments >= 0);
2644#ifdef _WIN64
2645 static const int kArgumentsWithoutStackSlot = 0;
2646#else
2647 static const int kArgumentsWithoutStackSlot = 6;
2648#endif
2649 return num_arguments > kArgumentsWithoutStackSlot ?
2650 num_arguments - kArgumentsWithoutStackSlot : 0;
2651}
2652
2653void MacroAssembler::PrepareCallCFunction(int num_arguments) {
2654 int frame_alignment = OS::ActivationFrameAlignment();
2655 ASSERT(frame_alignment != 0);
2656 ASSERT(num_arguments >= 0);
2657 // Make stack end at alignment and allocate space for arguments and old rsp.
2658 movq(kScratchRegister, rsp);
2659 ASSERT(IsPowerOf2(frame_alignment));
2660 int argument_slots_on_stack =
2661 ArgumentStackSlotsForCFunctionCall(num_arguments);
2662 subq(rsp, Immediate((argument_slots_on_stack + 1) * kPointerSize));
2663 and_(rsp, Immediate(-frame_alignment));
2664 movq(Operand(rsp, argument_slots_on_stack * kPointerSize), kScratchRegister);
2665}
2666
2667
2668void MacroAssembler::CallCFunction(ExternalReference function,
2669 int num_arguments) {
2670 movq(rax, function);
2671 CallCFunction(rax, num_arguments);
2672}
2673
2674
2675void MacroAssembler::CallCFunction(Register function, int num_arguments) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002676 // Check stack alignment.
2677 if (FLAG_debug_code) {
2678 CheckStackAlignment();
2679 }
2680
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002681 call(function);
2682 ASSERT(OS::ActivationFrameAlignment() != 0);
2683 ASSERT(num_arguments >= 0);
2684 int argument_slots_on_stack =
2685 ArgumentStackSlotsForCFunctionCall(num_arguments);
2686 movq(rsp, Operand(rsp, argument_slots_on_stack * kPointerSize));
2687}
2688
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002689
ager@chromium.org4af710e2009-09-15 12:20:11 +00002690CodePatcher::CodePatcher(byte* address, int size)
2691 : address_(address), size_(size), masm_(address, size + Assembler::kGap) {
2692 // Create a new macro assembler pointing to the address of the code to patch.
2693 // The size is adjusted with kGap on order for the assembler to generate size
2694 // bytes of instructions without failing with buffer size constraints.
2695 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
2696}
2697
2698
2699CodePatcher::~CodePatcher() {
2700 // Indicate that code has changed.
2701 CPU::FlushICache(address_, size_);
2702
2703 // Check that the code was patched as expected.
2704 ASSERT(masm_.pc_ == address_ + size_);
2705 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
2706}
2707
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002708} } // namespace v8::internal