blob: de2070ab8d02341df16efee65cbdf413b1114252 [file] [log] [blame]
ager@chromium.orga1645e22009-09-09 19:27:10 +00001// Copyright 2009 the V8 project authors. All rights reserved.
ager@chromium.org5ec48922009-05-05 07:25:34 +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
ager@chromium.org9085a012009-05-11 19:22:57 +000028#ifndef V8_X64_MACRO_ASSEMBLER_X64_H_
29#define V8_X64_MACRO_ASSEMBLER_X64_H_
30
31#include "assembler.h"
32
kasperl@chromium.org71affb52009-05-26 05:44:31 +000033namespace v8 {
34namespace internal {
ager@chromium.org9085a012009-05-11 19:22:57 +000035
ager@chromium.orge2902be2009-06-08 12:21:35 +000036// Default scratch register used by MacroAssembler (and other code that needs
37// a spare register). The register isn't callee save, and not used by the
38// function calling convention.
39static const Register kScratchRegister = r10;
40
ager@chromium.org9085a012009-05-11 19:22:57 +000041// Forward declaration.
42class JumpTarget;
43
ager@chromium.org4af710e2009-09-15 12:20:11 +000044struct SmiIndex {
45 SmiIndex(Register index_register, ScaleFactor scale)
46 : reg(index_register),
47 scale(scale) {}
48 Register reg;
49 ScaleFactor scale;
50};
ager@chromium.org9085a012009-05-11 19:22:57 +000051
ager@chromium.org9085a012009-05-11 19:22:57 +000052// MacroAssembler implements a collection of frequently used macros.
53class MacroAssembler: public Assembler {
54 public:
55 MacroAssembler(void* buffer, int size);
56
ager@chromium.org18ad94b2009-09-02 08:22:29 +000057 void LoadRoot(Register destination, Heap::RootListIndex index);
58 void CompareRoot(Register with, Heap::RootListIndex index);
59 void PushRoot(Heap::RootListIndex index);
60
ager@chromium.org9085a012009-05-11 19:22:57 +000061 // ---------------------------------------------------------------------------
62 // GC Support
63
64 // Set the remembered set bit for [object+offset].
65 // object is the object being stored into, value is the object being stored.
66 // If offset is zero, then the scratch register contains the array index into
67 // the elements array represented as a Smi.
68 // All registers are clobbered by the operation.
69 void RecordWrite(Register object,
70 int offset,
71 Register value,
72 Register scratch);
73
74#ifdef ENABLE_DEBUGGER_SUPPORT
75 // ---------------------------------------------------------------------------
76 // Debugger Support
77
78 void SaveRegistersToMemory(RegList regs);
79 void RestoreRegistersFromMemory(RegList regs);
80 void PushRegistersFromMemory(RegList regs);
81 void PopRegistersToMemory(RegList regs);
82 void CopyRegistersFromStackToMemory(Register base,
83 Register scratch,
84 RegList regs);
85#endif
86
87 // ---------------------------------------------------------------------------
88 // Activation frames
89
90 void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
91 void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); }
92
93 void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); }
94 void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
95
96 // Enter specific kind of exit frame; either EXIT or
ager@chromium.orga1645e22009-09-09 19:27:10 +000097 // EXIT_DEBUG. Expects the number of arguments in register rax and
98 // sets up the number of arguments in register rdi and the pointer
99 // to the first argument in register rsi.
100 void EnterExitFrame(StackFrame::Type type, int result_size = 1);
ager@chromium.org9085a012009-05-11 19:22:57 +0000101
ager@chromium.orga1645e22009-09-09 19:27:10 +0000102 // Leave the current exit frame. Expects/provides the return value in
103 // register rax:rdx (untouched) and the pointer to the first
104 // argument in register rsi.
105 void LeaveExitFrame(StackFrame::Type type, int result_size = 1);
ager@chromium.org9085a012009-05-11 19:22:57 +0000106
107
108 // ---------------------------------------------------------------------------
109 // JavaScript invokes
110
111 // Invoke the JavaScript function code by either calling or jumping.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000112 void InvokeCode(Register code,
ager@chromium.org9085a012009-05-11 19:22:57 +0000113 const ParameterCount& expected,
114 const ParameterCount& actual,
115 InvokeFlag flag);
116
117 void InvokeCode(Handle<Code> code,
118 const ParameterCount& expected,
119 const ParameterCount& actual,
120 RelocInfo::Mode rmode,
121 InvokeFlag flag);
122
123 // Invoke the JavaScript function in the given register. Changes the
124 // current context to the context in the function before invoking.
125 void InvokeFunction(Register function,
126 const ParameterCount& actual,
127 InvokeFlag flag);
128
129 // Invoke specified builtin JavaScript function. Adds an entry to
130 // the unresolved list if the name does not resolve.
131 void InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag);
132
133 // Store the code object for the given builtin in the target register.
134 void GetBuiltinEntry(Register target, Builtins::JavaScript id);
135
ager@chromium.org4af710e2009-09-15 12:20:11 +0000136
137 // ---------------------------------------------------------------------------
138 // Smi tagging, untagging and operations on tagged smis.
139
140 // Conversions between tagged smi values and non-tagged integer values.
141
142 // Tag an integer value. The result must be known to be a valid smi value.
143 // Only uses the low 32 bits of the src register.
144 void Integer32ToSmi(Register dst, Register src);
145
146 // Tag an integer value if possible, or jump the integer value cannot be
147 // represented as a smi. Only uses the low 32 bit of the src registers.
148 void Integer32ToSmi(Register dst, Register src, Label* on_overflow);
149
150 // Adds constant to src and tags the result as a smi.
151 // Result must be a valid smi.
152 void Integer64AddToSmi(Register dst, Register src, int constant);
153
154 // Convert smi to 32-bit integer. I.e., not sign extended into
155 // high 32 bits of destination.
156 void SmiToInteger32(Register dst, Register src);
157
158 // Convert smi to 64-bit integer (sign extended if necessary).
159 void SmiToInteger64(Register dst, Register src);
160
161 // Multiply a positive smi's integer value by a power of two.
162 // Provides result as 64-bit integer value.
163 void PositiveSmiTimesPowerOfTwoToInteger64(Register dst,
164 Register src,
165 int power);
166
167 // Functions performing a check on a known or potential smi. Returns
168 // a condition that is satisfied if the check is successful.
169
170 // Is the value a tagged smi.
171 Condition CheckSmi(Register src);
172
173 // Is the value not a tagged smi.
174 Condition CheckNotSmi(Register src);
175
176 // Is the value a positive tagged smi.
177 Condition CheckPositiveSmi(Register src);
178
179 // Is the value not a positive tagged smi.
180 Condition CheckNotPositiveSmi(Register src);
181
182 // Are both values are tagged smis.
183 Condition CheckBothSmi(Register first, Register second);
184
185 // Is one of the values not a tagged smi.
186 Condition CheckNotBothSmi(Register first, Register second);
187
188 // Is the value the minimum smi value (since we are using
189 // two's complement numbers, negating the value is known to yield
190 // a non-smi value).
191 Condition CheckIsMinSmi(Register src);
192
193 // Check whether a tagged smi is equal to a constant.
194 Condition CheckSmiEqualsConstant(Register src, int constant);
195
196 // Checks whether an 32-bit integer value is a valid for conversion
197 // to a smi.
198 Condition CheckInteger32ValidSmiValue(Register src);
199
200 // Test-and-jump functions. Typically combines a check function
201 // above with a conditional jump.
202
203 // Jump if the value cannot be represented by a smi.
204 void JumpIfNotValidSmiValue(Register src, Label* on_invalid);
205
206 // Jump to label if the value is a tagged smi.
207 void JumpIfSmi(Register src, Label* on_smi);
208
209 // Jump to label if the value is not a tagged smi.
210 void JumpIfNotSmi(Register src, Label* on_not_smi);
211
212 // Jump to label if the value is not a positive tagged smi.
213 void JumpIfNotPositiveSmi(Register src, Label* on_not_smi);
214
215 // Jump to label if the value is a tagged smi with value equal
216 // to the constant.
217 void JumpIfSmiEqualsConstant(Register src, int constant, Label* on_equals);
218
219 // Jump if either or both register are not smi values.
220 void JumpIfNotBothSmi(Register src1, Register src2, Label* on_not_both_smi);
221
222 // Operations on tagged smi values.
223
224 // Smis represent a subset of integers. The subset is always equivalent to
225 // a two's complement interpretation of a fixed number of bits.
226
227 // Optimistically adds an integer constant to a supposed smi.
228 // If the src is not a smi, or the result is not a smi, jump to
229 // the label.
230 void SmiTryAddConstant(Register dst,
231 Register src,
232 int32_t constant,
233 Label* on_not_smi_result);
234
235 // Add an integer constant to a tagged smi, giving a tagged smi as result,
236 // or jumping to a label if the result cannot be represented by a smi.
237 // If the label is NULL, no testing on the result is done.
238 void SmiAddConstant(Register dst,
239 Register src,
240 int32_t constant,
241 Label* on_not_smi_result);
242
243 // Subtract an integer constant from a tagged smi, giving a tagged smi as
244 // result, or jumping to a label if the result cannot be represented by a smi.
245 // If the label is NULL, no testing on the result is done.
246 void SmiSubConstant(Register dst,
247 Register src,
248 int32_t constant,
249 Label* on_not_smi_result);
250
251 // Negating a smi can give a negative zero or too large positive value.
252 void SmiNeg(Register dst,
253 Register src,
254 Label* on_not_smi_result);
255
256 // Adds smi values and return the result as a smi.
257 // If dst is src1, then src1 will be destroyed, even if
258 // the operation is unsuccessful.
259 void SmiAdd(Register dst,
260 Register src1,
261 Register src2,
262 Label* on_not_smi_result);
263
264 // Subtracts smi values and return the result as a smi.
265 // If dst is src1, then src1 will be destroyed, even if
266 // the operation is unsuccessful.
267 void SmiSub(Register dst,
268 Register src1,
269 Register src2,
270 Label* on_not_smi_result);
271
272 // Multiplies smi values and return the result as a smi,
273 // if possible.
274 // If dst is src1, then src1 will be destroyed, even if
275 // the operation is unsuccessful.
276 void SmiMul(Register dst,
277 Register src1,
278 Register src2,
279 Label* on_not_smi_result);
280
281 // Divides one smi by another and returns the quotient.
282 // Clobbers rax and rdx registers.
283 void SmiDiv(Register dst,
284 Register src1,
285 Register src2,
286 Label* on_not_smi_result);
287
288 // Divides one smi by another and returns the remainder.
289 // Clobbers rax and rdx registers.
290 void SmiMod(Register dst,
291 Register src1,
292 Register src2,
293 Label* on_not_smi_result);
294
295 // Bitwise operations.
296 void SmiNot(Register dst, Register src);
297 void SmiAnd(Register dst, Register src1, Register src2);
298 void SmiOr(Register dst, Register src1, Register src2);
299 void SmiXor(Register dst, Register src1, Register src2);
300 void SmiAndConstant(Register dst, Register src1, int constant);
301 void SmiOrConstant(Register dst, Register src1, int constant);
302 void SmiXorConstant(Register dst, Register src1, int constant);
303
304 void SmiShiftLeftConstant(Register dst,
305 Register src,
306 int shift_value,
307 Label* on_not_smi_result);
308 void SmiShiftLogicalRightConstant(Register dst,
309 Register src,
310 int shift_value,
311 Label* on_not_smi_result);
312 void SmiShiftArithmeticRightConstant(Register dst,
313 Register src,
314 int shift_value);
315
316 // Shifts a smi value to the left, and returns the result if that is a smi.
317 // Uses and clobbers rcx, so dst may not be rcx.
318 void SmiShiftLeft(Register dst,
319 Register src1,
320 Register src2,
321 Label* on_not_smi_result);
322 // Shifts a smi value to the right, shifting in zero bits at the top, and
323 // returns the unsigned intepretation of the result if that is a smi.
324 // Uses and clobbers rcx, so dst may not be rcx.
325 void SmiShiftLogicalRight(Register dst,
326 Register src1,
327 Register src2,
328 Label* on_not_smi_result);
329 // Shifts a smi value to the right, sign extending the top, and
330 // returns the signed intepretation of the result. That will always
331 // be a valid smi value, since it's numerically smaller than the
332 // original.
333 // Uses and clobbers rcx, so dst may not be rcx.
334 void SmiShiftArithmeticRight(Register dst,
335 Register src1,
336 Register src2);
337
338 // Specialized operations
339
340 // Select the non-smi register of two registers where exactly one is a
341 // smi. If neither are smis, jump to the failure label.
342 void SelectNonSmi(Register dst,
343 Register src1,
344 Register src2,
345 Label* on_not_smis);
346
347 // Converts, if necessary, a smi to a combination of number and
348 // multiplier to be used as a scaled index.
349 // The src register contains a *positive* smi value. The shift is the
350 // power of two to multiply the index value by (e.g.
351 // to index by smi-value * kPointerSize, pass the smi and kPointerSizeLog2).
352 // The returned index register may be either src or dst, depending
353 // on what is most efficient. If src and dst are different registers,
354 // src is always unchanged.
355 SmiIndex SmiToIndex(Register dst, Register src, int shift);
356
357 // Converts a positive smi to a negative index.
358 SmiIndex SmiToNegativeIndex(Register dst, Register src, int shift);
359
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000360 // ---------------------------------------------------------------------------
361 // Macro instructions
362
ager@chromium.org9085a012009-05-11 19:22:57 +0000363 // Expression support
ager@chromium.orge2902be2009-06-08 12:21:35 +0000364 void Set(Register dst, int64_t x);
365 void Set(const Operand& dst, int64_t x);
ager@chromium.org9085a012009-05-11 19:22:57 +0000366
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000367 // Handle support
368 bool IsUnsafeSmi(Smi* value);
369 bool IsUnsafeSmi(Handle<Object> value) {
370 return IsUnsafeSmi(Smi::cast(*value));
371 }
372
373 void LoadUnsafeSmi(Register dst, Smi* source);
374 void LoadUnsafeSmi(Register dst, Handle<Object> source) {
375 LoadUnsafeSmi(dst, Smi::cast(*source));
376 }
377
378 void Move(Register dst, Handle<Object> source);
379 void Move(const Operand& dst, Handle<Object> source);
380 void Cmp(Register dst, Handle<Object> source);
ager@chromium.org3e875802009-06-29 08:26:34 +0000381 void Cmp(const Operand& dst, Handle<Object> source);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000382 void Push(Handle<Object> source);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000383 void Push(Smi* smi);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000384
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000385 // Control Flow
386 void Jump(Address destination, RelocInfo::Mode rmode);
387 void Jump(ExternalReference ext);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000388 void Jump(Handle<Code> code_object, RelocInfo::Mode rmode);
389
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000390 void Call(Address destination, RelocInfo::Mode rmode);
391 void Call(ExternalReference ext);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000392 void Call(Handle<Code> code_object, RelocInfo::Mode rmode);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000393
ager@chromium.org9085a012009-05-11 19:22:57 +0000394 // Compare object type for heap object.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000395 // Always use unsigned comparisons: above and below, not less and greater.
ager@chromium.org9085a012009-05-11 19:22:57 +0000396 // Incoming register is heap_object and outgoing register is map.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000397 // They may be the same register, and may be kScratchRegister.
ager@chromium.org9085a012009-05-11 19:22:57 +0000398 void CmpObjectType(Register heap_object, InstanceType type, Register map);
399
400 // Compare instance type for map.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000401 // Always use unsigned comparisons: above and below, not less and greater.
ager@chromium.org9085a012009-05-11 19:22:57 +0000402 void CmpInstanceType(Register map, InstanceType type);
403
404 // FCmp is similar to integer cmp, but requires unsigned
405 // jcc instructions (je, ja, jae, jb, jbe, je, and jz).
406 void FCmp();
407
408 // ---------------------------------------------------------------------------
409 // Exception handling
410
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000411 // Push a new try handler and link into try handler chain. The return
412 // address must be pushed before calling this helper.
ager@chromium.org9085a012009-05-11 19:22:57 +0000413 void PushTryHandler(CodeLocation try_location, HandlerType type);
414
415
416 // ---------------------------------------------------------------------------
417 // Inline caching support
418
419 // Generates code that verifies that the maps of objects in the
420 // prototype chain of object hasn't changed since the code was
421 // generated and branches to the miss label if any map has. If
422 // necessary the function also generates code for security check
423 // in case of global object holders. The scratch and holder
424 // registers are always clobbered, but the object register is only
425 // clobbered if it the same as the holder register. The function
426 // returns a register containing the holder - either object_reg or
427 // holder_reg.
428 Register CheckMaps(JSObject* object, Register object_reg,
429 JSObject* holder, Register holder_reg,
430 Register scratch, Label* miss);
431
432 // Generate code for checking access rights - used for security checks
433 // on access to global objects across environments. The holder register
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000434 // is left untouched, but the scratch register and kScratchRegister,
435 // which must be different, are clobbered.
ager@chromium.org9085a012009-05-11 19:22:57 +0000436 void CheckAccessGlobalProxy(Register holder_reg,
437 Register scratch,
438 Label* miss);
439
440
441 // ---------------------------------------------------------------------------
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000442 // Allocation support
443
444 // Allocate an object in new space. If the new space is exhausted control
445 // continues at the gc_required label. The allocated object is returned in
446 // result and end of the new object is returned in result_end. The register
447 // scratch can be passed as no_reg in which case an additional object
448 // reference will be added to the reloc info. The returned pointers in result
449 // and result_end have not yet been tagged as heap objects. If
450 // result_contains_top_on_entry is true the content of result is known to be
451 // the allocation top on entry (could be result_end from a previous call to
452 // AllocateObjectInNewSpace). If result_contains_top_on_entry is true scratch
453 // should be no_reg as it is never used.
454 void AllocateObjectInNewSpace(int object_size,
455 Register result,
456 Register result_end,
457 Register scratch,
458 Label* gc_required,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000459 AllocationFlags flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000460
461 void AllocateObjectInNewSpace(int header_size,
462 ScaleFactor element_size,
463 Register element_count,
464 Register result,
465 Register result_end,
466 Register scratch,
467 Label* gc_required,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000468 AllocationFlags flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000469
470 void AllocateObjectInNewSpace(Register object_size,
471 Register result,
472 Register result_end,
473 Register scratch,
474 Label* gc_required,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000475 AllocationFlags flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000476
477 // Undo allocation in new space. The object passed and objects allocated after
478 // it will no longer be allocated. Make sure that no pointers are left to the
479 // object(s) no longer allocated as they would be invalid when allocation is
480 // un-done.
481 void UndoAllocationInNewSpace(Register object);
482
483 // ---------------------------------------------------------------------------
ager@chromium.org9085a012009-05-11 19:22:57 +0000484 // Support functions.
485
486 // Check if result is zero and op is negative.
487 void NegativeZeroTest(Register result, Register op, Label* then_label);
488
489 // Check if result is zero and op is negative in code using jump targets.
490 void NegativeZeroTest(CodeGenerator* cgen,
491 Register result,
492 Register op,
493 JumpTarget* then_target);
494
495 // Check if result is zero and any of op1 and op2 are negative.
496 // Register scratch is destroyed, and it must be different from op2.
497 void NegativeZeroTest(Register result, Register op1, Register op2,
498 Register scratch, Label* then_label);
499
500 // Try to get function prototype of a function and puts the value in
501 // the result register. Checks that the function really is a
502 // function and jumps to the miss label if the fast checks fail. The
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000503 // function register will be untouched; the other register may be
ager@chromium.org9085a012009-05-11 19:22:57 +0000504 // clobbered.
505 void TryGetFunctionPrototype(Register function,
506 Register result,
ager@chromium.org9085a012009-05-11 19:22:57 +0000507 Label* miss);
508
509 // Generates code for reporting that an illegal operation has
510 // occurred.
511 void IllegalOperation(int num_arguments);
512
513 // ---------------------------------------------------------------------------
514 // Runtime calls
515
516 // Call a code stub.
517 void CallStub(CodeStub* stub);
518
519 // Return from a code stub after popping its arguments.
520 void StubReturn(int argc);
521
522 // Call a runtime routine.
523 // Eventually this should be used for all C calls.
524 void CallRuntime(Runtime::Function* f, int num_arguments);
525
526 // Convenience function: Same as above, but takes the fid instead.
527 void CallRuntime(Runtime::FunctionId id, int num_arguments);
528
529 // Tail call of a runtime routine (jump).
530 // Like JumpToBuiltin, but also takes care of passing the number
531 // of arguments.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000532 void TailCallRuntime(const ExternalReference& ext,
533 int num_arguments,
534 int result_size);
ager@chromium.org9085a012009-05-11 19:22:57 +0000535
536 // Jump to the builtin routine.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000537 void JumpToBuiltin(const ExternalReference& ext, int result_size);
ager@chromium.org9085a012009-05-11 19:22:57 +0000538
539
540 // ---------------------------------------------------------------------------
541 // Utilities
542
543 void Ret();
544
545 struct Unresolved {
546 int pc;
547 uint32_t flags; // see Bootstrapper::FixupFlags decoders/encoders.
548 const char* name;
549 };
550 List<Unresolved>* unresolved() { return &unresolved_; }
551
552 Handle<Object> CodeObject() { return code_object_; }
553
554
555 // ---------------------------------------------------------------------------
556 // StatsCounter support
557
558 void SetCounter(StatsCounter* counter, int value);
559 void IncrementCounter(StatsCounter* counter, int value);
560 void DecrementCounter(StatsCounter* counter, int value);
561
562
563 // ---------------------------------------------------------------------------
564 // Debugging
565
566 // Calls Abort(msg) if the condition cc is not satisfied.
567 // Use --debug_code to enable.
568 void Assert(Condition cc, const char* msg);
569
570 // Like Assert(), but always enabled.
571 void Check(Condition cc, const char* msg);
572
573 // Print a message to stdout and abort execution.
574 void Abort(const char* msg);
575
576 // Verify restrictions about code generated in stubs.
577 void set_generating_stub(bool value) { generating_stub_ = value; }
578 bool generating_stub() { return generating_stub_; }
579 void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
580 bool allow_stub_calls() { return allow_stub_calls_; }
581
582 private:
583 List<Unresolved> unresolved_;
584 bool generating_stub_;
585 bool allow_stub_calls_;
586 Handle<Object> code_object_; // This handle will be patched with the code
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000587 // object on installation.
ager@chromium.org9085a012009-05-11 19:22:57 +0000588
589 // Helper functions for generating invokes.
590 void InvokePrologue(const ParameterCount& expected,
591 const ParameterCount& actual,
592 Handle<Code> code_constant,
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000593 Register code_register,
ager@chromium.org9085a012009-05-11 19:22:57 +0000594 Label* done,
595 InvokeFlag flag);
596
597 // Get the code for the given builtin. Returns if able to resolve
598 // the function in the 'resolved' flag.
599 Handle<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved);
600
601 // Activation support.
602 void EnterFrame(StackFrame::Type type);
603 void LeaveFrame(StackFrame::Type type);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000604
605 // Allocation support helpers.
606 void LoadAllocationTopHelper(Register result,
607 Register result_end,
608 Register scratch,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000609 AllocationFlags flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000610 void UpdateAllocationTopHelper(Register result_end, Register scratch);
ager@chromium.org9085a012009-05-11 19:22:57 +0000611};
612
613
ager@chromium.org4af710e2009-09-15 12:20:11 +0000614// The code patcher is used to patch (typically) small parts of code e.g. for
615// debugging and other types of instrumentation. When using the code patcher
616// the exact number of bytes specified must be emitted. Is not legal to emit
617// relocation information. If any of these constraints are violated it causes
618// an assertion.
619class CodePatcher {
620 public:
621 CodePatcher(byte* address, int size);
622 virtual ~CodePatcher();
623
624 // Macro assembler to emit code.
625 MacroAssembler* masm() { return &masm_; }
626
627 private:
628 byte* address_; // The address of the code being patched.
629 int size_; // Number of bytes of the expected patch size.
630 MacroAssembler masm_; // Macro assembler used to generate the code.
631};
632
633
ager@chromium.org9085a012009-05-11 19:22:57 +0000634// -----------------------------------------------------------------------------
635// Static helper functions.
636
637// Generate an Operand for loading a field from an object.
638static inline Operand FieldOperand(Register object, int offset) {
639 return Operand(object, offset - kHeapObjectTag);
640}
641
642
643// Generate an Operand for loading an indexed field from an object.
644static inline Operand FieldOperand(Register object,
645 Register index,
646 ScaleFactor scale,
647 int offset) {
648 return Operand(object, index, scale, offset - kHeapObjectTag);
649}
650
651
652#ifdef GENERATED_CODE_COVERAGE
653extern void LogGeneratedCodeCoverage(const char* file_line);
654#define CODE_COVERAGE_STRINGIFY(x) #x
655#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
656#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
657#define ACCESS_MASM(masm) { \
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000658 byte* x64_coverage_function = \
ager@chromium.org9085a012009-05-11 19:22:57 +0000659 reinterpret_cast<byte*>(FUNCTION_ADDR(LogGeneratedCodeCoverage)); \
660 masm->pushfd(); \
661 masm->pushad(); \
662 masm->push(Immediate(reinterpret_cast<int>(&__FILE_LINE__))); \
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000663 masm->call(x64_coverage_function, RelocInfo::RUNTIME_ENTRY); \
ager@chromium.org9085a012009-05-11 19:22:57 +0000664 masm->pop(rax); \
665 masm->popad(); \
666 masm->popfd(); \
667 } \
668 masm->
669#else
670#define ACCESS_MASM(masm) masm->
671#endif
672
673
674} } // namespace v8::internal
675
676#endif // V8_X64_MACRO_ASSEMBLER_X64_H_