blob: 352933678b74c2ae36bbd7a8cad29583d59e0095 [file] [log] [blame]
ager@chromium.orga1645e22009-09-09 19:27:10 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "bootstrapper.h"
31#include "codegen-inl.h"
32#include "debug.h"
33#include "runtime.h"
34#include "serialize.h"
35
kasperl@chromium.org71affb52009-05-26 05:44:31 +000036namespace v8 {
37namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000039// -------------------------------------------------------------------------
40// MacroAssembler implementation.
41
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042MacroAssembler::MacroAssembler(void* buffer, int size)
43 : Assembler(buffer, size),
kasper.lund7276f142008-07-30 08:49:36 +000044 generating_stub_(false),
kasperl@chromium.org061ef742009-02-27 12:16:20 +000045 allow_stub_calls_(true),
46 code_object_(Heap::undefined_value()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047}
48
49
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000050void MacroAssembler::RecordWriteHelper(Register object,
51 Register addr,
52 Register scratch) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053 Label fast;
54
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +000055 // Compute the page start address from the heap object pointer, and reuse
56 // the 'object' register for it.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000057 and_(object, ~Page::kPageAlignmentMask);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +000058 Register page_start = object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +000060 // Compute the bit addr in the remembered set/index of the pointer in the
61 // page. Reuse 'addr' as pointer_offset.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000062 sub(addr, Operand(page_start));
63 shr(addr, kObjectAlignmentBits);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +000064 Register pointer_offset = addr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065
66 // If the bit offset lies beyond the normal remembered set range, it is in
67 // the extra remembered set area of a large object.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000068 cmp(pointer_offset, Page::kPageSize / kPointerSize);
69 j(less, &fast);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000070
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +000071 // Adjust 'page_start' so that addressing using 'pointer_offset' hits the
72 // extra remembered set after the large object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +000074 // Find the length of the large object (FixedArray).
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000075 mov(scratch, Operand(page_start, Page::kObjectStartOffset
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +000076 + FixedArray::kLengthOffset));
77 Register array_length = scratch;
78
79 // Extra remembered set starts right after the large object (a FixedArray), at
80 // page_start + kObjectStartOffset + objectSize
81 // where objectSize is FixedArray::kHeaderSize + kPointerSize * array_length.
82 // Add the delta between the end of the normal RSet and the start of the
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000083 // extra RSet to 'page_start', so that addressing the bit using
84 // 'pointer_offset' hits the extra RSet words.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000085 lea(page_start,
86 Operand(page_start, array_length, times_pointer_size,
87 Page::kObjectStartOffset + FixedArray::kHeaderSize
88 - Page::kRSetEndOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000089
90 // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction
91 // to limit code size. We should probably evaluate this decision by
92 // measuring the performance of an equivalent implementation using
93 // "simpler" instructions
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000094 bind(&fast);
95 bts(Operand(page_start, Page::kRSetOffset), pointer_offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096}
97
98
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000099void MacroAssembler::InNewSpace(Register object,
100 Register scratch,
101 Condition cc,
102 Label* branch) {
103 if (Serializer::enabled()) {
104 // Can't do arithmetic on external references if it might get serialized.
105 mov(scratch, Operand(object));
106 // The mask isn't really an address. We load it as an external reference in
107 // case the size of the new space is different between the snapshot maker
108 // and the running system.
109 and_(Operand(scratch), Immediate(ExternalReference::new_space_mask()));
110 cmp(Operand(scratch), Immediate(ExternalReference::new_space_start()));
111 j(cc, branch);
112 } else {
113 int32_t new_space_start = reinterpret_cast<int32_t>(
114 ExternalReference::new_space_start().address());
115 lea(scratch, Operand(object, -new_space_start));
116 and_(scratch, Heap::NewSpaceMask());
117 j(cc, branch);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000118 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000119}
120
121
122// Set the remembered set bit for [object+offset].
123// object is the object being stored into, value is the object being stored.
124// If offset is zero, then the scratch register contains the array index into
125// the elements array represented as a Smi.
126// All registers are clobbered by the operation.
127void MacroAssembler::RecordWrite(Register object, int offset,
128 Register value, Register scratch) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000129 // The compiled code assumes that record write doesn't change the
130 // context register, so we check that none of the clobbered
131 // registers are esi.
132 ASSERT(!object.is(esi) && !value.is(esi) && !scratch.is(esi));
133
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000134 // First, check if a remembered set write is even needed. The tests below
135 // catch stores of Smis and stores into young gen (which does not have space
136 // for the remembered set bits.
137 Label done;
138
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000139 // Skip barrier if writing a smi.
140 ASSERT_EQ(0, kSmiTag);
141 test(value, Immediate(kSmiTagMask));
142 j(zero, &done);
143
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000144 InNewSpace(object, value, equal, &done);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000145
146 if ((offset > 0) && (offset < Page::kMaxHeapObjectSize)) {
147 // Compute the bit offset in the remembered set, leave it in 'value'.
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000148 lea(value, Operand(object, offset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000149 and_(value, Page::kPageAlignmentMask);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000150 shr(value, kPointerSizeLog2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000151
152 // Compute the page address from the heap object pointer, leave it in
153 // 'object'.
154 and_(object, ~Page::kPageAlignmentMask);
155
156 // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction
157 // to limit code size. We should probably evaluate this decision by
158 // measuring the performance of an equivalent implementation using
159 // "simpler" instructions
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000160 bts(Operand(object, Page::kRSetOffset), value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000161 } else {
162 Register dst = scratch;
163 if (offset != 0) {
164 lea(dst, Operand(object, offset));
165 } else {
166 // array access: calculate the destination address in the same manner as
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000167 // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset
168 // into an array of words.
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000169 ASSERT_EQ(1, kSmiTagSize);
170 ASSERT_EQ(0, kSmiTag);
171 lea(dst, Operand(object, dst, times_half_pointer_size,
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000172 FixedArray::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000173 }
174 // If we are already generating a shared stub, not inlining the
175 // record write code isn't going to save us any memory.
176 if (generating_stub()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000177 RecordWriteHelper(object, dst, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000178 } else {
179 RecordWriteStub stub(object, dst, value);
180 CallStub(&stub);
181 }
182 }
183
184 bind(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000185
186 // Clobber all input registers when running with the debug-code flag
187 // turned on to provoke errors.
188 if (FLAG_debug_code) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000189 mov(object, Immediate(BitCast<int32_t>(kZapValue)));
190 mov(value, Immediate(BitCast<int32_t>(kZapValue)));
191 mov(scratch, Immediate(BitCast<int32_t>(kZapValue)));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000192 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000193}
194
195
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000196void MacroAssembler::StackLimitCheck(Label* on_stack_overflow) {
197 cmp(esp,
198 Operand::StaticVariable(ExternalReference::address_of_stack_limit()));
199 j(below, on_stack_overflow);
200}
201
202
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000203#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000204void MacroAssembler::SaveRegistersToMemory(RegList regs) {
205 ASSERT((regs & ~kJSCallerSaved) == 0);
206 // Copy the content of registers to memory location.
207 for (int i = 0; i < kNumJSCallerSaved; i++) {
208 int r = JSCallerSavedCode(i);
209 if ((regs & (1 << r)) != 0) {
210 Register reg = { r };
211 ExternalReference reg_addr =
212 ExternalReference(Debug_Address::Register(i));
213 mov(Operand::StaticVariable(reg_addr), reg);
214 }
215 }
216}
217
218
219void MacroAssembler::RestoreRegistersFromMemory(RegList regs) {
220 ASSERT((regs & ~kJSCallerSaved) == 0);
221 // Copy the content of memory location to registers.
222 for (int i = kNumJSCallerSaved; --i >= 0;) {
223 int r = JSCallerSavedCode(i);
224 if ((regs & (1 << r)) != 0) {
225 Register reg = { r };
226 ExternalReference reg_addr =
227 ExternalReference(Debug_Address::Register(i));
228 mov(reg, Operand::StaticVariable(reg_addr));
229 }
230 }
231}
232
233
234void MacroAssembler::PushRegistersFromMemory(RegList regs) {
235 ASSERT((regs & ~kJSCallerSaved) == 0);
236 // Push the content of the memory location to the stack.
237 for (int i = 0; i < kNumJSCallerSaved; i++) {
238 int r = JSCallerSavedCode(i);
239 if ((regs & (1 << r)) != 0) {
240 ExternalReference reg_addr =
241 ExternalReference(Debug_Address::Register(i));
242 push(Operand::StaticVariable(reg_addr));
243 }
244 }
245}
246
247
248void MacroAssembler::PopRegistersToMemory(RegList regs) {
249 ASSERT((regs & ~kJSCallerSaved) == 0);
250 // Pop the content from the stack to the memory location.
251 for (int i = kNumJSCallerSaved; --i >= 0;) {
252 int r = JSCallerSavedCode(i);
253 if ((regs & (1 << r)) != 0) {
254 ExternalReference reg_addr =
255 ExternalReference(Debug_Address::Register(i));
256 pop(Operand::StaticVariable(reg_addr));
257 }
258 }
259}
260
261
262void MacroAssembler::CopyRegistersFromStackToMemory(Register base,
263 Register scratch,
264 RegList regs) {
265 ASSERT((regs & ~kJSCallerSaved) == 0);
266 // Copy the content of the stack to the memory location and adjust base.
267 for (int i = kNumJSCallerSaved; --i >= 0;) {
268 int r = JSCallerSavedCode(i);
269 if ((regs & (1 << r)) != 0) {
270 mov(scratch, Operand(base, 0));
271 ExternalReference reg_addr =
272 ExternalReference(Debug_Address::Register(i));
273 mov(Operand::StaticVariable(reg_addr), scratch);
274 lea(base, Operand(base, kPointerSize));
275 }
276 }
277}
ager@chromium.org5c838252010-02-19 08:53:10 +0000278
279void MacroAssembler::DebugBreak() {
280 Set(eax, Immediate(0));
281 mov(ebx, Immediate(ExternalReference(Runtime::kDebugBreak)));
282 CEntryStub ces(1);
283 call(ces.GetCode(), RelocInfo::DEBUG_BREAK);
284}
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000285#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000286
287void MacroAssembler::Set(Register dst, const Immediate& x) {
288 if (x.is_zero()) {
289 xor_(dst, Operand(dst)); // shorter than mov
290 } else {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000291 mov(dst, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000292 }
293}
294
295
296void MacroAssembler::Set(const Operand& dst, const Immediate& x) {
297 mov(dst, x);
298}
299
300
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000301void MacroAssembler::CmpObjectType(Register heap_object,
302 InstanceType type,
303 Register map) {
304 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
305 CmpInstanceType(map, type);
306}
307
308
309void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
310 cmpb(FieldOperand(map, Map::kInstanceTypeOffset),
311 static_cast<int8_t>(type));
312}
313
314
ager@chromium.org5c838252010-02-19 08:53:10 +0000315void MacroAssembler::CheckMap(Register obj,
316 Handle<Map> map,
317 Label* fail,
318 bool is_heap_object) {
319 if (!is_heap_object) {
320 test(obj, Immediate(kSmiTagMask));
321 j(zero, fail);
322 }
323 cmp(FieldOperand(obj, HeapObject::kMapOffset), Immediate(map));
324 j(not_equal, fail);
325}
326
327
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000328Condition MacroAssembler::IsObjectStringType(Register heap_object,
329 Register map,
330 Register instance_type) {
331 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
332 movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
333 ASSERT(kNotStringTag != 0);
334 test(instance_type, Immediate(kIsNotStringMask));
335 return zero;
336}
337
338
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000339void MacroAssembler::FCmp() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000340 if (CpuFeatures::IsSupported(CMOV)) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000341 fucomip();
342 ffree(0);
343 fincstp();
344 } else {
345 fucompp();
346 push(eax);
347 fnstsw_ax();
348 sahf();
349 pop(eax);
350 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000351}
352
353
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000354void MacroAssembler::AbortIfNotNumber(Register object) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000355 Label ok;
356 test(object, Immediate(kSmiTagMask));
357 j(zero, &ok);
358 cmp(FieldOperand(object, HeapObject::kMapOffset),
359 Factory::heap_number_map());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000360 Assert(equal, "Operand not a number");
ager@chromium.org5c838252010-02-19 08:53:10 +0000361 bind(&ok);
362}
363
364
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000365void MacroAssembler::AbortIfNotSmi(Register object) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000366 test(object, Immediate(kSmiTagMask));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000367 Assert(equal, "Operand not a smi");
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000368}
369
370
ager@chromium.org7c537e22008-10-16 08:43:32 +0000371void MacroAssembler::EnterFrame(StackFrame::Type type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000372 push(ebp);
373 mov(ebp, Operand(esp));
374 push(esi);
375 push(Immediate(Smi::FromInt(type)));
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000376 push(Immediate(CodeObject()));
377 if (FLAG_debug_code) {
378 cmp(Operand(esp, 0), Immediate(Factory::undefined_value()));
379 Check(not_equal, "code object not properly patched");
380 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381}
382
383
ager@chromium.org7c537e22008-10-16 08:43:32 +0000384void MacroAssembler::LeaveFrame(StackFrame::Type type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000385 if (FLAG_debug_code) {
386 cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset),
387 Immediate(Smi::FromInt(type)));
388 Check(equal, "stack frame types must match");
389 }
390 leave();
391}
392
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000393void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000394 // Setup the frame structure on the stack.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000395 ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize);
ager@chromium.org236ad962008-09-25 09:45:57 +0000396 ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize);
397 ASSERT(ExitFrameConstants::kCallerFPOffset == 0 * kPointerSize);
398 push(ebp);
399 mov(ebp, Operand(esp));
400
401 // Reserve room for entry stack pointer and push the debug marker.
402 ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize);
ager@chromium.org5c838252010-02-19 08:53:10 +0000403 push(Immediate(0)); // Saved entry sp, patched before call.
404 push(Immediate(CodeObject())); // Accessed from ExitFrame::code_slot.
ager@chromium.org236ad962008-09-25 09:45:57 +0000405
406 // Save the frame pointer and the context in top.
407 ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
408 ExternalReference context_address(Top::k_context_address);
409 mov(Operand::StaticVariable(c_entry_fp_address), ebp);
410 mov(Operand::StaticVariable(context_address), esi);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000411}
ager@chromium.org236ad962008-09-25 09:45:57 +0000412
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000413void MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode, int argc) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000414#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org236ad962008-09-25 09:45:57 +0000415 // Save the state of all registers to the stack from the memory
416 // location. This is needed to allow nested break points.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000417 if (mode == ExitFrame::MODE_DEBUG) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000418 // TODO(1243899): This should be symmetric to
419 // CopyRegistersFromStackToMemory() but it isn't! esp is assumed
420 // correct here, but computed for the other call. Very error
421 // prone! FIX THIS. Actually there are deeper problems with
422 // register saving than this asymmetry (see the bug report
423 // associated with this issue).
424 PushRegistersFromMemory(kJSCallerSaved);
425 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000426#endif
ager@chromium.org236ad962008-09-25 09:45:57 +0000427
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000428 // Reserve space for arguments.
429 sub(Operand(esp), Immediate(argc * kPointerSize));
ager@chromium.org236ad962008-09-25 09:45:57 +0000430
431 // Get the required frame alignment for the OS.
432 static const int kFrameAlignment = OS::ActivationFrameAlignment();
433 if (kFrameAlignment > 0) {
434 ASSERT(IsPowerOf2(kFrameAlignment));
435 and_(esp, -kFrameAlignment);
436 }
437
438 // Patch the saved entry sp.
439 mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp);
440}
441
442
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000443void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) {
444 EnterExitFramePrologue(mode);
445
446 // Setup argc and argv in callee-saved registers.
447 int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
448 mov(edi, Operand(eax));
449 lea(esi, Operand(ebp, eax, times_4, offset));
450
451 EnterExitFrameEpilogue(mode, 2);
452}
453
454
455void MacroAssembler::EnterApiExitFrame(ExitFrame::Mode mode,
456 int stack_space,
457 int argc) {
458 EnterExitFramePrologue(mode);
459
460 int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
461 lea(esi, Operand(ebp, (stack_space * kPointerSize) + offset));
462
463 EnterExitFrameEpilogue(mode, argc);
464}
465
466
467void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000468#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org236ad962008-09-25 09:45:57 +0000469 // Restore the memory copy of the registers by digging them out from
470 // the stack. This is needed to allow nested break points.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000471 if (mode == ExitFrame::MODE_DEBUG) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000472 // It's okay to clobber register ebx below because we don't need
473 // the function pointer after this.
474 const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000475 int kOffset = ExitFrameConstants::kCodeOffset - kCallerSavedSize;
ager@chromium.org236ad962008-09-25 09:45:57 +0000476 lea(ebx, Operand(ebp, kOffset));
477 CopyRegistersFromStackToMemory(ebx, ecx, kJSCallerSaved);
478 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000479#endif
ager@chromium.org236ad962008-09-25 09:45:57 +0000480
481 // Get the return address from the stack and restore the frame pointer.
482 mov(ecx, Operand(ebp, 1 * kPointerSize));
483 mov(ebp, Operand(ebp, 0 * kPointerSize));
484
485 // Pop the arguments and the receiver from the caller stack.
486 lea(esp, Operand(esi, 1 * kPointerSize));
487
488 // Restore current context from top and clear it in debug mode.
489 ExternalReference context_address(Top::k_context_address);
490 mov(esi, Operand::StaticVariable(context_address));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000491#ifdef DEBUG
492 mov(Operand::StaticVariable(context_address), Immediate(0));
493#endif
ager@chromium.org236ad962008-09-25 09:45:57 +0000494
495 // Push the return address to get ready to return.
496 push(ecx);
497
498 // Clear the top frame.
499 ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
500 mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
501}
502
503
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000504void MacroAssembler::PushTryHandler(CodeLocation try_location,
505 HandlerType type) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000506 // Adjust this code if not the case.
507 ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000508 // The pc (return address) is already on TOS.
509 if (try_location == IN_JAVASCRIPT) {
510 if (type == TRY_CATCH_HANDLER) {
511 push(Immediate(StackHandler::TRY_CATCH));
512 } else {
513 push(Immediate(StackHandler::TRY_FINALLY));
514 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000515 push(ebp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000516 } else {
517 ASSERT(try_location == IN_JS_ENTRY);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000518 // The frame pointer does not point to a JS frame so we save NULL
519 // for ebp. We expect the code throwing an exception to check ebp
520 // before dereferencing it to restore the context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000521 push(Immediate(StackHandler::ENTRY));
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000522 push(Immediate(0)); // NULL frame pointer.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000523 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000524 // Save the current handler as the next handler.
525 push(Operand::StaticVariable(ExternalReference(Top::k_handler_address)));
526 // Link this handler as the new current one.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000527 mov(Operand::StaticVariable(ExternalReference(Top::k_handler_address)), esp);
528}
529
530
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000531void MacroAssembler::PopTryHandler() {
532 ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
533 pop(Operand::StaticVariable(ExternalReference(Top::k_handler_address)));
534 add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize));
535}
536
537
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000538Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
539 JSObject* holder, Register holder_reg,
540 Register scratch,
ager@chromium.org5c838252010-02-19 08:53:10 +0000541 int save_at_depth,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000542 Label* miss) {
543 // Make sure there's no overlap between scratch and the other
544 // registers.
545 ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg));
546
547 // Keep track of the current object in register reg.
548 Register reg = object_reg;
ager@chromium.org5c838252010-02-19 08:53:10 +0000549 int depth = 0;
550
551 if (save_at_depth == depth) {
552 mov(Operand(esp, kPointerSize), object_reg);
553 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000554
555 // Check the maps in the prototype chain.
556 // Traverse the prototype chain from the object and do map checks.
557 while (object != holder) {
558 depth++;
559
560 // Only global objects and objects that do not require access
561 // checks are allowed in stubs.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000562 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000563
564 JSObject* prototype = JSObject::cast(object->GetPrototype());
565 if (Heap::InNewSpace(prototype)) {
566 // Get the map of the current object.
567 mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
568 cmp(Operand(scratch), Immediate(Handle<Map>(object->map())));
569 // Branch on the result of the map check.
570 j(not_equal, miss, not_taken);
571 // Check access rights to the global object. This has to happen
572 // after the map check so that we know that the object is
573 // actually a global object.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000574 if (object->IsJSGlobalProxy()) {
575 CheckAccessGlobalProxy(reg, scratch, miss);
576
577 // Restore scratch register to be the map of the object.
578 // We load the prototype from the map in the scratch register.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000579 mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
580 }
581 // The prototype is in new space; we cannot store a reference
582 // to it in the code. Load it from the map.
583 reg = holder_reg; // from now the object is in holder_reg
584 mov(reg, FieldOperand(scratch, Map::kPrototypeOffset));
585 } else {
586 // Check the map of the current object.
587 cmp(FieldOperand(reg, HeapObject::kMapOffset),
588 Immediate(Handle<Map>(object->map())));
589 // Branch on the result of the map check.
590 j(not_equal, miss, not_taken);
591 // Check access rights to the global object. This has to happen
592 // after the map check so that we know that the object is
593 // actually a global object.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000594 if (object->IsJSGlobalProxy()) {
595 CheckAccessGlobalProxy(reg, scratch, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000596 }
597 // The prototype is in old space; load it directly.
598 reg = holder_reg; // from now the object is in holder_reg
599 mov(reg, Handle<JSObject>(prototype));
600 }
601
ager@chromium.org5c838252010-02-19 08:53:10 +0000602 if (save_at_depth == depth) {
603 mov(Operand(esp, kPointerSize), reg);
604 }
605
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000606 // Go to the next object in the prototype chain.
607 object = prototype;
608 }
609
610 // Check the holder map.
611 cmp(FieldOperand(reg, HeapObject::kMapOffset),
612 Immediate(Handle<Map>(holder->map())));
613 j(not_equal, miss, not_taken);
614
615 // Log the check depth.
ager@chromium.org5c838252010-02-19 08:53:10 +0000616 LOG(IntEvent("check-maps-depth", depth + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000617
618 // Perform security check for access to the global object and return
619 // the holder register.
620 ASSERT(object == holder);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000621 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
622 if (object->IsJSGlobalProxy()) {
623 CheckAccessGlobalProxy(reg, scratch, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624 }
625 return reg;
626}
627
628
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000629void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
ager@chromium.orge2902be2009-06-08 12:21:35 +0000630 Register scratch,
631 Label* miss) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000632 Label same_contexts;
633
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000634 ASSERT(!holder_reg.is(scratch));
635
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000636 // Load current lexical context from the stack frame.
637 mov(scratch, Operand(ebp, StandardFrameConstants::kContextOffset));
638
639 // When generating debug code, make sure the lexical context is set.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640 if (FLAG_debug_code) {
641 cmp(Operand(scratch), Immediate(0));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000642 Check(not_equal, "we should not have an empty lexical context");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000643 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000644 // Load the global context of the current context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000645 int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
646 mov(scratch, FieldOperand(scratch, offset));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000647 mov(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
648
649 // Check the context is a global context.
650 if (FLAG_debug_code) {
651 push(scratch);
652 // Read the first word and compare to global_context_map.
653 mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
654 cmp(scratch, Factory::global_context_map());
655 Check(equal, "JSGlobalObject::global_context should be a global context.");
656 pop(scratch);
657 }
658
659 // Check if both contexts are the same.
660 cmp(scratch, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
661 j(equal, &same_contexts, taken);
662
663 // Compare security tokens, save holder_reg on the stack so we can use it
664 // as a temporary register.
665 //
666 // TODO(119): avoid push(holder_reg)/pop(holder_reg)
667 push(holder_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000668 // Check that the security token in the calling global object is
669 // compatible with the security token in the receiving global
670 // object.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000671 mov(holder_reg, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
672
673 // Check the context is a global context.
674 if (FLAG_debug_code) {
675 cmp(holder_reg, Factory::null_value());
676 Check(not_equal, "JSGlobalProxy::context() should not be null.");
677
678 push(holder_reg);
679 // Read the first word and compare to global_context_map(),
680 mov(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset));
681 cmp(holder_reg, Factory::global_context_map());
682 Check(equal, "JSGlobalObject::global_context should be a global context.");
683 pop(holder_reg);
684 }
685
686 int token_offset = Context::kHeaderSize +
687 Context::SECURITY_TOKEN_INDEX * kPointerSize;
688 mov(scratch, FieldOperand(scratch, token_offset));
689 cmp(scratch, FieldOperand(holder_reg, token_offset));
690 pop(holder_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000691 j(not_equal, miss, not_taken);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000692
693 bind(&same_contexts);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000694}
695
696
ager@chromium.orga1645e22009-09-09 19:27:10 +0000697void MacroAssembler::LoadAllocationTopHelper(Register result,
698 Register result_end,
699 Register scratch,
700 AllocationFlags flags) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000701 ExternalReference new_space_allocation_top =
702 ExternalReference::new_space_allocation_top_address();
703
704 // Just return if allocation top is already known.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000705 if ((flags & RESULT_CONTAINS_TOP) != 0) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000706 // No use of scratch if allocation top is provided.
707 ASSERT(scratch.is(no_reg));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000708#ifdef DEBUG
709 // Assert that result actually contains top on entry.
710 cmp(result, Operand::StaticVariable(new_space_allocation_top));
711 Check(equal, "Unexpected allocation top");
712#endif
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000713 return;
714 }
715
716 // Move address of new object to result. Use scratch register if available.
717 if (scratch.is(no_reg)) {
718 mov(result, Operand::StaticVariable(new_space_allocation_top));
719 } else {
720 ASSERT(!scratch.is(result_end));
721 mov(Operand(scratch), Immediate(new_space_allocation_top));
722 mov(result, Operand(scratch, 0));
723 }
724}
725
726
727void MacroAssembler::UpdateAllocationTopHelper(Register result_end,
728 Register scratch) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000729 if (FLAG_debug_code) {
730 test(result_end, Immediate(kObjectAlignmentMask));
731 Check(zero, "Unaligned allocation in new space");
732 }
733
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000734 ExternalReference new_space_allocation_top =
735 ExternalReference::new_space_allocation_top_address();
736
737 // Update new top. Use scratch if available.
738 if (scratch.is(no_reg)) {
739 mov(Operand::StaticVariable(new_space_allocation_top), result_end);
740 } else {
741 mov(Operand(scratch, 0), result_end);
742 }
743}
744
ager@chromium.orga1645e22009-09-09 19:27:10 +0000745
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000746void MacroAssembler::AllocateInNewSpace(int object_size,
747 Register result,
748 Register result_end,
749 Register scratch,
750 Label* gc_required,
751 AllocationFlags flags) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000752 ASSERT(!result.is(result_end));
753
754 // Load address of new object into result.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000755 LoadAllocationTopHelper(result, result_end, scratch, flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000756
757 // Calculate new top and bail out if new space is exhausted.
758 ExternalReference new_space_allocation_limit =
759 ExternalReference::new_space_allocation_limit_address();
760 lea(result_end, Operand(result, object_size));
761 cmp(result_end, Operand::StaticVariable(new_space_allocation_limit));
762 j(above, gc_required, not_taken);
763
ager@chromium.orga1645e22009-09-09 19:27:10 +0000764 // Tag result if requested.
765 if ((flags & TAG_OBJECT) != 0) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000766 lea(result, Operand(result, kHeapObjectTag));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000767 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000768
769 // Update allocation top.
770 UpdateAllocationTopHelper(result_end, scratch);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000771}
772
773
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000774void MacroAssembler::AllocateInNewSpace(int header_size,
775 ScaleFactor element_size,
776 Register element_count,
777 Register result,
778 Register result_end,
779 Register scratch,
780 Label* gc_required,
781 AllocationFlags flags) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000782 ASSERT(!result.is(result_end));
783
784 // Load address of new object into result.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000785 LoadAllocationTopHelper(result, result_end, scratch, flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000786
787 // Calculate new top and bail out if new space is exhausted.
788 ExternalReference new_space_allocation_limit =
789 ExternalReference::new_space_allocation_limit_address();
790 lea(result_end, Operand(result, element_count, element_size, header_size));
791 cmp(result_end, Operand::StaticVariable(new_space_allocation_limit));
792 j(above, gc_required);
793
ager@chromium.orga1645e22009-09-09 19:27:10 +0000794 // Tag result if requested.
795 if ((flags & TAG_OBJECT) != 0) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000796 lea(result, Operand(result, kHeapObjectTag));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000797 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000798
799 // Update allocation top.
800 UpdateAllocationTopHelper(result_end, scratch);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000801}
802
803
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000804void MacroAssembler::AllocateInNewSpace(Register object_size,
805 Register result,
806 Register result_end,
807 Register scratch,
808 Label* gc_required,
809 AllocationFlags flags) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000810 ASSERT(!result.is(result_end));
811
812 // Load address of new object into result.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000813 LoadAllocationTopHelper(result, result_end, scratch, flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000814
815 // Calculate new top and bail out if new space is exhausted.
816 ExternalReference new_space_allocation_limit =
817 ExternalReference::new_space_allocation_limit_address();
818 if (!object_size.is(result_end)) {
819 mov(result_end, object_size);
820 }
821 add(result_end, Operand(result));
822 cmp(result_end, Operand::StaticVariable(new_space_allocation_limit));
823 j(above, gc_required, not_taken);
824
ager@chromium.orga1645e22009-09-09 19:27:10 +0000825 // Tag result if requested.
826 if ((flags & TAG_OBJECT) != 0) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000827 lea(result, Operand(result, kHeapObjectTag));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000828 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000829
830 // Update allocation top.
831 UpdateAllocationTopHelper(result_end, scratch);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000832}
833
834
835void MacroAssembler::UndoAllocationInNewSpace(Register object) {
836 ExternalReference new_space_allocation_top =
837 ExternalReference::new_space_allocation_top_address();
838
839 // Make sure the object has no tag before resetting top.
840 and_(Operand(object), Immediate(~kHeapObjectTagMask));
841#ifdef DEBUG
842 cmp(object, Operand::StaticVariable(new_space_allocation_top));
843 Check(below, "Undo allocation of non allocated memory");
844#endif
845 mov(Operand::StaticVariable(new_space_allocation_top), object);
846}
847
848
ager@chromium.org3811b432009-10-28 14:53:37 +0000849void MacroAssembler::AllocateHeapNumber(Register result,
850 Register scratch1,
851 Register scratch2,
852 Label* gc_required) {
853 // Allocate heap number in new space.
854 AllocateInNewSpace(HeapNumber::kSize,
855 result,
856 scratch1,
857 scratch2,
858 gc_required,
859 TAG_OBJECT);
860
861 // Set the map.
862 mov(FieldOperand(result, HeapObject::kMapOffset),
863 Immediate(Factory::heap_number_map()));
864}
865
866
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000867void MacroAssembler::AllocateTwoByteString(Register result,
868 Register length,
869 Register scratch1,
870 Register scratch2,
871 Register scratch3,
872 Label* gc_required) {
873 // Calculate the number of bytes needed for the characters in the string while
874 // observing object alignment.
875 ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000876 ASSERT(kShortSize == 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000877 // scratch1 = length * 2 + kObjectAlignmentMask.
878 lea(scratch1, Operand(length, length, times_1, kObjectAlignmentMask));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000879 and_(Operand(scratch1), Immediate(~kObjectAlignmentMask));
880
881 // Allocate two byte string in new space.
882 AllocateInNewSpace(SeqTwoByteString::kHeaderSize,
883 times_1,
884 scratch1,
885 result,
886 scratch2,
887 scratch3,
888 gc_required,
889 TAG_OBJECT);
890
891 // Set the map, length and hash field.
892 mov(FieldOperand(result, HeapObject::kMapOffset),
893 Immediate(Factory::string_map()));
894 mov(FieldOperand(result, String::kLengthOffset), length);
895 mov(FieldOperand(result, String::kHashFieldOffset),
896 Immediate(String::kEmptyHashField));
897}
898
899
900void MacroAssembler::AllocateAsciiString(Register result,
901 Register length,
902 Register scratch1,
903 Register scratch2,
904 Register scratch3,
905 Label* gc_required) {
906 // Calculate the number of bytes needed for the characters in the string while
907 // observing object alignment.
908 ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
909 mov(scratch1, length);
910 ASSERT(kCharSize == 1);
911 add(Operand(scratch1), Immediate(kObjectAlignmentMask));
912 and_(Operand(scratch1), Immediate(~kObjectAlignmentMask));
913
914 // Allocate ascii string in new space.
915 AllocateInNewSpace(SeqAsciiString::kHeaderSize,
916 times_1,
917 scratch1,
918 result,
919 scratch2,
920 scratch3,
921 gc_required,
922 TAG_OBJECT);
923
924 // Set the map, length and hash field.
925 mov(FieldOperand(result, HeapObject::kMapOffset),
926 Immediate(Factory::ascii_string_map()));
927 mov(FieldOperand(result, String::kLengthOffset), length);
928 mov(FieldOperand(result, String::kHashFieldOffset),
929 Immediate(String::kEmptyHashField));
930}
931
932
933void MacroAssembler::AllocateConsString(Register result,
934 Register scratch1,
935 Register scratch2,
936 Label* gc_required) {
937 // Allocate heap number in new space.
938 AllocateInNewSpace(ConsString::kSize,
939 result,
940 scratch1,
941 scratch2,
942 gc_required,
943 TAG_OBJECT);
944
945 // Set the map. The other fields are left uninitialized.
946 mov(FieldOperand(result, HeapObject::kMapOffset),
947 Immediate(Factory::cons_string_map()));
948}
949
950
951void MacroAssembler::AllocateAsciiConsString(Register result,
952 Register scratch1,
953 Register scratch2,
954 Label* gc_required) {
955 // Allocate heap number in new space.
956 AllocateInNewSpace(ConsString::kSize,
957 result,
958 scratch1,
959 scratch2,
960 gc_required,
961 TAG_OBJECT);
962
963 // Set the map. The other fields are left uninitialized.
964 mov(FieldOperand(result, HeapObject::kMapOffset),
965 Immediate(Factory::cons_ascii_string_map()));
966}
967
968
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000969void MacroAssembler::NegativeZeroTest(CodeGenerator* cgen,
970 Register result,
971 Register op,
972 JumpTarget* then_target) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000973 JumpTarget ok;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000974 test(result, Operand(result));
975 ok.Branch(not_zero, taken);
976 test(op, Operand(op));
977 then_target->Branch(sign, not_taken);
978 ok.Bind();
979}
980
981
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000982void MacroAssembler::NegativeZeroTest(Register result,
983 Register op,
984 Label* then_label) {
985 Label ok;
986 test(result, Operand(result));
987 j(not_zero, &ok, taken);
988 test(op, Operand(op));
989 j(sign, then_label, not_taken);
990 bind(&ok);
991}
992
993
994void MacroAssembler::NegativeZeroTest(Register result,
995 Register op1,
996 Register op2,
997 Register scratch,
998 Label* then_label) {
999 Label ok;
1000 test(result, Operand(result));
1001 j(not_zero, &ok, taken);
1002 mov(scratch, Operand(op1));
1003 or_(scratch, Operand(op2));
1004 j(sign, then_label, not_taken);
1005 bind(&ok);
1006}
1007
1008
ager@chromium.org7c537e22008-10-16 08:43:32 +00001009void MacroAssembler::TryGetFunctionPrototype(Register function,
1010 Register result,
1011 Register scratch,
1012 Label* miss) {
1013 // Check that the receiver isn't a smi.
1014 test(function, Immediate(kSmiTagMask));
1015 j(zero, miss, not_taken);
1016
1017 // Check that the function really is a function.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001018 CmpObjectType(function, JS_FUNCTION_TYPE, result);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001019 j(not_equal, miss, not_taken);
1020
1021 // Make sure that the function has an instance prototype.
1022 Label non_instance;
1023 movzx_b(scratch, FieldOperand(result, Map::kBitFieldOffset));
1024 test(scratch, Immediate(1 << Map::kHasNonInstancePrototype));
1025 j(not_zero, &non_instance, not_taken);
1026
1027 // Get the prototype or initial map from the function.
1028 mov(result,
1029 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
1030
1031 // If the prototype or initial map is the hole, don't return it and
1032 // simply miss the cache instead. This will allow us to allocate a
1033 // prototype object on-demand in the runtime system.
1034 cmp(Operand(result), Immediate(Factory::the_hole_value()));
1035 j(equal, miss, not_taken);
1036
1037 // If the function does not have an initial map, we're done.
1038 Label done;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001039 CmpObjectType(result, MAP_TYPE, scratch);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001040 j(not_equal, &done);
1041
1042 // Get the prototype from the initial map.
1043 mov(result, FieldOperand(result, Map::kPrototypeOffset));
1044 jmp(&done);
1045
1046 // Non-instance prototype: Fetch prototype from constructor field
1047 // in initial map.
1048 bind(&non_instance);
1049 mov(result, FieldOperand(result, Map::kConstructorOffset));
1050
1051 // All done.
1052 bind(&done);
1053}
1054
1055
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001056void MacroAssembler::CallStub(CodeStub* stub) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001057 ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs.
ager@chromium.org236ad962008-09-25 09:45:57 +00001058 call(stub->GetCode(), RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001059}
1060
1061
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001062Object* MacroAssembler::TryCallStub(CodeStub* stub) {
1063 ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs.
1064 Object* result = stub->TryGetCode();
1065 if (!result->IsFailure()) {
1066 call(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET);
1067 }
1068 return result;
1069}
1070
1071
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001072void MacroAssembler::TailCallStub(CodeStub* stub) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001073 ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001074 jmp(stub->GetCode(), RelocInfo::CODE_TARGET);
1075}
1076
1077
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001078Object* MacroAssembler::TryTailCallStub(CodeStub* stub) {
1079 ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs.
1080 Object* result = stub->TryGetCode();
1081 if (!result->IsFailure()) {
1082 jmp(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET);
1083 }
1084 return result;
1085}
1086
1087
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088void MacroAssembler::StubReturn(int argc) {
1089 ASSERT(argc >= 1 && generating_stub());
1090 ret((argc - 1) * kPointerSize);
1091}
1092
1093
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001094void MacroAssembler::IllegalOperation(int num_arguments) {
1095 if (num_arguments > 0) {
1096 add(Operand(esp), Immediate(num_arguments * kPointerSize));
1097 }
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001098 mov(eax, Immediate(Factory::undefined_value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001099}
1100
1101
1102void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) {
1103 CallRuntime(Runtime::FunctionForId(id), num_arguments);
1104}
1105
1106
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001107Object* MacroAssembler::TryCallRuntime(Runtime::FunctionId id,
1108 int num_arguments) {
1109 return TryCallRuntime(Runtime::FunctionForId(id), num_arguments);
1110}
1111
1112
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001113void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
mads.s.ager31e71382008-08-13 09:32:07 +00001114 // If the expected number of arguments of the runtime function is
1115 // constant, we check that the actual number of arguments match the
1116 // expectation.
1117 if (f->nargs >= 0 && f->nargs != num_arguments) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001118 IllegalOperation(num_arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001119 return;
1120 }
1121
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001122 // TODO(1236192): Most runtime routines don't need the number of
1123 // arguments passed in because it is constant. At some point we
1124 // should remove this need and make the runtime routine entry code
1125 // smarter.
1126 Set(eax, Immediate(num_arguments));
1127 mov(ebx, Immediate(ExternalReference(f)));
1128 CEntryStub ces(1);
1129 CallStub(&ces);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001130}
1131
1132
ager@chromium.org5c838252010-02-19 08:53:10 +00001133void MacroAssembler::CallExternalReference(ExternalReference ref,
1134 int num_arguments) {
1135 mov(eax, Immediate(num_arguments));
1136 mov(ebx, Immediate(ref));
1137
1138 CEntryStub stub(1);
1139 CallStub(&stub);
1140}
1141
1142
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001143Object* MacroAssembler::TryCallRuntime(Runtime::Function* f,
1144 int num_arguments) {
1145 if (f->nargs >= 0 && f->nargs != num_arguments) {
1146 IllegalOperation(num_arguments);
1147 // Since we did not call the stub, there was no allocation failure.
1148 // Return some non-failure object.
1149 return Heap::undefined_value();
1150 }
1151
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001152 // TODO(1236192): Most runtime routines don't need the number of
1153 // arguments passed in because it is constant. At some point we
1154 // should remove this need and make the runtime routine entry code
1155 // smarter.
1156 Set(eax, Immediate(num_arguments));
1157 mov(ebx, Immediate(ExternalReference(f)));
1158 CEntryStub ces(1);
1159 return TryCallStub(&ces);
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001160}
1161
1162
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001163void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
1164 int num_arguments,
1165 int result_size) {
mads.s.ager31e71382008-08-13 09:32:07 +00001166 // TODO(1236192): Most runtime routines don't need the number of
1167 // arguments passed in because it is constant. At some point we
1168 // should remove this need and make the runtime routine entry code
1169 // smarter.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001170 Set(eax, Immediate(num_arguments));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001171 JumpToExternalReference(ext);
1172}
1173
1174
1175void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
1176 int num_arguments,
1177 int result_size) {
1178 TailCallExternalReference(ExternalReference(fid), num_arguments, result_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179}
1180
1181
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001182void MacroAssembler::PushHandleScope(Register scratch) {
1183 // Push the number of extensions, smi-tagged so the gc will ignore it.
1184 ExternalReference extensions_address =
1185 ExternalReference::handle_scope_extensions_address();
1186 mov(scratch, Operand::StaticVariable(extensions_address));
1187 ASSERT_EQ(0, kSmiTag);
1188 shl(scratch, kSmiTagSize);
1189 push(scratch);
1190 mov(Operand::StaticVariable(extensions_address), Immediate(0));
1191 // Push next and limit pointers which will be wordsize aligned and
1192 // hence automatically smi tagged.
1193 ExternalReference next_address =
1194 ExternalReference::handle_scope_next_address();
1195 push(Operand::StaticVariable(next_address));
1196 ExternalReference limit_address =
1197 ExternalReference::handle_scope_limit_address();
1198 push(Operand::StaticVariable(limit_address));
1199}
1200
1201
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001202Object* MacroAssembler::PopHandleScopeHelper(Register saved,
1203 Register scratch,
1204 bool gc_allowed) {
1205 Object* result = NULL;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001206 ExternalReference extensions_address =
1207 ExternalReference::handle_scope_extensions_address();
1208 Label write_back;
1209 mov(scratch, Operand::StaticVariable(extensions_address));
1210 cmp(Operand(scratch), Immediate(0));
1211 j(equal, &write_back);
1212 // Calling a runtime function messes with registers so we save and
1213 // restore any one we're asked not to change
1214 if (saved.is_valid()) push(saved);
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001215 if (gc_allowed) {
1216 CallRuntime(Runtime::kDeleteHandleScopeExtensions, 0);
1217 } else {
1218 result = TryCallRuntime(Runtime::kDeleteHandleScopeExtensions, 0);
1219 if (result->IsFailure()) return result;
1220 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001221 if (saved.is_valid()) pop(saved);
1222
1223 bind(&write_back);
1224 ExternalReference limit_address =
1225 ExternalReference::handle_scope_limit_address();
1226 pop(Operand::StaticVariable(limit_address));
1227 ExternalReference next_address =
1228 ExternalReference::handle_scope_next_address();
1229 pop(Operand::StaticVariable(next_address));
1230 pop(scratch);
1231 shr(scratch, kSmiTagSize);
1232 mov(Operand::StaticVariable(extensions_address), scratch);
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001233
1234 return result;
1235}
1236
1237
1238void MacroAssembler::PopHandleScope(Register saved, Register scratch) {
1239 PopHandleScopeHelper(saved, scratch, true);
1240}
1241
1242
1243Object* MacroAssembler::TryPopHandleScope(Register saved, Register scratch) {
1244 return PopHandleScopeHelper(saved, scratch, false);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001245}
1246
1247
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001248void MacroAssembler::JumpToExternalReference(const ExternalReference& ext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249 // Set the entry point and jump to the C entry runtime stub.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001250 mov(ebx, Immediate(ext));
ager@chromium.orga1645e22009-09-09 19:27:10 +00001251 CEntryStub ces(1);
ager@chromium.org236ad962008-09-25 09:45:57 +00001252 jmp(ces.GetCode(), RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001253}
1254
1255
1256void MacroAssembler::InvokePrologue(const ParameterCount& expected,
1257 const ParameterCount& actual,
1258 Handle<Code> code_constant,
1259 const Operand& code_operand,
1260 Label* done,
1261 InvokeFlag flag) {
1262 bool definitely_matches = false;
1263 Label invoke;
1264 if (expected.is_immediate()) {
1265 ASSERT(actual.is_immediate());
1266 if (expected.immediate() == actual.immediate()) {
1267 definitely_matches = true;
1268 } else {
1269 mov(eax, actual.immediate());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001270 const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
1271 if (expected.immediate() == sentinel) {
1272 // Don't worry about adapting arguments for builtins that
1273 // don't want that done. Skip adaption code by making it look
1274 // like we have a match between expected and actual number of
1275 // arguments.
1276 definitely_matches = true;
1277 } else {
1278 mov(ebx, expected.immediate());
1279 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280 }
1281 } else {
1282 if (actual.is_immediate()) {
1283 // Expected is in register, actual is immediate. This is the
1284 // case when we invoke function values without going through the
1285 // IC mechanism.
1286 cmp(expected.reg(), actual.immediate());
1287 j(equal, &invoke);
1288 ASSERT(expected.reg().is(ebx));
1289 mov(eax, actual.immediate());
1290 } else if (!expected.reg().is(actual.reg())) {
1291 // Both expected and actual are in (different) registers. This
1292 // is the case when we invoke functions using call and apply.
1293 cmp(expected.reg(), Operand(actual.reg()));
1294 j(equal, &invoke);
1295 ASSERT(actual.reg().is(eax));
1296 ASSERT(expected.reg().is(ebx));
1297 }
1298 }
1299
1300 if (!definitely_matches) {
1301 Handle<Code> adaptor =
1302 Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
1303 if (!code_constant.is_null()) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001304 mov(edx, Immediate(code_constant));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag));
1306 } else if (!code_operand.is_reg(edx)) {
1307 mov(edx, code_operand);
1308 }
1309
1310 if (flag == CALL_FUNCTION) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001311 call(adaptor, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312 jmp(done);
1313 } else {
ager@chromium.org236ad962008-09-25 09:45:57 +00001314 jmp(adaptor, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315 }
1316 bind(&invoke);
1317 }
1318}
1319
1320
1321void MacroAssembler::InvokeCode(const Operand& code,
1322 const ParameterCount& expected,
1323 const ParameterCount& actual,
1324 InvokeFlag flag) {
1325 Label done;
1326 InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag);
1327 if (flag == CALL_FUNCTION) {
1328 call(code);
1329 } else {
1330 ASSERT(flag == JUMP_FUNCTION);
1331 jmp(code);
1332 }
1333 bind(&done);
1334}
1335
1336
1337void MacroAssembler::InvokeCode(Handle<Code> code,
1338 const ParameterCount& expected,
1339 const ParameterCount& actual,
ager@chromium.org236ad962008-09-25 09:45:57 +00001340 RelocInfo::Mode rmode,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001341 InvokeFlag flag) {
1342 Label done;
1343 Operand dummy(eax);
1344 InvokePrologue(expected, actual, code, dummy, &done, flag);
1345 if (flag == CALL_FUNCTION) {
1346 call(code, rmode);
1347 } else {
1348 ASSERT(flag == JUMP_FUNCTION);
1349 jmp(code, rmode);
1350 }
1351 bind(&done);
1352}
1353
1354
1355void MacroAssembler::InvokeFunction(Register fun,
1356 const ParameterCount& actual,
1357 InvokeFlag flag) {
1358 ASSERT(fun.is(edi));
1359 mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1360 mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1361 mov(ebx, FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
1362 mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
1363 lea(edx, FieldOperand(edx, Code::kHeaderSize));
1364
1365 ParameterCount expected(ebx);
1366 InvokeCode(Operand(edx), expected, actual, flag);
1367}
1368
1369
ager@chromium.org5c838252010-02-19 08:53:10 +00001370void MacroAssembler::InvokeFunction(JSFunction* function,
1371 const ParameterCount& actual,
1372 InvokeFlag flag) {
1373 ASSERT(function->is_compiled());
1374 // Get the function and setup the context.
1375 mov(edi, Immediate(Handle<JSFunction>(function)));
1376 mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001377
ager@chromium.org5c838252010-02-19 08:53:10 +00001378 // Invoke the cached code.
1379 Handle<Code> code(function->code());
1380 ParameterCount expected(function->shared()->formal_parameter_count());
1381 InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag);
1382}
1383
1384
1385void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001386 // Calls are not allowed in some stubs.
kasper.lund7276f142008-07-30 08:49:36 +00001387 ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001388
1389 // Rely on the assertion to check that the number of provided
1390 // arguments match the expected number of arguments. Fake a
1391 // parameter count to avoid emitting code to do the check.
1392 ParameterCount expected(0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001393 GetBuiltinEntry(edx, id);
1394 InvokeCode(Operand(edx), expected, expected, flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001395}
1396
1397
1398void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001399 // Load the JavaScript builtin function from the builtins object.
1400 mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
1401 mov(edi, FieldOperand(edi, GlobalObject::kBuiltinsOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001402 int builtins_offset =
1403 JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
ager@chromium.org5c838252010-02-19 08:53:10 +00001404 mov(edi, FieldOperand(edi, builtins_offset));
1405 // Load the code entry point from the function into the target register.
1406 mov(target, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1407 mov(target, FieldOperand(target, SharedFunctionInfo::kCodeOffset));
1408 add(Operand(target), Immediate(Code::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001409}
1410
1411
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001412void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
1413 if (context_chain_length > 0) {
1414 // Move up the chain of contexts to the context containing the slot.
1415 mov(dst, Operand(esi, Context::SlotOffset(Context::CLOSURE_INDEX)));
1416 // Load the function context (which is the incoming, outer context).
1417 mov(dst, FieldOperand(dst, JSFunction::kContextOffset));
1418 for (int i = 1; i < context_chain_length; i++) {
1419 mov(dst, Operand(dst, Context::SlotOffset(Context::CLOSURE_INDEX)));
1420 mov(dst, FieldOperand(dst, JSFunction::kContextOffset));
1421 }
1422 // The context may be an intermediate context, not a function context.
1423 mov(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
1424 } else { // Slot is in the current function context.
1425 // The context may be an intermediate context, not a function context.
1426 mov(dst, Operand(esi, Context::SlotOffset(Context::FCONTEXT_INDEX)));
1427 }
1428}
1429
1430
1431
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001432void MacroAssembler::Ret() {
1433 ret(0);
1434}
1435
1436
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001437void MacroAssembler::Drop(int stack_elements) {
1438 if (stack_elements > 0) {
1439 add(Operand(esp), Immediate(stack_elements * kPointerSize));
1440 }
1441}
1442
1443
1444void MacroAssembler::Move(Register dst, Handle<Object> value) {
1445 mov(dst, value);
1446}
1447
1448
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001449void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
1450 if (FLAG_native_code_counters && counter->Enabled()) {
1451 mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
1452 }
1453}
1454
1455
1456void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) {
1457 ASSERT(value > 0);
1458 if (FLAG_native_code_counters && counter->Enabled()) {
1459 Operand operand = Operand::StaticVariable(ExternalReference(counter));
1460 if (value == 1) {
1461 inc(operand);
1462 } else {
1463 add(operand, Immediate(value));
1464 }
1465 }
1466}
1467
1468
1469void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
1470 ASSERT(value > 0);
1471 if (FLAG_native_code_counters && counter->Enabled()) {
1472 Operand operand = Operand::StaticVariable(ExternalReference(counter));
1473 if (value == 1) {
1474 dec(operand);
1475 } else {
1476 sub(operand, Immediate(value));
1477 }
1478 }
1479}
1480
1481
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001482void MacroAssembler::IncrementCounter(Condition cc,
1483 StatsCounter* counter,
1484 int value) {
1485 ASSERT(value > 0);
1486 if (FLAG_native_code_counters && counter->Enabled()) {
1487 Label skip;
1488 j(NegateCondition(cc), &skip);
1489 pushfd();
1490 IncrementCounter(counter, value);
1491 popfd();
1492 bind(&skip);
1493 }
1494}
1495
1496
1497void MacroAssembler::DecrementCounter(Condition cc,
1498 StatsCounter* counter,
1499 int value) {
1500 ASSERT(value > 0);
1501 if (FLAG_native_code_counters && counter->Enabled()) {
1502 Label skip;
1503 j(NegateCondition(cc), &skip);
1504 pushfd();
1505 DecrementCounter(counter, value);
1506 popfd();
1507 bind(&skip);
1508 }
1509}
1510
1511
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001512void MacroAssembler::Assert(Condition cc, const char* msg) {
1513 if (FLAG_debug_code) Check(cc, msg);
1514}
1515
1516
1517void MacroAssembler::Check(Condition cc, const char* msg) {
1518 Label L;
1519 j(cc, &L, taken);
1520 Abort(msg);
1521 // will not return here
1522 bind(&L);
1523}
1524
1525
1526void MacroAssembler::Abort(const char* msg) {
1527 // We want to pass the msg string like a smi to avoid GC
1528 // problems, however msg is not guaranteed to be aligned
1529 // properly. Instead, we pass an aligned pointer that is
ager@chromium.org32912102009-01-16 10:38:43 +00001530 // a proper v8 smi, but also pass the alignment difference
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531 // from the real pointer as a smi.
1532 intptr_t p1 = reinterpret_cast<intptr_t>(msg);
1533 intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag;
1534 ASSERT(reinterpret_cast<Object*>(p0)->IsSmi());
1535#ifdef DEBUG
1536 if (msg != NULL) {
1537 RecordComment("Abort message: ");
1538 RecordComment(msg);
1539 }
1540#endif
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001541 // Disable stub call restrictions to always allow calls to abort.
1542 set_allow_stub_calls(true);
1543
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001544 push(eax);
1545 push(Immediate(p0));
1546 push(Immediate(reinterpret_cast<intptr_t>(Smi::FromInt(p1 - p0))));
1547 CallRuntime(Runtime::kAbort, 2);
1548 // will not return here
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001549 int3();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001550}
1551
1552
ager@chromium.org5c838252010-02-19 08:53:10 +00001553void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii(
1554 Register instance_type,
1555 Register scratch,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001556 Label* failure) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001557 if (!scratch.is(instance_type)) {
1558 mov(scratch, instance_type);
1559 }
1560 and_(scratch,
1561 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask);
1562 cmp(scratch, kStringTag | kSeqStringTag | kAsciiStringTag);
1563 j(not_equal, failure);
1564}
1565
1566
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001567void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register object1,
1568 Register object2,
1569 Register scratch1,
1570 Register scratch2,
1571 Label* failure) {
1572 // Check that both objects are not smis.
1573 ASSERT_EQ(0, kSmiTag);
1574 mov(scratch1, Operand(object1));
1575 and_(scratch1, Operand(object2));
1576 test(scratch1, Immediate(kSmiTagMask));
1577 j(zero, failure);
1578
1579 // Load instance type for both strings.
1580 mov(scratch1, FieldOperand(object1, HeapObject::kMapOffset));
1581 mov(scratch2, FieldOperand(object2, HeapObject::kMapOffset));
1582 movzx_b(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset));
1583 movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset));
1584
1585 // Check that both are flat ascii strings.
1586 const int kFlatAsciiStringMask =
1587 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
1588 const int kFlatAsciiStringTag = ASCII_STRING_TYPE;
1589 // Interleave bits from both instance types and compare them in one check.
1590 ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
1591 and_(scratch1, kFlatAsciiStringMask);
1592 and_(scratch2, kFlatAsciiStringMask);
1593 lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
1594 cmp(scratch1, kFlatAsciiStringTag | (kFlatAsciiStringTag << 3));
1595 j(not_equal, failure);
1596}
1597
1598
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001599void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
1600 int frameAlignment = OS::ActivationFrameAlignment();
1601 if (frameAlignment != 0) {
1602 // Make stack end at alignment and make room for num_arguments words
1603 // and the original value of esp.
1604 mov(scratch, esp);
1605 sub(Operand(esp), Immediate((num_arguments + 1) * kPointerSize));
1606 ASSERT(IsPowerOf2(frameAlignment));
1607 and_(esp, -frameAlignment);
1608 mov(Operand(esp, num_arguments * kPointerSize), scratch);
1609 } else {
1610 sub(Operand(esp), Immediate(num_arguments * kPointerSize));
1611 }
1612}
1613
1614
1615void MacroAssembler::CallCFunction(ExternalReference function,
1616 int num_arguments) {
1617 // Trashing eax is ok as it will be the return value.
1618 mov(Operand(eax), Immediate(function));
1619 CallCFunction(eax, num_arguments);
1620}
1621
1622
1623void MacroAssembler::CallCFunction(Register function,
1624 int num_arguments) {
1625 call(Operand(function));
1626 if (OS::ActivationFrameAlignment() != 0) {
1627 mov(esp, Operand(esp, num_arguments * kPointerSize));
1628 } else {
1629 add(Operand(esp), Immediate(num_arguments * sizeof(int32_t)));
1630 }
1631}
1632
1633
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001634CodePatcher::CodePatcher(byte* address, int size)
ager@chromium.orga1645e22009-09-09 19:27:10 +00001635 : address_(address), size_(size), masm_(address, size + Assembler::kGap) {
ager@chromium.org32912102009-01-16 10:38:43 +00001636 // Create a new macro assembler pointing to the address of the code to patch.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001637 // The size is adjusted with kGap on order for the assembler to generate size
1638 // bytes of instructions without failing with buffer size constraints.
1639 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
1640}
1641
1642
1643CodePatcher::~CodePatcher() {
1644 // Indicate that code has changed.
1645 CPU::FlushICache(address_, size_);
1646
1647 // Check that the code was patched as expected.
1648 ASSERT(masm_.pc_ == address_ + size_);
1649 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
1650}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001651
1652
1653} } // namespace v8::internal