blob: de0ef8ece9b27c84f0eab2b5d08fb80dbcde1ae1 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 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),
44 unresolved_(0),
kasper.lund7276f142008-07-30 08:49:36 +000045 generating_stub_(false),
kasperl@chromium.org061ef742009-02-27 12:16:20 +000046 allow_stub_calls_(true),
47 code_object_(Heap::undefined_value()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048}
49
50
51static void RecordWriteHelper(MacroAssembler* masm,
52 Register object,
53 Register addr,
54 Register scratch) {
55 Label fast;
56
57 // Compute the page address from the heap object pointer, leave it
58 // in 'object'.
59 masm->and_(object, ~Page::kPageAlignmentMask);
60
61 // Compute the bit addr in the remembered set, leave it in "addr".
62 masm->sub(addr, Operand(object));
63 masm->shr(addr, kObjectAlignmentBits);
64
65 // If the bit offset lies beyond the normal remembered set range, it is in
66 // the extra remembered set area of a large object.
67 masm->cmp(addr, Page::kPageSize / kPointerSize);
68 masm->j(less, &fast);
69
70 // Adjust 'addr' to be relative to the start of the extra remembered set
71 // and the page address in 'object' to be the address of the extra
72 // remembered set.
73 masm->sub(Operand(addr), Immediate(Page::kPageSize / kPointerSize));
74 // Load the array length into 'scratch' and multiply by four to get the
75 // size in bytes of the elements.
76 masm->mov(scratch, Operand(object, Page::kObjectStartOffset
77 + FixedArray::kLengthOffset));
78 masm->shl(scratch, kObjectAlignmentBits);
79 // Add the page header, array header, and array body size to the page
80 // address.
81 masm->add(Operand(object), Immediate(Page::kObjectStartOffset
kasperl@chromium.orge959c182009-07-27 08:59:04 +000082 + FixedArray::kHeaderSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000083 masm->add(object, Operand(scratch));
84
85
86 // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction
87 // to limit code size. We should probably evaluate this decision by
88 // measuring the performance of an equivalent implementation using
89 // "simpler" instructions
90 masm->bind(&fast);
91 masm->bts(Operand(object, 0), addr);
92}
93
94
95class RecordWriteStub : public CodeStub {
96 public:
97 RecordWriteStub(Register object, Register addr, Register scratch)
98 : object_(object), addr_(addr), scratch_(scratch) { }
99
100 void Generate(MacroAssembler* masm);
101
102 private:
103 Register object_;
104 Register addr_;
105 Register scratch_;
106
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000107#ifdef DEBUG
108 void Print() {
109 PrintF("RecordWriteStub (object reg %d), (addr reg %d), (scratch reg %d)\n",
110 object_.code(), addr_.code(), scratch_.code());
111 }
112#endif
113
114 // Minor key encoding in 12 bits of three registers (object, address and
115 // scratch) OOOOAAAASSSS.
116 class ScratchBits: public BitField<uint32_t, 0, 4> {};
117 class AddressBits: public BitField<uint32_t, 4, 4> {};
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000118 class ObjectBits: public BitField<uint32_t, 8, 4> {};
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000119
120 Major MajorKey() { return RecordWrite; }
121
122 int MinorKey() {
123 // Encode the registers.
124 return ObjectBits::encode(object_.code()) |
125 AddressBits::encode(addr_.code()) |
126 ScratchBits::encode(scratch_.code());
127 }
128};
129
130
131void RecordWriteStub::Generate(MacroAssembler* masm) {
132 RecordWriteHelper(masm, object_, addr_, scratch_);
133 masm->ret(0);
134}
135
136
137// Set the remembered set bit for [object+offset].
138// object is the object being stored into, value is the object being stored.
139// If offset is zero, then the scratch register contains the array index into
140// the elements array represented as a Smi.
141// All registers are clobbered by the operation.
142void MacroAssembler::RecordWrite(Register object, int offset,
143 Register value, Register scratch) {
144 // First, check if a remembered set write is even needed. The tests below
145 // catch stores of Smis and stores into young gen (which does not have space
146 // for the remembered set bits.
147 Label done;
148
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000149 // Skip barrier if writing a smi.
150 ASSERT_EQ(0, kSmiTag);
151 test(value, Immediate(kSmiTagMask));
152 j(zero, &done);
153
154 if (Serializer::enabled()) {
155 // Can't do arithmetic on external references if it might get serialized.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000156 mov(value, Operand(object));
157 and_(value, Heap::NewSpaceMask());
158 cmp(Operand(value), Immediate(ExternalReference::new_space_start()));
159 j(equal, &done);
160 } else {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000161 int32_t new_space_start = reinterpret_cast<int32_t>(
162 ExternalReference::new_space_start().address());
163 lea(value, Operand(object, -new_space_start));
164 and_(value, Heap::NewSpaceMask());
165 j(equal, &done);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000166 }
167
168 if ((offset > 0) && (offset < Page::kMaxHeapObjectSize)) {
169 // Compute the bit offset in the remembered set, leave it in 'value'.
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000170 lea(value, Operand(object, offset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000171 and_(value, Page::kPageAlignmentMask);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000172 shr(value, kPointerSizeLog2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000173
174 // Compute the page address from the heap object pointer, leave it in
175 // 'object'.
176 and_(object, ~Page::kPageAlignmentMask);
177
178 // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction
179 // to limit code size. We should probably evaluate this decision by
180 // measuring the performance of an equivalent implementation using
181 // "simpler" instructions
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000182 bts(Operand(object, Page::kRSetOffset), value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000183 } else {
184 Register dst = scratch;
185 if (offset != 0) {
186 lea(dst, Operand(object, offset));
187 } else {
188 // array access: calculate the destination address in the same manner as
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000189 // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset
190 // into an array of words.
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000191 ASSERT_EQ(1, kSmiTagSize);
192 ASSERT_EQ(0, kSmiTag);
193 lea(dst, Operand(object, dst, times_half_pointer_size,
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000194 FixedArray::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000195 }
196 // If we are already generating a shared stub, not inlining the
197 // record write code isn't going to save us any memory.
198 if (generating_stub()) {
199 RecordWriteHelper(this, object, dst, value);
200 } else {
201 RecordWriteStub stub(object, dst, value);
202 CallStub(&stub);
203 }
204 }
205
206 bind(&done);
207}
208
209
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000210#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000211void MacroAssembler::SaveRegistersToMemory(RegList regs) {
212 ASSERT((regs & ~kJSCallerSaved) == 0);
213 // Copy the content of registers to memory location.
214 for (int i = 0; i < kNumJSCallerSaved; i++) {
215 int r = JSCallerSavedCode(i);
216 if ((regs & (1 << r)) != 0) {
217 Register reg = { r };
218 ExternalReference reg_addr =
219 ExternalReference(Debug_Address::Register(i));
220 mov(Operand::StaticVariable(reg_addr), reg);
221 }
222 }
223}
224
225
226void MacroAssembler::RestoreRegistersFromMemory(RegList regs) {
227 ASSERT((regs & ~kJSCallerSaved) == 0);
228 // Copy the content of memory location to registers.
229 for (int i = kNumJSCallerSaved; --i >= 0;) {
230 int r = JSCallerSavedCode(i);
231 if ((regs & (1 << r)) != 0) {
232 Register reg = { r };
233 ExternalReference reg_addr =
234 ExternalReference(Debug_Address::Register(i));
235 mov(reg, Operand::StaticVariable(reg_addr));
236 }
237 }
238}
239
240
241void MacroAssembler::PushRegistersFromMemory(RegList regs) {
242 ASSERT((regs & ~kJSCallerSaved) == 0);
243 // Push the content of the memory location to the stack.
244 for (int i = 0; i < kNumJSCallerSaved; i++) {
245 int r = JSCallerSavedCode(i);
246 if ((regs & (1 << r)) != 0) {
247 ExternalReference reg_addr =
248 ExternalReference(Debug_Address::Register(i));
249 push(Operand::StaticVariable(reg_addr));
250 }
251 }
252}
253
254
255void MacroAssembler::PopRegistersToMemory(RegList regs) {
256 ASSERT((regs & ~kJSCallerSaved) == 0);
257 // Pop the content from the stack to the memory location.
258 for (int i = kNumJSCallerSaved; --i >= 0;) {
259 int r = JSCallerSavedCode(i);
260 if ((regs & (1 << r)) != 0) {
261 ExternalReference reg_addr =
262 ExternalReference(Debug_Address::Register(i));
263 pop(Operand::StaticVariable(reg_addr));
264 }
265 }
266}
267
268
269void MacroAssembler::CopyRegistersFromStackToMemory(Register base,
270 Register scratch,
271 RegList regs) {
272 ASSERT((regs & ~kJSCallerSaved) == 0);
273 // Copy the content of the stack to the memory location and adjust base.
274 for (int i = kNumJSCallerSaved; --i >= 0;) {
275 int r = JSCallerSavedCode(i);
276 if ((regs & (1 << r)) != 0) {
277 mov(scratch, Operand(base, 0));
278 ExternalReference reg_addr =
279 ExternalReference(Debug_Address::Register(i));
280 mov(Operand::StaticVariable(reg_addr), scratch);
281 lea(base, Operand(base, kPointerSize));
282 }
283 }
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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000315void MacroAssembler::FCmp() {
316 fcompp();
317 push(eax);
318 fnstsw_ax();
319 sahf();
320 pop(eax);
321}
322
323
ager@chromium.org7c537e22008-10-16 08:43:32 +0000324void MacroAssembler::EnterFrame(StackFrame::Type type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325 push(ebp);
326 mov(ebp, Operand(esp));
327 push(esi);
328 push(Immediate(Smi::FromInt(type)));
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000329 push(Immediate(CodeObject()));
330 if (FLAG_debug_code) {
331 cmp(Operand(esp, 0), Immediate(Factory::undefined_value()));
332 Check(not_equal, "code object not properly patched");
333 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000334}
335
336
ager@chromium.org7c537e22008-10-16 08:43:32 +0000337void MacroAssembler::LeaveFrame(StackFrame::Type type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338 if (FLAG_debug_code) {
339 cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset),
340 Immediate(Smi::FromInt(type)));
341 Check(equal, "stack frame types must match");
342 }
343 leave();
344}
345
346
ager@chromium.org236ad962008-09-25 09:45:57 +0000347void MacroAssembler::EnterExitFrame(StackFrame::Type type) {
348 ASSERT(type == StackFrame::EXIT || type == StackFrame::EXIT_DEBUG);
349
350 // Setup the frame structure on the stack.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000351 ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize);
ager@chromium.org236ad962008-09-25 09:45:57 +0000352 ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize);
353 ASSERT(ExitFrameConstants::kCallerFPOffset == 0 * kPointerSize);
354 push(ebp);
355 mov(ebp, Operand(esp));
356
357 // Reserve room for entry stack pointer and push the debug marker.
358 ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize);
359 push(Immediate(0)); // saved entry sp, patched before call
360 push(Immediate(type == StackFrame::EXIT_DEBUG ? 1 : 0));
361
362 // Save the frame pointer and the context in top.
363 ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
364 ExternalReference context_address(Top::k_context_address);
365 mov(Operand::StaticVariable(c_entry_fp_address), ebp);
366 mov(Operand::StaticVariable(context_address), esi);
367
368 // Setup argc and argv in callee-saved registers.
369 int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
370 mov(edi, Operand(eax));
371 lea(esi, Operand(ebp, eax, times_4, offset));
372
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000373#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org236ad962008-09-25 09:45:57 +0000374 // Save the state of all registers to the stack from the memory
375 // location. This is needed to allow nested break points.
376 if (type == StackFrame::EXIT_DEBUG) {
377 // TODO(1243899): This should be symmetric to
378 // CopyRegistersFromStackToMemory() but it isn't! esp is assumed
379 // correct here, but computed for the other call. Very error
380 // prone! FIX THIS. Actually there are deeper problems with
381 // register saving than this asymmetry (see the bug report
382 // associated with this issue).
383 PushRegistersFromMemory(kJSCallerSaved);
384 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000385#endif
ager@chromium.org236ad962008-09-25 09:45:57 +0000386
387 // Reserve space for two arguments: argc and argv.
388 sub(Operand(esp), Immediate(2 * kPointerSize));
389
390 // Get the required frame alignment for the OS.
391 static const int kFrameAlignment = OS::ActivationFrameAlignment();
392 if (kFrameAlignment > 0) {
393 ASSERT(IsPowerOf2(kFrameAlignment));
394 and_(esp, -kFrameAlignment);
395 }
396
397 // Patch the saved entry sp.
398 mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp);
399}
400
401
402void MacroAssembler::LeaveExitFrame(StackFrame::Type type) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000403#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org236ad962008-09-25 09:45:57 +0000404 // Restore the memory copy of the registers by digging them out from
405 // the stack. This is needed to allow nested break points.
406 if (type == StackFrame::EXIT_DEBUG) {
407 // It's okay to clobber register ebx below because we don't need
408 // the function pointer after this.
409 const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
410 int kOffset = ExitFrameConstants::kDebugMarkOffset - kCallerSavedSize;
411 lea(ebx, Operand(ebp, kOffset));
412 CopyRegistersFromStackToMemory(ebx, ecx, kJSCallerSaved);
413 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000414#endif
ager@chromium.org236ad962008-09-25 09:45:57 +0000415
416 // Get the return address from the stack and restore the frame pointer.
417 mov(ecx, Operand(ebp, 1 * kPointerSize));
418 mov(ebp, Operand(ebp, 0 * kPointerSize));
419
420 // Pop the arguments and the receiver from the caller stack.
421 lea(esp, Operand(esi, 1 * kPointerSize));
422
423 // Restore current context from top and clear it in debug mode.
424 ExternalReference context_address(Top::k_context_address);
425 mov(esi, Operand::StaticVariable(context_address));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000426#ifdef DEBUG
427 mov(Operand::StaticVariable(context_address), Immediate(0));
428#endif
ager@chromium.org236ad962008-09-25 09:45:57 +0000429
430 // Push the return address to get ready to return.
431 push(ecx);
432
433 // Clear the top frame.
434 ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
435 mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
436}
437
438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000439void MacroAssembler::PushTryHandler(CodeLocation try_location,
440 HandlerType type) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000441 // Adjust this code if not the case.
442 ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000443 // The pc (return address) is already on TOS.
444 if (try_location == IN_JAVASCRIPT) {
445 if (type == TRY_CATCH_HANDLER) {
446 push(Immediate(StackHandler::TRY_CATCH));
447 } else {
448 push(Immediate(StackHandler::TRY_FINALLY));
449 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000450 push(ebp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000451 } else {
452 ASSERT(try_location == IN_JS_ENTRY);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000453 // The frame pointer does not point to a JS frame so we save NULL
454 // for ebp. We expect the code throwing an exception to check ebp
455 // before dereferencing it to restore the context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000456 push(Immediate(StackHandler::ENTRY));
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000457 push(Immediate(0)); // NULL frame pointer.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000458 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000459 // Save the current handler as the next handler.
460 push(Operand::StaticVariable(ExternalReference(Top::k_handler_address)));
461 // Link this handler as the new current one.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000462 mov(Operand::StaticVariable(ExternalReference(Top::k_handler_address)), esp);
463}
464
465
466Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
467 JSObject* holder, Register holder_reg,
468 Register scratch,
469 Label* miss) {
470 // Make sure there's no overlap between scratch and the other
471 // registers.
472 ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg));
473
474 // Keep track of the current object in register reg.
475 Register reg = object_reg;
476 int depth = 1;
477
478 // Check the maps in the prototype chain.
479 // Traverse the prototype chain from the object and do map checks.
480 while (object != holder) {
481 depth++;
482
483 // Only global objects and objects that do not require access
484 // checks are allowed in stubs.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000485 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000486
487 JSObject* prototype = JSObject::cast(object->GetPrototype());
488 if (Heap::InNewSpace(prototype)) {
489 // Get the map of the current object.
490 mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
491 cmp(Operand(scratch), Immediate(Handle<Map>(object->map())));
492 // Branch on the result of the map check.
493 j(not_equal, miss, not_taken);
494 // Check access rights to the global object. This has to happen
495 // after the map check so that we know that the object is
496 // actually a global object.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000497 if (object->IsJSGlobalProxy()) {
498 CheckAccessGlobalProxy(reg, scratch, miss);
499
500 // Restore scratch register to be the map of the object.
501 // We load the prototype from the map in the scratch register.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000502 mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
503 }
504 // The prototype is in new space; we cannot store a reference
505 // to it in the code. Load it from the map.
506 reg = holder_reg; // from now the object is in holder_reg
507 mov(reg, FieldOperand(scratch, Map::kPrototypeOffset));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000508
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000509 } else {
510 // Check the map of the current object.
511 cmp(FieldOperand(reg, HeapObject::kMapOffset),
512 Immediate(Handle<Map>(object->map())));
513 // Branch on the result of the map check.
514 j(not_equal, miss, not_taken);
515 // Check access rights to the global object. This has to happen
516 // after the map check so that we know that the object is
517 // actually a global object.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000518 if (object->IsJSGlobalProxy()) {
519 CheckAccessGlobalProxy(reg, scratch, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000520 }
521 // The prototype is in old space; load it directly.
522 reg = holder_reg; // from now the object is in holder_reg
523 mov(reg, Handle<JSObject>(prototype));
524 }
525
526 // Go to the next object in the prototype chain.
527 object = prototype;
528 }
529
530 // Check the holder map.
531 cmp(FieldOperand(reg, HeapObject::kMapOffset),
532 Immediate(Handle<Map>(holder->map())));
533 j(not_equal, miss, not_taken);
534
535 // Log the check depth.
536 LOG(IntEvent("check-maps-depth", depth));
537
538 // Perform security check for access to the global object and return
539 // the holder register.
540 ASSERT(object == holder);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000541 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
542 if (object->IsJSGlobalProxy()) {
543 CheckAccessGlobalProxy(reg, scratch, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000544 }
545 return reg;
546}
547
548
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000549void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
ager@chromium.orge2902be2009-06-08 12:21:35 +0000550 Register scratch,
551 Label* miss) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000552 Label same_contexts;
553
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000554 ASSERT(!holder_reg.is(scratch));
555
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000556 // Load current lexical context from the stack frame.
557 mov(scratch, Operand(ebp, StandardFrameConstants::kContextOffset));
558
559 // When generating debug code, make sure the lexical context is set.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000560 if (FLAG_debug_code) {
561 cmp(Operand(scratch), Immediate(0));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000562 Check(not_equal, "we should not have an empty lexical context");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000563 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000564 // Load the global context of the current context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000565 int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
566 mov(scratch, FieldOperand(scratch, offset));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000567 mov(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
568
569 // Check the context is a global context.
570 if (FLAG_debug_code) {
571 push(scratch);
572 // Read the first word and compare to global_context_map.
573 mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
574 cmp(scratch, Factory::global_context_map());
575 Check(equal, "JSGlobalObject::global_context should be a global context.");
576 pop(scratch);
577 }
578
579 // Check if both contexts are the same.
580 cmp(scratch, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
581 j(equal, &same_contexts, taken);
582
583 // Compare security tokens, save holder_reg on the stack so we can use it
584 // as a temporary register.
585 //
586 // TODO(119): avoid push(holder_reg)/pop(holder_reg)
587 push(holder_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000588 // Check that the security token in the calling global object is
589 // compatible with the security token in the receiving global
590 // object.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000591 mov(holder_reg, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
592
593 // Check the context is a global context.
594 if (FLAG_debug_code) {
595 cmp(holder_reg, Factory::null_value());
596 Check(not_equal, "JSGlobalProxy::context() should not be null.");
597
598 push(holder_reg);
599 // Read the first word and compare to global_context_map(),
600 mov(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset));
601 cmp(holder_reg, Factory::global_context_map());
602 Check(equal, "JSGlobalObject::global_context should be a global context.");
603 pop(holder_reg);
604 }
605
606 int token_offset = Context::kHeaderSize +
607 Context::SECURITY_TOKEN_INDEX * kPointerSize;
608 mov(scratch, FieldOperand(scratch, token_offset));
609 cmp(scratch, FieldOperand(holder_reg, token_offset));
610 pop(holder_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000611 j(not_equal, miss, not_taken);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000612
613 bind(&same_contexts);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000614}
615
616
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000617void MacroAssembler::NegativeZeroTest(CodeGenerator* cgen,
618 Register result,
619 Register op,
620 JumpTarget* then_target) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000621 JumpTarget ok;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000622 test(result, Operand(result));
623 ok.Branch(not_zero, taken);
624 test(op, Operand(op));
625 then_target->Branch(sign, not_taken);
626 ok.Bind();
627}
628
629
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000630void MacroAssembler::NegativeZeroTest(Register result,
631 Register op,
632 Label* then_label) {
633 Label ok;
634 test(result, Operand(result));
635 j(not_zero, &ok, taken);
636 test(op, Operand(op));
637 j(sign, then_label, not_taken);
638 bind(&ok);
639}
640
641
642void MacroAssembler::NegativeZeroTest(Register result,
643 Register op1,
644 Register op2,
645 Register scratch,
646 Label* then_label) {
647 Label ok;
648 test(result, Operand(result));
649 j(not_zero, &ok, taken);
650 mov(scratch, Operand(op1));
651 or_(scratch, Operand(op2));
652 j(sign, then_label, not_taken);
653 bind(&ok);
654}
655
656
ager@chromium.org7c537e22008-10-16 08:43:32 +0000657void MacroAssembler::TryGetFunctionPrototype(Register function,
658 Register result,
659 Register scratch,
660 Label* miss) {
661 // Check that the receiver isn't a smi.
662 test(function, Immediate(kSmiTagMask));
663 j(zero, miss, not_taken);
664
665 // Check that the function really is a function.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000666 CmpObjectType(function, JS_FUNCTION_TYPE, result);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000667 j(not_equal, miss, not_taken);
668
669 // Make sure that the function has an instance prototype.
670 Label non_instance;
671 movzx_b(scratch, FieldOperand(result, Map::kBitFieldOffset));
672 test(scratch, Immediate(1 << Map::kHasNonInstancePrototype));
673 j(not_zero, &non_instance, not_taken);
674
675 // Get the prototype or initial map from the function.
676 mov(result,
677 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
678
679 // If the prototype or initial map is the hole, don't return it and
680 // simply miss the cache instead. This will allow us to allocate a
681 // prototype object on-demand in the runtime system.
682 cmp(Operand(result), Immediate(Factory::the_hole_value()));
683 j(equal, miss, not_taken);
684
685 // If the function does not have an initial map, we're done.
686 Label done;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000687 CmpObjectType(result, MAP_TYPE, scratch);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000688 j(not_equal, &done);
689
690 // Get the prototype from the initial map.
691 mov(result, FieldOperand(result, Map::kPrototypeOffset));
692 jmp(&done);
693
694 // Non-instance prototype: Fetch prototype from constructor field
695 // in initial map.
696 bind(&non_instance);
697 mov(result, FieldOperand(result, Map::kConstructorOffset));
698
699 // All done.
700 bind(&done);
701}
702
703
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000704void MacroAssembler::CallStub(CodeStub* stub) {
kasper.lund7276f142008-07-30 08:49:36 +0000705 ASSERT(allow_stub_calls()); // calls are not allowed in some stubs
ager@chromium.org236ad962008-09-25 09:45:57 +0000706 call(stub->GetCode(), RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000707}
708
709
710void MacroAssembler::StubReturn(int argc) {
711 ASSERT(argc >= 1 && generating_stub());
712 ret((argc - 1) * kPointerSize);
713}
714
715
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000716void MacroAssembler::IllegalOperation(int num_arguments) {
717 if (num_arguments > 0) {
718 add(Operand(esp), Immediate(num_arguments * kPointerSize));
719 }
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000720 mov(eax, Immediate(Factory::undefined_value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000721}
722
723
724void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) {
725 CallRuntime(Runtime::FunctionForId(id), num_arguments);
726}
727
728
729void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
mads.s.ager31e71382008-08-13 09:32:07 +0000730 // If the expected number of arguments of the runtime function is
731 // constant, we check that the actual number of arguments match the
732 // expectation.
733 if (f->nargs >= 0 && f->nargs != num_arguments) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000734 IllegalOperation(num_arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000735 return;
736 }
737
mads.s.ager31e71382008-08-13 09:32:07 +0000738 Runtime::FunctionId function_id =
739 static_cast<Runtime::FunctionId>(f->stub_id);
740 RuntimeStub stub(function_id, num_arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000741 CallStub(&stub);
742}
743
744
mads.s.ager31e71382008-08-13 09:32:07 +0000745void MacroAssembler::TailCallRuntime(const ExternalReference& ext,
746 int num_arguments) {
747 // TODO(1236192): Most runtime routines don't need the number of
748 // arguments passed in because it is constant. At some point we
749 // should remove this need and make the runtime routine entry code
750 // smarter.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000751 Set(eax, Immediate(num_arguments));
mads.s.ager31e71382008-08-13 09:32:07 +0000752 JumpToBuiltin(ext);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000753}
754
755
756void MacroAssembler::JumpToBuiltin(const ExternalReference& ext) {
757 // Set the entry point and jump to the C entry runtime stub.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000758 mov(ebx, Immediate(ext));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000759 CEntryStub ces;
ager@chromium.org236ad962008-09-25 09:45:57 +0000760 jmp(ces.GetCode(), RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000761}
762
763
764void MacroAssembler::InvokePrologue(const ParameterCount& expected,
765 const ParameterCount& actual,
766 Handle<Code> code_constant,
767 const Operand& code_operand,
768 Label* done,
769 InvokeFlag flag) {
770 bool definitely_matches = false;
771 Label invoke;
772 if (expected.is_immediate()) {
773 ASSERT(actual.is_immediate());
774 if (expected.immediate() == actual.immediate()) {
775 definitely_matches = true;
776 } else {
777 mov(eax, actual.immediate());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000778 const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
779 if (expected.immediate() == sentinel) {
780 // Don't worry about adapting arguments for builtins that
781 // don't want that done. Skip adaption code by making it look
782 // like we have a match between expected and actual number of
783 // arguments.
784 definitely_matches = true;
785 } else {
786 mov(ebx, expected.immediate());
787 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000788 }
789 } else {
790 if (actual.is_immediate()) {
791 // Expected is in register, actual is immediate. This is the
792 // case when we invoke function values without going through the
793 // IC mechanism.
794 cmp(expected.reg(), actual.immediate());
795 j(equal, &invoke);
796 ASSERT(expected.reg().is(ebx));
797 mov(eax, actual.immediate());
798 } else if (!expected.reg().is(actual.reg())) {
799 // Both expected and actual are in (different) registers. This
800 // is the case when we invoke functions using call and apply.
801 cmp(expected.reg(), Operand(actual.reg()));
802 j(equal, &invoke);
803 ASSERT(actual.reg().is(eax));
804 ASSERT(expected.reg().is(ebx));
805 }
806 }
807
808 if (!definitely_matches) {
809 Handle<Code> adaptor =
810 Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
811 if (!code_constant.is_null()) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000812 mov(edx, Immediate(code_constant));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000813 add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag));
814 } else if (!code_operand.is_reg(edx)) {
815 mov(edx, code_operand);
816 }
817
818 if (flag == CALL_FUNCTION) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000819 call(adaptor, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000820 jmp(done);
821 } else {
ager@chromium.org236ad962008-09-25 09:45:57 +0000822 jmp(adaptor, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000823 }
824 bind(&invoke);
825 }
826}
827
828
829void MacroAssembler::InvokeCode(const Operand& code,
830 const ParameterCount& expected,
831 const ParameterCount& actual,
832 InvokeFlag flag) {
833 Label done;
834 InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag);
835 if (flag == CALL_FUNCTION) {
836 call(code);
837 } else {
838 ASSERT(flag == JUMP_FUNCTION);
839 jmp(code);
840 }
841 bind(&done);
842}
843
844
845void MacroAssembler::InvokeCode(Handle<Code> code,
846 const ParameterCount& expected,
847 const ParameterCount& actual,
ager@chromium.org236ad962008-09-25 09:45:57 +0000848 RelocInfo::Mode rmode,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000849 InvokeFlag flag) {
850 Label done;
851 Operand dummy(eax);
852 InvokePrologue(expected, actual, code, dummy, &done, flag);
853 if (flag == CALL_FUNCTION) {
854 call(code, rmode);
855 } else {
856 ASSERT(flag == JUMP_FUNCTION);
857 jmp(code, rmode);
858 }
859 bind(&done);
860}
861
862
863void MacroAssembler::InvokeFunction(Register fun,
864 const ParameterCount& actual,
865 InvokeFlag flag) {
866 ASSERT(fun.is(edi));
867 mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
868 mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
869 mov(ebx, FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
870 mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
871 lea(edx, FieldOperand(edx, Code::kHeaderSize));
872
873 ParameterCount expected(ebx);
874 InvokeCode(Operand(edx), expected, actual, flag);
875}
876
877
878void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
879 bool resolved;
880 Handle<Code> code = ResolveBuiltin(id, &resolved);
881
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000882 // Calls are not allowed in some stubs.
kasper.lund7276f142008-07-30 08:49:36 +0000883 ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000884
885 // Rely on the assertion to check that the number of provided
886 // arguments match the expected number of arguments. Fake a
887 // parameter count to avoid emitting code to do the check.
888 ParameterCount expected(0);
ager@chromium.org236ad962008-09-25 09:45:57 +0000889 InvokeCode(Handle<Code>(code), expected, expected,
890 RelocInfo::CODE_TARGET, flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891
892 const char* name = Builtins::GetName(id);
893 int argc = Builtins::GetArgumentsCount(id);
894
895 if (!resolved) {
896 uint32_t flags =
897 Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000898 Bootstrapper::FixupFlagsIsPCRelative::encode(true) |
899 Bootstrapper::FixupFlagsUseCodeObject::encode(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000900 Unresolved entry = { pc_offset() - sizeof(int32_t), flags, name };
901 unresolved_.Add(entry);
902 }
903}
904
905
906void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
907 bool resolved;
908 Handle<Code> code = ResolveBuiltin(id, &resolved);
909
910 const char* name = Builtins::GetName(id);
911 int argc = Builtins::GetArgumentsCount(id);
912
913 mov(Operand(target), Immediate(code));
914 if (!resolved) {
915 uint32_t flags =
916 Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000917 Bootstrapper::FixupFlagsIsPCRelative::encode(false) |
918 Bootstrapper::FixupFlagsUseCodeObject::encode(true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000919 Unresolved entry = { pc_offset() - sizeof(int32_t), flags, name };
920 unresolved_.Add(entry);
921 }
922 add(Operand(target), Immediate(Code::kHeaderSize - kHeapObjectTag));
923}
924
925
926Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
927 bool* resolved) {
928 // Move the builtin function into the temporary function slot by
929 // reading it from the builtins object. NOTE: We should be able to
930 // reduce this to two instructions by putting the function table in
931 // the global object instead of the "builtins" object and by using a
932 // real register for the function.
933 mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
934 mov(edx, FieldOperand(edx, GlobalObject::kBuiltinsOffset));
935 int builtins_offset =
936 JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
937 mov(edi, FieldOperand(edx, builtins_offset));
938
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000939
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000940 return Builtins::GetCode(id, resolved);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000941}
942
943
944void MacroAssembler::Ret() {
945 ret(0);
946}
947
948
949void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
950 if (FLAG_native_code_counters && counter->Enabled()) {
951 mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
952 }
953}
954
955
956void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) {
957 ASSERT(value > 0);
958 if (FLAG_native_code_counters && counter->Enabled()) {
959 Operand operand = Operand::StaticVariable(ExternalReference(counter));
960 if (value == 1) {
961 inc(operand);
962 } else {
963 add(operand, Immediate(value));
964 }
965 }
966}
967
968
969void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
970 ASSERT(value > 0);
971 if (FLAG_native_code_counters && counter->Enabled()) {
972 Operand operand = Operand::StaticVariable(ExternalReference(counter));
973 if (value == 1) {
974 dec(operand);
975 } else {
976 sub(operand, Immediate(value));
977 }
978 }
979}
980
981
982void MacroAssembler::Assert(Condition cc, const char* msg) {
983 if (FLAG_debug_code) Check(cc, msg);
984}
985
986
987void MacroAssembler::Check(Condition cc, const char* msg) {
988 Label L;
989 j(cc, &L, taken);
990 Abort(msg);
991 // will not return here
992 bind(&L);
993}
994
995
996void MacroAssembler::Abort(const char* msg) {
997 // We want to pass the msg string like a smi to avoid GC
998 // problems, however msg is not guaranteed to be aligned
999 // properly. Instead, we pass an aligned pointer that is
ager@chromium.org32912102009-01-16 10:38:43 +00001000 // a proper v8 smi, but also pass the alignment difference
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001001 // from the real pointer as a smi.
1002 intptr_t p1 = reinterpret_cast<intptr_t>(msg);
1003 intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag;
1004 ASSERT(reinterpret_cast<Object*>(p0)->IsSmi());
1005#ifdef DEBUG
1006 if (msg != NULL) {
1007 RecordComment("Abort message: ");
1008 RecordComment(msg);
1009 }
1010#endif
1011 push(eax);
1012 push(Immediate(p0));
1013 push(Immediate(reinterpret_cast<intptr_t>(Smi::FromInt(p1 - p0))));
1014 CallRuntime(Runtime::kAbort, 2);
1015 // will not return here
1016}
1017
1018
1019CodePatcher::CodePatcher(byte* address, int size)
1020 : address_(address), size_(size), masm_(address, size + Assembler::kGap) {
ager@chromium.org32912102009-01-16 10:38:43 +00001021 // Create a new macro assembler pointing to the address of the code to patch.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001022 // The size is adjusted with kGap on order for the assembler to generate size
1023 // bytes of instructions without failing with buffer size constraints.
1024 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
1025}
1026
1027
1028CodePatcher::~CodePatcher() {
1029 // Indicate that code has changed.
1030 CPU::FlushICache(address_, size_);
1031
1032 // Check that the code was patched as expected.
1033 ASSERT(masm_.pc_ == address_ + size_);
1034 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
1035}
1036
1037
1038} } // namespace v8::internal