blob: 4cf59c4e89cf5dcc72d396127e4bf1ddea3327ec [file] [log] [blame]
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001// Copyright 2011 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;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000061class PostCallGenerator;
ager@chromium.org9085a012009-05-11 19:22:57 +000062
ager@chromium.org4af710e2009-09-15 12:20:11 +000063struct SmiIndex {
64 SmiIndex(Register index_register, ScaleFactor scale)
65 : reg(index_register),
66 scale(scale) {}
67 Register reg;
68 ScaleFactor scale;
69};
ager@chromium.org9085a012009-05-11 19:22:57 +000070
ager@chromium.org9085a012009-05-11 19:22:57 +000071// MacroAssembler implements a collection of frequently used macros.
72class MacroAssembler: public Assembler {
73 public:
74 MacroAssembler(void* buffer, int size);
75
ager@chromium.org18ad94b2009-09-02 08:22:29 +000076 void LoadRoot(Register destination, Heap::RootListIndex index);
77 void CompareRoot(Register with, Heap::RootListIndex index);
ricow@chromium.org83aa5492011-02-07 12:42:56 +000078 void CompareRoot(const Operand& with, Heap::RootListIndex index);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000079 void PushRoot(Heap::RootListIndex index);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000080 void StoreRoot(Register source, Heap::RootListIndex index);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000081
ager@chromium.org9085a012009-05-11 19:22:57 +000082 // ---------------------------------------------------------------------------
83 // GC Support
84
ricow@chromium.org30ce4112010-05-31 10:38:25 +000085 // For page containing |object| mark region covering |addr| dirty.
86 // RecordWriteHelper only works if the object is not in new
ager@chromium.orgac091b72010-05-05 07:34:42 +000087 // space.
88 void RecordWriteHelper(Register object,
89 Register addr,
90 Register scratch);
91
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000092 // Check if object is in new space. The condition cc can be equal or
93 // not_equal. If it is equal a jump will be done if the object is on new
94 // space. The register scratch can be object itself, but it will be clobbered.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000095 template <typename LabelType>
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000096 void InNewSpace(Register object,
97 Register scratch,
98 Condition cc,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000099 LabelType* branch);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000100
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000101 // For page containing |object| mark region covering [object+offset]
102 // dirty. |object| is the object being stored into, |value| is the
103 // object being stored. If |offset| is zero, then the |scratch|
104 // register contains the array index into the elements array
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000105 // represented as an untagged 32-bit integer. All registers are
106 // clobbered by the operation. RecordWrite filters out smis so it
107 // does not update the write barrier if the value is a smi.
ager@chromium.org9085a012009-05-11 19:22:57 +0000108 void RecordWrite(Register object,
109 int offset,
110 Register value,
111 Register scratch);
112
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000113 // For page containing |object| mark region covering [address]
114 // dirty. |object| is the object being stored into, |value| is the
115 // object being stored. All registers are clobbered by the
116 // operation. RecordWrite filters out smis so it does not update
117 // the write barrier if the value is a smi.
118 void RecordWrite(Register object,
119 Register address,
120 Register value);
121
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000122 // For page containing |object| mark region covering [object+offset] dirty.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000123 // The value is known to not be a smi.
124 // object is the object being stored into, value is the object being stored.
125 // If offset is zero, then the scratch register contains the array index into
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000126 // the elements array represented as an untagged 32-bit integer.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000127 // All registers are clobbered by the operation.
128 void RecordWriteNonSmi(Register object,
129 int offset,
130 Register value,
131 Register scratch);
132
ager@chromium.org9085a012009-05-11 19:22:57 +0000133#ifdef ENABLE_DEBUGGER_SUPPORT
134 // ---------------------------------------------------------------------------
135 // Debugger Support
136
ager@chromium.org5c838252010-02-19 08:53:10 +0000137 void DebugBreak();
ager@chromium.org9085a012009-05-11 19:22:57 +0000138#endif
139
140 // ---------------------------------------------------------------------------
141 // Activation frames
142
143 void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
144 void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); }
145
146 void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); }
147 void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
148
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000149 // Enter specific kind of exit frame; either in normal or
150 // debug mode. Expects the number of arguments in register rax and
ager@chromium.orga1645e22009-09-09 19:27:10 +0000151 // sets up the number of arguments in register rdi and the pointer
152 // to the first argument in register rsi.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000153 //
154 // Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack
155 // accessible via StackSpaceOperand.
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000156 void EnterExitFrame(int arg_stack_space = 0, bool save_doubles = false);
ager@chromium.org9085a012009-05-11 19:22:57 +0000157
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000158 // Enter specific kind of exit frame. Allocates arg_stack_space * kPointerSize
159 // memory (not GCed) on the stack accessible via StackSpaceOperand.
160 void EnterApiExitFrame(int arg_stack_space);
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000161
ager@chromium.orga1645e22009-09-09 19:27:10 +0000162 // Leave the current exit frame. Expects/provides the return value in
163 // register rax:rdx (untouched) and the pointer to the first
164 // argument in register rsi.
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000165 void LeaveExitFrame(bool save_doubles = false);
ager@chromium.org9085a012009-05-11 19:22:57 +0000166
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000167 // Leave the current exit frame. Expects/provides the return value in
168 // register rax (untouched).
169 void LeaveApiExitFrame();
ager@chromium.org9085a012009-05-11 19:22:57 +0000170
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000171 // Push and pop the registers that can hold pointers.
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000172 void PushSafepointRegisters() { Pushad(); }
173 void PopSafepointRegisters() { Popad(); }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000174 // Store the value in register src in the safepoint register stack
175 // slot for register dst.
176 void StoreToSafepointRegisterSlot(Register dst, Register src);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000177 void LoadFromSafepointRegisterSlot(Register dst, Register src);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000178
ager@chromium.org9085a012009-05-11 19:22:57 +0000179 // ---------------------------------------------------------------------------
180 // JavaScript invokes
181
182 // Invoke the JavaScript function code by either calling or jumping.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000183 void InvokeCode(Register code,
ager@chromium.org9085a012009-05-11 19:22:57 +0000184 const ParameterCount& expected,
185 const ParameterCount& actual,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000186 InvokeFlag flag,
187 PostCallGenerator* post_call_generator = NULL);
ager@chromium.org9085a012009-05-11 19:22:57 +0000188
189 void InvokeCode(Handle<Code> code,
190 const ParameterCount& expected,
191 const ParameterCount& actual,
192 RelocInfo::Mode rmode,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000193 InvokeFlag flag,
194 PostCallGenerator* post_call_generator = NULL);
ager@chromium.org9085a012009-05-11 19:22:57 +0000195
196 // Invoke the JavaScript function in the given register. Changes the
197 // current context to the context in the function before invoking.
198 void InvokeFunction(Register function,
199 const ParameterCount& actual,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000200 InvokeFlag flag,
201 PostCallGenerator* post_call_generator = NULL);
ager@chromium.org9085a012009-05-11 19:22:57 +0000202
ager@chromium.org5c838252010-02-19 08:53:10 +0000203 void InvokeFunction(JSFunction* function,
204 const ParameterCount& actual,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000205 InvokeFlag flag,
206 PostCallGenerator* post_call_generator = NULL);
ager@chromium.org5c838252010-02-19 08:53:10 +0000207
ager@chromium.org9085a012009-05-11 19:22:57 +0000208 // Invoke specified builtin JavaScript function. Adds an entry to
209 // the unresolved list if the name does not resolve.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000210 void InvokeBuiltin(Builtins::JavaScript id,
211 InvokeFlag flag,
212 PostCallGenerator* post_call_generator = NULL);
ager@chromium.org9085a012009-05-11 19:22:57 +0000213
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000214 // Store the function for the given builtin in the target register.
215 void GetBuiltinFunction(Register target, Builtins::JavaScript id);
216
ager@chromium.org9085a012009-05-11 19:22:57 +0000217 // Store the code object for the given builtin in the target register.
218 void GetBuiltinEntry(Register target, Builtins::JavaScript id);
219
ager@chromium.org4af710e2009-09-15 12:20:11 +0000220
221 // ---------------------------------------------------------------------------
222 // Smi tagging, untagging and operations on tagged smis.
223
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000224 void InitializeSmiConstantRegister() {
225 movq(kSmiConstantRegister,
226 reinterpret_cast<uint64_t>(Smi::FromInt(kSmiConstantRegisterValue)),
227 RelocInfo::NONE);
228 }
229
ager@chromium.org4af710e2009-09-15 12:20:11 +0000230 // Conversions between tagged smi values and non-tagged integer values.
231
232 // Tag an integer value. The result must be known to be a valid smi value.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000233 // Only uses the low 32 bits of the src register. Sets the N and Z flags
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000234 // based on the value of the resulting smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000235 void Integer32ToSmi(Register dst, Register src);
236
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000237 // Stores an integer32 value into a memory field that already holds a smi.
238 void Integer32ToSmiField(const Operand& dst, Register src);
239
ager@chromium.org4af710e2009-09-15 12:20:11 +0000240 // Adds constant to src and tags the result as a smi.
241 // Result must be a valid smi.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000242 void Integer64PlusConstantToSmi(Register dst, Register src, int constant);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000243
244 // Convert smi to 32-bit integer. I.e., not sign extended into
245 // high 32 bits of destination.
246 void SmiToInteger32(Register dst, Register src);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000247 void SmiToInteger32(Register dst, const Operand& src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000248
249 // Convert smi to 64-bit integer (sign extended if necessary).
250 void SmiToInteger64(Register dst, Register src);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000251 void SmiToInteger64(Register dst, const Operand& src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000252
253 // Multiply a positive smi's integer value by a power of two.
254 // Provides result as 64-bit integer value.
255 void PositiveSmiTimesPowerOfTwoToInteger64(Register dst,
256 Register src,
257 int power);
258
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000259 // Divide a positive smi's integer value by a power of two.
260 // Provides result as 32-bit integer value.
261 void PositiveSmiDivPowerOfTwoToInteger32(Register dst,
262 Register src,
263 int power);
264
265
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000266 // Simple comparison of smis.
267 void SmiCompare(Register dst, Register src);
268 void SmiCompare(Register dst, Smi* src);
ager@chromium.orgac091b72010-05-05 07:34:42 +0000269 void SmiCompare(Register dst, const Operand& src);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000270 void SmiCompare(const Operand& dst, Register src);
271 void SmiCompare(const Operand& dst, Smi* src);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000272 // Compare the int32 in src register to the value of the smi stored at dst.
273 void SmiCompareInteger32(const Operand& dst, Register src);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000274 // Sets sign and zero flags depending on value of smi in register.
275 void SmiTest(Register src);
276
ager@chromium.org4af710e2009-09-15 12:20:11 +0000277 // Functions performing a check on a known or potential smi. Returns
278 // a condition that is satisfied if the check is successful.
279
280 // Is the value a tagged smi.
281 Condition CheckSmi(Register src);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000282 Condition CheckSmi(const Operand& src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000283
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000284 // Is the value a non-negative tagged smi.
285 Condition CheckNonNegativeSmi(Register src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000286
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000287 // Are both values tagged smis.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000288 Condition CheckBothSmi(Register first, Register second);
289
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000290 // Are both values non-negative tagged smis.
291 Condition CheckBothNonNegativeSmi(Register first, Register second);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000292
293 // Are either value a tagged smi.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000294 Condition CheckEitherSmi(Register first,
295 Register second,
296 Register scratch = kScratchRegister);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000297
ager@chromium.org4af710e2009-09-15 12:20:11 +0000298 // Is the value the minimum smi value (since we are using
299 // two's complement numbers, negating the value is known to yield
300 // a non-smi value).
301 Condition CheckIsMinSmi(Register src);
302
ager@chromium.org4af710e2009-09-15 12:20:11 +0000303 // Checks whether an 32-bit integer value is a valid for conversion
304 // to a smi.
305 Condition CheckInteger32ValidSmiValue(Register src);
306
ager@chromium.org3811b432009-10-28 14:53:37 +0000307 // Checks whether an 32-bit unsigned integer value is a valid for
308 // conversion to a smi.
309 Condition CheckUInteger32ValidSmiValue(Register src);
310
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000311 // Check whether src is a Smi, and set dst to zero if it is a smi,
312 // and to one if it isn't.
313 void CheckSmiToIndicator(Register dst, Register src);
314 void CheckSmiToIndicator(Register dst, const Operand& src);
315
ager@chromium.org4af710e2009-09-15 12:20:11 +0000316 // Test-and-jump functions. Typically combines a check function
317 // above with a conditional jump.
318
319 // Jump if the value cannot be represented by a smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000320 template <typename LabelType>
321 void JumpIfNotValidSmiValue(Register src, LabelType* on_invalid);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000322
ager@chromium.org3811b432009-10-28 14:53:37 +0000323 // Jump if the unsigned integer value cannot be represented by a smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000324 template <typename LabelType>
325 void JumpIfUIntNotValidSmiValue(Register src, LabelType* on_invalid);
ager@chromium.org3811b432009-10-28 14:53:37 +0000326
ager@chromium.org4af710e2009-09-15 12:20:11 +0000327 // Jump to label if the value is a tagged smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000328 template <typename LabelType>
329 void JumpIfSmi(Register src, LabelType* on_smi);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000330
331 // Jump to label if the value is not a tagged smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000332 template <typename LabelType>
333 void JumpIfNotSmi(Register src, LabelType* on_not_smi);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000334
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000335 // Jump to label if the value is not a non-negative tagged smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000336 template <typename LabelType>
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000337 void JumpUnlessNonNegativeSmi(Register src, LabelType* on_not_smi);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000338
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000339 // Jump to label if the value, which must be a tagged smi, has value equal
ager@chromium.org4af710e2009-09-15 12:20:11 +0000340 // to the constant.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000341 template <typename LabelType>
342 void JumpIfSmiEqualsConstant(Register src,
343 Smi* constant,
344 LabelType* on_equals);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000345
ager@chromium.org4af710e2009-09-15 12:20:11 +0000346 // Jump if either or both register are not smi values.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000347 template <typename LabelType>
348 void JumpIfNotBothSmi(Register src1,
349 Register src2,
350 LabelType* on_not_both_smi);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000351
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000352 // Jump if either or both register are not non-negative smi values.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000353 template <typename LabelType>
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000354 void JumpUnlessBothNonNegativeSmi(Register src1, Register src2,
355 LabelType* on_not_both_smi);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000356
ager@chromium.org4af710e2009-09-15 12:20:11 +0000357 // Operations on tagged smi values.
358
359 // Smis represent a subset of integers. The subset is always equivalent to
360 // a two's complement interpretation of a fixed number of bits.
361
362 // Optimistically adds an integer constant to a supposed smi.
363 // If the src is not a smi, or the result is not a smi, jump to
364 // the label.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000365 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000366 void SmiTryAddConstant(Register dst,
367 Register src,
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000368 Smi* constant,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000369 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000370
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000371 // Add an integer constant to a tagged smi, giving a tagged smi as result.
372 // No overflow testing on the result is done.
373 void SmiAddConstant(Register dst, Register src, Smi* constant);
374
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000375 // Add an integer constant to a tagged smi, giving a tagged smi as result.
376 // No overflow testing on the result is done.
377 void SmiAddConstant(const Operand& dst, Smi* constant);
378
ager@chromium.org4af710e2009-09-15 12:20:11 +0000379 // Add an integer constant to a tagged smi, giving a tagged smi as result,
380 // or jumping to a label if the result cannot be represented by a smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000381 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000382 void SmiAddConstant(Register dst,
383 Register src,
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000384 Smi* constant,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000385 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000386
387 // Subtract an integer constant from a tagged smi, giving a tagged smi as
ager@chromium.orgac091b72010-05-05 07:34:42 +0000388 // result. No testing on the result is done. Sets the N and Z flags
389 // based on the value of the resulting integer.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000390 void SmiSubConstant(Register dst, Register src, Smi* constant);
391
392 // Subtract an integer constant from a tagged smi, giving a tagged smi as
ager@chromium.org4af710e2009-09-15 12:20:11 +0000393 // result, or jumping to a label if the result cannot be represented by a smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000394 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000395 void SmiSubConstant(Register dst,
396 Register src,
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000397 Smi* constant,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000398 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000399
400 // Negating a smi can give a negative zero or too large positive value.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000401 // NOTICE: This operation jumps on success, not failure!
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000402 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000403 void SmiNeg(Register dst,
404 Register src,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000405 LabelType* on_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000406
407 // Adds smi values and return the result as a smi.
408 // If dst is src1, then src1 will be destroyed, even if
409 // the operation is unsuccessful.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000410 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000411 void SmiAdd(Register dst,
412 Register src1,
413 Register src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000414 LabelType* on_not_smi_result);
415
416 void SmiAdd(Register dst,
417 Register src1,
418 Register src2);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000419
420 // Subtracts smi values and return the result as a smi.
421 // If dst is src1, then src1 will be destroyed, even if
422 // the operation is unsuccessful.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000423 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000424 void SmiSub(Register dst,
425 Register src1,
426 Register src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000427 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000428
ager@chromium.orgac091b72010-05-05 07:34:42 +0000429 void SmiSub(Register dst,
430 Register src1,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000431 Register src2);
432
433 template <typename LabelType>
434 void SmiSub(Register dst,
435 Register src1,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000436 const Operand& src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000437 LabelType* on_not_smi_result);
438
439 void SmiSub(Register dst,
440 Register src1,
441 const Operand& src2);
ager@chromium.orgac091b72010-05-05 07:34:42 +0000442
ager@chromium.org4af710e2009-09-15 12:20:11 +0000443 // Multiplies smi values and return the result as a smi,
444 // if possible.
445 // If dst is src1, then src1 will be destroyed, even if
446 // the operation is unsuccessful.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000447 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000448 void SmiMul(Register dst,
449 Register src1,
450 Register src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000451 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000452
453 // Divides one smi by another and returns the quotient.
454 // Clobbers rax and rdx registers.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000455 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000456 void SmiDiv(Register dst,
457 Register src1,
458 Register src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000459 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000460
461 // Divides one smi by another and returns the remainder.
462 // Clobbers rax and rdx registers.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000463 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000464 void SmiMod(Register dst,
465 Register src1,
466 Register src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000467 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000468
469 // Bitwise operations.
470 void SmiNot(Register dst, Register src);
471 void SmiAnd(Register dst, Register src1, Register src2);
472 void SmiOr(Register dst, Register src1, Register src2);
473 void SmiXor(Register dst, Register src1, Register src2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000474 void SmiAndConstant(Register dst, Register src1, Smi* constant);
475 void SmiOrConstant(Register dst, Register src1, Smi* constant);
476 void SmiXorConstant(Register dst, Register src1, Smi* constant);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000477
478 void SmiShiftLeftConstant(Register dst,
479 Register src,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000480 int shift_value);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000481 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000482 void SmiShiftLogicalRightConstant(Register dst,
483 Register src,
484 int shift_value,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000485 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000486 void SmiShiftArithmeticRightConstant(Register dst,
487 Register src,
488 int shift_value);
489
490 // Shifts a smi value to the left, and returns the result if that is a smi.
491 // Uses and clobbers rcx, so dst may not be rcx.
492 void SmiShiftLeft(Register dst,
493 Register src1,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000494 Register src2);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000495 // Shifts a smi value to the right, shifting in zero bits at the top, and
496 // returns the unsigned intepretation of the result if that is a smi.
497 // Uses and clobbers rcx, so dst may not be rcx.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000498 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000499 void SmiShiftLogicalRight(Register dst,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000500 Register src1,
501 Register src2,
502 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000503 // Shifts a smi value to the right, sign extending the top, and
504 // returns the signed intepretation of the result. That will always
505 // be a valid smi value, since it's numerically smaller than the
506 // original.
507 // Uses and clobbers rcx, so dst may not be rcx.
508 void SmiShiftArithmeticRight(Register dst,
509 Register src1,
510 Register src2);
511
512 // Specialized operations
513
514 // Select the non-smi register of two registers where exactly one is a
515 // smi. If neither are smis, jump to the failure label.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000516 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000517 void SelectNonSmi(Register dst,
518 Register src1,
519 Register src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000520 LabelType* on_not_smis);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000521
522 // Converts, if necessary, a smi to a combination of number and
523 // multiplier to be used as a scaled index.
524 // The src register contains a *positive* smi value. The shift is the
525 // power of two to multiply the index value by (e.g.
526 // to index by smi-value * kPointerSize, pass the smi and kPointerSizeLog2).
527 // The returned index register may be either src or dst, depending
528 // on what is most efficient. If src and dst are different registers,
529 // src is always unchanged.
530 SmiIndex SmiToIndex(Register dst, Register src, int shift);
531
532 // Converts a positive smi to a negative index.
533 SmiIndex SmiToNegativeIndex(Register dst, Register src, int shift);
534
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000535 // Basic Smi operations.
ager@chromium.org3811b432009-10-28 14:53:37 +0000536 void Move(Register dst, Smi* source) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000537 LoadSmiConstant(dst, source);
ager@chromium.org3811b432009-10-28 14:53:37 +0000538 }
539
540 void Move(const Operand& dst, Smi* source) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000541 Register constant = GetSmiConstant(source);
542 movq(dst, constant);
ager@chromium.org3811b432009-10-28 14:53:37 +0000543 }
544
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000545 void Push(Smi* smi);
546 void Test(const Operand& dst, Smi* source);
547
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000548 // ---------------------------------------------------------------------------
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000549 // String macros.
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000550
551 // If object is a string, its map is loaded into object_map.
552 template <typename LabelType>
553 void JumpIfNotString(Register object,
554 Register object_map,
555 LabelType* not_string);
556
557
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000558 template <typename LabelType>
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000559 void JumpIfNotBothSequentialAsciiStrings(Register first_object,
560 Register second_object,
561 Register scratch1,
562 Register scratch2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000563 LabelType* on_not_both_flat_ascii);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000564
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000565 // Check whether the instance type represents a flat ascii string. Jump to the
566 // label if not. If the instance type can be scratched specify same register
567 // for both instance type and scratch.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000568 template <typename LabelType>
569 void JumpIfInstanceTypeIsNotSequentialAscii(
570 Register instance_type,
571 Register scratch,
572 LabelType *on_not_flat_ascii_string);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000573
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000574 template <typename LabelType>
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000575 void JumpIfBothInstanceTypesAreNotSequentialAscii(
576 Register first_object_instance_type,
577 Register second_object_instance_type,
578 Register scratch1,
579 Register scratch2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000580 LabelType* on_fail);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000581
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000582 // ---------------------------------------------------------------------------
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000583 // Macro instructions.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000584
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000585 // Load a register with a long value as efficiently as possible.
ager@chromium.orge2902be2009-06-08 12:21:35 +0000586 void Set(Register dst, int64_t x);
587 void Set(const Operand& dst, int64_t x);
ager@chromium.org9085a012009-05-11 19:22:57 +0000588
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000589 // Move if the registers are not identical.
590 void Move(Register target, Register source);
591
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000592 // Handle support
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000593 void Move(Register dst, Handle<Object> source);
594 void Move(const Operand& dst, Handle<Object> source);
595 void Cmp(Register dst, Handle<Object> source);
ager@chromium.org3e875802009-06-29 08:26:34 +0000596 void Cmp(const Operand& dst, Handle<Object> source);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000597 void Push(Handle<Object> source);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000598
599 // Emit code to discard a non-negative number of pointer-sized elements
600 // from the stack, clobbering only the rsp register.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000601 void Drop(int stack_elements);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000602
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000603 void Call(Label* target) { call(target); }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000604
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000605 // Control Flow
606 void Jump(Address destination, RelocInfo::Mode rmode);
607 void Jump(ExternalReference ext);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000608 void Jump(Handle<Code> code_object, RelocInfo::Mode rmode);
609
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000610 void Call(Address destination, RelocInfo::Mode rmode);
611 void Call(ExternalReference ext);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000612 void Call(Handle<Code> code_object, RelocInfo::Mode rmode);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000613
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000614 // Emit call to the code we are currently generating.
615 void CallSelf() {
616 Handle<Code> self(reinterpret_cast<Code**>(CodeObject().location()));
617 Call(self, RelocInfo::CODE_TARGET);
618 }
619
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000620 // Non-x64 instructions.
621 // Push/pop all general purpose registers.
622 // Does not push rsp/rbp nor any of the assembler's special purpose registers
623 // (kScratchRegister, kSmiConstantRegister, kRootRegister).
624 void Pushad();
625 void Popad();
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000626 // Sets the stack as after performing Popad, without actually loading the
627 // registers.
628 void Dropad();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000629
ager@chromium.org9085a012009-05-11 19:22:57 +0000630 // Compare object type for heap object.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000631 // Always use unsigned comparisons: above and below, not less and greater.
ager@chromium.org9085a012009-05-11 19:22:57 +0000632 // Incoming register is heap_object and outgoing register is map.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000633 // They may be the same register, and may be kScratchRegister.
ager@chromium.org9085a012009-05-11 19:22:57 +0000634 void CmpObjectType(Register heap_object, InstanceType type, Register map);
635
636 // Compare instance type for map.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000637 // Always use unsigned comparisons: above and below, not less and greater.
ager@chromium.org9085a012009-05-11 19:22:57 +0000638 void CmpInstanceType(Register map, InstanceType type);
639
ager@chromium.org5c838252010-02-19 08:53:10 +0000640 // Check if the map of an object is equal to a specified map and
641 // branch to label if not. Skip the smi check if not required
642 // (object is known to be a heap object)
643 void CheckMap(Register obj,
644 Handle<Map> map,
645 Label* fail,
646 bool is_heap_object);
647
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000648 // Check if the object in register heap_object is a string. Afterwards the
649 // register map contains the object map and the register instance_type
650 // contains the instance_type. The registers map and instance_type can be the
651 // same in which case it contains the instance type afterwards. Either of the
652 // registers map and instance_type can be the same as heap_object.
653 Condition IsObjectStringType(Register heap_object,
654 Register map,
655 Register instance_type);
656
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000657 // FCmp compares and pops the two values on top of the FPU stack.
658 // The flag results are similar to integer cmp, but requires unsigned
ager@chromium.org9085a012009-05-11 19:22:57 +0000659 // jcc instructions (je, ja, jae, jb, jbe, je, and jz).
660 void FCmp();
661
ager@chromium.org5c838252010-02-19 08:53:10 +0000662 // Abort execution if argument is not a number. Used in debug code.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000663 void AbortIfNotNumber(Register object);
ager@chromium.org5c838252010-02-19 08:53:10 +0000664
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000665 // Abort execution if argument is a smi. Used in debug code.
666 void AbortIfSmi(Register object);
667
lrn@chromium.org25156de2010-04-06 13:10:27 +0000668 // Abort execution if argument is not a smi. Used in debug code.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000669 void AbortIfNotSmi(Register object);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000670
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000671 // Abort execution if argument is a string. Used in debug code.
672 void AbortIfNotString(Register object);
673
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000674 // Abort execution if argument is not the root value with the given index.
675 void AbortIfNotRootValue(Register src,
676 Heap::RootListIndex root_value_index,
677 const char* message);
678
ager@chromium.org9085a012009-05-11 19:22:57 +0000679 // ---------------------------------------------------------------------------
680 // Exception handling
681
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000682 // Push a new try handler and link into try handler chain. The return
683 // address must be pushed before calling this helper.
ager@chromium.org9085a012009-05-11 19:22:57 +0000684 void PushTryHandler(CodeLocation try_location, HandlerType type);
685
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000686 // Unlink the stack handler on top of the stack from the try handler chain.
687 void PopTryHandler();
ager@chromium.org9085a012009-05-11 19:22:57 +0000688
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000689 // Activate the top handler in the try hander chain and pass the
690 // thrown value.
691 void Throw(Register value);
692
693 // Propagate an uncatchable exception out of the current JS stack.
694 void ThrowUncatchable(UncatchableExceptionType type, Register value);
695
ager@chromium.org9085a012009-05-11 19:22:57 +0000696 // ---------------------------------------------------------------------------
697 // Inline caching support
698
ager@chromium.org9085a012009-05-11 19:22:57 +0000699 // Generate code for checking access rights - used for security checks
700 // on access to global objects across environments. The holder register
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000701 // is left untouched, but the scratch register and kScratchRegister,
702 // which must be different, are clobbered.
ager@chromium.org9085a012009-05-11 19:22:57 +0000703 void CheckAccessGlobalProxy(Register holder_reg,
704 Register scratch,
705 Label* miss);
706
707
708 // ---------------------------------------------------------------------------
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000709 // Allocation support
710
711 // Allocate an object in new space. If the new space is exhausted control
712 // continues at the gc_required label. The allocated object is returned in
713 // result and end of the new object is returned in result_end. The register
714 // scratch can be passed as no_reg in which case an additional object
715 // reference will be added to the reloc info. The returned pointers in result
716 // and result_end have not yet been tagged as heap objects. If
717 // result_contains_top_on_entry is true the content of result is known to be
718 // the allocation top on entry (could be result_end from a previous call to
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000719 // AllocateInNewSpace). If result_contains_top_on_entry is true scratch
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000720 // should be no_reg as it is never used.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000721 void AllocateInNewSpace(int object_size,
722 Register result,
723 Register result_end,
724 Register scratch,
725 Label* gc_required,
726 AllocationFlags flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000727
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000728 void AllocateInNewSpace(int header_size,
729 ScaleFactor element_size,
730 Register element_count,
731 Register result,
732 Register result_end,
733 Register scratch,
734 Label* gc_required,
735 AllocationFlags flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000736
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000737 void AllocateInNewSpace(Register object_size,
738 Register result,
739 Register result_end,
740 Register scratch,
741 Label* gc_required,
742 AllocationFlags flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000743
744 // Undo allocation in new space. The object passed and objects allocated after
745 // it will no longer be allocated. Make sure that no pointers are left to the
746 // object(s) no longer allocated as they would be invalid when allocation is
747 // un-done.
748 void UndoAllocationInNewSpace(Register object);
749
ager@chromium.org3811b432009-10-28 14:53:37 +0000750 // Allocate a heap number in new space with undefined value. Returns
751 // tagged pointer in result register, or jumps to gc_required if new
752 // space is full.
753 void AllocateHeapNumber(Register result,
754 Register scratch,
755 Label* gc_required);
756
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000757 // Allocate a sequential string. All the header fields of the string object
758 // are initialized.
759 void AllocateTwoByteString(Register result,
760 Register length,
761 Register scratch1,
762 Register scratch2,
763 Register scratch3,
764 Label* gc_required);
765 void AllocateAsciiString(Register result,
766 Register length,
767 Register scratch1,
768 Register scratch2,
769 Register scratch3,
770 Label* gc_required);
771
772 // Allocate a raw cons string object. Only the map field of the result is
773 // initialized.
774 void AllocateConsString(Register result,
775 Register scratch1,
776 Register scratch2,
777 Label* gc_required);
778 void AllocateAsciiConsString(Register result,
779 Register scratch1,
780 Register scratch2,
781 Label* gc_required);
782
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000783 // ---------------------------------------------------------------------------
ager@chromium.org9085a012009-05-11 19:22:57 +0000784 // Support functions.
785
786 // Check if result is zero and op is negative.
787 void NegativeZeroTest(Register result, Register op, Label* then_label);
788
789 // Check if result is zero and op is negative in code using jump targets.
790 void NegativeZeroTest(CodeGenerator* cgen,
791 Register result,
792 Register op,
793 JumpTarget* then_target);
794
795 // Check if result is zero and any of op1 and op2 are negative.
796 // Register scratch is destroyed, and it must be different from op2.
797 void NegativeZeroTest(Register result, Register op1, Register op2,
798 Register scratch, Label* then_label);
799
800 // Try to get function prototype of a function and puts the value in
801 // the result register. Checks that the function really is a
802 // function and jumps to the miss label if the fast checks fail. The
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000803 // function register will be untouched; the other register may be
ager@chromium.org9085a012009-05-11 19:22:57 +0000804 // clobbered.
805 void TryGetFunctionPrototype(Register function,
806 Register result,
ager@chromium.org9085a012009-05-11 19:22:57 +0000807 Label* miss);
808
809 // Generates code for reporting that an illegal operation has
810 // occurred.
811 void IllegalOperation(int num_arguments);
812
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000813 // Picks out an array index from the hash field.
814 // Register use:
815 // hash - holds the index's hash. Clobbered.
816 // index - holds the overwritten index on exit.
817 void IndexFromHash(Register hash, Register index);
818
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000819 // Find the function context up the context chain.
820 void LoadContext(Register dst, int context_chain_length);
821
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000822 // Load the global function with the given index.
823 void LoadGlobalFunction(int index, Register function);
824
825 // Load the initial map from the global function. The registers
826 // function and map can be the same.
827 void LoadGlobalFunctionInitialMap(Register function, Register map);
828
ager@chromium.org9085a012009-05-11 19:22:57 +0000829 // ---------------------------------------------------------------------------
830 // Runtime calls
831
832 // Call a code stub.
833 void CallStub(CodeStub* stub);
834
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000835 // Call a code stub and return the code object called. Try to generate
836 // the code if necessary. Do not perform a GC but instead return a retry
837 // after GC failure.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000838 MUST_USE_RESULT MaybeObject* TryCallStub(CodeStub* stub);
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000839
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000840 // Tail call a code stub (jump).
841 void TailCallStub(CodeStub* stub);
842
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000843 // Tail call a code stub (jump) and return the code object called. Try to
844 // generate the code if necessary. Do not perform a GC but instead return
845 // a retry after GC failure.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000846 MUST_USE_RESULT MaybeObject* TryTailCallStub(CodeStub* stub);
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000847
ager@chromium.org9085a012009-05-11 19:22:57 +0000848 // Return from a code stub after popping its arguments.
849 void StubReturn(int argc);
850
851 // Call a runtime routine.
ager@chromium.org9085a012009-05-11 19:22:57 +0000852 void CallRuntime(Runtime::Function* f, int num_arguments);
853
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000854 // Call a runtime function and save the value of XMM registers.
855 void CallRuntimeSaveDoubles(Runtime::FunctionId id);
856
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000857 // Call a runtime function, returning the CodeStub object called.
858 // Try to generate the stub code if necessary. Do not perform a GC
859 // but instead return a retry after GC failure.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000860 MUST_USE_RESULT MaybeObject* TryCallRuntime(Runtime::Function* f,
861 int num_arguments);
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000862
ager@chromium.org9085a012009-05-11 19:22:57 +0000863 // Convenience function: Same as above, but takes the fid instead.
864 void CallRuntime(Runtime::FunctionId id, int num_arguments);
865
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000866 // Convenience function: Same as above, but takes the fid instead.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000867 MUST_USE_RESULT MaybeObject* TryCallRuntime(Runtime::FunctionId id,
868 int num_arguments);
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000869
ager@chromium.org5c838252010-02-19 08:53:10 +0000870 // Convenience function: call an external reference.
871 void CallExternalReference(const ExternalReference& ext,
872 int num_arguments);
873
ager@chromium.org9085a012009-05-11 19:22:57 +0000874 // Tail call of a runtime routine (jump).
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000875 // Like JumpToExternalReference, but also takes care of passing the number
876 // of parameters.
877 void TailCallExternalReference(const ExternalReference& ext,
878 int num_arguments,
879 int result_size);
880
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000881 MUST_USE_RESULT MaybeObject* TryTailCallExternalReference(
882 const ExternalReference& ext, int num_arguments, int result_size);
883
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000884 // Convenience function: tail call a runtime routine (jump).
885 void TailCallRuntime(Runtime::FunctionId fid,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000886 int num_arguments,
887 int result_size);
ager@chromium.org9085a012009-05-11 19:22:57 +0000888
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000889 MUST_USE_RESULT MaybeObject* TryTailCallRuntime(Runtime::FunctionId fid,
890 int num_arguments,
891 int result_size);
892
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000893 // Jump to a runtime routine.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000894 void JumpToExternalReference(const ExternalReference& ext, int result_size);
ager@chromium.org9085a012009-05-11 19:22:57 +0000895
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000896 // Jump to a runtime routine.
897 MaybeObject* TryJumpToExternalReference(const ExternalReference& ext,
898 int result_size);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000899
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000900 // Prepares stack to put arguments (aligns and so on).
901 // WIN64 calling convention requires to put the pointer to the return value
902 // slot into rcx (rcx must be preserverd until TryCallApiFunctionAndReturn).
903 // Saves context (rsi). Clobbers rax. Allocates arg_stack_space * kPointerSize
904 // inside the exit frame (not GCed) accessible via StackSpaceOperand.
905 void PrepareCallApiFunction(int arg_stack_space);
906
907 // Calls an API function. Allocates HandleScope, extracts
908 // returned value from handle and propagates exceptions.
909 // Clobbers r12, r14, rbx and caller-save registers. Restores context.
910 // On return removes stack_space * kPointerSize (GCed).
911 MUST_USE_RESULT MaybeObject* TryCallApiFunctionAndReturn(
912 ApiFunction* function, int stack_space);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000913
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000914 // Before calling a C-function from generated code, align arguments on stack.
915 // After aligning the frame, arguments must be stored in esp[0], esp[4],
916 // etc., not pushed. The argument count assumes all arguments are word sized.
917 // The number of slots reserved for arguments depends on platform. On Windows
918 // stack slots are reserved for the arguments passed in registers. On other
919 // platforms stack slots are only reserved for the arguments actually passed
920 // on the stack.
921 void PrepareCallCFunction(int num_arguments);
922
923 // Calls a C function and cleans up the space for arguments allocated
924 // by PrepareCallCFunction. The called function is not allowed to trigger a
925 // garbage collection, since that might move the code and invalidate the
926 // return address (unless this is somehow accounted for by the called
927 // function).
928 void CallCFunction(ExternalReference function, int num_arguments);
929 void CallCFunction(Register function, int num_arguments);
930
931 // Calculate the number of stack slots to reserve for arguments when calling a
932 // C function.
933 int ArgumentStackSlotsForCFunctionCall(int num_arguments);
ager@chromium.org9085a012009-05-11 19:22:57 +0000934
935 // ---------------------------------------------------------------------------
936 // Utilities
937
938 void Ret();
939
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000940 // Return and drop arguments from stack, where the number of arguments
941 // may be bigger than 2^16 - 1. Requires a scratch register.
942 void Ret(int bytes_dropped, Register scratch);
943
ager@chromium.org9085a012009-05-11 19:22:57 +0000944 Handle<Object> CodeObject() { return code_object_; }
945
946
947 // ---------------------------------------------------------------------------
948 // StatsCounter support
949
950 void SetCounter(StatsCounter* counter, int value);
951 void IncrementCounter(StatsCounter* counter, int value);
952 void DecrementCounter(StatsCounter* counter, int value);
953
954
955 // ---------------------------------------------------------------------------
956 // Debugging
957
958 // Calls Abort(msg) if the condition cc is not satisfied.
959 // Use --debug_code to enable.
960 void Assert(Condition cc, const char* msg);
961
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000962 void AssertFastElements(Register elements);
963
ager@chromium.org9085a012009-05-11 19:22:57 +0000964 // Like Assert(), but always enabled.
965 void Check(Condition cc, const char* msg);
966
967 // Print a message to stdout and abort execution.
968 void Abort(const char* msg);
969
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000970 // Check that the stack is aligned.
971 void CheckStackAlignment();
972
ager@chromium.org9085a012009-05-11 19:22:57 +0000973 // Verify restrictions about code generated in stubs.
974 void set_generating_stub(bool value) { generating_stub_ = value; }
975 bool generating_stub() { return generating_stub_; }
976 void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
977 bool allow_stub_calls() { return allow_stub_calls_; }
978
979 private:
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000980 // Order general registers are pushed by Pushad.
981 // rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r12, r14.
982 static int kSafepointPushRegisterIndices[Register::kNumRegisters];
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000983 static const int kNumSafepointSavedRegisters = 11;
984
ager@chromium.org9085a012009-05-11 19:22:57 +0000985 bool generating_stub_;
986 bool allow_stub_calls_;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000987
988 // Returns a register holding the smi value. The register MUST NOT be
989 // modified. It may be the "smi 1 constant" register.
990 Register GetSmiConstant(Smi* value);
991
992 // Moves the smi value to the destination register.
993 void LoadSmiConstant(Register dst, Smi* value);
994
ager@chromium.org5c838252010-02-19 08:53:10 +0000995 // This handle will be patched with the code object on installation.
996 Handle<Object> code_object_;
ager@chromium.org9085a012009-05-11 19:22:57 +0000997
998 // Helper functions for generating invokes.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000999 template <typename LabelType>
ager@chromium.org9085a012009-05-11 19:22:57 +00001000 void InvokePrologue(const ParameterCount& expected,
1001 const ParameterCount& actual,
1002 Handle<Code> code_constant,
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001003 Register code_register,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001004 LabelType* done,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001005 InvokeFlag flag,
1006 PostCallGenerator* post_call_generator);
ager@chromium.org9085a012009-05-11 19:22:57 +00001007
ager@chromium.org9085a012009-05-11 19:22:57 +00001008 // Activation support.
1009 void EnterFrame(StackFrame::Type type);
1010 void LeaveFrame(StackFrame::Type type);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001011
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001012 void EnterExitFramePrologue(bool save_rax);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001013
1014 // Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack
1015 // accessible via StackSpaceOperand.
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001016 void EnterExitFrameEpilogue(int arg_stack_space, bool save_doubles);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001017
1018 void LeaveExitFrameEpilogue();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001019
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001020 // Allocation support helpers.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001021 // Loads the top of new-space into the result register.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001022 // Otherwise the address of the new-space top is loaded into scratch (if
1023 // scratch is valid), and the new-space top is loaded into result.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001024 void LoadAllocationTopHelper(Register result,
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001025 Register scratch,
ager@chromium.orga1645e22009-09-09 19:27:10 +00001026 AllocationFlags flags);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001027 // Update allocation top with value in result_end register.
1028 // If scratch is valid, it contains the address of the allocation top.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001029 void UpdateAllocationTopHelper(Register result_end, Register scratch);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001030
1031 // Helper for PopHandleScope. Allowed to perform a GC and returns
1032 // NULL if gc_allowed. Does not perform a GC if !gc_allowed, and
1033 // possibly returns a failure object indicating an allocation failure.
1034 Object* PopHandleScopeHelper(Register saved,
1035 Register scratch,
1036 bool gc_allowed);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001037
1038
1039 // Compute memory operands for safepoint stack slots.
1040 Operand SafepointRegisterSlot(Register reg);
1041 static int SafepointRegisterStackIndex(int reg_code) {
1042 return kNumSafepointRegisters - kSafepointPushRegisterIndices[reg_code] - 1;
1043 }
1044
1045 // Needs access to SafepointRegisterStackIndex for optimized frame
1046 // traversal.
1047 friend class OptimizedFrame;
ager@chromium.org9085a012009-05-11 19:22:57 +00001048};
1049
1050
ager@chromium.org4af710e2009-09-15 12:20:11 +00001051// The code patcher is used to patch (typically) small parts of code e.g. for
1052// debugging and other types of instrumentation. When using the code patcher
1053// the exact number of bytes specified must be emitted. Is not legal to emit
1054// relocation information. If any of these constraints are violated it causes
1055// an assertion.
1056class CodePatcher {
1057 public:
1058 CodePatcher(byte* address, int size);
1059 virtual ~CodePatcher();
1060
1061 // Macro assembler to emit code.
1062 MacroAssembler* masm() { return &masm_; }
1063
1064 private:
1065 byte* address_; // The address of the code being patched.
1066 int size_; // Number of bytes of the expected patch size.
1067 MacroAssembler masm_; // Macro assembler used to generate the code.
1068};
1069
1070
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001071// Helper class for generating code or data associated with the code
1072// right after a call instruction. As an example this can be used to
1073// generate safepoint data after calls for crankshaft.
1074class PostCallGenerator {
1075 public:
1076 PostCallGenerator() { }
1077 virtual ~PostCallGenerator() { }
1078 virtual void Generate() = 0;
1079};
1080
1081
ager@chromium.org9085a012009-05-11 19:22:57 +00001082// -----------------------------------------------------------------------------
1083// Static helper functions.
1084
1085// Generate an Operand for loading a field from an object.
1086static inline Operand FieldOperand(Register object, int offset) {
1087 return Operand(object, offset - kHeapObjectTag);
1088}
1089
1090
1091// Generate an Operand for loading an indexed field from an object.
1092static inline Operand FieldOperand(Register object,
1093 Register index,
1094 ScaleFactor scale,
1095 int offset) {
1096 return Operand(object, index, scale, offset - kHeapObjectTag);
1097}
1098
1099
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001100static inline Operand ContextOperand(Register context, int index) {
1101 return Operand(context, Context::SlotOffset(index));
1102}
1103
1104
1105static inline Operand GlobalObjectOperand() {
1106 return ContextOperand(rsi, Context::GLOBAL_INDEX);
1107}
1108
1109
1110// Provides access to exit frame stack space (not GCed).
1111static inline Operand StackSpaceOperand(int index) {
1112#ifdef _WIN64
1113 const int kShaddowSpace = 4;
1114 return Operand(rsp, (index + kShaddowSpace) * kPointerSize);
1115#else
1116 return Operand(rsp, index * kPointerSize);
1117#endif
1118}
1119
1120
1121
ager@chromium.org9085a012009-05-11 19:22:57 +00001122#ifdef GENERATED_CODE_COVERAGE
1123extern void LogGeneratedCodeCoverage(const char* file_line);
1124#define CODE_COVERAGE_STRINGIFY(x) #x
1125#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
1126#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
1127#define ACCESS_MASM(masm) { \
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001128 byte* x64_coverage_function = \
ager@chromium.org9085a012009-05-11 19:22:57 +00001129 reinterpret_cast<byte*>(FUNCTION_ADDR(LogGeneratedCodeCoverage)); \
1130 masm->pushfd(); \
1131 masm->pushad(); \
1132 masm->push(Immediate(reinterpret_cast<int>(&__FILE_LINE__))); \
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001133 masm->call(x64_coverage_function, RelocInfo::RUNTIME_ENTRY); \
ager@chromium.org9085a012009-05-11 19:22:57 +00001134 masm->pop(rax); \
1135 masm->popad(); \
1136 masm->popfd(); \
1137 } \
1138 masm->
1139#else
1140#define ACCESS_MASM(masm) masm->
1141#endif
1142
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001143// -----------------------------------------------------------------------------
1144// Template implementations.
1145
1146static int kSmiShift = kSmiTagSize + kSmiShiftSize;
1147
1148
1149template <typename LabelType>
1150void MacroAssembler::SmiNeg(Register dst,
1151 Register src,
1152 LabelType* on_smi_result) {
1153 if (dst.is(src)) {
1154 ASSERT(!dst.is(kScratchRegister));
1155 movq(kScratchRegister, src);
1156 neg(dst); // Low 32 bits are retained as zero by negation.
1157 // Test if result is zero or Smi::kMinValue.
1158 cmpq(dst, kScratchRegister);
1159 j(not_equal, on_smi_result);
1160 movq(src, kScratchRegister);
1161 } else {
1162 movq(dst, src);
1163 neg(dst);
1164 cmpq(dst, src);
1165 // If the result is zero or Smi::kMinValue, negation failed to create a smi.
1166 j(not_equal, on_smi_result);
1167 }
1168}
1169
1170
1171template <typename LabelType>
1172void MacroAssembler::SmiAdd(Register dst,
1173 Register src1,
1174 Register src2,
1175 LabelType* on_not_smi_result) {
1176 ASSERT_NOT_NULL(on_not_smi_result);
1177 ASSERT(!dst.is(src2));
1178 if (dst.is(src1)) {
1179 movq(kScratchRegister, src1);
1180 addq(kScratchRegister, src2);
1181 j(overflow, on_not_smi_result);
1182 movq(dst, kScratchRegister);
1183 } else {
1184 movq(dst, src1);
1185 addq(dst, src2);
1186 j(overflow, on_not_smi_result);
1187 }
1188}
1189
1190
1191template <typename LabelType>
1192void MacroAssembler::SmiSub(Register dst,
1193 Register src1,
1194 Register src2,
1195 LabelType* on_not_smi_result) {
1196 ASSERT_NOT_NULL(on_not_smi_result);
1197 ASSERT(!dst.is(src2));
1198 if (dst.is(src1)) {
1199 cmpq(dst, src2);
1200 j(overflow, on_not_smi_result);
1201 subq(dst, src2);
1202 } else {
1203 movq(dst, src1);
1204 subq(dst, src2);
1205 j(overflow, on_not_smi_result);
1206 }
1207}
1208
1209
1210template <typename LabelType>
1211void MacroAssembler::SmiSub(Register dst,
1212 Register src1,
1213 const Operand& src2,
1214 LabelType* on_not_smi_result) {
1215 ASSERT_NOT_NULL(on_not_smi_result);
1216 if (dst.is(src1)) {
1217 movq(kScratchRegister, src2);
1218 cmpq(src1, kScratchRegister);
1219 j(overflow, on_not_smi_result);
1220 subq(src1, kScratchRegister);
1221 } else {
1222 movq(dst, src1);
1223 subq(dst, src2);
1224 j(overflow, on_not_smi_result);
1225 }
1226}
1227
1228
1229template <typename LabelType>
1230void MacroAssembler::SmiMul(Register dst,
1231 Register src1,
1232 Register src2,
1233 LabelType* on_not_smi_result) {
1234 ASSERT(!dst.is(src2));
1235 ASSERT(!dst.is(kScratchRegister));
1236 ASSERT(!src1.is(kScratchRegister));
1237 ASSERT(!src2.is(kScratchRegister));
1238
1239 if (dst.is(src1)) {
1240 NearLabel failure, zero_correct_result;
1241 movq(kScratchRegister, src1); // Create backup for later testing.
1242 SmiToInteger64(dst, src1);
1243 imul(dst, src2);
1244 j(overflow, &failure);
1245
1246 // Check for negative zero result. If product is zero, and one
1247 // argument is negative, go to slow case.
1248 NearLabel correct_result;
1249 testq(dst, dst);
1250 j(not_zero, &correct_result);
1251
1252 movq(dst, kScratchRegister);
1253 xor_(dst, src2);
1254 j(positive, &zero_correct_result); // Result was positive zero.
1255
1256 bind(&failure); // Reused failure exit, restores src1.
1257 movq(src1, kScratchRegister);
1258 jmp(on_not_smi_result);
1259
1260 bind(&zero_correct_result);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001261 Set(dst, 0);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001262
1263 bind(&correct_result);
1264 } else {
1265 SmiToInteger64(dst, src1);
1266 imul(dst, src2);
1267 j(overflow, on_not_smi_result);
1268 // Check for negative zero result. If product is zero, and one
1269 // argument is negative, go to slow case.
1270 NearLabel correct_result;
1271 testq(dst, dst);
1272 j(not_zero, &correct_result);
1273 // One of src1 and src2 is zero, the check whether the other is
1274 // negative.
1275 movq(kScratchRegister, src1);
1276 xor_(kScratchRegister, src2);
1277 j(negative, on_not_smi_result);
1278 bind(&correct_result);
1279 }
1280}
1281
1282
1283template <typename LabelType>
1284void MacroAssembler::SmiTryAddConstant(Register dst,
1285 Register src,
1286 Smi* constant,
1287 LabelType* on_not_smi_result) {
1288 // Does not assume that src is a smi.
1289 ASSERT_EQ(static_cast<int>(1), static_cast<int>(kSmiTagMask));
1290 ASSERT_EQ(0, kSmiTag);
1291 ASSERT(!dst.is(kScratchRegister));
1292 ASSERT(!src.is(kScratchRegister));
1293
1294 JumpIfNotSmi(src, on_not_smi_result);
1295 Register tmp = (dst.is(src) ? kScratchRegister : dst);
1296 LoadSmiConstant(tmp, constant);
1297 addq(tmp, src);
1298 j(overflow, on_not_smi_result);
1299 if (dst.is(src)) {
1300 movq(dst, tmp);
1301 }
1302}
1303
1304
1305template <typename LabelType>
1306void MacroAssembler::SmiAddConstant(Register dst,
1307 Register src,
1308 Smi* constant,
1309 LabelType* on_not_smi_result) {
1310 if (constant->value() == 0) {
1311 if (!dst.is(src)) {
1312 movq(dst, src);
1313 }
1314 } else if (dst.is(src)) {
1315 ASSERT(!dst.is(kScratchRegister));
1316
1317 LoadSmiConstant(kScratchRegister, constant);
1318 addq(kScratchRegister, src);
1319 j(overflow, on_not_smi_result);
1320 movq(dst, kScratchRegister);
1321 } else {
1322 LoadSmiConstant(dst, constant);
1323 addq(dst, src);
1324 j(overflow, on_not_smi_result);
1325 }
1326}
1327
1328
1329template <typename LabelType>
1330void MacroAssembler::SmiSubConstant(Register dst,
1331 Register src,
1332 Smi* constant,
1333 LabelType* on_not_smi_result) {
1334 if (constant->value() == 0) {
1335 if (!dst.is(src)) {
1336 movq(dst, src);
1337 }
1338 } else if (dst.is(src)) {
1339 ASSERT(!dst.is(kScratchRegister));
1340 if (constant->value() == Smi::kMinValue) {
1341 // Subtracting min-value from any non-negative value will overflow.
1342 // We test the non-negativeness before doing the subtraction.
1343 testq(src, src);
1344 j(not_sign, on_not_smi_result);
1345 LoadSmiConstant(kScratchRegister, constant);
1346 subq(dst, kScratchRegister);
1347 } else {
1348 // Subtract by adding the negation.
1349 LoadSmiConstant(kScratchRegister, Smi::FromInt(-constant->value()));
1350 addq(kScratchRegister, dst);
1351 j(overflow, on_not_smi_result);
1352 movq(dst, kScratchRegister);
1353 }
1354 } else {
1355 if (constant->value() == Smi::kMinValue) {
1356 // Subtracting min-value from any non-negative value will overflow.
1357 // We test the non-negativeness before doing the subtraction.
1358 testq(src, src);
1359 j(not_sign, on_not_smi_result);
1360 LoadSmiConstant(dst, constant);
1361 // Adding and subtracting the min-value gives the same result, it only
1362 // differs on the overflow bit, which we don't check here.
1363 addq(dst, src);
1364 } else {
1365 // Subtract by adding the negation.
1366 LoadSmiConstant(dst, Smi::FromInt(-(constant->value())));
1367 addq(dst, src);
1368 j(overflow, on_not_smi_result);
1369 }
1370 }
1371}
1372
1373
1374template <typename LabelType>
1375void MacroAssembler::SmiDiv(Register dst,
1376 Register src1,
1377 Register src2,
1378 LabelType* on_not_smi_result) {
1379 ASSERT(!src1.is(kScratchRegister));
1380 ASSERT(!src2.is(kScratchRegister));
1381 ASSERT(!dst.is(kScratchRegister));
1382 ASSERT(!src2.is(rax));
1383 ASSERT(!src2.is(rdx));
1384 ASSERT(!src1.is(rdx));
1385
1386 // Check for 0 divisor (result is +/-Infinity).
1387 NearLabel positive_divisor;
1388 testq(src2, src2);
1389 j(zero, on_not_smi_result);
1390
1391 if (src1.is(rax)) {
1392 movq(kScratchRegister, src1);
1393 }
1394 SmiToInteger32(rax, src1);
1395 // We need to rule out dividing Smi::kMinValue by -1, since that would
1396 // overflow in idiv and raise an exception.
1397 // We combine this with negative zero test (negative zero only happens
1398 // when dividing zero by a negative number).
1399
1400 // We overshoot a little and go to slow case if we divide min-value
1401 // by any negative value, not just -1.
1402 NearLabel safe_div;
1403 testl(rax, Immediate(0x7fffffff));
1404 j(not_zero, &safe_div);
1405 testq(src2, src2);
1406 if (src1.is(rax)) {
1407 j(positive, &safe_div);
1408 movq(src1, kScratchRegister);
1409 jmp(on_not_smi_result);
1410 } else {
1411 j(negative, on_not_smi_result);
1412 }
1413 bind(&safe_div);
1414
1415 SmiToInteger32(src2, src2);
1416 // Sign extend src1 into edx:eax.
1417 cdq();
1418 idivl(src2);
1419 Integer32ToSmi(src2, src2);
1420 // Check that the remainder is zero.
1421 testl(rdx, rdx);
1422 if (src1.is(rax)) {
1423 NearLabel smi_result;
1424 j(zero, &smi_result);
1425 movq(src1, kScratchRegister);
1426 jmp(on_not_smi_result);
1427 bind(&smi_result);
1428 } else {
1429 j(not_zero, on_not_smi_result);
1430 }
1431 if (!dst.is(src1) && src1.is(rax)) {
1432 movq(src1, kScratchRegister);
1433 }
1434 Integer32ToSmi(dst, rax);
1435}
1436
1437
1438template <typename LabelType>
1439void MacroAssembler::SmiMod(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(!src2.is(rax));
1447 ASSERT(!src2.is(rdx));
1448 ASSERT(!src1.is(rdx));
1449 ASSERT(!src1.is(src2));
1450
1451 testq(src2, src2);
1452 j(zero, on_not_smi_result);
1453
1454 if (src1.is(rax)) {
1455 movq(kScratchRegister, src1);
1456 }
1457 SmiToInteger32(rax, src1);
1458 SmiToInteger32(src2, src2);
1459
1460 // Test for the edge case of dividing Smi::kMinValue by -1 (will overflow).
1461 NearLabel safe_div;
1462 cmpl(rax, Immediate(Smi::kMinValue));
1463 j(not_equal, &safe_div);
1464 cmpl(src2, Immediate(-1));
1465 j(not_equal, &safe_div);
1466 // Retag inputs and go slow case.
1467 Integer32ToSmi(src2, src2);
1468 if (src1.is(rax)) {
1469 movq(src1, kScratchRegister);
1470 }
1471 jmp(on_not_smi_result);
1472 bind(&safe_div);
1473
1474 // Sign extend eax into edx:eax.
1475 cdq();
1476 idivl(src2);
1477 // Restore smi tags on inputs.
1478 Integer32ToSmi(src2, src2);
1479 if (src1.is(rax)) {
1480 movq(src1, kScratchRegister);
1481 }
1482 // Check for a negative zero result. If the result is zero, and the
1483 // dividend is negative, go slow to return a floating point negative zero.
1484 NearLabel smi_result;
1485 testl(rdx, rdx);
1486 j(not_zero, &smi_result);
1487 testq(src1, src1);
1488 j(negative, on_not_smi_result);
1489 bind(&smi_result);
1490 Integer32ToSmi(dst, rdx);
1491}
1492
1493
1494template <typename LabelType>
1495void MacroAssembler::SmiShiftLogicalRightConstant(
1496 Register dst, Register src, int shift_value, LabelType* on_not_smi_result) {
1497 // Logic right shift interprets its result as an *unsigned* number.
1498 if (dst.is(src)) {
1499 UNIMPLEMENTED(); // Not used.
1500 } else {
1501 movq(dst, src);
1502 if (shift_value == 0) {
1503 testq(dst, dst);
1504 j(negative, on_not_smi_result);
1505 }
1506 shr(dst, Immediate(shift_value + kSmiShift));
1507 shl(dst, Immediate(kSmiShift));
1508 }
1509}
1510
1511
1512template <typename LabelType>
1513void MacroAssembler::SmiShiftLogicalRight(Register dst,
1514 Register src1,
1515 Register src2,
1516 LabelType* on_not_smi_result) {
1517 ASSERT(!dst.is(kScratchRegister));
1518 ASSERT(!src1.is(kScratchRegister));
1519 ASSERT(!src2.is(kScratchRegister));
1520 ASSERT(!dst.is(rcx));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001521 // dst and src1 can be the same, because the one case that bails out
1522 // is a shift by 0, which leaves dst, and therefore src1, unchanged.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001523 NearLabel result_ok;
1524 if (src1.is(rcx) || src2.is(rcx)) {
1525 movq(kScratchRegister, rcx);
1526 }
1527 if (!dst.is(src1)) {
1528 movq(dst, src1);
1529 }
1530 SmiToInteger32(rcx, src2);
1531 orl(rcx, Immediate(kSmiShift));
1532 shr_cl(dst); // Shift is rcx modulo 0x1f + 32.
1533 shl(dst, Immediate(kSmiShift));
1534 testq(dst, dst);
1535 if (src1.is(rcx) || src2.is(rcx)) {
1536 NearLabel positive_result;
1537 j(positive, &positive_result);
1538 if (src1.is(rcx)) {
1539 movq(src1, kScratchRegister);
1540 } else {
1541 movq(src2, kScratchRegister);
1542 }
1543 jmp(on_not_smi_result);
1544 bind(&positive_result);
1545 } else {
1546 j(negative, on_not_smi_result); // src2 was zero and src1 negative.
1547 }
1548}
1549
1550
1551template <typename LabelType>
1552void MacroAssembler::SelectNonSmi(Register dst,
1553 Register src1,
1554 Register src2,
1555 LabelType* on_not_smis) {
1556 ASSERT(!dst.is(kScratchRegister));
1557 ASSERT(!src1.is(kScratchRegister));
1558 ASSERT(!src2.is(kScratchRegister));
1559 ASSERT(!dst.is(src1));
1560 ASSERT(!dst.is(src2));
1561 // Both operands must not be smis.
1562#ifdef DEBUG
1563 if (allow_stub_calls()) { // Check contains a stub call.
1564 Condition not_both_smis = NegateCondition(CheckBothSmi(src1, src2));
1565 Check(not_both_smis, "Both registers were smis in SelectNonSmi.");
1566 }
1567#endif
1568 ASSERT_EQ(0, kSmiTag);
1569 ASSERT_EQ(0, Smi::FromInt(0));
1570 movl(kScratchRegister, Immediate(kSmiTagMask));
1571 and_(kScratchRegister, src1);
1572 testl(kScratchRegister, src2);
1573 // If non-zero then both are smis.
1574 j(not_zero, on_not_smis);
1575
1576 // Exactly one operand is a smi.
1577 ASSERT_EQ(1, static_cast<int>(kSmiTagMask));
1578 // kScratchRegister still holds src1 & kSmiTag, which is either zero or one.
1579 subq(kScratchRegister, Immediate(1));
1580 // If src1 is a smi, then scratch register all 1s, else it is all 0s.
1581 movq(dst, src1);
1582 xor_(dst, src2);
1583 and_(dst, kScratchRegister);
1584 // If src1 is a smi, dst holds src1 ^ src2, else it is zero.
1585 xor_(dst, src1);
1586 // If src1 is a smi, dst is src2, else it is src1, i.e., the non-smi.
1587}
1588
1589
1590template <typename LabelType>
1591void MacroAssembler::JumpIfSmi(Register src, LabelType* on_smi) {
1592 ASSERT_EQ(0, kSmiTag);
1593 Condition smi = CheckSmi(src);
1594 j(smi, on_smi);
1595}
1596
1597
1598template <typename LabelType>
1599void MacroAssembler::JumpIfNotSmi(Register src, LabelType* on_not_smi) {
1600 Condition smi = CheckSmi(src);
1601 j(NegateCondition(smi), on_not_smi);
1602}
1603
1604
1605template <typename LabelType>
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00001606void MacroAssembler::JumpUnlessNonNegativeSmi(
1607 Register src, LabelType* on_not_smi_or_negative) {
1608 Condition non_negative_smi = CheckNonNegativeSmi(src);
1609 j(NegateCondition(non_negative_smi), on_not_smi_or_negative);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001610}
1611
1612
1613template <typename LabelType>
1614void MacroAssembler::JumpIfSmiEqualsConstant(Register src,
1615 Smi* constant,
1616 LabelType* on_equals) {
1617 SmiCompare(src, constant);
1618 j(equal, on_equals);
1619}
1620
1621
1622template <typename LabelType>
1623void MacroAssembler::JumpIfNotValidSmiValue(Register src,
1624 LabelType* on_invalid) {
1625 Condition is_valid = CheckInteger32ValidSmiValue(src);
1626 j(NegateCondition(is_valid), on_invalid);
1627}
1628
1629
1630template <typename LabelType>
1631void MacroAssembler::JumpIfUIntNotValidSmiValue(Register src,
1632 LabelType* on_invalid) {
1633 Condition is_valid = CheckUInteger32ValidSmiValue(src);
1634 j(NegateCondition(is_valid), on_invalid);
1635}
1636
1637
1638template <typename LabelType>
1639void MacroAssembler::JumpIfNotBothSmi(Register src1,
1640 Register src2,
1641 LabelType* on_not_both_smi) {
1642 Condition both_smi = CheckBothSmi(src1, src2);
1643 j(NegateCondition(both_smi), on_not_both_smi);
1644}
1645
1646
1647template <typename LabelType>
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00001648void MacroAssembler::JumpUnlessBothNonNegativeSmi(Register src1,
1649 Register src2,
1650 LabelType* on_not_both_smi) {
1651 Condition both_smi = CheckBothNonNegativeSmi(src1, src2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001652 j(NegateCondition(both_smi), on_not_both_smi);
1653}
1654
1655
1656template <typename LabelType>
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001657void MacroAssembler::JumpIfNotString(Register object,
1658 Register object_map,
1659 LabelType* not_string) {
1660 Condition is_smi = CheckSmi(object);
1661 j(is_smi, not_string);
1662 CmpObjectType(object, FIRST_NONSTRING_TYPE, object_map);
1663 j(above_equal, not_string);
1664}
1665
1666
1667template <typename LabelType>
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001668void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register first_object,
1669 Register second_object,
1670 Register scratch1,
1671 Register scratch2,
1672 LabelType* on_fail) {
1673 // Check that both objects are not smis.
1674 Condition either_smi = CheckEitherSmi(first_object, second_object);
1675 j(either_smi, on_fail);
1676
1677 // Load instance type for both strings.
1678 movq(scratch1, FieldOperand(first_object, HeapObject::kMapOffset));
1679 movq(scratch2, FieldOperand(second_object, HeapObject::kMapOffset));
1680 movzxbl(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset));
1681 movzxbl(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset));
1682
1683 // Check that both are flat ascii strings.
1684 ASSERT(kNotStringTag != 0);
1685 const int kFlatAsciiStringMask =
1686 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
1687 const int kFlatAsciiStringTag = ASCII_STRING_TYPE;
1688
1689 andl(scratch1, Immediate(kFlatAsciiStringMask));
1690 andl(scratch2, Immediate(kFlatAsciiStringMask));
1691 // Interleave the bits to check both scratch1 and scratch2 in one test.
1692 ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
1693 lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
1694 cmpl(scratch1,
1695 Immediate(kFlatAsciiStringTag + (kFlatAsciiStringTag << 3)));
1696 j(not_equal, on_fail);
1697}
1698
1699
1700template <typename LabelType>
1701void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii(
1702 Register instance_type,
1703 Register scratch,
1704 LabelType *failure) {
1705 if (!scratch.is(instance_type)) {
1706 movl(scratch, instance_type);
1707 }
1708
1709 const int kFlatAsciiStringMask =
1710 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
1711
1712 andl(scratch, Immediate(kFlatAsciiStringMask));
1713 cmpl(scratch, Immediate(kStringTag | kSeqStringTag | kAsciiStringTag));
1714 j(not_equal, failure);
1715}
1716
1717
1718template <typename LabelType>
1719void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialAscii(
1720 Register first_object_instance_type,
1721 Register second_object_instance_type,
1722 Register scratch1,
1723 Register scratch2,
1724 LabelType* on_fail) {
1725 // Load instance type for both strings.
1726 movq(scratch1, first_object_instance_type);
1727 movq(scratch2, second_object_instance_type);
1728
1729 // Check that both are flat ascii strings.
1730 ASSERT(kNotStringTag != 0);
1731 const int kFlatAsciiStringMask =
1732 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
1733 const int kFlatAsciiStringTag = ASCII_STRING_TYPE;
1734
1735 andl(scratch1, Immediate(kFlatAsciiStringMask));
1736 andl(scratch2, Immediate(kFlatAsciiStringMask));
1737 // Interleave the bits to check both scratch1 and scratch2 in one test.
1738 ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
1739 lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
1740 cmpl(scratch1,
1741 Immediate(kFlatAsciiStringTag + (kFlatAsciiStringTag << 3)));
1742 j(not_equal, on_fail);
1743}
1744
1745
1746template <typename LabelType>
1747void MacroAssembler::InNewSpace(Register object,
1748 Register scratch,
1749 Condition cc,
1750 LabelType* branch) {
1751 if (Serializer::enabled()) {
1752 // Can't do arithmetic on external references if it might get serialized.
1753 // The mask isn't really an address. We load it as an external reference in
1754 // case the size of the new space is different between the snapshot maker
1755 // and the running system.
1756 if (scratch.is(object)) {
1757 movq(kScratchRegister, ExternalReference::new_space_mask());
1758 and_(scratch, kScratchRegister);
1759 } else {
1760 movq(scratch, ExternalReference::new_space_mask());
1761 and_(scratch, object);
1762 }
1763 movq(kScratchRegister, ExternalReference::new_space_start());
1764 cmpq(scratch, kScratchRegister);
1765 j(cc, branch);
1766 } else {
1767 ASSERT(is_int32(static_cast<int64_t>(Heap::NewSpaceMask())));
1768 intptr_t new_space_start =
1769 reinterpret_cast<intptr_t>(Heap::NewSpaceStart());
1770 movq(kScratchRegister, -new_space_start, RelocInfo::NONE);
1771 if (scratch.is(object)) {
1772 addq(scratch, kScratchRegister);
1773 } else {
1774 lea(scratch, Operand(object, kScratchRegister, times_1, 0));
1775 }
1776 and_(scratch, Immediate(static_cast<int32_t>(Heap::NewSpaceMask())));
1777 j(cc, branch);
1778 }
1779}
1780
1781
1782template <typename LabelType>
1783void MacroAssembler::InvokePrologue(const ParameterCount& expected,
1784 const ParameterCount& actual,
1785 Handle<Code> code_constant,
1786 Register code_register,
1787 LabelType* done,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001788 InvokeFlag flag,
1789 PostCallGenerator* post_call_generator) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001790 bool definitely_matches = false;
1791 NearLabel invoke;
1792 if (expected.is_immediate()) {
1793 ASSERT(actual.is_immediate());
1794 if (expected.immediate() == actual.immediate()) {
1795 definitely_matches = true;
1796 } else {
1797 Set(rax, actual.immediate());
1798 if (expected.immediate() ==
1799 SharedFunctionInfo::kDontAdaptArgumentsSentinel) {
1800 // Don't worry about adapting arguments for built-ins that
1801 // don't want that done. Skip adaption code by making it look
1802 // like we have a match between expected and actual number of
1803 // arguments.
1804 definitely_matches = true;
1805 } else {
1806 Set(rbx, expected.immediate());
1807 }
1808 }
1809 } else {
1810 if (actual.is_immediate()) {
1811 // Expected is in register, actual is immediate. This is the
1812 // case when we invoke function values without going through the
1813 // IC mechanism.
1814 cmpq(expected.reg(), Immediate(actual.immediate()));
1815 j(equal, &invoke);
1816 ASSERT(expected.reg().is(rbx));
1817 Set(rax, actual.immediate());
1818 } else if (!expected.reg().is(actual.reg())) {
1819 // Both expected and actual are in (different) registers. This
1820 // is the case when we invoke functions using call and apply.
1821 cmpq(expected.reg(), actual.reg());
1822 j(equal, &invoke);
1823 ASSERT(actual.reg().is(rax));
1824 ASSERT(expected.reg().is(rbx));
1825 }
1826 }
1827
1828 if (!definitely_matches) {
1829 Handle<Code> adaptor =
1830 Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
1831 if (!code_constant.is_null()) {
1832 movq(rdx, code_constant, RelocInfo::EMBEDDED_OBJECT);
1833 addq(rdx, Immediate(Code::kHeaderSize - kHeapObjectTag));
1834 } else if (!code_register.is(rdx)) {
1835 movq(rdx, code_register);
1836 }
1837
1838 if (flag == CALL_FUNCTION) {
1839 Call(adaptor, RelocInfo::CODE_TARGET);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001840 if (post_call_generator != NULL) post_call_generator->Generate();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001841 jmp(done);
1842 } else {
1843 Jump(adaptor, RelocInfo::CODE_TARGET);
1844 }
1845 bind(&invoke);
1846 }
1847}
1848
ager@chromium.org9085a012009-05-11 19:22:57 +00001849
1850} } // namespace v8::internal
1851
1852#endif // V8_X64_MACRO_ASSEMBLER_X64_H_