blob: 5caa4c41864310376cc77bc38f73ba00d753f979 [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
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_IA32)
31
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include "bootstrapper.h"
33#include "codegen-inl.h"
34#include "debug.h"
35#include "runtime.h"
36#include "serialize.h"
37
kasperl@chromium.org71affb52009-05-26 05:44:31 +000038namespace v8 {
39namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000041// -------------------------------------------------------------------------
42// MacroAssembler implementation.
43
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044MacroAssembler::MacroAssembler(void* buffer, int size)
45 : Assembler(buffer, size),
kasper.lund7276f142008-07-30 08:49:36 +000046 generating_stub_(false),
kasperl@chromium.org061ef742009-02-27 12:16:20 +000047 allow_stub_calls_(true),
48 code_object_(Heap::undefined_value()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049}
50
51
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000052void MacroAssembler::RecordWriteHelper(Register object,
53 Register addr,
54 Register scratch) {
ager@chromium.orgac091b72010-05-05 07:34:42 +000055 if (FLAG_debug_code) {
56 // Check that the object is not in new space.
57 Label not_in_new_space;
58 InNewSpace(object, scratch, not_equal, &not_in_new_space);
59 Abort("new-space object passed to RecordWriteHelper");
60 bind(&not_in_new_space);
61 }
62
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +000063 // Compute the page start address from the heap object pointer, and reuse
64 // the 'object' register for it.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000065 and_(object, ~Page::kPageAlignmentMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000066
ricow@chromium.org30ce4112010-05-31 10:38:25 +000067 // Compute number of region covering addr. See Page::GetRegionNumberForAddress
68 // method for more details.
69 and_(addr, Page::kPageAlignmentMask);
70 shr(addr, Page::kRegionSizeLog2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000071
ricow@chromium.org30ce4112010-05-31 10:38:25 +000072 // Set dirty mark for region.
73 bts(Operand(object, Page::kDirtyFlagOffset), addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000074}
75
76
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000077void MacroAssembler::InNewSpace(Register object,
78 Register scratch,
79 Condition cc,
80 Label* branch) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000081 ASSERT(cc == equal || cc == not_equal);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000082 if (Serializer::enabled()) {
83 // Can't do arithmetic on external references if it might get serialized.
84 mov(scratch, Operand(object));
85 // The mask isn't really an address. We load it as an external reference in
86 // case the size of the new space is different between the snapshot maker
87 // and the running system.
88 and_(Operand(scratch), Immediate(ExternalReference::new_space_mask()));
89 cmp(Operand(scratch), Immediate(ExternalReference::new_space_start()));
90 j(cc, branch);
91 } else {
92 int32_t new_space_start = reinterpret_cast<int32_t>(
93 ExternalReference::new_space_start().address());
94 lea(scratch, Operand(object, -new_space_start));
95 and_(scratch, Heap::NewSpaceMask());
96 j(cc, branch);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098}
99
100
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000101// For page containing |object| mark region covering [object+offset] dirty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000102// object is the object being stored into, value is the object being stored.
103// If offset is zero, then the scratch register contains the array index into
104// the elements array represented as a Smi.
105// All registers are clobbered by the operation.
106void MacroAssembler::RecordWrite(Register object, int offset,
107 Register value, Register scratch) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000108 // The compiled code assumes that record write doesn't change the
109 // context register, so we check that none of the clobbered
110 // registers are esi.
111 ASSERT(!object.is(esi) && !value.is(esi) && !scratch.is(esi));
112
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000113 // First, check if a write barrier is even needed. The tests below
114 // catch stores of Smis and stores into young gen.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000115 Label done;
116
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000117 // Skip barrier if writing a smi.
118 ASSERT_EQ(0, kSmiTag);
119 test(value, Immediate(kSmiTagMask));
120 j(zero, &done);
121
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000122 InNewSpace(object, value, equal, &done);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123
whesse@chromium.orge88a9ed2010-04-15 15:07:46 +0000124 // The offset is relative to a tagged or untagged HeapObject pointer,
125 // so either offset or offset + kHeapObjectTag must be a
126 // multiple of kPointerSize.
127 ASSERT(IsAligned(offset, kPointerSize) ||
128 IsAligned(offset + kHeapObjectTag, kPointerSize));
129
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000130 Register dst = scratch;
131 if (offset != 0) {
132 lea(dst, Operand(object, offset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000133 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000134 // Array access: calculate the destination address in the same manner as
135 // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset
136 // into an array of words.
137 ASSERT_EQ(1, kSmiTagSize);
138 ASSERT_EQ(0, kSmiTag);
139 lea(dst, Operand(object, dst, times_half_pointer_size,
140 FixedArray::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000141 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000142 RecordWriteHelper(object, dst, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000143
144 bind(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000145
146 // Clobber all input registers when running with the debug-code flag
147 // turned on to provoke errors.
148 if (FLAG_debug_code) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000149 mov(object, Immediate(BitCast<int32_t>(kZapValue)));
150 mov(value, Immediate(BitCast<int32_t>(kZapValue)));
151 mov(scratch, Immediate(BitCast<int32_t>(kZapValue)));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000153}
154
155
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000156void MacroAssembler::StackLimitCheck(Label* on_stack_overflow) {
157 cmp(esp,
158 Operand::StaticVariable(ExternalReference::address_of_stack_limit()));
159 j(below, on_stack_overflow);
160}
161
162
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000163#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000164void MacroAssembler::SaveRegistersToMemory(RegList regs) {
165 ASSERT((regs & ~kJSCallerSaved) == 0);
166 // Copy the content of registers to memory location.
167 for (int i = 0; i < kNumJSCallerSaved; i++) {
168 int r = JSCallerSavedCode(i);
169 if ((regs & (1 << r)) != 0) {
170 Register reg = { r };
171 ExternalReference reg_addr =
172 ExternalReference(Debug_Address::Register(i));
173 mov(Operand::StaticVariable(reg_addr), reg);
174 }
175 }
176}
177
178
179void MacroAssembler::RestoreRegistersFromMemory(RegList regs) {
180 ASSERT((regs & ~kJSCallerSaved) == 0);
181 // Copy the content of memory location to registers.
182 for (int i = kNumJSCallerSaved; --i >= 0;) {
183 int r = JSCallerSavedCode(i);
184 if ((regs & (1 << r)) != 0) {
185 Register reg = { r };
186 ExternalReference reg_addr =
187 ExternalReference(Debug_Address::Register(i));
188 mov(reg, Operand::StaticVariable(reg_addr));
189 }
190 }
191}
192
193
194void MacroAssembler::PushRegistersFromMemory(RegList regs) {
195 ASSERT((regs & ~kJSCallerSaved) == 0);
196 // Push the content of the memory location to the stack.
197 for (int i = 0; i < kNumJSCallerSaved; i++) {
198 int r = JSCallerSavedCode(i);
199 if ((regs & (1 << r)) != 0) {
200 ExternalReference reg_addr =
201 ExternalReference(Debug_Address::Register(i));
202 push(Operand::StaticVariable(reg_addr));
203 }
204 }
205}
206
207
208void MacroAssembler::PopRegistersToMemory(RegList regs) {
209 ASSERT((regs & ~kJSCallerSaved) == 0);
210 // Pop the content from the stack to the memory location.
211 for (int i = kNumJSCallerSaved; --i >= 0;) {
212 int r = JSCallerSavedCode(i);
213 if ((regs & (1 << r)) != 0) {
214 ExternalReference reg_addr =
215 ExternalReference(Debug_Address::Register(i));
216 pop(Operand::StaticVariable(reg_addr));
217 }
218 }
219}
220
221
222void MacroAssembler::CopyRegistersFromStackToMemory(Register base,
223 Register scratch,
224 RegList regs) {
225 ASSERT((regs & ~kJSCallerSaved) == 0);
226 // Copy the content of the stack to the memory location and adjust base.
227 for (int i = kNumJSCallerSaved; --i >= 0;) {
228 int r = JSCallerSavedCode(i);
229 if ((regs & (1 << r)) != 0) {
230 mov(scratch, Operand(base, 0));
231 ExternalReference reg_addr =
232 ExternalReference(Debug_Address::Register(i));
233 mov(Operand::StaticVariable(reg_addr), scratch);
234 lea(base, Operand(base, kPointerSize));
235 }
236 }
237}
ager@chromium.org5c838252010-02-19 08:53:10 +0000238
239void MacroAssembler::DebugBreak() {
240 Set(eax, Immediate(0));
241 mov(ebx, Immediate(ExternalReference(Runtime::kDebugBreak)));
242 CEntryStub ces(1);
243 call(ces.GetCode(), RelocInfo::DEBUG_BREAK);
244}
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000245#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000246
247void MacroAssembler::Set(Register dst, const Immediate& x) {
248 if (x.is_zero()) {
249 xor_(dst, Operand(dst)); // shorter than mov
250 } else {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000251 mov(dst, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000252 }
253}
254
255
256void MacroAssembler::Set(const Operand& dst, const Immediate& x) {
257 mov(dst, x);
258}
259
260
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000261void MacroAssembler::CmpObjectType(Register heap_object,
262 InstanceType type,
263 Register map) {
264 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
265 CmpInstanceType(map, type);
266}
267
268
269void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
270 cmpb(FieldOperand(map, Map::kInstanceTypeOffset),
271 static_cast<int8_t>(type));
272}
273
274
ager@chromium.org5c838252010-02-19 08:53:10 +0000275void MacroAssembler::CheckMap(Register obj,
276 Handle<Map> map,
277 Label* fail,
278 bool is_heap_object) {
279 if (!is_heap_object) {
280 test(obj, Immediate(kSmiTagMask));
281 j(zero, fail);
282 }
283 cmp(FieldOperand(obj, HeapObject::kMapOffset), Immediate(map));
284 j(not_equal, fail);
285}
286
287
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000288Condition MacroAssembler::IsObjectStringType(Register heap_object,
289 Register map,
290 Register instance_type) {
291 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
292 movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
293 ASSERT(kNotStringTag != 0);
294 test(instance_type, Immediate(kIsNotStringMask));
295 return zero;
296}
297
298
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000299void MacroAssembler::FCmp() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000300 if (CpuFeatures::IsSupported(CMOV)) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000301 fucomip();
302 ffree(0);
303 fincstp();
304 } else {
305 fucompp();
306 push(eax);
307 fnstsw_ax();
308 sahf();
309 pop(eax);
310 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000311}
312
313
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000314void MacroAssembler::AbortIfNotNumber(Register object) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000315 Label ok;
316 test(object, Immediate(kSmiTagMask));
317 j(zero, &ok);
318 cmp(FieldOperand(object, HeapObject::kMapOffset),
319 Factory::heap_number_map());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000320 Assert(equal, "Operand not a number");
ager@chromium.org5c838252010-02-19 08:53:10 +0000321 bind(&ok);
322}
323
324
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000325void MacroAssembler::AbortIfNotSmi(Register object) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000326 test(object, Immediate(kSmiTagMask));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000327 Assert(equal, "Operand not a smi");
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000328}
329
330
ager@chromium.org7c537e22008-10-16 08:43:32 +0000331void MacroAssembler::EnterFrame(StackFrame::Type type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000332 push(ebp);
333 mov(ebp, Operand(esp));
334 push(esi);
335 push(Immediate(Smi::FromInt(type)));
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000336 push(Immediate(CodeObject()));
337 if (FLAG_debug_code) {
338 cmp(Operand(esp, 0), Immediate(Factory::undefined_value()));
339 Check(not_equal, "code object not properly patched");
340 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000341}
342
343
ager@chromium.org7c537e22008-10-16 08:43:32 +0000344void MacroAssembler::LeaveFrame(StackFrame::Type type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345 if (FLAG_debug_code) {
346 cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset),
347 Immediate(Smi::FromInt(type)));
348 Check(equal, "stack frame types must match");
349 }
350 leave();
351}
352
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000353void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000354 // Setup the frame structure on the stack.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000355 ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize);
ager@chromium.org236ad962008-09-25 09:45:57 +0000356 ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize);
357 ASSERT(ExitFrameConstants::kCallerFPOffset == 0 * kPointerSize);
358 push(ebp);
359 mov(ebp, Operand(esp));
360
361 // Reserve room for entry stack pointer and push the debug marker.
362 ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize);
ager@chromium.org5c838252010-02-19 08:53:10 +0000363 push(Immediate(0)); // Saved entry sp, patched before call.
364 push(Immediate(CodeObject())); // Accessed from ExitFrame::code_slot.
ager@chromium.org236ad962008-09-25 09:45:57 +0000365
366 // Save the frame pointer and the context in top.
367 ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
368 ExternalReference context_address(Top::k_context_address);
369 mov(Operand::StaticVariable(c_entry_fp_address), ebp);
370 mov(Operand::StaticVariable(context_address), esi);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000371}
ager@chromium.org236ad962008-09-25 09:45:57 +0000372
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000373void MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode, int argc) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000374#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org236ad962008-09-25 09:45:57 +0000375 // Save the state of all registers to the stack from the memory
376 // location. This is needed to allow nested break points.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000377 if (mode == ExitFrame::MODE_DEBUG) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000378 // TODO(1243899): This should be symmetric to
379 // CopyRegistersFromStackToMemory() but it isn't! esp is assumed
380 // correct here, but computed for the other call. Very error
381 // prone! FIX THIS. Actually there are deeper problems with
382 // register saving than this asymmetry (see the bug report
383 // associated with this issue).
384 PushRegistersFromMemory(kJSCallerSaved);
385 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000386#endif
ager@chromium.org236ad962008-09-25 09:45:57 +0000387
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000388 // Reserve space for arguments.
389 sub(Operand(esp), Immediate(argc * kPointerSize));
ager@chromium.org236ad962008-09-25 09:45:57 +0000390
391 // Get the required frame alignment for the OS.
392 static const int kFrameAlignment = OS::ActivationFrameAlignment();
393 if (kFrameAlignment > 0) {
394 ASSERT(IsPowerOf2(kFrameAlignment));
395 and_(esp, -kFrameAlignment);
396 }
397
398 // Patch the saved entry sp.
399 mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp);
400}
401
402
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000403void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) {
404 EnterExitFramePrologue(mode);
405
406 // Setup argc and argv in callee-saved registers.
407 int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
408 mov(edi, Operand(eax));
409 lea(esi, Operand(ebp, eax, times_4, offset));
410
411 EnterExitFrameEpilogue(mode, 2);
412}
413
414
415void MacroAssembler::EnterApiExitFrame(ExitFrame::Mode mode,
416 int stack_space,
417 int argc) {
418 EnterExitFramePrologue(mode);
419
420 int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
421 lea(esi, Operand(ebp, (stack_space * kPointerSize) + offset));
422
423 EnterExitFrameEpilogue(mode, argc);
424}
425
426
427void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000428#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org236ad962008-09-25 09:45:57 +0000429 // Restore the memory copy of the registers by digging them out from
430 // the stack. This is needed to allow nested break points.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000431 if (mode == ExitFrame::MODE_DEBUG) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000432 // It's okay to clobber register ebx below because we don't need
433 // the function pointer after this.
434 const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000435 int kOffset = ExitFrameConstants::kCodeOffset - kCallerSavedSize;
ager@chromium.org236ad962008-09-25 09:45:57 +0000436 lea(ebx, Operand(ebp, kOffset));
437 CopyRegistersFromStackToMemory(ebx, ecx, kJSCallerSaved);
438 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000439#endif
ager@chromium.org236ad962008-09-25 09:45:57 +0000440
441 // Get the return address from the stack and restore the frame pointer.
442 mov(ecx, Operand(ebp, 1 * kPointerSize));
443 mov(ebp, Operand(ebp, 0 * kPointerSize));
444
445 // Pop the arguments and the receiver from the caller stack.
446 lea(esp, Operand(esi, 1 * kPointerSize));
447
448 // Restore current context from top and clear it in debug mode.
449 ExternalReference context_address(Top::k_context_address);
450 mov(esi, Operand::StaticVariable(context_address));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000451#ifdef DEBUG
452 mov(Operand::StaticVariable(context_address), Immediate(0));
453#endif
ager@chromium.org236ad962008-09-25 09:45:57 +0000454
455 // Push the return address to get ready to return.
456 push(ecx);
457
458 // Clear the top frame.
459 ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
460 mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
461}
462
463
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000464void MacroAssembler::PushTryHandler(CodeLocation try_location,
465 HandlerType type) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000466 // Adjust this code if not the case.
467 ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000468 // The pc (return address) is already on TOS.
469 if (try_location == IN_JAVASCRIPT) {
470 if (type == TRY_CATCH_HANDLER) {
471 push(Immediate(StackHandler::TRY_CATCH));
472 } else {
473 push(Immediate(StackHandler::TRY_FINALLY));
474 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000475 push(ebp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000476 } else {
477 ASSERT(try_location == IN_JS_ENTRY);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000478 // The frame pointer does not point to a JS frame so we save NULL
479 // for ebp. We expect the code throwing an exception to check ebp
480 // before dereferencing it to restore the context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000481 push(Immediate(StackHandler::ENTRY));
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000482 push(Immediate(0)); // NULL frame pointer.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000483 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000484 // Save the current handler as the next handler.
485 push(Operand::StaticVariable(ExternalReference(Top::k_handler_address)));
486 // Link this handler as the new current one.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000487 mov(Operand::StaticVariable(ExternalReference(Top::k_handler_address)), esp);
488}
489
490
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000491void MacroAssembler::PopTryHandler() {
492 ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
493 pop(Operand::StaticVariable(ExternalReference(Top::k_handler_address)));
494 add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize));
495}
496
497
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000498Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
499 JSObject* holder, Register holder_reg,
500 Register scratch,
ager@chromium.org5c838252010-02-19 08:53:10 +0000501 int save_at_depth,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000502 Label* miss) {
503 // Make sure there's no overlap between scratch and the other
504 // registers.
505 ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg));
506
507 // Keep track of the current object in register reg.
508 Register reg = object_reg;
ager@chromium.org5c838252010-02-19 08:53:10 +0000509 int depth = 0;
510
511 if (save_at_depth == depth) {
512 mov(Operand(esp, kPointerSize), object_reg);
513 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000514
515 // Check the maps in the prototype chain.
516 // Traverse the prototype chain from the object and do map checks.
517 while (object != holder) {
518 depth++;
519
520 // Only global objects and objects that do not require access
521 // checks are allowed in stubs.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000522 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000523
524 JSObject* prototype = JSObject::cast(object->GetPrototype());
525 if (Heap::InNewSpace(prototype)) {
526 // Get the map of the current object.
527 mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
528 cmp(Operand(scratch), Immediate(Handle<Map>(object->map())));
529 // Branch on the result of the map check.
530 j(not_equal, miss, not_taken);
531 // Check access rights to the global object. This has to happen
532 // after the map check so that we know that the object is
533 // actually a global object.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000534 if (object->IsJSGlobalProxy()) {
535 CheckAccessGlobalProxy(reg, scratch, miss);
536
537 // Restore scratch register to be the map of the object.
538 // We load the prototype from the map in the scratch register.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000539 mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
540 }
541 // The prototype is in new space; we cannot store a reference
542 // to it in the code. Load it from the map.
543 reg = holder_reg; // from now the object is in holder_reg
544 mov(reg, FieldOperand(scratch, Map::kPrototypeOffset));
545 } else {
546 // Check the map of the current object.
547 cmp(FieldOperand(reg, HeapObject::kMapOffset),
548 Immediate(Handle<Map>(object->map())));
549 // Branch on the result of the map check.
550 j(not_equal, miss, not_taken);
551 // Check access rights to the global object. This has to happen
552 // after the map check so that we know that the object is
553 // actually a global object.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000554 if (object->IsJSGlobalProxy()) {
555 CheckAccessGlobalProxy(reg, scratch, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000556 }
557 // The prototype is in old space; load it directly.
558 reg = holder_reg; // from now the object is in holder_reg
559 mov(reg, Handle<JSObject>(prototype));
560 }
561
ager@chromium.org5c838252010-02-19 08:53:10 +0000562 if (save_at_depth == depth) {
563 mov(Operand(esp, kPointerSize), reg);
564 }
565
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566 // Go to the next object in the prototype chain.
567 object = prototype;
568 }
569
570 // Check the holder map.
571 cmp(FieldOperand(reg, HeapObject::kMapOffset),
572 Immediate(Handle<Map>(holder->map())));
573 j(not_equal, miss, not_taken);
574
575 // Log the check depth.
ager@chromium.org5c838252010-02-19 08:53:10 +0000576 LOG(IntEvent("check-maps-depth", depth + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000577
578 // Perform security check for access to the global object and return
579 // the holder register.
580 ASSERT(object == holder);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000581 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
582 if (object->IsJSGlobalProxy()) {
583 CheckAccessGlobalProxy(reg, scratch, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000584 }
585 return reg;
586}
587
588
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000589void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
ager@chromium.orge2902be2009-06-08 12:21:35 +0000590 Register scratch,
591 Label* miss) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000592 Label same_contexts;
593
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000594 ASSERT(!holder_reg.is(scratch));
595
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000596 // Load current lexical context from the stack frame.
597 mov(scratch, Operand(ebp, StandardFrameConstants::kContextOffset));
598
599 // When generating debug code, make sure the lexical context is set.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000600 if (FLAG_debug_code) {
601 cmp(Operand(scratch), Immediate(0));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000602 Check(not_equal, "we should not have an empty lexical context");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000603 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000604 // Load the global context of the current context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000605 int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
606 mov(scratch, FieldOperand(scratch, offset));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000607 mov(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
608
609 // Check the context is a global context.
610 if (FLAG_debug_code) {
611 push(scratch);
612 // Read the first word and compare to global_context_map.
613 mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
614 cmp(scratch, Factory::global_context_map());
615 Check(equal, "JSGlobalObject::global_context should be a global context.");
616 pop(scratch);
617 }
618
619 // Check if both contexts are the same.
620 cmp(scratch, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
621 j(equal, &same_contexts, taken);
622
623 // Compare security tokens, save holder_reg on the stack so we can use it
624 // as a temporary register.
625 //
626 // TODO(119): avoid push(holder_reg)/pop(holder_reg)
627 push(holder_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000628 // Check that the security token in the calling global object is
629 // compatible with the security token in the receiving global
630 // object.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000631 mov(holder_reg, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
632
633 // Check the context is a global context.
634 if (FLAG_debug_code) {
635 cmp(holder_reg, Factory::null_value());
636 Check(not_equal, "JSGlobalProxy::context() should not be null.");
637
638 push(holder_reg);
639 // Read the first word and compare to global_context_map(),
640 mov(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset));
641 cmp(holder_reg, Factory::global_context_map());
642 Check(equal, "JSGlobalObject::global_context should be a global context.");
643 pop(holder_reg);
644 }
645
646 int token_offset = Context::kHeaderSize +
647 Context::SECURITY_TOKEN_INDEX * kPointerSize;
648 mov(scratch, FieldOperand(scratch, token_offset));
649 cmp(scratch, FieldOperand(holder_reg, token_offset));
650 pop(holder_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000651 j(not_equal, miss, not_taken);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000652
653 bind(&same_contexts);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000654}
655
656
ager@chromium.orga1645e22009-09-09 19:27:10 +0000657void MacroAssembler::LoadAllocationTopHelper(Register result,
658 Register result_end,
659 Register scratch,
660 AllocationFlags flags) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000661 ExternalReference new_space_allocation_top =
662 ExternalReference::new_space_allocation_top_address();
663
664 // Just return if allocation top is already known.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000665 if ((flags & RESULT_CONTAINS_TOP) != 0) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000666 // No use of scratch if allocation top is provided.
667 ASSERT(scratch.is(no_reg));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000668#ifdef DEBUG
669 // Assert that result actually contains top on entry.
670 cmp(result, Operand::StaticVariable(new_space_allocation_top));
671 Check(equal, "Unexpected allocation top");
672#endif
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000673 return;
674 }
675
676 // Move address of new object to result. Use scratch register if available.
677 if (scratch.is(no_reg)) {
678 mov(result, Operand::StaticVariable(new_space_allocation_top));
679 } else {
680 ASSERT(!scratch.is(result_end));
681 mov(Operand(scratch), Immediate(new_space_allocation_top));
682 mov(result, Operand(scratch, 0));
683 }
684}
685
686
687void MacroAssembler::UpdateAllocationTopHelper(Register result_end,
688 Register scratch) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000689 if (FLAG_debug_code) {
690 test(result_end, Immediate(kObjectAlignmentMask));
691 Check(zero, "Unaligned allocation in new space");
692 }
693
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000694 ExternalReference new_space_allocation_top =
695 ExternalReference::new_space_allocation_top_address();
696
697 // Update new top. Use scratch if available.
698 if (scratch.is(no_reg)) {
699 mov(Operand::StaticVariable(new_space_allocation_top), result_end);
700 } else {
701 mov(Operand(scratch, 0), result_end);
702 }
703}
704
ager@chromium.orga1645e22009-09-09 19:27:10 +0000705
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000706void MacroAssembler::AllocateInNewSpace(int object_size,
707 Register result,
708 Register result_end,
709 Register scratch,
710 Label* gc_required,
711 AllocationFlags flags) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000712 ASSERT(!result.is(result_end));
713
714 // Load address of new object into result.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000715 LoadAllocationTopHelper(result, result_end, scratch, flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000716
717 // Calculate new top and bail out if new space is exhausted.
718 ExternalReference new_space_allocation_limit =
719 ExternalReference::new_space_allocation_limit_address();
720 lea(result_end, Operand(result, object_size));
721 cmp(result_end, Operand::StaticVariable(new_space_allocation_limit));
722 j(above, gc_required, not_taken);
723
ager@chromium.orga1645e22009-09-09 19:27:10 +0000724 // Tag result if requested.
725 if ((flags & TAG_OBJECT) != 0) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000726 lea(result, Operand(result, kHeapObjectTag));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000727 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000728
729 // Update allocation top.
730 UpdateAllocationTopHelper(result_end, scratch);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000731}
732
733
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000734void MacroAssembler::AllocateInNewSpace(int header_size,
735 ScaleFactor element_size,
736 Register element_count,
737 Register result,
738 Register result_end,
739 Register scratch,
740 Label* gc_required,
741 AllocationFlags flags) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000742 ASSERT(!result.is(result_end));
743
744 // Load address of new object into result.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000745 LoadAllocationTopHelper(result, result_end, scratch, flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000746
747 // Calculate new top and bail out if new space is exhausted.
748 ExternalReference new_space_allocation_limit =
749 ExternalReference::new_space_allocation_limit_address();
750 lea(result_end, Operand(result, element_count, element_size, header_size));
751 cmp(result_end, Operand::StaticVariable(new_space_allocation_limit));
752 j(above, gc_required);
753
ager@chromium.orga1645e22009-09-09 19:27:10 +0000754 // Tag result if requested.
755 if ((flags & TAG_OBJECT) != 0) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000756 lea(result, Operand(result, kHeapObjectTag));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000757 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000758
759 // Update allocation top.
760 UpdateAllocationTopHelper(result_end, scratch);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000761}
762
763
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000764void MacroAssembler::AllocateInNewSpace(Register object_size,
765 Register result,
766 Register result_end,
767 Register scratch,
768 Label* gc_required,
769 AllocationFlags flags) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000770 ASSERT(!result.is(result_end));
771
772 // Load address of new object into result.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000773 LoadAllocationTopHelper(result, result_end, scratch, flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000774
775 // Calculate new top and bail out if new space is exhausted.
776 ExternalReference new_space_allocation_limit =
777 ExternalReference::new_space_allocation_limit_address();
778 if (!object_size.is(result_end)) {
779 mov(result_end, object_size);
780 }
781 add(result_end, Operand(result));
782 cmp(result_end, Operand::StaticVariable(new_space_allocation_limit));
783 j(above, gc_required, not_taken);
784
ager@chromium.orga1645e22009-09-09 19:27:10 +0000785 // Tag result if requested.
786 if ((flags & TAG_OBJECT) != 0) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000787 lea(result, Operand(result, kHeapObjectTag));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000788 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000789
790 // Update allocation top.
791 UpdateAllocationTopHelper(result_end, scratch);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000792}
793
794
795void MacroAssembler::UndoAllocationInNewSpace(Register object) {
796 ExternalReference new_space_allocation_top =
797 ExternalReference::new_space_allocation_top_address();
798
799 // Make sure the object has no tag before resetting top.
800 and_(Operand(object), Immediate(~kHeapObjectTagMask));
801#ifdef DEBUG
802 cmp(object, Operand::StaticVariable(new_space_allocation_top));
803 Check(below, "Undo allocation of non allocated memory");
804#endif
805 mov(Operand::StaticVariable(new_space_allocation_top), object);
806}
807
808
ager@chromium.org3811b432009-10-28 14:53:37 +0000809void MacroAssembler::AllocateHeapNumber(Register result,
810 Register scratch1,
811 Register scratch2,
812 Label* gc_required) {
813 // Allocate heap number in new space.
814 AllocateInNewSpace(HeapNumber::kSize,
815 result,
816 scratch1,
817 scratch2,
818 gc_required,
819 TAG_OBJECT);
820
821 // Set the map.
822 mov(FieldOperand(result, HeapObject::kMapOffset),
823 Immediate(Factory::heap_number_map()));
824}
825
826
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000827void MacroAssembler::AllocateTwoByteString(Register result,
828 Register length,
829 Register scratch1,
830 Register scratch2,
831 Register scratch3,
832 Label* gc_required) {
833 // Calculate the number of bytes needed for the characters in the string while
834 // observing object alignment.
835 ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000836 ASSERT(kShortSize == 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000837 // scratch1 = length * 2 + kObjectAlignmentMask.
838 lea(scratch1, Operand(length, length, times_1, kObjectAlignmentMask));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000839 and_(Operand(scratch1), Immediate(~kObjectAlignmentMask));
840
841 // Allocate two byte string in new space.
842 AllocateInNewSpace(SeqTwoByteString::kHeaderSize,
843 times_1,
844 scratch1,
845 result,
846 scratch2,
847 scratch3,
848 gc_required,
849 TAG_OBJECT);
850
851 // Set the map, length and hash field.
852 mov(FieldOperand(result, HeapObject::kMapOffset),
853 Immediate(Factory::string_map()));
ager@chromium.orgac091b72010-05-05 07:34:42 +0000854 mov(scratch1, length);
855 SmiTag(scratch1);
856 mov(FieldOperand(result, String::kLengthOffset), scratch1);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000857 mov(FieldOperand(result, String::kHashFieldOffset),
858 Immediate(String::kEmptyHashField));
859}
860
861
862void MacroAssembler::AllocateAsciiString(Register result,
863 Register length,
864 Register scratch1,
865 Register scratch2,
866 Register scratch3,
867 Label* gc_required) {
868 // Calculate the number of bytes needed for the characters in the string while
869 // observing object alignment.
870 ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
871 mov(scratch1, length);
872 ASSERT(kCharSize == 1);
873 add(Operand(scratch1), Immediate(kObjectAlignmentMask));
874 and_(Operand(scratch1), Immediate(~kObjectAlignmentMask));
875
876 // Allocate ascii string in new space.
877 AllocateInNewSpace(SeqAsciiString::kHeaderSize,
878 times_1,
879 scratch1,
880 result,
881 scratch2,
882 scratch3,
883 gc_required,
884 TAG_OBJECT);
885
886 // Set the map, length and hash field.
887 mov(FieldOperand(result, HeapObject::kMapOffset),
888 Immediate(Factory::ascii_string_map()));
ager@chromium.orgac091b72010-05-05 07:34:42 +0000889 mov(scratch1, length);
890 SmiTag(scratch1);
891 mov(FieldOperand(result, String::kLengthOffset), scratch1);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000892 mov(FieldOperand(result, String::kHashFieldOffset),
893 Immediate(String::kEmptyHashField));
894}
895
896
897void MacroAssembler::AllocateConsString(Register result,
898 Register scratch1,
899 Register scratch2,
900 Label* gc_required) {
901 // Allocate heap number in new space.
902 AllocateInNewSpace(ConsString::kSize,
903 result,
904 scratch1,
905 scratch2,
906 gc_required,
907 TAG_OBJECT);
908
909 // Set the map. The other fields are left uninitialized.
910 mov(FieldOperand(result, HeapObject::kMapOffset),
911 Immediate(Factory::cons_string_map()));
912}
913
914
915void MacroAssembler::AllocateAsciiConsString(Register result,
916 Register scratch1,
917 Register scratch2,
918 Label* gc_required) {
919 // Allocate heap number in new space.
920 AllocateInNewSpace(ConsString::kSize,
921 result,
922 scratch1,
923 scratch2,
924 gc_required,
925 TAG_OBJECT);
926
927 // Set the map. The other fields are left uninitialized.
928 mov(FieldOperand(result, HeapObject::kMapOffset),
929 Immediate(Factory::cons_ascii_string_map()));
930}
931
932
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000933void MacroAssembler::NegativeZeroTest(CodeGenerator* cgen,
934 Register result,
935 Register op,
936 JumpTarget* then_target) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000937 JumpTarget ok;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000938 test(result, Operand(result));
939 ok.Branch(not_zero, taken);
940 test(op, Operand(op));
941 then_target->Branch(sign, not_taken);
942 ok.Bind();
943}
944
945
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000946void MacroAssembler::NegativeZeroTest(Register result,
947 Register op,
948 Label* then_label) {
949 Label ok;
950 test(result, Operand(result));
951 j(not_zero, &ok, taken);
952 test(op, Operand(op));
953 j(sign, then_label, not_taken);
954 bind(&ok);
955}
956
957
958void MacroAssembler::NegativeZeroTest(Register result,
959 Register op1,
960 Register op2,
961 Register scratch,
962 Label* then_label) {
963 Label ok;
964 test(result, Operand(result));
965 j(not_zero, &ok, taken);
966 mov(scratch, Operand(op1));
967 or_(scratch, Operand(op2));
968 j(sign, then_label, not_taken);
969 bind(&ok);
970}
971
972
ager@chromium.org7c537e22008-10-16 08:43:32 +0000973void MacroAssembler::TryGetFunctionPrototype(Register function,
974 Register result,
975 Register scratch,
976 Label* miss) {
977 // Check that the receiver isn't a smi.
978 test(function, Immediate(kSmiTagMask));
979 j(zero, miss, not_taken);
980
981 // Check that the function really is a function.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000982 CmpObjectType(function, JS_FUNCTION_TYPE, result);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000983 j(not_equal, miss, not_taken);
984
985 // Make sure that the function has an instance prototype.
986 Label non_instance;
987 movzx_b(scratch, FieldOperand(result, Map::kBitFieldOffset));
988 test(scratch, Immediate(1 << Map::kHasNonInstancePrototype));
989 j(not_zero, &non_instance, not_taken);
990
991 // Get the prototype or initial map from the function.
992 mov(result,
993 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
994
995 // If the prototype or initial map is the hole, don't return it and
996 // simply miss the cache instead. This will allow us to allocate a
997 // prototype object on-demand in the runtime system.
998 cmp(Operand(result), Immediate(Factory::the_hole_value()));
999 j(equal, miss, not_taken);
1000
1001 // If the function does not have an initial map, we're done.
1002 Label done;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001003 CmpObjectType(result, MAP_TYPE, scratch);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001004 j(not_equal, &done);
1005
1006 // Get the prototype from the initial map.
1007 mov(result, FieldOperand(result, Map::kPrototypeOffset));
1008 jmp(&done);
1009
1010 // Non-instance prototype: Fetch prototype from constructor field
1011 // in initial map.
1012 bind(&non_instance);
1013 mov(result, FieldOperand(result, Map::kConstructorOffset));
1014
1015 // All done.
1016 bind(&done);
1017}
1018
1019
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001020void MacroAssembler::CallStub(CodeStub* stub) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001021 ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs.
ager@chromium.org236ad962008-09-25 09:45:57 +00001022 call(stub->GetCode(), RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001023}
1024
1025
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001026Object* MacroAssembler::TryCallStub(CodeStub* stub) {
1027 ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs.
1028 Object* result = stub->TryGetCode();
1029 if (!result->IsFailure()) {
1030 call(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET);
1031 }
1032 return result;
1033}
1034
1035
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001036void MacroAssembler::TailCallStub(CodeStub* stub) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001037 ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001038 jmp(stub->GetCode(), RelocInfo::CODE_TARGET);
1039}
1040
1041
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001042Object* MacroAssembler::TryTailCallStub(CodeStub* stub) {
1043 ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs.
1044 Object* result = stub->TryGetCode();
1045 if (!result->IsFailure()) {
1046 jmp(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET);
1047 }
1048 return result;
1049}
1050
1051
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001052void MacroAssembler::StubReturn(int argc) {
1053 ASSERT(argc >= 1 && generating_stub());
1054 ret((argc - 1) * kPointerSize);
1055}
1056
1057
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001058void MacroAssembler::IllegalOperation(int num_arguments) {
1059 if (num_arguments > 0) {
1060 add(Operand(esp), Immediate(num_arguments * kPointerSize));
1061 }
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001062 mov(eax, Immediate(Factory::undefined_value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001063}
1064
1065
1066void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) {
1067 CallRuntime(Runtime::FunctionForId(id), num_arguments);
1068}
1069
1070
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001071Object* MacroAssembler::TryCallRuntime(Runtime::FunctionId id,
1072 int num_arguments) {
1073 return TryCallRuntime(Runtime::FunctionForId(id), num_arguments);
1074}
1075
1076
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001077void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
mads.s.ager31e71382008-08-13 09:32:07 +00001078 // If the expected number of arguments of the runtime function is
1079 // constant, we check that the actual number of arguments match the
1080 // expectation.
1081 if (f->nargs >= 0 && f->nargs != num_arguments) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001082 IllegalOperation(num_arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001083 return;
1084 }
1085
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001086 // TODO(1236192): Most runtime routines don't need the number of
1087 // arguments passed in because it is constant. At some point we
1088 // should remove this need and make the runtime routine entry code
1089 // smarter.
1090 Set(eax, Immediate(num_arguments));
1091 mov(ebx, Immediate(ExternalReference(f)));
1092 CEntryStub ces(1);
1093 CallStub(&ces);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001094}
1095
1096
ager@chromium.org5c838252010-02-19 08:53:10 +00001097void MacroAssembler::CallExternalReference(ExternalReference ref,
1098 int num_arguments) {
1099 mov(eax, Immediate(num_arguments));
1100 mov(ebx, Immediate(ref));
1101
1102 CEntryStub stub(1);
1103 CallStub(&stub);
1104}
1105
1106
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001107Object* MacroAssembler::TryCallRuntime(Runtime::Function* f,
1108 int num_arguments) {
1109 if (f->nargs >= 0 && f->nargs != num_arguments) {
1110 IllegalOperation(num_arguments);
1111 // Since we did not call the stub, there was no allocation failure.
1112 // Return some non-failure object.
1113 return Heap::undefined_value();
1114 }
1115
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001116 // TODO(1236192): Most runtime routines don't need the number of
1117 // arguments passed in because it is constant. At some point we
1118 // should remove this need and make the runtime routine entry code
1119 // smarter.
1120 Set(eax, Immediate(num_arguments));
1121 mov(ebx, Immediate(ExternalReference(f)));
1122 CEntryStub ces(1);
1123 return TryCallStub(&ces);
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001124}
1125
1126
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001127void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
1128 int num_arguments,
1129 int result_size) {
mads.s.ager31e71382008-08-13 09:32:07 +00001130 // TODO(1236192): Most runtime routines don't need the number of
1131 // arguments passed in because it is constant. At some point we
1132 // should remove this need and make the runtime routine entry code
1133 // smarter.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001134 Set(eax, Immediate(num_arguments));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001135 JumpToExternalReference(ext);
1136}
1137
1138
1139void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
1140 int num_arguments,
1141 int result_size) {
1142 TailCallExternalReference(ExternalReference(fid), num_arguments, result_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001143}
1144
1145
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001146void MacroAssembler::PushHandleScope(Register scratch) {
1147 // Push the number of extensions, smi-tagged so the gc will ignore it.
1148 ExternalReference extensions_address =
1149 ExternalReference::handle_scope_extensions_address();
1150 mov(scratch, Operand::StaticVariable(extensions_address));
1151 ASSERT_EQ(0, kSmiTag);
1152 shl(scratch, kSmiTagSize);
1153 push(scratch);
1154 mov(Operand::StaticVariable(extensions_address), Immediate(0));
1155 // Push next and limit pointers which will be wordsize aligned and
1156 // hence automatically smi tagged.
1157 ExternalReference next_address =
1158 ExternalReference::handle_scope_next_address();
1159 push(Operand::StaticVariable(next_address));
1160 ExternalReference limit_address =
1161 ExternalReference::handle_scope_limit_address();
1162 push(Operand::StaticVariable(limit_address));
1163}
1164
1165
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001166Object* MacroAssembler::PopHandleScopeHelper(Register saved,
1167 Register scratch,
1168 bool gc_allowed) {
1169 Object* result = NULL;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001170 ExternalReference extensions_address =
1171 ExternalReference::handle_scope_extensions_address();
1172 Label write_back;
1173 mov(scratch, Operand::StaticVariable(extensions_address));
1174 cmp(Operand(scratch), Immediate(0));
1175 j(equal, &write_back);
1176 // Calling a runtime function messes with registers so we save and
1177 // restore any one we're asked not to change
1178 if (saved.is_valid()) push(saved);
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001179 if (gc_allowed) {
1180 CallRuntime(Runtime::kDeleteHandleScopeExtensions, 0);
1181 } else {
1182 result = TryCallRuntime(Runtime::kDeleteHandleScopeExtensions, 0);
1183 if (result->IsFailure()) return result;
1184 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001185 if (saved.is_valid()) pop(saved);
1186
1187 bind(&write_back);
1188 ExternalReference limit_address =
1189 ExternalReference::handle_scope_limit_address();
1190 pop(Operand::StaticVariable(limit_address));
1191 ExternalReference next_address =
1192 ExternalReference::handle_scope_next_address();
1193 pop(Operand::StaticVariable(next_address));
1194 pop(scratch);
1195 shr(scratch, kSmiTagSize);
1196 mov(Operand::StaticVariable(extensions_address), scratch);
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001197
1198 return result;
1199}
1200
1201
1202void MacroAssembler::PopHandleScope(Register saved, Register scratch) {
1203 PopHandleScopeHelper(saved, scratch, true);
1204}
1205
1206
1207Object* MacroAssembler::TryPopHandleScope(Register saved, Register scratch) {
1208 return PopHandleScopeHelper(saved, scratch, false);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001209}
1210
1211
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001212void MacroAssembler::JumpToExternalReference(const ExternalReference& ext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001213 // Set the entry point and jump to the C entry runtime stub.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001214 mov(ebx, Immediate(ext));
ager@chromium.orga1645e22009-09-09 19:27:10 +00001215 CEntryStub ces(1);
ager@chromium.org236ad962008-09-25 09:45:57 +00001216 jmp(ces.GetCode(), RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001217}
1218
1219
1220void MacroAssembler::InvokePrologue(const ParameterCount& expected,
1221 const ParameterCount& actual,
1222 Handle<Code> code_constant,
1223 const Operand& code_operand,
1224 Label* done,
1225 InvokeFlag flag) {
1226 bool definitely_matches = false;
1227 Label invoke;
1228 if (expected.is_immediate()) {
1229 ASSERT(actual.is_immediate());
1230 if (expected.immediate() == actual.immediate()) {
1231 definitely_matches = true;
1232 } else {
1233 mov(eax, actual.immediate());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001234 const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
1235 if (expected.immediate() == sentinel) {
1236 // Don't worry about adapting arguments for builtins that
1237 // don't want that done. Skip adaption code by making it look
1238 // like we have a match between expected and actual number of
1239 // arguments.
1240 definitely_matches = true;
1241 } else {
1242 mov(ebx, expected.immediate());
1243 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001244 }
1245 } else {
1246 if (actual.is_immediate()) {
1247 // Expected is in register, actual is immediate. This is the
1248 // case when we invoke function values without going through the
1249 // IC mechanism.
1250 cmp(expected.reg(), actual.immediate());
1251 j(equal, &invoke);
1252 ASSERT(expected.reg().is(ebx));
1253 mov(eax, actual.immediate());
1254 } else if (!expected.reg().is(actual.reg())) {
1255 // Both expected and actual are in (different) registers. This
1256 // is the case when we invoke functions using call and apply.
1257 cmp(expected.reg(), Operand(actual.reg()));
1258 j(equal, &invoke);
1259 ASSERT(actual.reg().is(eax));
1260 ASSERT(expected.reg().is(ebx));
1261 }
1262 }
1263
1264 if (!definitely_matches) {
1265 Handle<Code> adaptor =
1266 Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
1267 if (!code_constant.is_null()) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001268 mov(edx, Immediate(code_constant));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269 add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag));
1270 } else if (!code_operand.is_reg(edx)) {
1271 mov(edx, code_operand);
1272 }
1273
1274 if (flag == CALL_FUNCTION) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001275 call(adaptor, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001276 jmp(done);
1277 } else {
ager@chromium.org236ad962008-09-25 09:45:57 +00001278 jmp(adaptor, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001279 }
1280 bind(&invoke);
1281 }
1282}
1283
1284
1285void MacroAssembler::InvokeCode(const Operand& code,
1286 const ParameterCount& expected,
1287 const ParameterCount& actual,
1288 InvokeFlag flag) {
1289 Label done;
1290 InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag);
1291 if (flag == CALL_FUNCTION) {
1292 call(code);
1293 } else {
1294 ASSERT(flag == JUMP_FUNCTION);
1295 jmp(code);
1296 }
1297 bind(&done);
1298}
1299
1300
1301void MacroAssembler::InvokeCode(Handle<Code> code,
1302 const ParameterCount& expected,
1303 const ParameterCount& actual,
ager@chromium.org236ad962008-09-25 09:45:57 +00001304 RelocInfo::Mode rmode,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 InvokeFlag flag) {
1306 Label done;
1307 Operand dummy(eax);
1308 InvokePrologue(expected, actual, code, dummy, &done, flag);
1309 if (flag == CALL_FUNCTION) {
1310 call(code, rmode);
1311 } else {
1312 ASSERT(flag == JUMP_FUNCTION);
1313 jmp(code, rmode);
1314 }
1315 bind(&done);
1316}
1317
1318
1319void MacroAssembler::InvokeFunction(Register fun,
1320 const ParameterCount& actual,
1321 InvokeFlag flag) {
1322 ASSERT(fun.is(edi));
1323 mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1324 mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1325 mov(ebx, FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001326 SmiUntag(ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327 mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
1328 lea(edx, FieldOperand(edx, Code::kHeaderSize));
1329
1330 ParameterCount expected(ebx);
1331 InvokeCode(Operand(edx), expected, actual, flag);
1332}
1333
1334
ager@chromium.org5c838252010-02-19 08:53:10 +00001335void MacroAssembler::InvokeFunction(JSFunction* function,
1336 const ParameterCount& actual,
1337 InvokeFlag flag) {
1338 ASSERT(function->is_compiled());
1339 // Get the function and setup the context.
1340 mov(edi, Immediate(Handle<JSFunction>(function)));
1341 mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001342
ager@chromium.org5c838252010-02-19 08:53:10 +00001343 // Invoke the cached code.
1344 Handle<Code> code(function->code());
1345 ParameterCount expected(function->shared()->formal_parameter_count());
1346 InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag);
1347}
1348
1349
1350void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001351 // Calls are not allowed in some stubs.
kasper.lund7276f142008-07-30 08:49:36 +00001352 ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001353
1354 // Rely on the assertion to check that the number of provided
1355 // arguments match the expected number of arguments. Fake a
1356 // parameter count to avoid emitting code to do the check.
1357 ParameterCount expected(0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001358 GetBuiltinEntry(edx, id);
1359 InvokeCode(Operand(edx), expected, expected, flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360}
1361
1362
1363void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001364 ASSERT(!target.is(edi));
1365
1366 // Load the builtins object into target register.
1367 mov(target, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
1368 mov(target, FieldOperand(target, GlobalObject::kBuiltinsOffset));
1369
ager@chromium.org5c838252010-02-19 08:53:10 +00001370 // Load the JavaScript builtin function from the builtins object.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001371 mov(edi, FieldOperand(target, JSBuiltinsObject::OffsetOfFunctionWithId(id)));
1372
1373 // Load the code entry point from the builtins object.
1374 mov(target, FieldOperand(target, JSBuiltinsObject::OffsetOfCodeWithId(id)));
1375 if (FLAG_debug_code) {
1376 // Make sure the code objects in the builtins object and in the
1377 // builtin function are the same.
1378 push(target);
1379 mov(target, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1380 mov(target, FieldOperand(target, SharedFunctionInfo::kCodeOffset));
1381 cmp(target, Operand(esp, 0));
1382 Assert(equal, "Builtin code object changed");
1383 pop(target);
1384 }
1385 lea(target, FieldOperand(target, Code::kHeaderSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001386}
1387
1388
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001389void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
1390 if (context_chain_length > 0) {
1391 // Move up the chain of contexts to the context containing the slot.
1392 mov(dst, Operand(esi, Context::SlotOffset(Context::CLOSURE_INDEX)));
1393 // Load the function context (which is the incoming, outer context).
1394 mov(dst, FieldOperand(dst, JSFunction::kContextOffset));
1395 for (int i = 1; i < context_chain_length; i++) {
1396 mov(dst, Operand(dst, Context::SlotOffset(Context::CLOSURE_INDEX)));
1397 mov(dst, FieldOperand(dst, JSFunction::kContextOffset));
1398 }
1399 // The context may be an intermediate context, not a function context.
1400 mov(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
1401 } else { // Slot is in the current function context.
1402 // The context may be an intermediate context, not a function context.
1403 mov(dst, Operand(esi, Context::SlotOffset(Context::FCONTEXT_INDEX)));
1404 }
1405}
1406
1407
1408
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001409void MacroAssembler::Ret() {
1410 ret(0);
1411}
1412
1413
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001414void MacroAssembler::Drop(int stack_elements) {
1415 if (stack_elements > 0) {
1416 add(Operand(esp), Immediate(stack_elements * kPointerSize));
1417 }
1418}
1419
1420
1421void MacroAssembler::Move(Register dst, Handle<Object> value) {
1422 mov(dst, value);
1423}
1424
1425
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001426void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
1427 if (FLAG_native_code_counters && counter->Enabled()) {
1428 mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
1429 }
1430}
1431
1432
1433void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) {
1434 ASSERT(value > 0);
1435 if (FLAG_native_code_counters && counter->Enabled()) {
1436 Operand operand = Operand::StaticVariable(ExternalReference(counter));
1437 if (value == 1) {
1438 inc(operand);
1439 } else {
1440 add(operand, Immediate(value));
1441 }
1442 }
1443}
1444
1445
1446void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
1447 ASSERT(value > 0);
1448 if (FLAG_native_code_counters && counter->Enabled()) {
1449 Operand operand = Operand::StaticVariable(ExternalReference(counter));
1450 if (value == 1) {
1451 dec(operand);
1452 } else {
1453 sub(operand, Immediate(value));
1454 }
1455 }
1456}
1457
1458
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001459void MacroAssembler::IncrementCounter(Condition cc,
1460 StatsCounter* counter,
1461 int value) {
1462 ASSERT(value > 0);
1463 if (FLAG_native_code_counters && counter->Enabled()) {
1464 Label skip;
1465 j(NegateCondition(cc), &skip);
1466 pushfd();
1467 IncrementCounter(counter, value);
1468 popfd();
1469 bind(&skip);
1470 }
1471}
1472
1473
1474void MacroAssembler::DecrementCounter(Condition cc,
1475 StatsCounter* counter,
1476 int value) {
1477 ASSERT(value > 0);
1478 if (FLAG_native_code_counters && counter->Enabled()) {
1479 Label skip;
1480 j(NegateCondition(cc), &skip);
1481 pushfd();
1482 DecrementCounter(counter, value);
1483 popfd();
1484 bind(&skip);
1485 }
1486}
1487
1488
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489void MacroAssembler::Assert(Condition cc, const char* msg) {
1490 if (FLAG_debug_code) Check(cc, msg);
1491}
1492
1493
1494void MacroAssembler::Check(Condition cc, const char* msg) {
1495 Label L;
1496 j(cc, &L, taken);
1497 Abort(msg);
1498 // will not return here
1499 bind(&L);
1500}
1501
1502
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001503void MacroAssembler::CheckStackAlignment() {
1504 int frame_alignment = OS::ActivationFrameAlignment();
1505 int frame_alignment_mask = frame_alignment - 1;
1506 if (frame_alignment > kPointerSize) {
1507 ASSERT(IsPowerOf2(frame_alignment));
1508 Label alignment_as_expected;
1509 test(esp, Immediate(frame_alignment_mask));
1510 j(zero, &alignment_as_expected);
1511 // Abort if stack is not aligned.
1512 int3();
1513 bind(&alignment_as_expected);
1514 }
1515}
1516
1517
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001518void MacroAssembler::Abort(const char* msg) {
1519 // We want to pass the msg string like a smi to avoid GC
1520 // problems, however msg is not guaranteed to be aligned
1521 // properly. Instead, we pass an aligned pointer that is
ager@chromium.org32912102009-01-16 10:38:43 +00001522 // a proper v8 smi, but also pass the alignment difference
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001523 // from the real pointer as a smi.
1524 intptr_t p1 = reinterpret_cast<intptr_t>(msg);
1525 intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag;
1526 ASSERT(reinterpret_cast<Object*>(p0)->IsSmi());
1527#ifdef DEBUG
1528 if (msg != NULL) {
1529 RecordComment("Abort message: ");
1530 RecordComment(msg);
1531 }
1532#endif
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001533 // Disable stub call restrictions to always allow calls to abort.
1534 set_allow_stub_calls(true);
1535
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001536 push(eax);
1537 push(Immediate(p0));
1538 push(Immediate(reinterpret_cast<intptr_t>(Smi::FromInt(p1 - p0))));
1539 CallRuntime(Runtime::kAbort, 2);
1540 // will not return here
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001541 int3();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542}
1543
1544
ager@chromium.org5c838252010-02-19 08:53:10 +00001545void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii(
1546 Register instance_type,
1547 Register scratch,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001548 Label* failure) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001549 if (!scratch.is(instance_type)) {
1550 mov(scratch, instance_type);
1551 }
1552 and_(scratch,
1553 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask);
1554 cmp(scratch, kStringTag | kSeqStringTag | kAsciiStringTag);
1555 j(not_equal, failure);
1556}
1557
1558
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001559void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register object1,
1560 Register object2,
1561 Register scratch1,
1562 Register scratch2,
1563 Label* failure) {
1564 // Check that both objects are not smis.
1565 ASSERT_EQ(0, kSmiTag);
1566 mov(scratch1, Operand(object1));
1567 and_(scratch1, Operand(object2));
1568 test(scratch1, Immediate(kSmiTagMask));
1569 j(zero, failure);
1570
1571 // Load instance type for both strings.
1572 mov(scratch1, FieldOperand(object1, HeapObject::kMapOffset));
1573 mov(scratch2, FieldOperand(object2, HeapObject::kMapOffset));
1574 movzx_b(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset));
1575 movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset));
1576
1577 // Check that both are flat ascii strings.
1578 const int kFlatAsciiStringMask =
1579 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
1580 const int kFlatAsciiStringTag = ASCII_STRING_TYPE;
1581 // Interleave bits from both instance types and compare them in one check.
1582 ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
1583 and_(scratch1, kFlatAsciiStringMask);
1584 and_(scratch2, kFlatAsciiStringMask);
1585 lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
1586 cmp(scratch1, kFlatAsciiStringTag | (kFlatAsciiStringTag << 3));
1587 j(not_equal, failure);
1588}
1589
1590
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001591void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
1592 int frameAlignment = OS::ActivationFrameAlignment();
1593 if (frameAlignment != 0) {
1594 // Make stack end at alignment and make room for num_arguments words
1595 // and the original value of esp.
1596 mov(scratch, esp);
1597 sub(Operand(esp), Immediate((num_arguments + 1) * kPointerSize));
1598 ASSERT(IsPowerOf2(frameAlignment));
1599 and_(esp, -frameAlignment);
1600 mov(Operand(esp, num_arguments * kPointerSize), scratch);
1601 } else {
1602 sub(Operand(esp), Immediate(num_arguments * kPointerSize));
1603 }
1604}
1605
1606
1607void MacroAssembler::CallCFunction(ExternalReference function,
1608 int num_arguments) {
1609 // Trashing eax is ok as it will be the return value.
1610 mov(Operand(eax), Immediate(function));
1611 CallCFunction(eax, num_arguments);
1612}
1613
1614
1615void MacroAssembler::CallCFunction(Register function,
1616 int num_arguments) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001617 // Check stack alignment.
1618 if (FLAG_debug_code) {
1619 CheckStackAlignment();
1620 }
1621
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001622 call(Operand(function));
1623 if (OS::ActivationFrameAlignment() != 0) {
1624 mov(esp, Operand(esp, num_arguments * kPointerSize));
1625 } else {
1626 add(Operand(esp), Immediate(num_arguments * sizeof(int32_t)));
1627 }
1628}
1629
1630
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001631CodePatcher::CodePatcher(byte* address, int size)
ager@chromium.orga1645e22009-09-09 19:27:10 +00001632 : address_(address), size_(size), masm_(address, size + Assembler::kGap) {
ager@chromium.org32912102009-01-16 10:38:43 +00001633 // Create a new macro assembler pointing to the address of the code to patch.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001634 // The size is adjusted with kGap on order for the assembler to generate size
1635 // bytes of instructions without failing with buffer size constraints.
1636 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
1637}
1638
1639
1640CodePatcher::~CodePatcher() {
1641 // Indicate that code has changed.
1642 CPU::FlushICache(address_, size_);
1643
1644 // Check that the code was patched as expected.
1645 ASSERT(masm_.pc_ == address_ + size_);
1646 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
1647}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001648
1649
1650} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001651
1652#endif // V8_TARGET_ARCH_IA32