blob: b2d085f9050603cea10da75c20b28b77548cd0ef [file] [log] [blame]
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001// Copyright 2010 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
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000036// Flags used for the AllocateInNewSpace functions.
37enum AllocationFlags {
38 // No special flags.
39 NO_ALLOCATION_FLAGS = 0,
40 // Return the pointer to the allocated already tagged as a heap object.
41 TAG_OBJECT = 1 << 0,
42 // The content of the result register already contains the allocation top in
43 // new space.
44 RESULT_CONTAINS_TOP = 1 << 1
45};
46
ager@chromium.orge2902be2009-06-08 12:21:35 +000047// Default scratch register used by MacroAssembler (and other code that needs
48// a spare register). The register isn't callee save, and not used by the
49// function calling convention.
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +000050static const Register kScratchRegister = { 10 }; // r10.
51static const Register kSmiConstantRegister = { 15 }; // r15 (callee save).
52static const Register kRootRegister = { 13 }; // r13 (callee save).
53// Value of smi in kSmiConstantRegister.
54static const int kSmiConstantRegisterValue = 1;
ager@chromium.orge2902be2009-06-08 12:21:35 +000055
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000056// Convenience for platform-independent signatures.
57typedef Operand MemOperand;
58
ager@chromium.org9085a012009-05-11 19:22:57 +000059// Forward declaration.
60class JumpTarget;
61
ager@chromium.org4af710e2009-09-15 12:20:11 +000062struct SmiIndex {
63 SmiIndex(Register index_register, ScaleFactor scale)
64 : reg(index_register),
65 scale(scale) {}
66 Register reg;
67 ScaleFactor scale;
68};
ager@chromium.org9085a012009-05-11 19:22:57 +000069
ager@chromium.org9085a012009-05-11 19:22:57 +000070// MacroAssembler implements a collection of frequently used macros.
71class MacroAssembler: public Assembler {
72 public:
73 MacroAssembler(void* buffer, int size);
74
ager@chromium.org18ad94b2009-09-02 08:22:29 +000075 void LoadRoot(Register destination, Heap::RootListIndex index);
76 void CompareRoot(Register with, Heap::RootListIndex index);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000077 void CompareRoot(Operand with, Heap::RootListIndex index);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000078 void PushRoot(Heap::RootListIndex index);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000079 void StoreRoot(Register source, Heap::RootListIndex index);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000080
ager@chromium.org9085a012009-05-11 19:22:57 +000081 // ---------------------------------------------------------------------------
82 // GC Support
83
ricow@chromium.org30ce4112010-05-31 10:38:25 +000084 // For page containing |object| mark region covering |addr| dirty.
85 // RecordWriteHelper only works if the object is not in new
ager@chromium.orgac091b72010-05-05 07:34:42 +000086 // space.
87 void RecordWriteHelper(Register object,
88 Register addr,
89 Register scratch);
90
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000091 // Check if object is in new space. The condition cc can be equal or
92 // not_equal. If it is equal a jump will be done if the object is on new
93 // space. The register scratch can be object itself, but it will be clobbered.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000094 template <typename LabelType>
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000095 void InNewSpace(Register object,
96 Register scratch,
97 Condition cc,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000098 LabelType* branch);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000099
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000100 // For page containing |object| mark region covering [object+offset]
101 // dirty. |object| is the object being stored into, |value| is the
102 // object being stored. If |offset| is zero, then the |scratch|
103 // register contains the array index into the elements array
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000104 // represented as an untagged 32-bit integer. All registers are
105 // clobbered by the operation. RecordWrite filters out smis so it
106 // does not update the write barrier if the value is a smi.
ager@chromium.org9085a012009-05-11 19:22:57 +0000107 void RecordWrite(Register object,
108 int offset,
109 Register value,
110 Register scratch);
111
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000112 // For page containing |object| mark region covering [address]
113 // dirty. |object| is the object being stored into, |value| is the
114 // object being stored. All registers are clobbered by the
115 // operation. RecordWrite filters out smis so it does not update
116 // the write barrier if the value is a smi.
117 void RecordWrite(Register object,
118 Register address,
119 Register value);
120
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000121 // For page containing |object| mark region covering [object+offset] dirty.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000122 // The value is known to not be a smi.
123 // object is the object being stored into, value is the object being stored.
124 // If offset is zero, then the scratch register contains the array index into
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000125 // the elements array represented as an untagged 32-bit integer.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000126 // All registers are clobbered by the operation.
127 void RecordWriteNonSmi(Register object,
128 int offset,
129 Register value,
130 Register scratch);
131
ager@chromium.org9085a012009-05-11 19:22:57 +0000132#ifdef ENABLE_DEBUGGER_SUPPORT
133 // ---------------------------------------------------------------------------
134 // Debugger Support
135
ager@chromium.org5c838252010-02-19 08:53:10 +0000136 void DebugBreak();
ager@chromium.org9085a012009-05-11 19:22:57 +0000137#endif
138
139 // ---------------------------------------------------------------------------
140 // Activation frames
141
142 void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
143 void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); }
144
145 void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); }
146 void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
147
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000148 // Enter specific kind of exit frame; either in normal or
149 // debug mode. Expects the number of arguments in register rax and
ager@chromium.orga1645e22009-09-09 19:27:10 +0000150 // sets up the number of arguments in register rdi and the pointer
151 // to the first argument in register rsi.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000152 //
153 // Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack
154 // accessible via StackSpaceOperand.
155 void EnterExitFrame(int arg_stack_space = 0);
ager@chromium.org9085a012009-05-11 19:22:57 +0000156
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000157 // Enter specific kind of exit frame. Allocates arg_stack_space * kPointerSize
158 // memory (not GCed) on the stack accessible via StackSpaceOperand.
159 void EnterApiExitFrame(int arg_stack_space);
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000160
ager@chromium.orga1645e22009-09-09 19:27:10 +0000161 // Leave the current exit frame. Expects/provides the return value in
162 // register rax:rdx (untouched) and the pointer to the first
163 // argument in register rsi.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000164 void LeaveExitFrame();
ager@chromium.org9085a012009-05-11 19:22:57 +0000165
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000166 // Leave the current exit frame. Expects/provides the return value in
167 // register rax (untouched).
168 void LeaveApiExitFrame();
ager@chromium.org9085a012009-05-11 19:22:57 +0000169
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000170 // Push and pop the registers that can hold pointers.
171 void PushSafepointRegisters() { UNIMPLEMENTED(); }
172 void PopSafepointRegisters() { UNIMPLEMENTED(); }
173 static int SafepointRegisterStackIndex(int reg_code) {
174 UNIMPLEMENTED();
175 return 0;
176 }
177
ager@chromium.org9085a012009-05-11 19:22:57 +0000178 // ---------------------------------------------------------------------------
179 // JavaScript invokes
180
181 // Invoke the JavaScript function code by either calling or jumping.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000182 void InvokeCode(Register code,
ager@chromium.org9085a012009-05-11 19:22:57 +0000183 const ParameterCount& expected,
184 const ParameterCount& actual,
185 InvokeFlag flag);
186
187 void InvokeCode(Handle<Code> code,
188 const ParameterCount& expected,
189 const ParameterCount& actual,
190 RelocInfo::Mode rmode,
191 InvokeFlag flag);
192
193 // Invoke the JavaScript function in the given register. Changes the
194 // current context to the context in the function before invoking.
195 void InvokeFunction(Register function,
196 const ParameterCount& actual,
197 InvokeFlag flag);
198
ager@chromium.org5c838252010-02-19 08:53:10 +0000199 void InvokeFunction(JSFunction* function,
200 const ParameterCount& actual,
201 InvokeFlag flag);
202
ager@chromium.org9085a012009-05-11 19:22:57 +0000203 // Invoke specified builtin JavaScript function. Adds an entry to
204 // the unresolved list if the name does not resolve.
205 void InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag);
206
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000207 // Store the function for the given builtin in the target register.
208 void GetBuiltinFunction(Register target, Builtins::JavaScript id);
209
ager@chromium.org9085a012009-05-11 19:22:57 +0000210 // Store the code object for the given builtin in the target register.
211 void GetBuiltinEntry(Register target, Builtins::JavaScript id);
212
ager@chromium.org4af710e2009-09-15 12:20:11 +0000213
214 // ---------------------------------------------------------------------------
215 // Smi tagging, untagging and operations on tagged smis.
216
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000217 void InitializeSmiConstantRegister() {
218 movq(kSmiConstantRegister,
219 reinterpret_cast<uint64_t>(Smi::FromInt(kSmiConstantRegisterValue)),
220 RelocInfo::NONE);
221 }
222
ager@chromium.org4af710e2009-09-15 12:20:11 +0000223 // Conversions between tagged smi values and non-tagged integer values.
224
225 // Tag an integer value. The result must be known to be a valid smi value.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000226 // Only uses the low 32 bits of the src register. Sets the N and Z flags
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000227 // based on the value of the resulting smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000228 void Integer32ToSmi(Register dst, Register src);
229
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000230 // Stores an integer32 value into a memory field that already holds a smi.
231 void Integer32ToSmiField(const Operand& dst, Register src);
232
ager@chromium.org4af710e2009-09-15 12:20:11 +0000233 // Adds constant to src and tags the result as a smi.
234 // Result must be a valid smi.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000235 void Integer64PlusConstantToSmi(Register dst, Register src, int constant);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000236
237 // Convert smi to 32-bit integer. I.e., not sign extended into
238 // high 32 bits of destination.
239 void SmiToInteger32(Register dst, Register src);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000240 void SmiToInteger32(Register dst, const Operand& src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000241
242 // Convert smi to 64-bit integer (sign extended if necessary).
243 void SmiToInteger64(Register dst, Register src);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000244 void SmiToInteger64(Register dst, const Operand& src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000245
246 // Multiply a positive smi's integer value by a power of two.
247 // Provides result as 64-bit integer value.
248 void PositiveSmiTimesPowerOfTwoToInteger64(Register dst,
249 Register src,
250 int power);
251
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000252 // Divide a positive smi's integer value by a power of two.
253 // Provides result as 32-bit integer value.
254 void PositiveSmiDivPowerOfTwoToInteger32(Register dst,
255 Register src,
256 int power);
257
258
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000259 // Simple comparison of smis.
260 void SmiCompare(Register dst, Register src);
261 void SmiCompare(Register dst, Smi* src);
ager@chromium.orgac091b72010-05-05 07:34:42 +0000262 void SmiCompare(Register dst, const Operand& src);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000263 void SmiCompare(const Operand& dst, Register src);
264 void SmiCompare(const Operand& dst, Smi* src);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000265 // Compare the int32 in src register to the value of the smi stored at dst.
266 void SmiCompareInteger32(const Operand& dst, Register src);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000267 // Sets sign and zero flags depending on value of smi in register.
268 void SmiTest(Register src);
269
ager@chromium.org4af710e2009-09-15 12:20:11 +0000270 // Functions performing a check on a known or potential smi. Returns
271 // a condition that is satisfied if the check is successful.
272
273 // Is the value a tagged smi.
274 Condition CheckSmi(Register src);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000275 Condition CheckSmi(const Operand& src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000276
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000277 // Is the value a non-negative tagged smi.
278 Condition CheckNonNegativeSmi(Register src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000279
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000280 // Are both values tagged smis.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000281 Condition CheckBothSmi(Register first, Register second);
282
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000283 // Are both values non-negative tagged smis.
284 Condition CheckBothNonNegativeSmi(Register first, Register second);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000285
286 // Are either value a tagged smi.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000287 Condition CheckEitherSmi(Register first,
288 Register second,
289 Register scratch = kScratchRegister);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000290
ager@chromium.org4af710e2009-09-15 12:20:11 +0000291 // Is the value the minimum smi value (since we are using
292 // two's complement numbers, negating the value is known to yield
293 // a non-smi value).
294 Condition CheckIsMinSmi(Register src);
295
ager@chromium.org4af710e2009-09-15 12:20:11 +0000296 // Checks whether an 32-bit integer value is a valid for conversion
297 // to a smi.
298 Condition CheckInteger32ValidSmiValue(Register src);
299
ager@chromium.org3811b432009-10-28 14:53:37 +0000300 // Checks whether an 32-bit unsigned integer value is a valid for
301 // conversion to a smi.
302 Condition CheckUInteger32ValidSmiValue(Register src);
303
ager@chromium.org4af710e2009-09-15 12:20:11 +0000304 // Test-and-jump functions. Typically combines a check function
305 // above with a conditional jump.
306
307 // Jump if the value cannot be represented by a smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000308 template <typename LabelType>
309 void JumpIfNotValidSmiValue(Register src, LabelType* on_invalid);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000310
ager@chromium.org3811b432009-10-28 14:53:37 +0000311 // Jump if the unsigned integer value cannot be represented by a smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000312 template <typename LabelType>
313 void JumpIfUIntNotValidSmiValue(Register src, LabelType* on_invalid);
ager@chromium.org3811b432009-10-28 14:53:37 +0000314
ager@chromium.org4af710e2009-09-15 12:20:11 +0000315 // Jump to label if the value is a tagged smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000316 template <typename LabelType>
317 void JumpIfSmi(Register src, LabelType* on_smi);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000318
319 // Jump to label if the value is not a tagged smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000320 template <typename LabelType>
321 void JumpIfNotSmi(Register src, LabelType* on_not_smi);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000322
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000323 // Jump to label if the value is not a non-negative tagged smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000324 template <typename LabelType>
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000325 void JumpUnlessNonNegativeSmi(Register src, LabelType* on_not_smi);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000326
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000327 // Jump to label if the value, which must be a tagged smi, has value equal
ager@chromium.org4af710e2009-09-15 12:20:11 +0000328 // to the constant.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000329 template <typename LabelType>
330 void JumpIfSmiEqualsConstant(Register src,
331 Smi* constant,
332 LabelType* on_equals);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000333
ager@chromium.org4af710e2009-09-15 12:20:11 +0000334 // Jump if either or both register are not smi values.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000335 template <typename LabelType>
336 void JumpIfNotBothSmi(Register src1,
337 Register src2,
338 LabelType* on_not_both_smi);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000339
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000340 // Jump if either or both register are not non-negative smi values.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000341 template <typename LabelType>
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000342 void JumpUnlessBothNonNegativeSmi(Register src1, Register src2,
343 LabelType* on_not_both_smi);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000344
ager@chromium.org4af710e2009-09-15 12:20:11 +0000345 // Operations on tagged smi values.
346
347 // Smis represent a subset of integers. The subset is always equivalent to
348 // a two's complement interpretation of a fixed number of bits.
349
350 // Optimistically adds an integer constant to a supposed smi.
351 // If the src is not a smi, or the result is not a smi, jump to
352 // the label.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000353 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000354 void SmiTryAddConstant(Register dst,
355 Register src,
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000356 Smi* constant,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000357 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000358
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000359 // Add an integer constant to a tagged smi, giving a tagged smi as result.
360 // No overflow testing on the result is done.
361 void SmiAddConstant(Register dst, Register src, Smi* constant);
362
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000363 // Add an integer constant to a tagged smi, giving a tagged smi as result.
364 // No overflow testing on the result is done.
365 void SmiAddConstant(const Operand& dst, Smi* constant);
366
ager@chromium.org4af710e2009-09-15 12:20:11 +0000367 // Add an integer constant to a tagged smi, giving a tagged smi as result,
368 // or jumping to a label if the result cannot be represented by a smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000369 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000370 void SmiAddConstant(Register dst,
371 Register src,
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000372 Smi* constant,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000373 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000374
375 // Subtract an integer constant from a tagged smi, giving a tagged smi as
ager@chromium.orgac091b72010-05-05 07:34:42 +0000376 // result. No testing on the result is done. Sets the N and Z flags
377 // based on the value of the resulting integer.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000378 void SmiSubConstant(Register dst, Register src, Smi* constant);
379
380 // Subtract an integer constant from a tagged smi, giving a tagged smi as
ager@chromium.org4af710e2009-09-15 12:20:11 +0000381 // result, or jumping to a label if the result cannot be represented by a smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000382 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000383 void SmiSubConstant(Register dst,
384 Register src,
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000385 Smi* constant,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000386 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000387
388 // Negating a smi can give a negative zero or too large positive value.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000389 // NOTICE: This operation jumps on success, not failure!
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000390 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000391 void SmiNeg(Register dst,
392 Register src,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000393 LabelType* on_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000394
395 // Adds smi values and return the result as a smi.
396 // If dst is src1, then src1 will be destroyed, even if
397 // the operation is unsuccessful.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000398 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000399 void SmiAdd(Register dst,
400 Register src1,
401 Register src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000402 LabelType* on_not_smi_result);
403
404 void SmiAdd(Register dst,
405 Register src1,
406 Register src2);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000407
408 // Subtracts smi values and return the result as a smi.
409 // If dst is src1, then src1 will be destroyed, even if
410 // the operation is unsuccessful.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000411 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000412 void SmiSub(Register dst,
413 Register src1,
414 Register src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000415 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000416
ager@chromium.orgac091b72010-05-05 07:34:42 +0000417 void SmiSub(Register dst,
418 Register src1,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000419 Register src2);
420
421 template <typename LabelType>
422 void SmiSub(Register dst,
423 Register src1,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000424 const Operand& src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000425 LabelType* on_not_smi_result);
426
427 void SmiSub(Register dst,
428 Register src1,
429 const Operand& src2);
ager@chromium.orgac091b72010-05-05 07:34:42 +0000430
ager@chromium.org4af710e2009-09-15 12:20:11 +0000431 // Multiplies smi values and return the result as a smi,
432 // if possible.
433 // If dst is src1, then src1 will be destroyed, even if
434 // the operation is unsuccessful.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000435 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000436 void SmiMul(Register dst,
437 Register src1,
438 Register src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000439 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000440
441 // Divides one smi by another and returns the quotient.
442 // Clobbers rax and rdx registers.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000443 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000444 void SmiDiv(Register dst,
445 Register src1,
446 Register src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000447 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000448
449 // Divides one smi by another and returns the remainder.
450 // Clobbers rax and rdx registers.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000451 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000452 void SmiMod(Register dst,
453 Register src1,
454 Register src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000455 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000456
457 // Bitwise operations.
458 void SmiNot(Register dst, Register src);
459 void SmiAnd(Register dst, Register src1, Register src2);
460 void SmiOr(Register dst, Register src1, Register src2);
461 void SmiXor(Register dst, Register src1, Register src2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000462 void SmiAndConstant(Register dst, Register src1, Smi* constant);
463 void SmiOrConstant(Register dst, Register src1, Smi* constant);
464 void SmiXorConstant(Register dst, Register src1, Smi* constant);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000465
466 void SmiShiftLeftConstant(Register dst,
467 Register src,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000468 int shift_value);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000469 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000470 void SmiShiftLogicalRightConstant(Register dst,
471 Register src,
472 int shift_value,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000473 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000474 void SmiShiftArithmeticRightConstant(Register dst,
475 Register src,
476 int shift_value);
477
478 // Shifts a smi value to the left, and returns the result if that is a smi.
479 // Uses and clobbers rcx, so dst may not be rcx.
480 void SmiShiftLeft(Register dst,
481 Register src1,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000482 Register src2);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000483 // Shifts a smi value to the right, shifting in zero bits at the top, and
484 // returns the unsigned intepretation of the result if that is a smi.
485 // Uses and clobbers rcx, so dst may not be rcx.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000486 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000487 void SmiShiftLogicalRight(Register dst,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000488 Register src1,
489 Register src2,
490 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000491 // Shifts a smi value to the right, sign extending the top, and
492 // returns the signed intepretation of the result. That will always
493 // be a valid smi value, since it's numerically smaller than the
494 // original.
495 // Uses and clobbers rcx, so dst may not be rcx.
496 void SmiShiftArithmeticRight(Register dst,
497 Register src1,
498 Register src2);
499
500 // Specialized operations
501
502 // Select the non-smi register of two registers where exactly one is a
503 // smi. If neither are smis, jump to the failure label.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000504 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000505 void SelectNonSmi(Register dst,
506 Register src1,
507 Register src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000508 LabelType* on_not_smis);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000509
510 // Converts, if necessary, a smi to a combination of number and
511 // multiplier to be used as a scaled index.
512 // The src register contains a *positive* smi value. The shift is the
513 // power of two to multiply the index value by (e.g.
514 // to index by smi-value * kPointerSize, pass the smi and kPointerSizeLog2).
515 // The returned index register may be either src or dst, depending
516 // on what is most efficient. If src and dst are different registers,
517 // src is always unchanged.
518 SmiIndex SmiToIndex(Register dst, Register src, int shift);
519
520 // Converts a positive smi to a negative index.
521 SmiIndex SmiToNegativeIndex(Register dst, Register src, int shift);
522
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000523 // Basic Smi operations.
ager@chromium.org3811b432009-10-28 14:53:37 +0000524 void Move(Register dst, Smi* source) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000525 LoadSmiConstant(dst, source);
ager@chromium.org3811b432009-10-28 14:53:37 +0000526 }
527
528 void Move(const Operand& dst, Smi* source) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000529 Register constant = GetSmiConstant(source);
530 movq(dst, constant);
ager@chromium.org3811b432009-10-28 14:53:37 +0000531 }
532
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000533 void Push(Smi* smi);
534 void Test(const Operand& dst, Smi* source);
535
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000536 // ---------------------------------------------------------------------------
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000537 // String macros.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000538 template <typename LabelType>
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000539 void JumpIfNotBothSequentialAsciiStrings(Register first_object,
540 Register second_object,
541 Register scratch1,
542 Register scratch2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000543 LabelType* on_not_both_flat_ascii);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000544
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000545 // Check whether the instance type represents a flat ascii string. Jump to the
546 // label if not. If the instance type can be scratched specify same register
547 // for both instance type and scratch.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000548 template <typename LabelType>
549 void JumpIfInstanceTypeIsNotSequentialAscii(
550 Register instance_type,
551 Register scratch,
552 LabelType *on_not_flat_ascii_string);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000553
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000554 template <typename LabelType>
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000555 void JumpIfBothInstanceTypesAreNotSequentialAscii(
556 Register first_object_instance_type,
557 Register second_object_instance_type,
558 Register scratch1,
559 Register scratch2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000560 LabelType* on_fail);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000561
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000562 // ---------------------------------------------------------------------------
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000563 // Macro instructions.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000564
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000565 // Load a register with a long value as efficiently as possible.
ager@chromium.orge2902be2009-06-08 12:21:35 +0000566 void Set(Register dst, int64_t x);
567 void Set(const Operand& dst, int64_t x);
ager@chromium.org9085a012009-05-11 19:22:57 +0000568
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000569 // Move if the registers are not identical.
570 void Move(Register target, Register source);
571
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000572 // Handle support
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000573 void Move(Register dst, Handle<Object> source);
574 void Move(const Operand& dst, Handle<Object> source);
575 void Cmp(Register dst, Handle<Object> source);
ager@chromium.org3e875802009-06-29 08:26:34 +0000576 void Cmp(const Operand& dst, Handle<Object> source);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000577 void Push(Handle<Object> source);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000578
579 // Emit code to discard a non-negative number of pointer-sized elements
580 // from the stack, clobbering only the rsp register.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000581 void Drop(int stack_elements);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000582
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000583 void Call(Label* target) { call(target); }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000584
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000585 // Control Flow
586 void Jump(Address destination, RelocInfo::Mode rmode);
587 void Jump(ExternalReference ext);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000588 void Jump(Handle<Code> code_object, RelocInfo::Mode rmode);
589
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000590 void Call(Address destination, RelocInfo::Mode rmode);
591 void Call(ExternalReference ext);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000592 void Call(Handle<Code> code_object, RelocInfo::Mode rmode);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000593
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000594 // Non-x64 instructions.
595 // Push/pop all general purpose registers.
596 // Does not push rsp/rbp nor any of the assembler's special purpose registers
597 // (kScratchRegister, kSmiConstantRegister, kRootRegister).
598 void Pushad();
599 void Popad();
600
ager@chromium.org9085a012009-05-11 19:22:57 +0000601 // Compare object type for heap object.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000602 // Always use unsigned comparisons: above and below, not less and greater.
ager@chromium.org9085a012009-05-11 19:22:57 +0000603 // Incoming register is heap_object and outgoing register is map.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000604 // They may be the same register, and may be kScratchRegister.
ager@chromium.org9085a012009-05-11 19:22:57 +0000605 void CmpObjectType(Register heap_object, InstanceType type, Register map);
606
607 // Compare instance type for map.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000608 // Always use unsigned comparisons: above and below, not less and greater.
ager@chromium.org9085a012009-05-11 19:22:57 +0000609 void CmpInstanceType(Register map, InstanceType type);
610
ager@chromium.org5c838252010-02-19 08:53:10 +0000611 // Check if the map of an object is equal to a specified map and
612 // branch to label if not. Skip the smi check if not required
613 // (object is known to be a heap object)
614 void CheckMap(Register obj,
615 Handle<Map> map,
616 Label* fail,
617 bool is_heap_object);
618
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000619 // Check if the object in register heap_object is a string. Afterwards the
620 // register map contains the object map and the register instance_type
621 // contains the instance_type. The registers map and instance_type can be the
622 // same in which case it contains the instance type afterwards. Either of the
623 // registers map and instance_type can be the same as heap_object.
624 Condition IsObjectStringType(Register heap_object,
625 Register map,
626 Register instance_type);
627
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000628 // FCmp compares and pops the two values on top of the FPU stack.
629 // The flag results are similar to integer cmp, but requires unsigned
ager@chromium.org9085a012009-05-11 19:22:57 +0000630 // jcc instructions (je, ja, jae, jb, jbe, je, and jz).
631 void FCmp();
632
ager@chromium.org5c838252010-02-19 08:53:10 +0000633 // Abort execution if argument is not a number. Used in debug code.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000634 void AbortIfNotNumber(Register object);
ager@chromium.org5c838252010-02-19 08:53:10 +0000635
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000636 // Abort execution if argument is a smi. Used in debug code.
637 void AbortIfSmi(Register object);
638
lrn@chromium.org25156de2010-04-06 13:10:27 +0000639 // Abort execution if argument is not a smi. Used in debug code.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000640 void AbortIfNotSmi(Register object);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000641
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000642 // Abort execution if argument is not the root value with the given index.
643 void AbortIfNotRootValue(Register src,
644 Heap::RootListIndex root_value_index,
645 const char* message);
646
ager@chromium.org9085a012009-05-11 19:22:57 +0000647 // ---------------------------------------------------------------------------
648 // Exception handling
649
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000650 // Push a new try handler and link into try handler chain. The return
651 // address must be pushed before calling this helper.
ager@chromium.org9085a012009-05-11 19:22:57 +0000652 void PushTryHandler(CodeLocation try_location, HandlerType type);
653
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000654 // Unlink the stack handler on top of the stack from the try handler chain.
655 void PopTryHandler();
ager@chromium.org9085a012009-05-11 19:22:57 +0000656
657 // ---------------------------------------------------------------------------
658 // Inline caching support
659
ager@chromium.org9085a012009-05-11 19:22:57 +0000660 // Generate code for checking access rights - used for security checks
661 // on access to global objects across environments. The holder register
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000662 // is left untouched, but the scratch register and kScratchRegister,
663 // which must be different, are clobbered.
ager@chromium.org9085a012009-05-11 19:22:57 +0000664 void CheckAccessGlobalProxy(Register holder_reg,
665 Register scratch,
666 Label* miss);
667
668
669 // ---------------------------------------------------------------------------
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000670 // Allocation support
671
672 // Allocate an object in new space. If the new space is exhausted control
673 // continues at the gc_required label. The allocated object is returned in
674 // result and end of the new object is returned in result_end. The register
675 // scratch can be passed as no_reg in which case an additional object
676 // reference will be added to the reloc info. The returned pointers in result
677 // and result_end have not yet been tagged as heap objects. If
678 // result_contains_top_on_entry is true the content of result is known to be
679 // the allocation top on entry (could be result_end from a previous call to
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000680 // AllocateInNewSpace). If result_contains_top_on_entry is true scratch
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000681 // should be no_reg as it is never used.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000682 void AllocateInNewSpace(int object_size,
683 Register result,
684 Register result_end,
685 Register scratch,
686 Label* gc_required,
687 AllocationFlags flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000688
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000689 void AllocateInNewSpace(int header_size,
690 ScaleFactor element_size,
691 Register element_count,
692 Register result,
693 Register result_end,
694 Register scratch,
695 Label* gc_required,
696 AllocationFlags flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000697
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000698 void AllocateInNewSpace(Register object_size,
699 Register result,
700 Register result_end,
701 Register scratch,
702 Label* gc_required,
703 AllocationFlags flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000704
705 // Undo allocation in new space. The object passed and objects allocated after
706 // it will no longer be allocated. Make sure that no pointers are left to the
707 // object(s) no longer allocated as they would be invalid when allocation is
708 // un-done.
709 void UndoAllocationInNewSpace(Register object);
710
ager@chromium.org3811b432009-10-28 14:53:37 +0000711 // Allocate a heap number in new space with undefined value. Returns
712 // tagged pointer in result register, or jumps to gc_required if new
713 // space is full.
714 void AllocateHeapNumber(Register result,
715 Register scratch,
716 Label* gc_required);
717
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000718 // Allocate a sequential string. All the header fields of the string object
719 // are initialized.
720 void AllocateTwoByteString(Register result,
721 Register length,
722 Register scratch1,
723 Register scratch2,
724 Register scratch3,
725 Label* gc_required);
726 void AllocateAsciiString(Register result,
727 Register length,
728 Register scratch1,
729 Register scratch2,
730 Register scratch3,
731 Label* gc_required);
732
733 // Allocate a raw cons string object. Only the map field of the result is
734 // initialized.
735 void AllocateConsString(Register result,
736 Register scratch1,
737 Register scratch2,
738 Label* gc_required);
739 void AllocateAsciiConsString(Register result,
740 Register scratch1,
741 Register scratch2,
742 Label* gc_required);
743
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000744 // ---------------------------------------------------------------------------
ager@chromium.org9085a012009-05-11 19:22:57 +0000745 // Support functions.
746
747 // Check if result is zero and op is negative.
748 void NegativeZeroTest(Register result, Register op, Label* then_label);
749
750 // Check if result is zero and op is negative in code using jump targets.
751 void NegativeZeroTest(CodeGenerator* cgen,
752 Register result,
753 Register op,
754 JumpTarget* then_target);
755
756 // Check if result is zero and any of op1 and op2 are negative.
757 // Register scratch is destroyed, and it must be different from op2.
758 void NegativeZeroTest(Register result, Register op1, Register op2,
759 Register scratch, Label* then_label);
760
761 // Try to get function prototype of a function and puts the value in
762 // the result register. Checks that the function really is a
763 // function and jumps to the miss label if the fast checks fail. The
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000764 // function register will be untouched; the other register may be
ager@chromium.org9085a012009-05-11 19:22:57 +0000765 // clobbered.
766 void TryGetFunctionPrototype(Register function,
767 Register result,
ager@chromium.org9085a012009-05-11 19:22:57 +0000768 Label* miss);
769
770 // Generates code for reporting that an illegal operation has
771 // occurred.
772 void IllegalOperation(int num_arguments);
773
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000774 // Picks out an array index from the hash field.
775 // Register use:
776 // hash - holds the index's hash. Clobbered.
777 // index - holds the overwritten index on exit.
778 void IndexFromHash(Register hash, Register index);
779
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000780 // Find the function context up the context chain.
781 void LoadContext(Register dst, int context_chain_length);
782
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000783 // Load the global function with the given index.
784 void LoadGlobalFunction(int index, Register function);
785
786 // Load the initial map from the global function. The registers
787 // function and map can be the same.
788 void LoadGlobalFunctionInitialMap(Register function, Register map);
789
ager@chromium.org9085a012009-05-11 19:22:57 +0000790 // ---------------------------------------------------------------------------
791 // Runtime calls
792
793 // Call a code stub.
794 void CallStub(CodeStub* stub);
795
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000796 // Call a code stub and return the code object called. Try to generate
797 // the code if necessary. Do not perform a GC but instead return a retry
798 // after GC failure.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000799 MUST_USE_RESULT MaybeObject* TryCallStub(CodeStub* stub);
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000800
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000801 // Tail call a code stub (jump).
802 void TailCallStub(CodeStub* stub);
803
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000804 // Tail call a code stub (jump) and return the code object called. Try to
805 // generate the code if necessary. Do not perform a GC but instead return
806 // a retry after GC failure.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000807 MUST_USE_RESULT MaybeObject* TryTailCallStub(CodeStub* stub);
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000808
ager@chromium.org9085a012009-05-11 19:22:57 +0000809 // Return from a code stub after popping its arguments.
810 void StubReturn(int argc);
811
812 // Call a runtime routine.
ager@chromium.org9085a012009-05-11 19:22:57 +0000813 void CallRuntime(Runtime::Function* f, int num_arguments);
814
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000815 // Call a runtime function, returning the CodeStub object called.
816 // Try to generate the stub code if necessary. Do not perform a GC
817 // but instead return a retry after GC failure.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000818 MUST_USE_RESULT MaybeObject* TryCallRuntime(Runtime::Function* f,
819 int num_arguments);
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000820
ager@chromium.org9085a012009-05-11 19:22:57 +0000821 // Convenience function: Same as above, but takes the fid instead.
822 void CallRuntime(Runtime::FunctionId id, int num_arguments);
823
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000824 // Convenience function: Same as above, but takes the fid instead.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000825 MUST_USE_RESULT MaybeObject* TryCallRuntime(Runtime::FunctionId id,
826 int num_arguments);
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000827
ager@chromium.org5c838252010-02-19 08:53:10 +0000828 // Convenience function: call an external reference.
829 void CallExternalReference(const ExternalReference& ext,
830 int num_arguments);
831
ager@chromium.org9085a012009-05-11 19:22:57 +0000832 // Tail call of a runtime routine (jump).
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000833 // Like JumpToExternalReference, but also takes care of passing the number
834 // of parameters.
835 void TailCallExternalReference(const ExternalReference& ext,
836 int num_arguments,
837 int result_size);
838
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000839 MUST_USE_RESULT MaybeObject* TryTailCallExternalReference(
840 const ExternalReference& ext, int num_arguments, int result_size);
841
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000842 // Convenience function: tail call a runtime routine (jump).
843 void TailCallRuntime(Runtime::FunctionId fid,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000844 int num_arguments,
845 int result_size);
ager@chromium.org9085a012009-05-11 19:22:57 +0000846
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000847 MUST_USE_RESULT MaybeObject* TryTailCallRuntime(Runtime::FunctionId fid,
848 int num_arguments,
849 int result_size);
850
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000851 // Jump to a runtime routine.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000852 void JumpToExternalReference(const ExternalReference& ext, int result_size);
ager@chromium.org9085a012009-05-11 19:22:57 +0000853
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000854 // Jump to a runtime routine.
855 MaybeObject* TryJumpToExternalReference(const ExternalReference& ext,
856 int result_size);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000857
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000858 // Prepares stack to put arguments (aligns and so on).
859 // WIN64 calling convention requires to put the pointer to the return value
860 // slot into rcx (rcx must be preserverd until TryCallApiFunctionAndReturn).
861 // Saves context (rsi). Clobbers rax. Allocates arg_stack_space * kPointerSize
862 // inside the exit frame (not GCed) accessible via StackSpaceOperand.
863 void PrepareCallApiFunction(int arg_stack_space);
864
865 // Calls an API function. Allocates HandleScope, extracts
866 // returned value from handle and propagates exceptions.
867 // Clobbers r12, r14, rbx and caller-save registers. Restores context.
868 // On return removes stack_space * kPointerSize (GCed).
869 MUST_USE_RESULT MaybeObject* TryCallApiFunctionAndReturn(
870 ApiFunction* function, int stack_space);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000871
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000872 // Before calling a C-function from generated code, align arguments on stack.
873 // After aligning the frame, arguments must be stored in esp[0], esp[4],
874 // etc., not pushed. The argument count assumes all arguments are word sized.
875 // The number of slots reserved for arguments depends on platform. On Windows
876 // stack slots are reserved for the arguments passed in registers. On other
877 // platforms stack slots are only reserved for the arguments actually passed
878 // on the stack.
879 void PrepareCallCFunction(int num_arguments);
880
881 // Calls a C function and cleans up the space for arguments allocated
882 // by PrepareCallCFunction. The called function is not allowed to trigger a
883 // garbage collection, since that might move the code and invalidate the
884 // return address (unless this is somehow accounted for by the called
885 // function).
886 void CallCFunction(ExternalReference function, int num_arguments);
887 void CallCFunction(Register function, int num_arguments);
888
889 // Calculate the number of stack slots to reserve for arguments when calling a
890 // C function.
891 int ArgumentStackSlotsForCFunctionCall(int num_arguments);
ager@chromium.org9085a012009-05-11 19:22:57 +0000892
893 // ---------------------------------------------------------------------------
894 // Utilities
895
896 void Ret();
897
ager@chromium.org9085a012009-05-11 19:22:57 +0000898 Handle<Object> CodeObject() { return code_object_; }
899
900
901 // ---------------------------------------------------------------------------
902 // StatsCounter support
903
904 void SetCounter(StatsCounter* counter, int value);
905 void IncrementCounter(StatsCounter* counter, int value);
906 void DecrementCounter(StatsCounter* counter, int value);
907
908
909 // ---------------------------------------------------------------------------
910 // Debugging
911
912 // Calls Abort(msg) if the condition cc is not satisfied.
913 // Use --debug_code to enable.
914 void Assert(Condition cc, const char* msg);
915
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000916 void AssertFastElements(Register elements);
917
ager@chromium.org9085a012009-05-11 19:22:57 +0000918 // Like Assert(), but always enabled.
919 void Check(Condition cc, const char* msg);
920
921 // Print a message to stdout and abort execution.
922 void Abort(const char* msg);
923
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000924 // Check that the stack is aligned.
925 void CheckStackAlignment();
926
ager@chromium.org9085a012009-05-11 19:22:57 +0000927 // Verify restrictions about code generated in stubs.
928 void set_generating_stub(bool value) { generating_stub_ = value; }
929 bool generating_stub() { return generating_stub_; }
930 void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
931 bool allow_stub_calls() { return allow_stub_calls_; }
932
933 private:
ager@chromium.org9085a012009-05-11 19:22:57 +0000934 bool generating_stub_;
935 bool allow_stub_calls_;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000936
937 // Returns a register holding the smi value. The register MUST NOT be
938 // modified. It may be the "smi 1 constant" register.
939 Register GetSmiConstant(Smi* value);
940
941 // Moves the smi value to the destination register.
942 void LoadSmiConstant(Register dst, Smi* value);
943
ager@chromium.org5c838252010-02-19 08:53:10 +0000944 // This handle will be patched with the code object on installation.
945 Handle<Object> code_object_;
ager@chromium.org9085a012009-05-11 19:22:57 +0000946
947 // Helper functions for generating invokes.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000948 template <typename LabelType>
ager@chromium.org9085a012009-05-11 19:22:57 +0000949 void InvokePrologue(const ParameterCount& expected,
950 const ParameterCount& actual,
951 Handle<Code> code_constant,
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000952 Register code_register,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000953 LabelType* done,
ager@chromium.org9085a012009-05-11 19:22:57 +0000954 InvokeFlag flag);
955
ager@chromium.org9085a012009-05-11 19:22:57 +0000956 // Activation support.
957 void EnterFrame(StackFrame::Type type);
958 void LeaveFrame(StackFrame::Type type);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000959
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000960 void EnterExitFramePrologue(bool save_rax);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000961
962 // Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack
963 // accessible via StackSpaceOperand.
964 void EnterExitFrameEpilogue(int arg_stack_space);
965
966 void LeaveExitFrameEpilogue();
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000967
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000968 // Allocation support helpers.
ager@chromium.orgac091b72010-05-05 07:34:42 +0000969 // Loads the top of new-space into the result register.
ager@chromium.orgac091b72010-05-05 07:34:42 +0000970 // Otherwise the address of the new-space top is loaded into scratch (if
971 // scratch is valid), and the new-space top is loaded into result.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000972 void LoadAllocationTopHelper(Register result,
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000973 Register scratch,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000974 AllocationFlags flags);
ager@chromium.orgac091b72010-05-05 07:34:42 +0000975 // Update allocation top with value in result_end register.
976 // If scratch is valid, it contains the address of the allocation top.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000977 void UpdateAllocationTopHelper(Register result_end, Register scratch);
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000978
979 // Helper for PopHandleScope. Allowed to perform a GC and returns
980 // NULL if gc_allowed. Does not perform a GC if !gc_allowed, and
981 // possibly returns a failure object indicating an allocation failure.
982 Object* PopHandleScopeHelper(Register saved,
983 Register scratch,
984 bool gc_allowed);
ager@chromium.org9085a012009-05-11 19:22:57 +0000985};
986
987
ager@chromium.org4af710e2009-09-15 12:20:11 +0000988// The code patcher is used to patch (typically) small parts of code e.g. for
989// debugging and other types of instrumentation. When using the code patcher
990// the exact number of bytes specified must be emitted. Is not legal to emit
991// relocation information. If any of these constraints are violated it causes
992// an assertion.
993class CodePatcher {
994 public:
995 CodePatcher(byte* address, int size);
996 virtual ~CodePatcher();
997
998 // Macro assembler to emit code.
999 MacroAssembler* masm() { return &masm_; }
1000
1001 private:
1002 byte* address_; // The address of the code being patched.
1003 int size_; // Number of bytes of the expected patch size.
1004 MacroAssembler masm_; // Macro assembler used to generate the code.
1005};
1006
1007
ager@chromium.org9085a012009-05-11 19:22:57 +00001008// -----------------------------------------------------------------------------
1009// Static helper functions.
1010
1011// Generate an Operand for loading a field from an object.
1012static inline Operand FieldOperand(Register object, int offset) {
1013 return Operand(object, offset - kHeapObjectTag);
1014}
1015
1016
1017// Generate an Operand for loading an indexed field from an object.
1018static inline Operand FieldOperand(Register object,
1019 Register index,
1020 ScaleFactor scale,
1021 int offset) {
1022 return Operand(object, index, scale, offset - kHeapObjectTag);
1023}
1024
1025
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001026static inline Operand ContextOperand(Register context, int index) {
1027 return Operand(context, Context::SlotOffset(index));
1028}
1029
1030
1031static inline Operand GlobalObjectOperand() {
1032 return ContextOperand(rsi, Context::GLOBAL_INDEX);
1033}
1034
1035
1036// Provides access to exit frame stack space (not GCed).
1037static inline Operand StackSpaceOperand(int index) {
1038#ifdef _WIN64
1039 const int kShaddowSpace = 4;
1040 return Operand(rsp, (index + kShaddowSpace) * kPointerSize);
1041#else
1042 return Operand(rsp, index * kPointerSize);
1043#endif
1044}
1045
1046
1047
ager@chromium.org9085a012009-05-11 19:22:57 +00001048#ifdef GENERATED_CODE_COVERAGE
1049extern void LogGeneratedCodeCoverage(const char* file_line);
1050#define CODE_COVERAGE_STRINGIFY(x) #x
1051#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
1052#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
1053#define ACCESS_MASM(masm) { \
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001054 byte* x64_coverage_function = \
ager@chromium.org9085a012009-05-11 19:22:57 +00001055 reinterpret_cast<byte*>(FUNCTION_ADDR(LogGeneratedCodeCoverage)); \
1056 masm->pushfd(); \
1057 masm->pushad(); \
1058 masm->push(Immediate(reinterpret_cast<int>(&__FILE_LINE__))); \
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001059 masm->call(x64_coverage_function, RelocInfo::RUNTIME_ENTRY); \
ager@chromium.org9085a012009-05-11 19:22:57 +00001060 masm->pop(rax); \
1061 masm->popad(); \
1062 masm->popfd(); \
1063 } \
1064 masm->
1065#else
1066#define ACCESS_MASM(masm) masm->
1067#endif
1068
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001069// -----------------------------------------------------------------------------
1070// Template implementations.
1071
1072static int kSmiShift = kSmiTagSize + kSmiShiftSize;
1073
1074
1075template <typename LabelType>
1076void MacroAssembler::SmiNeg(Register dst,
1077 Register src,
1078 LabelType* on_smi_result) {
1079 if (dst.is(src)) {
1080 ASSERT(!dst.is(kScratchRegister));
1081 movq(kScratchRegister, src);
1082 neg(dst); // Low 32 bits are retained as zero by negation.
1083 // Test if result is zero or Smi::kMinValue.
1084 cmpq(dst, kScratchRegister);
1085 j(not_equal, on_smi_result);
1086 movq(src, kScratchRegister);
1087 } else {
1088 movq(dst, src);
1089 neg(dst);
1090 cmpq(dst, src);
1091 // If the result is zero or Smi::kMinValue, negation failed to create a smi.
1092 j(not_equal, on_smi_result);
1093 }
1094}
1095
1096
1097template <typename LabelType>
1098void MacroAssembler::SmiAdd(Register dst,
1099 Register src1,
1100 Register src2,
1101 LabelType* on_not_smi_result) {
1102 ASSERT_NOT_NULL(on_not_smi_result);
1103 ASSERT(!dst.is(src2));
1104 if (dst.is(src1)) {
1105 movq(kScratchRegister, src1);
1106 addq(kScratchRegister, src2);
1107 j(overflow, on_not_smi_result);
1108 movq(dst, kScratchRegister);
1109 } else {
1110 movq(dst, src1);
1111 addq(dst, src2);
1112 j(overflow, on_not_smi_result);
1113 }
1114}
1115
1116
1117template <typename LabelType>
1118void MacroAssembler::SmiSub(Register dst,
1119 Register src1,
1120 Register src2,
1121 LabelType* on_not_smi_result) {
1122 ASSERT_NOT_NULL(on_not_smi_result);
1123 ASSERT(!dst.is(src2));
1124 if (dst.is(src1)) {
1125 cmpq(dst, src2);
1126 j(overflow, on_not_smi_result);
1127 subq(dst, src2);
1128 } else {
1129 movq(dst, src1);
1130 subq(dst, src2);
1131 j(overflow, on_not_smi_result);
1132 }
1133}
1134
1135
1136template <typename LabelType>
1137void MacroAssembler::SmiSub(Register dst,
1138 Register src1,
1139 const Operand& src2,
1140 LabelType* on_not_smi_result) {
1141 ASSERT_NOT_NULL(on_not_smi_result);
1142 if (dst.is(src1)) {
1143 movq(kScratchRegister, src2);
1144 cmpq(src1, kScratchRegister);
1145 j(overflow, on_not_smi_result);
1146 subq(src1, kScratchRegister);
1147 } else {
1148 movq(dst, src1);
1149 subq(dst, src2);
1150 j(overflow, on_not_smi_result);
1151 }
1152}
1153
1154
1155template <typename LabelType>
1156void MacroAssembler::SmiMul(Register dst,
1157 Register src1,
1158 Register src2,
1159 LabelType* on_not_smi_result) {
1160 ASSERT(!dst.is(src2));
1161 ASSERT(!dst.is(kScratchRegister));
1162 ASSERT(!src1.is(kScratchRegister));
1163 ASSERT(!src2.is(kScratchRegister));
1164
1165 if (dst.is(src1)) {
1166 NearLabel failure, zero_correct_result;
1167 movq(kScratchRegister, src1); // Create backup for later testing.
1168 SmiToInteger64(dst, src1);
1169 imul(dst, src2);
1170 j(overflow, &failure);
1171
1172 // Check for negative zero result. If product is zero, and one
1173 // argument is negative, go to slow case.
1174 NearLabel correct_result;
1175 testq(dst, dst);
1176 j(not_zero, &correct_result);
1177
1178 movq(dst, kScratchRegister);
1179 xor_(dst, src2);
1180 j(positive, &zero_correct_result); // Result was positive zero.
1181
1182 bind(&failure); // Reused failure exit, restores src1.
1183 movq(src1, kScratchRegister);
1184 jmp(on_not_smi_result);
1185
1186 bind(&zero_correct_result);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001187 Set(dst, 0);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001188
1189 bind(&correct_result);
1190 } else {
1191 SmiToInteger64(dst, src1);
1192 imul(dst, src2);
1193 j(overflow, on_not_smi_result);
1194 // Check for negative zero result. If product is zero, and one
1195 // argument is negative, go to slow case.
1196 NearLabel correct_result;
1197 testq(dst, dst);
1198 j(not_zero, &correct_result);
1199 // One of src1 and src2 is zero, the check whether the other is
1200 // negative.
1201 movq(kScratchRegister, src1);
1202 xor_(kScratchRegister, src2);
1203 j(negative, on_not_smi_result);
1204 bind(&correct_result);
1205 }
1206}
1207
1208
1209template <typename LabelType>
1210void MacroAssembler::SmiTryAddConstant(Register dst,
1211 Register src,
1212 Smi* constant,
1213 LabelType* on_not_smi_result) {
1214 // Does not assume that src is a smi.
1215 ASSERT_EQ(static_cast<int>(1), static_cast<int>(kSmiTagMask));
1216 ASSERT_EQ(0, kSmiTag);
1217 ASSERT(!dst.is(kScratchRegister));
1218 ASSERT(!src.is(kScratchRegister));
1219
1220 JumpIfNotSmi(src, on_not_smi_result);
1221 Register tmp = (dst.is(src) ? kScratchRegister : dst);
1222 LoadSmiConstant(tmp, constant);
1223 addq(tmp, src);
1224 j(overflow, on_not_smi_result);
1225 if (dst.is(src)) {
1226 movq(dst, tmp);
1227 }
1228}
1229
1230
1231template <typename LabelType>
1232void MacroAssembler::SmiAddConstant(Register dst,
1233 Register src,
1234 Smi* constant,
1235 LabelType* on_not_smi_result) {
1236 if (constant->value() == 0) {
1237 if (!dst.is(src)) {
1238 movq(dst, src);
1239 }
1240 } else if (dst.is(src)) {
1241 ASSERT(!dst.is(kScratchRegister));
1242
1243 LoadSmiConstant(kScratchRegister, constant);
1244 addq(kScratchRegister, src);
1245 j(overflow, on_not_smi_result);
1246 movq(dst, kScratchRegister);
1247 } else {
1248 LoadSmiConstant(dst, constant);
1249 addq(dst, src);
1250 j(overflow, on_not_smi_result);
1251 }
1252}
1253
1254
1255template <typename LabelType>
1256void MacroAssembler::SmiSubConstant(Register dst,
1257 Register src,
1258 Smi* constant,
1259 LabelType* on_not_smi_result) {
1260 if (constant->value() == 0) {
1261 if (!dst.is(src)) {
1262 movq(dst, src);
1263 }
1264 } else if (dst.is(src)) {
1265 ASSERT(!dst.is(kScratchRegister));
1266 if (constant->value() == Smi::kMinValue) {
1267 // Subtracting min-value from any non-negative value will overflow.
1268 // We test the non-negativeness before doing the subtraction.
1269 testq(src, src);
1270 j(not_sign, on_not_smi_result);
1271 LoadSmiConstant(kScratchRegister, constant);
1272 subq(dst, kScratchRegister);
1273 } else {
1274 // Subtract by adding the negation.
1275 LoadSmiConstant(kScratchRegister, Smi::FromInt(-constant->value()));
1276 addq(kScratchRegister, dst);
1277 j(overflow, on_not_smi_result);
1278 movq(dst, kScratchRegister);
1279 }
1280 } else {
1281 if (constant->value() == Smi::kMinValue) {
1282 // Subtracting min-value from any non-negative value will overflow.
1283 // We test the non-negativeness before doing the subtraction.
1284 testq(src, src);
1285 j(not_sign, on_not_smi_result);
1286 LoadSmiConstant(dst, constant);
1287 // Adding and subtracting the min-value gives the same result, it only
1288 // differs on the overflow bit, which we don't check here.
1289 addq(dst, src);
1290 } else {
1291 // Subtract by adding the negation.
1292 LoadSmiConstant(dst, Smi::FromInt(-(constant->value())));
1293 addq(dst, src);
1294 j(overflow, on_not_smi_result);
1295 }
1296 }
1297}
1298
1299
1300template <typename LabelType>
1301void MacroAssembler::SmiDiv(Register dst,
1302 Register src1,
1303 Register src2,
1304 LabelType* on_not_smi_result) {
1305 ASSERT(!src1.is(kScratchRegister));
1306 ASSERT(!src2.is(kScratchRegister));
1307 ASSERT(!dst.is(kScratchRegister));
1308 ASSERT(!src2.is(rax));
1309 ASSERT(!src2.is(rdx));
1310 ASSERT(!src1.is(rdx));
1311
1312 // Check for 0 divisor (result is +/-Infinity).
1313 NearLabel positive_divisor;
1314 testq(src2, src2);
1315 j(zero, on_not_smi_result);
1316
1317 if (src1.is(rax)) {
1318 movq(kScratchRegister, src1);
1319 }
1320 SmiToInteger32(rax, src1);
1321 // We need to rule out dividing Smi::kMinValue by -1, since that would
1322 // overflow in idiv and raise an exception.
1323 // We combine this with negative zero test (negative zero only happens
1324 // when dividing zero by a negative number).
1325
1326 // We overshoot a little and go to slow case if we divide min-value
1327 // by any negative value, not just -1.
1328 NearLabel safe_div;
1329 testl(rax, Immediate(0x7fffffff));
1330 j(not_zero, &safe_div);
1331 testq(src2, src2);
1332 if (src1.is(rax)) {
1333 j(positive, &safe_div);
1334 movq(src1, kScratchRegister);
1335 jmp(on_not_smi_result);
1336 } else {
1337 j(negative, on_not_smi_result);
1338 }
1339 bind(&safe_div);
1340
1341 SmiToInteger32(src2, src2);
1342 // Sign extend src1 into edx:eax.
1343 cdq();
1344 idivl(src2);
1345 Integer32ToSmi(src2, src2);
1346 // Check that the remainder is zero.
1347 testl(rdx, rdx);
1348 if (src1.is(rax)) {
1349 NearLabel smi_result;
1350 j(zero, &smi_result);
1351 movq(src1, kScratchRegister);
1352 jmp(on_not_smi_result);
1353 bind(&smi_result);
1354 } else {
1355 j(not_zero, on_not_smi_result);
1356 }
1357 if (!dst.is(src1) && src1.is(rax)) {
1358 movq(src1, kScratchRegister);
1359 }
1360 Integer32ToSmi(dst, rax);
1361}
1362
1363
1364template <typename LabelType>
1365void MacroAssembler::SmiMod(Register dst,
1366 Register src1,
1367 Register src2,
1368 LabelType* on_not_smi_result) {
1369 ASSERT(!dst.is(kScratchRegister));
1370 ASSERT(!src1.is(kScratchRegister));
1371 ASSERT(!src2.is(kScratchRegister));
1372 ASSERT(!src2.is(rax));
1373 ASSERT(!src2.is(rdx));
1374 ASSERT(!src1.is(rdx));
1375 ASSERT(!src1.is(src2));
1376
1377 testq(src2, src2);
1378 j(zero, on_not_smi_result);
1379
1380 if (src1.is(rax)) {
1381 movq(kScratchRegister, src1);
1382 }
1383 SmiToInteger32(rax, src1);
1384 SmiToInteger32(src2, src2);
1385
1386 // Test for the edge case of dividing Smi::kMinValue by -1 (will overflow).
1387 NearLabel safe_div;
1388 cmpl(rax, Immediate(Smi::kMinValue));
1389 j(not_equal, &safe_div);
1390 cmpl(src2, Immediate(-1));
1391 j(not_equal, &safe_div);
1392 // Retag inputs and go slow case.
1393 Integer32ToSmi(src2, src2);
1394 if (src1.is(rax)) {
1395 movq(src1, kScratchRegister);
1396 }
1397 jmp(on_not_smi_result);
1398 bind(&safe_div);
1399
1400 // Sign extend eax into edx:eax.
1401 cdq();
1402 idivl(src2);
1403 // Restore smi tags on inputs.
1404 Integer32ToSmi(src2, src2);
1405 if (src1.is(rax)) {
1406 movq(src1, kScratchRegister);
1407 }
1408 // Check for a negative zero result. If the result is zero, and the
1409 // dividend is negative, go slow to return a floating point negative zero.
1410 NearLabel smi_result;
1411 testl(rdx, rdx);
1412 j(not_zero, &smi_result);
1413 testq(src1, src1);
1414 j(negative, on_not_smi_result);
1415 bind(&smi_result);
1416 Integer32ToSmi(dst, rdx);
1417}
1418
1419
1420template <typename LabelType>
1421void MacroAssembler::SmiShiftLogicalRightConstant(
1422 Register dst, Register src, int shift_value, LabelType* on_not_smi_result) {
1423 // Logic right shift interprets its result as an *unsigned* number.
1424 if (dst.is(src)) {
1425 UNIMPLEMENTED(); // Not used.
1426 } else {
1427 movq(dst, src);
1428 if (shift_value == 0) {
1429 testq(dst, dst);
1430 j(negative, on_not_smi_result);
1431 }
1432 shr(dst, Immediate(shift_value + kSmiShift));
1433 shl(dst, Immediate(kSmiShift));
1434 }
1435}
1436
1437
1438template <typename LabelType>
1439void MacroAssembler::SmiShiftLogicalRight(Register dst,
1440 Register src1,
1441 Register src2,
1442 LabelType* on_not_smi_result) {
1443 ASSERT(!dst.is(kScratchRegister));
1444 ASSERT(!src1.is(kScratchRegister));
1445 ASSERT(!src2.is(kScratchRegister));
1446 ASSERT(!dst.is(rcx));
1447 NearLabel result_ok;
1448 if (src1.is(rcx) || src2.is(rcx)) {
1449 movq(kScratchRegister, rcx);
1450 }
1451 if (!dst.is(src1)) {
1452 movq(dst, src1);
1453 }
1454 SmiToInteger32(rcx, src2);
1455 orl(rcx, Immediate(kSmiShift));
1456 shr_cl(dst); // Shift is rcx modulo 0x1f + 32.
1457 shl(dst, Immediate(kSmiShift));
1458 testq(dst, dst);
1459 if (src1.is(rcx) || src2.is(rcx)) {
1460 NearLabel positive_result;
1461 j(positive, &positive_result);
1462 if (src1.is(rcx)) {
1463 movq(src1, kScratchRegister);
1464 } else {
1465 movq(src2, kScratchRegister);
1466 }
1467 jmp(on_not_smi_result);
1468 bind(&positive_result);
1469 } else {
1470 j(negative, on_not_smi_result); // src2 was zero and src1 negative.
1471 }
1472}
1473
1474
1475template <typename LabelType>
1476void MacroAssembler::SelectNonSmi(Register dst,
1477 Register src1,
1478 Register src2,
1479 LabelType* on_not_smis) {
1480 ASSERT(!dst.is(kScratchRegister));
1481 ASSERT(!src1.is(kScratchRegister));
1482 ASSERT(!src2.is(kScratchRegister));
1483 ASSERT(!dst.is(src1));
1484 ASSERT(!dst.is(src2));
1485 // Both operands must not be smis.
1486#ifdef DEBUG
1487 if (allow_stub_calls()) { // Check contains a stub call.
1488 Condition not_both_smis = NegateCondition(CheckBothSmi(src1, src2));
1489 Check(not_both_smis, "Both registers were smis in SelectNonSmi.");
1490 }
1491#endif
1492 ASSERT_EQ(0, kSmiTag);
1493 ASSERT_EQ(0, Smi::FromInt(0));
1494 movl(kScratchRegister, Immediate(kSmiTagMask));
1495 and_(kScratchRegister, src1);
1496 testl(kScratchRegister, src2);
1497 // If non-zero then both are smis.
1498 j(not_zero, on_not_smis);
1499
1500 // Exactly one operand is a smi.
1501 ASSERT_EQ(1, static_cast<int>(kSmiTagMask));
1502 // kScratchRegister still holds src1 & kSmiTag, which is either zero or one.
1503 subq(kScratchRegister, Immediate(1));
1504 // If src1 is a smi, then scratch register all 1s, else it is all 0s.
1505 movq(dst, src1);
1506 xor_(dst, src2);
1507 and_(dst, kScratchRegister);
1508 // If src1 is a smi, dst holds src1 ^ src2, else it is zero.
1509 xor_(dst, src1);
1510 // If src1 is a smi, dst is src2, else it is src1, i.e., the non-smi.
1511}
1512
1513
1514template <typename LabelType>
1515void MacroAssembler::JumpIfSmi(Register src, LabelType* on_smi) {
1516 ASSERT_EQ(0, kSmiTag);
1517 Condition smi = CheckSmi(src);
1518 j(smi, on_smi);
1519}
1520
1521
1522template <typename LabelType>
1523void MacroAssembler::JumpIfNotSmi(Register src, LabelType* on_not_smi) {
1524 Condition smi = CheckSmi(src);
1525 j(NegateCondition(smi), on_not_smi);
1526}
1527
1528
1529template <typename LabelType>
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00001530void MacroAssembler::JumpUnlessNonNegativeSmi(
1531 Register src, LabelType* on_not_smi_or_negative) {
1532 Condition non_negative_smi = CheckNonNegativeSmi(src);
1533 j(NegateCondition(non_negative_smi), on_not_smi_or_negative);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001534}
1535
1536
1537template <typename LabelType>
1538void MacroAssembler::JumpIfSmiEqualsConstant(Register src,
1539 Smi* constant,
1540 LabelType* on_equals) {
1541 SmiCompare(src, constant);
1542 j(equal, on_equals);
1543}
1544
1545
1546template <typename LabelType>
1547void MacroAssembler::JumpIfNotValidSmiValue(Register src,
1548 LabelType* on_invalid) {
1549 Condition is_valid = CheckInteger32ValidSmiValue(src);
1550 j(NegateCondition(is_valid), on_invalid);
1551}
1552
1553
1554template <typename LabelType>
1555void MacroAssembler::JumpIfUIntNotValidSmiValue(Register src,
1556 LabelType* on_invalid) {
1557 Condition is_valid = CheckUInteger32ValidSmiValue(src);
1558 j(NegateCondition(is_valid), on_invalid);
1559}
1560
1561
1562template <typename LabelType>
1563void MacroAssembler::JumpIfNotBothSmi(Register src1,
1564 Register src2,
1565 LabelType* on_not_both_smi) {
1566 Condition both_smi = CheckBothSmi(src1, src2);
1567 j(NegateCondition(both_smi), on_not_both_smi);
1568}
1569
1570
1571template <typename LabelType>
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00001572void MacroAssembler::JumpUnlessBothNonNegativeSmi(Register src1,
1573 Register src2,
1574 LabelType* on_not_both_smi) {
1575 Condition both_smi = CheckBothNonNegativeSmi(src1, src2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001576 j(NegateCondition(both_smi), on_not_both_smi);
1577}
1578
1579
1580template <typename LabelType>
1581void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register first_object,
1582 Register second_object,
1583 Register scratch1,
1584 Register scratch2,
1585 LabelType* on_fail) {
1586 // Check that both objects are not smis.
1587 Condition either_smi = CheckEitherSmi(first_object, second_object);
1588 j(either_smi, on_fail);
1589
1590 // Load instance type for both strings.
1591 movq(scratch1, FieldOperand(first_object, HeapObject::kMapOffset));
1592 movq(scratch2, FieldOperand(second_object, HeapObject::kMapOffset));
1593 movzxbl(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset));
1594 movzxbl(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset));
1595
1596 // Check that both are flat ascii strings.
1597 ASSERT(kNotStringTag != 0);
1598 const int kFlatAsciiStringMask =
1599 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
1600 const int kFlatAsciiStringTag = ASCII_STRING_TYPE;
1601
1602 andl(scratch1, Immediate(kFlatAsciiStringMask));
1603 andl(scratch2, Immediate(kFlatAsciiStringMask));
1604 // Interleave the bits to check both scratch1 and scratch2 in one test.
1605 ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
1606 lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
1607 cmpl(scratch1,
1608 Immediate(kFlatAsciiStringTag + (kFlatAsciiStringTag << 3)));
1609 j(not_equal, on_fail);
1610}
1611
1612
1613template <typename LabelType>
1614void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii(
1615 Register instance_type,
1616 Register scratch,
1617 LabelType *failure) {
1618 if (!scratch.is(instance_type)) {
1619 movl(scratch, instance_type);
1620 }
1621
1622 const int kFlatAsciiStringMask =
1623 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
1624
1625 andl(scratch, Immediate(kFlatAsciiStringMask));
1626 cmpl(scratch, Immediate(kStringTag | kSeqStringTag | kAsciiStringTag));
1627 j(not_equal, failure);
1628}
1629
1630
1631template <typename LabelType>
1632void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialAscii(
1633 Register first_object_instance_type,
1634 Register second_object_instance_type,
1635 Register scratch1,
1636 Register scratch2,
1637 LabelType* on_fail) {
1638 // Load instance type for both strings.
1639 movq(scratch1, first_object_instance_type);
1640 movq(scratch2, second_object_instance_type);
1641
1642 // Check that both are flat ascii strings.
1643 ASSERT(kNotStringTag != 0);
1644 const int kFlatAsciiStringMask =
1645 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
1646 const int kFlatAsciiStringTag = ASCII_STRING_TYPE;
1647
1648 andl(scratch1, Immediate(kFlatAsciiStringMask));
1649 andl(scratch2, Immediate(kFlatAsciiStringMask));
1650 // Interleave the bits to check both scratch1 and scratch2 in one test.
1651 ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
1652 lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
1653 cmpl(scratch1,
1654 Immediate(kFlatAsciiStringTag + (kFlatAsciiStringTag << 3)));
1655 j(not_equal, on_fail);
1656}
1657
1658
1659template <typename LabelType>
1660void MacroAssembler::InNewSpace(Register object,
1661 Register scratch,
1662 Condition cc,
1663 LabelType* branch) {
1664 if (Serializer::enabled()) {
1665 // Can't do arithmetic on external references if it might get serialized.
1666 // The mask isn't really an address. We load it as an external reference in
1667 // case the size of the new space is different between the snapshot maker
1668 // and the running system.
1669 if (scratch.is(object)) {
1670 movq(kScratchRegister, ExternalReference::new_space_mask());
1671 and_(scratch, kScratchRegister);
1672 } else {
1673 movq(scratch, ExternalReference::new_space_mask());
1674 and_(scratch, object);
1675 }
1676 movq(kScratchRegister, ExternalReference::new_space_start());
1677 cmpq(scratch, kScratchRegister);
1678 j(cc, branch);
1679 } else {
1680 ASSERT(is_int32(static_cast<int64_t>(Heap::NewSpaceMask())));
1681 intptr_t new_space_start =
1682 reinterpret_cast<intptr_t>(Heap::NewSpaceStart());
1683 movq(kScratchRegister, -new_space_start, RelocInfo::NONE);
1684 if (scratch.is(object)) {
1685 addq(scratch, kScratchRegister);
1686 } else {
1687 lea(scratch, Operand(object, kScratchRegister, times_1, 0));
1688 }
1689 and_(scratch, Immediate(static_cast<int32_t>(Heap::NewSpaceMask())));
1690 j(cc, branch);
1691 }
1692}
1693
1694
1695template <typename LabelType>
1696void MacroAssembler::InvokePrologue(const ParameterCount& expected,
1697 const ParameterCount& actual,
1698 Handle<Code> code_constant,
1699 Register code_register,
1700 LabelType* done,
1701 InvokeFlag flag) {
1702 bool definitely_matches = false;
1703 NearLabel invoke;
1704 if (expected.is_immediate()) {
1705 ASSERT(actual.is_immediate());
1706 if (expected.immediate() == actual.immediate()) {
1707 definitely_matches = true;
1708 } else {
1709 Set(rax, actual.immediate());
1710 if (expected.immediate() ==
1711 SharedFunctionInfo::kDontAdaptArgumentsSentinel) {
1712 // Don't worry about adapting arguments for built-ins that
1713 // don't want that done. Skip adaption code by making it look
1714 // like we have a match between expected and actual number of
1715 // arguments.
1716 definitely_matches = true;
1717 } else {
1718 Set(rbx, expected.immediate());
1719 }
1720 }
1721 } else {
1722 if (actual.is_immediate()) {
1723 // Expected is in register, actual is immediate. This is the
1724 // case when we invoke function values without going through the
1725 // IC mechanism.
1726 cmpq(expected.reg(), Immediate(actual.immediate()));
1727 j(equal, &invoke);
1728 ASSERT(expected.reg().is(rbx));
1729 Set(rax, actual.immediate());
1730 } else if (!expected.reg().is(actual.reg())) {
1731 // Both expected and actual are in (different) registers. This
1732 // is the case when we invoke functions using call and apply.
1733 cmpq(expected.reg(), actual.reg());
1734 j(equal, &invoke);
1735 ASSERT(actual.reg().is(rax));
1736 ASSERT(expected.reg().is(rbx));
1737 }
1738 }
1739
1740 if (!definitely_matches) {
1741 Handle<Code> adaptor =
1742 Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
1743 if (!code_constant.is_null()) {
1744 movq(rdx, code_constant, RelocInfo::EMBEDDED_OBJECT);
1745 addq(rdx, Immediate(Code::kHeaderSize - kHeapObjectTag));
1746 } else if (!code_register.is(rdx)) {
1747 movq(rdx, code_register);
1748 }
1749
1750 if (flag == CALL_FUNCTION) {
1751 Call(adaptor, RelocInfo::CODE_TARGET);
1752 jmp(done);
1753 } else {
1754 Jump(adaptor, RelocInfo::CODE_TARGET);
1755 }
1756 bind(&invoke);
1757 }
1758}
1759
ager@chromium.org9085a012009-05-11 19:22:57 +00001760
1761} } // namespace v8::internal
1762
1763#endif // V8_X64_MACRO_ASSEMBLER_X64_H_