blob: 400bdce3dcfbd2a46b26beaece26e744dcea6bf8 [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.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000051static const Register kSmiConstantRegister = { 12 }; // r12 (callee save).
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +000052static const Register kRootRegister = { 13 }; // r13 (callee save).
53// Value of smi in kSmiConstantRegister.
54static const int kSmiConstantRegisterValue = 1;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000055// Actual value of root register is offset from the root array's start
56// to take advantage of negitive 8-bit displacement values.
57static const int kRootRegisterBias = 128;
ager@chromium.orge2902be2009-06-08 12:21:35 +000058
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000059// Convenience for platform-independent signatures.
60typedef Operand MemOperand;
61
ager@chromium.org9085a012009-05-11 19:22:57 +000062// Forward declaration.
63class JumpTarget;
64
ager@chromium.org4af710e2009-09-15 12:20:11 +000065struct SmiIndex {
66 SmiIndex(Register index_register, ScaleFactor scale)
67 : reg(index_register),
68 scale(scale) {}
69 Register reg;
70 ScaleFactor scale;
71};
ager@chromium.org9085a012009-05-11 19:22:57 +000072
ager@chromium.org9085a012009-05-11 19:22:57 +000073// MacroAssembler implements a collection of frequently used macros.
74class MacroAssembler: public Assembler {
75 public:
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000076 // The isolate parameter can be NULL if the macro assembler should
77 // not use isolate-dependent functionality. In this case, it's the
78 // responsibility of the caller to never invoke such function on the
79 // macro assembler.
80 MacroAssembler(Isolate* isolate, void* buffer, int size);
ager@chromium.org9085a012009-05-11 19:22:57 +000081
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000082 // Prevent the use of the RootArray during the lifetime of this
83 // scope object.
84 class NoRootArrayScope BASE_EMBEDDED {
85 public:
86 explicit NoRootArrayScope(MacroAssembler* assembler)
87 : variable_(&assembler->root_array_available_),
88 old_value_(assembler->root_array_available_) {
89 assembler->root_array_available_ = false;
90 }
91 ~NoRootArrayScope() {
92 *variable_ = old_value_;
93 }
94 private:
95 bool* variable_;
96 bool old_value_;
97 };
98
99 // Operand pointing to an external reference.
100 // May emit code to set up the scratch register. The operand is
101 // only guaranteed to be correct as long as the scratch register
102 // isn't changed.
103 // If the operand is used more than once, use a scratch register
104 // that is guaranteed not to be clobbered.
105 Operand ExternalOperand(ExternalReference reference,
106 Register scratch = kScratchRegister);
107 // Loads and stores the value of an external reference.
108 // Special case code for load and store to take advantage of
109 // load_rax/store_rax if possible/necessary.
110 // For other operations, just use:
111 // Operand operand = ExternalOperand(extref);
112 // operation(operand, ..);
113 void Load(Register destination, ExternalReference source);
114 void Store(ExternalReference destination, Register source);
115 // Loads the address of the external reference into the destination
116 // register.
117 void LoadAddress(Register destination, ExternalReference source);
118 // Returns the size of the code generated by LoadAddress.
119 // Used by CallSize(ExternalReference) to find the size of a call.
120 int LoadAddressSize(ExternalReference source);
121
122 // Operations on roots in the root-array.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000123 void LoadRoot(Register destination, Heap::RootListIndex index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000124 void StoreRoot(Register source, Heap::RootListIndex index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000125 // Load a root value where the index (or part of it) is variable.
126 // The variable_offset register is added to the fixed_offset value
127 // to get the index into the root-array.
128 void LoadRootIndexed(Register destination,
129 Register variable_offset,
130 int fixed_offset);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000131 void CompareRoot(Register with, Heap::RootListIndex index);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000132 void CompareRoot(const Operand& with, Heap::RootListIndex index);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000133 void PushRoot(Heap::RootListIndex index);
134
ager@chromium.org9085a012009-05-11 19:22:57 +0000135 // ---------------------------------------------------------------------------
136 // GC Support
137
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000138 // For page containing |object| mark region covering |addr| dirty.
139 // RecordWriteHelper only works if the object is not in new
ager@chromium.orgac091b72010-05-05 07:34:42 +0000140 // space.
141 void RecordWriteHelper(Register object,
142 Register addr,
143 Register scratch);
144
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000145 // Check if object is in new space. The condition cc can be equal or
146 // not_equal. If it is equal a jump will be done if the object is on new
147 // space. The register scratch can be object itself, but it will be clobbered.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000148 template <typename LabelType>
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000149 void InNewSpace(Register object,
150 Register scratch,
151 Condition cc,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000152 LabelType* branch);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000153
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000154 // For page containing |object| mark region covering [object+offset]
155 // dirty. |object| is the object being stored into, |value| is the
156 // object being stored. If |offset| is zero, then the |scratch|
157 // register contains the array index into the elements array
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000158 // represented as an untagged 32-bit integer. All registers are
159 // clobbered by the operation. RecordWrite filters out smis so it
160 // does not update the write barrier if the value is a smi.
ager@chromium.org9085a012009-05-11 19:22:57 +0000161 void RecordWrite(Register object,
162 int offset,
163 Register value,
164 Register scratch);
165
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000166 // For page containing |object| mark region covering [address]
167 // dirty. |object| is the object being stored into, |value| is the
168 // object being stored. All registers are clobbered by the
169 // operation. RecordWrite filters out smis so it does not update
170 // the write barrier if the value is a smi.
171 void RecordWrite(Register object,
172 Register address,
173 Register value);
174
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000175 // For page containing |object| mark region covering [object+offset] dirty.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000176 // The value is known to not be a smi.
177 // object is the object being stored into, value is the object being stored.
178 // If offset is zero, then the scratch register contains the array index into
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000179 // the elements array represented as an untagged 32-bit integer.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000180 // All registers are clobbered by the operation.
181 void RecordWriteNonSmi(Register object,
182 int offset,
183 Register value,
184 Register scratch);
185
ager@chromium.org9085a012009-05-11 19:22:57 +0000186#ifdef ENABLE_DEBUGGER_SUPPORT
187 // ---------------------------------------------------------------------------
188 // Debugger Support
189
ager@chromium.org5c838252010-02-19 08:53:10 +0000190 void DebugBreak();
ager@chromium.org9085a012009-05-11 19:22:57 +0000191#endif
192
193 // ---------------------------------------------------------------------------
194 // Activation frames
195
196 void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
197 void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); }
198
199 void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); }
200 void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
201
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000202 // Enter specific kind of exit frame; either in normal or
203 // debug mode. Expects the number of arguments in register rax and
ager@chromium.orga1645e22009-09-09 19:27:10 +0000204 // sets up the number of arguments in register rdi and the pointer
205 // to the first argument in register rsi.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000206 //
207 // Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack
208 // accessible via StackSpaceOperand.
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000209 void EnterExitFrame(int arg_stack_space = 0, bool save_doubles = false);
ager@chromium.org9085a012009-05-11 19:22:57 +0000210
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000211 // Enter specific kind of exit frame. Allocates arg_stack_space * kPointerSize
212 // memory (not GCed) on the stack accessible via StackSpaceOperand.
213 void EnterApiExitFrame(int arg_stack_space);
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000214
ager@chromium.orga1645e22009-09-09 19:27:10 +0000215 // Leave the current exit frame. Expects/provides the return value in
216 // register rax:rdx (untouched) and the pointer to the first
217 // argument in register rsi.
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000218 void LeaveExitFrame(bool save_doubles = false);
ager@chromium.org9085a012009-05-11 19:22:57 +0000219
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000220 // Leave the current exit frame. Expects/provides the return value in
221 // register rax (untouched).
222 void LeaveApiExitFrame();
ager@chromium.org9085a012009-05-11 19:22:57 +0000223
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000224 // Push and pop the registers that can hold pointers.
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000225 void PushSafepointRegisters() { Pushad(); }
226 void PopSafepointRegisters() { Popad(); }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000227 // Store the value in register src in the safepoint register stack
228 // slot for register dst.
229 void StoreToSafepointRegisterSlot(Register dst, Register src);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000230 void LoadFromSafepointRegisterSlot(Register dst, Register src);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000231
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000232 void InitializeRootRegister() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000233 ExternalReference roots_address =
234 ExternalReference::roots_address(isolate());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000235 movq(kRootRegister, roots_address);
236 addq(kRootRegister, Immediate(kRootRegisterBias));
237 }
238
ager@chromium.org9085a012009-05-11 19:22:57 +0000239 // ---------------------------------------------------------------------------
240 // JavaScript invokes
241
242 // Invoke the JavaScript function code by either calling or jumping.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000243 void InvokeCode(Register code,
ager@chromium.org9085a012009-05-11 19:22:57 +0000244 const ParameterCount& expected,
245 const ParameterCount& actual,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000246 InvokeFlag flag,
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +0000247 const CallWrapper& call_wrapper = NullCallWrapper());
ager@chromium.org9085a012009-05-11 19:22:57 +0000248
249 void InvokeCode(Handle<Code> code,
250 const ParameterCount& expected,
251 const ParameterCount& actual,
252 RelocInfo::Mode rmode,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000253 InvokeFlag flag,
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +0000254 const CallWrapper& call_wrapper = NullCallWrapper());
ager@chromium.org9085a012009-05-11 19:22:57 +0000255
256 // Invoke the JavaScript function in the given register. Changes the
257 // current context to the context in the function before invoking.
258 void InvokeFunction(Register function,
259 const ParameterCount& actual,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000260 InvokeFlag flag,
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +0000261 const CallWrapper& call_wrapper = NullCallWrapper());
ager@chromium.org9085a012009-05-11 19:22:57 +0000262
ager@chromium.org5c838252010-02-19 08:53:10 +0000263 void InvokeFunction(JSFunction* function,
264 const ParameterCount& actual,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000265 InvokeFlag flag,
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +0000266 const CallWrapper& call_wrapper = NullCallWrapper());
ager@chromium.org5c838252010-02-19 08:53:10 +0000267
ager@chromium.org9085a012009-05-11 19:22:57 +0000268 // Invoke specified builtin JavaScript function. Adds an entry to
269 // the unresolved list if the name does not resolve.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000270 void InvokeBuiltin(Builtins::JavaScript id,
271 InvokeFlag flag,
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +0000272 const CallWrapper& call_wrapper = NullCallWrapper());
ager@chromium.org9085a012009-05-11 19:22:57 +0000273
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000274 // Store the function for the given builtin in the target register.
275 void GetBuiltinFunction(Register target, Builtins::JavaScript id);
276
ager@chromium.org9085a012009-05-11 19:22:57 +0000277 // Store the code object for the given builtin in the target register.
278 void GetBuiltinEntry(Register target, Builtins::JavaScript id);
279
ager@chromium.org4af710e2009-09-15 12:20:11 +0000280
281 // ---------------------------------------------------------------------------
282 // Smi tagging, untagging and operations on tagged smis.
283
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000284 void InitializeSmiConstantRegister() {
285 movq(kSmiConstantRegister,
286 reinterpret_cast<uint64_t>(Smi::FromInt(kSmiConstantRegisterValue)),
287 RelocInfo::NONE);
288 }
289
ager@chromium.org4af710e2009-09-15 12:20:11 +0000290 // Conversions between tagged smi values and non-tagged integer values.
291
292 // Tag an integer value. The result must be known to be a valid smi value.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000293 // Only uses the low 32 bits of the src register. Sets the N and Z flags
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000294 // based on the value of the resulting smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000295 void Integer32ToSmi(Register dst, Register src);
296
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000297 // Stores an integer32 value into a memory field that already holds a smi.
298 void Integer32ToSmiField(const Operand& dst, Register src);
299
ager@chromium.org4af710e2009-09-15 12:20:11 +0000300 // Adds constant to src and tags the result as a smi.
301 // Result must be a valid smi.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000302 void Integer64PlusConstantToSmi(Register dst, Register src, int constant);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000303
304 // Convert smi to 32-bit integer. I.e., not sign extended into
305 // high 32 bits of destination.
306 void SmiToInteger32(Register dst, Register src);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000307 void SmiToInteger32(Register dst, const Operand& src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000308
309 // Convert smi to 64-bit integer (sign extended if necessary).
310 void SmiToInteger64(Register dst, Register src);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000311 void SmiToInteger64(Register dst, const Operand& src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000312
313 // Multiply a positive smi's integer value by a power of two.
314 // Provides result as 64-bit integer value.
315 void PositiveSmiTimesPowerOfTwoToInteger64(Register dst,
316 Register src,
317 int power);
318
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000319 // Divide a positive smi's integer value by a power of two.
320 // Provides result as 32-bit integer value.
321 void PositiveSmiDivPowerOfTwoToInteger32(Register dst,
322 Register src,
323 int power);
324
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000325 // Perform the logical or of two smi values and return a smi value.
326 // If either argument is not a smi, jump to on_not_smis and retain
327 // the original values of source registers. The destination register
328 // may be changed if it's not one of the source registers.
329 template <typename LabelType>
330 void SmiOrIfSmis(Register dst,
331 Register src1,
332 Register src2,
333 LabelType* on_not_smis);
334
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000335
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000336 // Simple comparison of smis. Both sides must be known smis to use these,
337 // otherwise use Cmp.
338 void SmiCompare(Register smi1, Register smi2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000339 void SmiCompare(Register dst, Smi* src);
ager@chromium.orgac091b72010-05-05 07:34:42 +0000340 void SmiCompare(Register dst, const Operand& src);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000341 void SmiCompare(const Operand& dst, Register src);
342 void SmiCompare(const Operand& dst, Smi* src);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000343 // Compare the int32 in src register to the value of the smi stored at dst.
344 void SmiCompareInteger32(const Operand& dst, Register src);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000345 // Sets sign and zero flags depending on value of smi in register.
346 void SmiTest(Register src);
347
ager@chromium.org4af710e2009-09-15 12:20:11 +0000348 // Functions performing a check on a known or potential smi. Returns
349 // a condition that is satisfied if the check is successful.
350
351 // Is the value a tagged smi.
352 Condition CheckSmi(Register src);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000353 Condition CheckSmi(const Operand& src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000354
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000355 // Is the value a non-negative tagged smi.
356 Condition CheckNonNegativeSmi(Register src);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000357
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000358 // Are both values tagged smis.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000359 Condition CheckBothSmi(Register first, Register second);
360
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000361 // Are both values non-negative tagged smis.
362 Condition CheckBothNonNegativeSmi(Register first, Register second);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000363
364 // Are either value a tagged smi.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000365 Condition CheckEitherSmi(Register first,
366 Register second,
367 Register scratch = kScratchRegister);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000368
ager@chromium.org4af710e2009-09-15 12:20:11 +0000369 // Is the value the minimum smi value (since we are using
370 // two's complement numbers, negating the value is known to yield
371 // a non-smi value).
372 Condition CheckIsMinSmi(Register src);
373
ager@chromium.org4af710e2009-09-15 12:20:11 +0000374 // Checks whether an 32-bit integer value is a valid for conversion
375 // to a smi.
376 Condition CheckInteger32ValidSmiValue(Register src);
377
ager@chromium.org3811b432009-10-28 14:53:37 +0000378 // Checks whether an 32-bit unsigned integer value is a valid for
379 // conversion to a smi.
380 Condition CheckUInteger32ValidSmiValue(Register src);
381
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000382 // Check whether src is a Smi, and set dst to zero if it is a smi,
383 // and to one if it isn't.
384 void CheckSmiToIndicator(Register dst, Register src);
385 void CheckSmiToIndicator(Register dst, const Operand& src);
386
ager@chromium.org4af710e2009-09-15 12:20:11 +0000387 // Test-and-jump functions. Typically combines a check function
388 // above with a conditional jump.
389
390 // Jump if the value cannot be represented by a smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000391 template <typename LabelType>
392 void JumpIfNotValidSmiValue(Register src, LabelType* on_invalid);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000393
ager@chromium.org3811b432009-10-28 14:53:37 +0000394 // Jump if the unsigned integer value cannot be represented by a smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000395 template <typename LabelType>
396 void JumpIfUIntNotValidSmiValue(Register src, LabelType* on_invalid);
ager@chromium.org3811b432009-10-28 14:53:37 +0000397
ager@chromium.org4af710e2009-09-15 12:20:11 +0000398 // Jump to label if the value is a tagged smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000399 template <typename LabelType>
400 void JumpIfSmi(Register src, LabelType* on_smi);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000401
402 // Jump to label if the value is not a tagged smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000403 template <typename LabelType>
404 void JumpIfNotSmi(Register src, LabelType* on_not_smi);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000405
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000406 // Jump to label if the value is not a non-negative tagged smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000407 template <typename LabelType>
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000408 void JumpUnlessNonNegativeSmi(Register src, LabelType* on_not_smi);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000409
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000410 // Jump to label if the value, which must be a tagged smi, has value equal
ager@chromium.org4af710e2009-09-15 12:20:11 +0000411 // to the constant.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000412 template <typename LabelType>
413 void JumpIfSmiEqualsConstant(Register src,
414 Smi* constant,
415 LabelType* on_equals);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000416
ager@chromium.org4af710e2009-09-15 12:20:11 +0000417 // Jump if either or both register are not smi values.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000418 template <typename LabelType>
419 void JumpIfNotBothSmi(Register src1,
420 Register src2,
421 LabelType* on_not_both_smi);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000422
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000423 // Jump if either or both register are not non-negative smi values.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000424 template <typename LabelType>
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000425 void JumpUnlessBothNonNegativeSmi(Register src1, Register src2,
426 LabelType* on_not_both_smi);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000427
ager@chromium.org4af710e2009-09-15 12:20:11 +0000428 // Operations on tagged smi values.
429
430 // Smis represent a subset of integers. The subset is always equivalent to
431 // a two's complement interpretation of a fixed number of bits.
432
433 // Optimistically adds an integer constant to a supposed smi.
434 // If the src is not a smi, or the result is not a smi, jump to
435 // the label.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000436 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000437 void SmiTryAddConstant(Register dst,
438 Register src,
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000439 Smi* constant,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000440 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000441
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000442 // Add an integer constant to a tagged smi, giving a tagged smi as result.
443 // No overflow testing on the result is done.
444 void SmiAddConstant(Register dst, Register src, Smi* constant);
445
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000446 // Add an integer constant to a tagged smi, giving a tagged smi as result.
447 // No overflow testing on the result is done.
448 void SmiAddConstant(const Operand& dst, Smi* constant);
449
ager@chromium.org4af710e2009-09-15 12:20:11 +0000450 // Add an integer constant to a tagged smi, giving a tagged smi as result,
451 // or jumping to a label if the result cannot be represented by a smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000452 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000453 void SmiAddConstant(Register dst,
454 Register src,
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000455 Smi* constant,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000456 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000457
458 // Subtract an integer constant from a tagged smi, giving a tagged smi as
ager@chromium.orgac091b72010-05-05 07:34:42 +0000459 // result. No testing on the result is done. Sets the N and Z flags
460 // based on the value of the resulting integer.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000461 void SmiSubConstant(Register dst, Register src, Smi* constant);
462
463 // Subtract an integer constant from a tagged smi, giving a tagged smi as
ager@chromium.org4af710e2009-09-15 12:20:11 +0000464 // result, or jumping to a label if the result cannot be represented by a smi.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000465 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000466 void SmiSubConstant(Register dst,
467 Register src,
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000468 Smi* constant,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000469 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000470
471 // Negating a smi can give a negative zero or too large positive value.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000472 // NOTICE: This operation jumps on success, not failure!
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000473 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000474 void SmiNeg(Register dst,
475 Register src,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000476 LabelType* on_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000477
478 // Adds smi values and return the result as a smi.
479 // If dst is src1, then src1 will be destroyed, even if
480 // the operation is unsuccessful.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000481 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000482 void SmiAdd(Register dst,
483 Register src1,
484 Register src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000485 LabelType* on_not_smi_result);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000486 template <typename LabelType>
487 void SmiAdd(Register dst,
488 Register src1,
489 const Operand& src2,
490 LabelType* on_not_smi_result);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000491
492 void SmiAdd(Register dst,
493 Register src1,
494 Register src2);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000495
496 // Subtracts smi values and return the result as a smi.
497 // If dst is src1, then src1 will be destroyed, even if
498 // the operation is unsuccessful.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000499 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000500 void SmiSub(Register dst,
501 Register src1,
502 Register src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000503 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000504
ager@chromium.orgac091b72010-05-05 07:34:42 +0000505 void SmiSub(Register dst,
506 Register src1,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000507 Register src2);
508
509 template <typename LabelType>
510 void SmiSub(Register dst,
511 Register src1,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000512 const Operand& src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000513 LabelType* on_not_smi_result);
514
515 void SmiSub(Register dst,
516 Register src1,
517 const Operand& src2);
ager@chromium.orgac091b72010-05-05 07:34:42 +0000518
ager@chromium.org4af710e2009-09-15 12:20:11 +0000519 // Multiplies smi values and return the result as a smi,
520 // if possible.
521 // If dst is src1, then src1 will be destroyed, even if
522 // the operation is unsuccessful.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000523 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000524 void SmiMul(Register dst,
525 Register src1,
526 Register src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000527 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000528
529 // Divides one smi by another and returns the quotient.
530 // Clobbers rax and rdx registers.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000531 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000532 void SmiDiv(Register dst,
533 Register src1,
534 Register src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000535 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000536
537 // Divides one smi by another and returns the remainder.
538 // Clobbers rax and rdx registers.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000539 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000540 void SmiMod(Register dst,
541 Register src1,
542 Register src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000543 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000544
545 // Bitwise operations.
546 void SmiNot(Register dst, Register src);
547 void SmiAnd(Register dst, Register src1, Register src2);
548 void SmiOr(Register dst, Register src1, Register src2);
549 void SmiXor(Register dst, Register src1, Register src2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000550 void SmiAndConstant(Register dst, Register src1, Smi* constant);
551 void SmiOrConstant(Register dst, Register src1, Smi* constant);
552 void SmiXorConstant(Register dst, Register src1, Smi* constant);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000553
554 void SmiShiftLeftConstant(Register dst,
555 Register src,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000556 int shift_value);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000557 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000558 void SmiShiftLogicalRightConstant(Register dst,
559 Register src,
560 int shift_value,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000561 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000562 void SmiShiftArithmeticRightConstant(Register dst,
563 Register src,
564 int shift_value);
565
566 // Shifts a smi value to the left, and returns the result if that is a smi.
567 // Uses and clobbers rcx, so dst may not be rcx.
568 void SmiShiftLeft(Register dst,
569 Register src1,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000570 Register src2);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000571 // Shifts a smi value to the right, shifting in zero bits at the top, and
572 // returns the unsigned intepretation of the result if that is a smi.
573 // Uses and clobbers rcx, so dst may not be rcx.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000574 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000575 void SmiShiftLogicalRight(Register dst,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000576 Register src1,
577 Register src2,
578 LabelType* on_not_smi_result);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000579 // Shifts a smi value to the right, sign extending the top, and
580 // returns the signed intepretation of the result. That will always
581 // be a valid smi value, since it's numerically smaller than the
582 // original.
583 // Uses and clobbers rcx, so dst may not be rcx.
584 void SmiShiftArithmeticRight(Register dst,
585 Register src1,
586 Register src2);
587
588 // Specialized operations
589
590 // Select the non-smi register of two registers where exactly one is a
591 // smi. If neither are smis, jump to the failure label.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000592 template <typename LabelType>
ager@chromium.org4af710e2009-09-15 12:20:11 +0000593 void SelectNonSmi(Register dst,
594 Register src1,
595 Register src2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000596 LabelType* on_not_smis);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000597
598 // Converts, if necessary, a smi to a combination of number and
599 // multiplier to be used as a scaled index.
600 // The src register contains a *positive* smi value. The shift is the
601 // power of two to multiply the index value by (e.g.
602 // to index by smi-value * kPointerSize, pass the smi and kPointerSizeLog2).
603 // The returned index register may be either src or dst, depending
604 // on what is most efficient. If src and dst are different registers,
605 // src is always unchanged.
606 SmiIndex SmiToIndex(Register dst, Register src, int shift);
607
608 // Converts a positive smi to a negative index.
609 SmiIndex SmiToNegativeIndex(Register dst, Register src, int shift);
610
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000611 // Add the value of a smi in memory to an int32 register.
612 // Sets flags as a normal add.
613 void AddSmiField(Register dst, const Operand& src);
614
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000615 // Basic Smi operations.
ager@chromium.org3811b432009-10-28 14:53:37 +0000616 void Move(Register dst, Smi* source) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000617 LoadSmiConstant(dst, source);
ager@chromium.org3811b432009-10-28 14:53:37 +0000618 }
619
620 void Move(const Operand& dst, Smi* source) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000621 Register constant = GetSmiConstant(source);
622 movq(dst, constant);
ager@chromium.org3811b432009-10-28 14:53:37 +0000623 }
624
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000625 void Push(Smi* smi);
626 void Test(const Operand& dst, Smi* source);
627
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000628 // ---------------------------------------------------------------------------
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000629 // String macros.
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000630
631 // If object is a string, its map is loaded into object_map.
632 template <typename LabelType>
633 void JumpIfNotString(Register object,
634 Register object_map,
635 LabelType* not_string);
636
637
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000638 template <typename LabelType>
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000639 void JumpIfNotBothSequentialAsciiStrings(Register first_object,
640 Register second_object,
641 Register scratch1,
642 Register scratch2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000643 LabelType* on_not_both_flat_ascii);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000644
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000645 // Check whether the instance type represents a flat ascii string. Jump to the
646 // label if not. If the instance type can be scratched specify same register
647 // for both instance type and scratch.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000648 template <typename LabelType>
649 void JumpIfInstanceTypeIsNotSequentialAscii(
650 Register instance_type,
651 Register scratch,
652 LabelType *on_not_flat_ascii_string);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000653
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000654 template <typename LabelType>
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000655 void JumpIfBothInstanceTypesAreNotSequentialAscii(
656 Register first_object_instance_type,
657 Register second_object_instance_type,
658 Register scratch1,
659 Register scratch2,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000660 LabelType* on_fail);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000661
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000662 // ---------------------------------------------------------------------------
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000663 // Macro instructions.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000664
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000665 // Load a register with a long value as efficiently as possible.
ager@chromium.orge2902be2009-06-08 12:21:35 +0000666 void Set(Register dst, int64_t x);
667 void Set(const Operand& dst, int64_t x);
ager@chromium.org9085a012009-05-11 19:22:57 +0000668
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000669 // Move if the registers are not identical.
670 void Move(Register target, Register source);
671
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000672 // Handle support
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000673 void Move(Register dst, Handle<Object> source);
674 void Move(const Operand& dst, Handle<Object> source);
675 void Cmp(Register dst, Handle<Object> source);
ager@chromium.org3e875802009-06-29 08:26:34 +0000676 void Cmp(const Operand& dst, Handle<Object> source);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000677 void Cmp(Register dst, Smi* src);
678 void Cmp(const Operand& dst, Smi* src);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000679 void Push(Handle<Object> source);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000680
681 // Emit code to discard a non-negative number of pointer-sized elements
682 // from the stack, clobbering only the rsp register.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000683 void Drop(int stack_elements);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000684
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000685 void Call(Label* target) { call(target); }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000686
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000687 // Control Flow
688 void Jump(Address destination, RelocInfo::Mode rmode);
689 void Jump(ExternalReference ext);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000690 void Jump(Handle<Code> code_object, RelocInfo::Mode rmode);
691
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000692 void Call(Address destination, RelocInfo::Mode rmode);
693 void Call(ExternalReference ext);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000694 void Call(Handle<Code> code_object,
695 RelocInfo::Mode rmode,
696 unsigned ast_id = kNoASTId);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000697
ricow@chromium.orgeb96f4f2011-03-09 13:41:48 +0000698 // The size of the code generated for different call instructions.
699 int CallSize(Address destination, RelocInfo::Mode rmode) {
700 return kCallInstructionLength;
701 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000702 int CallSize(ExternalReference ext);
ricow@chromium.orgeb96f4f2011-03-09 13:41:48 +0000703 int CallSize(Handle<Code> code_object) {
704 // Code calls use 32-bit relative addressing.
705 return kShortCallInstructionLength;
706 }
707 int CallSize(Register target) {
708 // Opcode: REX_opt FF /2 m64
709 return (target.high_bit() != 0) ? 3 : 2;
710 }
711 int CallSize(const Operand& target) {
712 // Opcode: REX_opt FF /2 m64
713 return (target.requires_rex() ? 2 : 1) + target.operand_size();
714 }
715
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000716 // Emit call to the code we are currently generating.
717 void CallSelf() {
718 Handle<Code> self(reinterpret_cast<Code**>(CodeObject().location()));
719 Call(self, RelocInfo::CODE_TARGET);
720 }
721
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000722 // Non-x64 instructions.
723 // Push/pop all general purpose registers.
724 // Does not push rsp/rbp nor any of the assembler's special purpose registers
725 // (kScratchRegister, kSmiConstantRegister, kRootRegister).
726 void Pushad();
727 void Popad();
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000728 // Sets the stack as after performing Popad, without actually loading the
729 // registers.
730 void Dropad();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000731
ager@chromium.org9085a012009-05-11 19:22:57 +0000732 // Compare object type for heap object.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000733 // Always use unsigned comparisons: above and below, not less and greater.
ager@chromium.org9085a012009-05-11 19:22:57 +0000734 // Incoming register is heap_object and outgoing register is map.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000735 // They may be the same register, and may be kScratchRegister.
ager@chromium.org9085a012009-05-11 19:22:57 +0000736 void CmpObjectType(Register heap_object, InstanceType type, Register map);
737
738 // Compare instance type for map.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000739 // Always use unsigned comparisons: above and below, not less and greater.
ager@chromium.org9085a012009-05-11 19:22:57 +0000740 void CmpInstanceType(Register map, InstanceType type);
741
ager@chromium.org5c838252010-02-19 08:53:10 +0000742 // Check if the map of an object is equal to a specified map and
743 // branch to label if not. Skip the smi check if not required
744 // (object is known to be a heap object)
745 void CheckMap(Register obj,
746 Handle<Map> map,
747 Label* fail,
748 bool is_heap_object);
749
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000750 // Check if the object in register heap_object is a string. Afterwards the
751 // register map contains the object map and the register instance_type
752 // contains the instance_type. The registers map and instance_type can be the
753 // same in which case it contains the instance type afterwards. Either of the
754 // registers map and instance_type can be the same as heap_object.
755 Condition IsObjectStringType(Register heap_object,
756 Register map,
757 Register instance_type);
758
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000759 // FCmp compares and pops the two values on top of the FPU stack.
760 // The flag results are similar to integer cmp, but requires unsigned
ager@chromium.org9085a012009-05-11 19:22:57 +0000761 // jcc instructions (je, ja, jae, jb, jbe, je, and jz).
762 void FCmp();
763
ager@chromium.org5c838252010-02-19 08:53:10 +0000764 // Abort execution if argument is not a number. Used in debug code.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000765 void AbortIfNotNumber(Register object);
ager@chromium.org5c838252010-02-19 08:53:10 +0000766
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000767 // Abort execution if argument is a smi. Used in debug code.
768 void AbortIfSmi(Register object);
769
lrn@chromium.org25156de2010-04-06 13:10:27 +0000770 // Abort execution if argument is not a smi. Used in debug code.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000771 void AbortIfNotSmi(Register object);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000772 void AbortIfNotSmi(const Operand& object);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000773
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000774 // Abort execution if argument is a string. Used in debug code.
775 void AbortIfNotString(Register object);
776
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000777 // Abort execution if argument is not the root value with the given index.
778 void AbortIfNotRootValue(Register src,
779 Heap::RootListIndex root_value_index,
780 const char* message);
781
ager@chromium.org9085a012009-05-11 19:22:57 +0000782 // ---------------------------------------------------------------------------
783 // Exception handling
784
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000785 // Push a new try handler and link into try handler chain. The return
786 // address must be pushed before calling this helper.
ager@chromium.org9085a012009-05-11 19:22:57 +0000787 void PushTryHandler(CodeLocation try_location, HandlerType type);
788
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000789 // Unlink the stack handler on top of the stack from the try handler chain.
790 void PopTryHandler();
ager@chromium.org9085a012009-05-11 19:22:57 +0000791
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000792 // Activate the top handler in the try hander chain and pass the
793 // thrown value.
794 void Throw(Register value);
795
796 // Propagate an uncatchable exception out of the current JS stack.
797 void ThrowUncatchable(UncatchableExceptionType type, Register value);
798
ager@chromium.org9085a012009-05-11 19:22:57 +0000799 // ---------------------------------------------------------------------------
800 // Inline caching support
801
ager@chromium.org9085a012009-05-11 19:22:57 +0000802 // Generate code for checking access rights - used for security checks
803 // on access to global objects across environments. The holder register
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000804 // is left untouched, but the scratch register and kScratchRegister,
805 // which must be different, are clobbered.
ager@chromium.org9085a012009-05-11 19:22:57 +0000806 void CheckAccessGlobalProxy(Register holder_reg,
807 Register scratch,
808 Label* miss);
809
810
811 // ---------------------------------------------------------------------------
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000812 // Allocation support
813
814 // Allocate an object in new space. If the new space is exhausted control
815 // continues at the gc_required label. The allocated object is returned in
816 // result and end of the new object is returned in result_end. The register
817 // scratch can be passed as no_reg in which case an additional object
818 // reference will be added to the reloc info. The returned pointers in result
819 // and result_end have not yet been tagged as heap objects. If
820 // result_contains_top_on_entry is true the content of result is known to be
821 // the allocation top on entry (could be result_end from a previous call to
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000822 // AllocateInNewSpace). If result_contains_top_on_entry is true scratch
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000823 // should be no_reg as it is never used.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000824 void AllocateInNewSpace(int object_size,
825 Register result,
826 Register result_end,
827 Register scratch,
828 Label* gc_required,
829 AllocationFlags flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000830
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000831 void AllocateInNewSpace(int header_size,
832 ScaleFactor element_size,
833 Register element_count,
834 Register result,
835 Register result_end,
836 Register scratch,
837 Label* gc_required,
838 AllocationFlags flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000839
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000840 void AllocateInNewSpace(Register object_size,
841 Register result,
842 Register result_end,
843 Register scratch,
844 Label* gc_required,
845 AllocationFlags flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000846
847 // Undo allocation in new space. The object passed and objects allocated after
848 // it will no longer be allocated. Make sure that no pointers are left to the
849 // object(s) no longer allocated as they would be invalid when allocation is
850 // un-done.
851 void UndoAllocationInNewSpace(Register object);
852
ager@chromium.org3811b432009-10-28 14:53:37 +0000853 // Allocate a heap number in new space with undefined value. Returns
854 // tagged pointer in result register, or jumps to gc_required if new
855 // space is full.
856 void AllocateHeapNumber(Register result,
857 Register scratch,
858 Label* gc_required);
859
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000860 // Allocate a sequential string. All the header fields of the string object
861 // are initialized.
862 void AllocateTwoByteString(Register result,
863 Register length,
864 Register scratch1,
865 Register scratch2,
866 Register scratch3,
867 Label* gc_required);
868 void AllocateAsciiString(Register result,
869 Register length,
870 Register scratch1,
871 Register scratch2,
872 Register scratch3,
873 Label* gc_required);
874
875 // Allocate a raw cons string object. Only the map field of the result is
876 // initialized.
877 void AllocateConsString(Register result,
878 Register scratch1,
879 Register scratch2,
880 Label* gc_required);
881 void AllocateAsciiConsString(Register result,
882 Register scratch1,
883 Register scratch2,
884 Label* gc_required);
885
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000886 // ---------------------------------------------------------------------------
ager@chromium.org9085a012009-05-11 19:22:57 +0000887 // Support functions.
888
889 // Check if result is zero and op is negative.
890 void NegativeZeroTest(Register result, Register op, Label* then_label);
891
892 // Check if result is zero and op is negative in code using jump targets.
893 void NegativeZeroTest(CodeGenerator* cgen,
894 Register result,
895 Register op,
896 JumpTarget* then_target);
897
898 // Check if result is zero and any of op1 and op2 are negative.
899 // Register scratch is destroyed, and it must be different from op2.
900 void NegativeZeroTest(Register result, Register op1, Register op2,
901 Register scratch, Label* then_label);
902
903 // Try to get function prototype of a function and puts the value in
904 // the result register. Checks that the function really is a
905 // function and jumps to the miss label if the fast checks fail. The
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000906 // function register will be untouched; the other register may be
ager@chromium.org9085a012009-05-11 19:22:57 +0000907 // clobbered.
908 void TryGetFunctionPrototype(Register function,
909 Register result,
ager@chromium.org9085a012009-05-11 19:22:57 +0000910 Label* miss);
911
912 // Generates code for reporting that an illegal operation has
913 // occurred.
914 void IllegalOperation(int num_arguments);
915
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000916 // Picks out an array index from the hash field.
917 // Register use:
918 // hash - holds the index's hash. Clobbered.
919 // index - holds the overwritten index on exit.
920 void IndexFromHash(Register hash, Register index);
921
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000922 // Find the function context up the context chain.
923 void LoadContext(Register dst, int context_chain_length);
924
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000925 // Load the global function with the given index.
926 void LoadGlobalFunction(int index, Register function);
927
928 // Load the initial map from the global function. The registers
929 // function and map can be the same.
930 void LoadGlobalFunctionInitialMap(Register function, Register map);
931
ager@chromium.org9085a012009-05-11 19:22:57 +0000932 // ---------------------------------------------------------------------------
933 // Runtime calls
934
935 // Call a code stub.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000936 void CallStub(CodeStub* stub, unsigned ast_id = kNoASTId);
ager@chromium.org9085a012009-05-11 19:22:57 +0000937
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000938 // Call a code stub and return the code object called. Try to generate
939 // the code if necessary. Do not perform a GC but instead return a retry
940 // after GC failure.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000941 MUST_USE_RESULT MaybeObject* TryCallStub(CodeStub* stub);
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000942
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000943 // Tail call a code stub (jump).
944 void TailCallStub(CodeStub* stub);
945
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000946 // Tail call a code stub (jump) and return the code object called. Try to
947 // generate the code if necessary. Do not perform a GC but instead return
948 // a retry after GC failure.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000949 MUST_USE_RESULT MaybeObject* TryTailCallStub(CodeStub* stub);
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000950
ager@chromium.org9085a012009-05-11 19:22:57 +0000951 // Return from a code stub after popping its arguments.
952 void StubReturn(int argc);
953
954 // Call a runtime routine.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000955 void CallRuntime(const Runtime::Function* f, int num_arguments);
ager@chromium.org9085a012009-05-11 19:22:57 +0000956
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000957 // Call a runtime function and save the value of XMM registers.
958 void CallRuntimeSaveDoubles(Runtime::FunctionId id);
959
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000960 // Call a runtime function, returning the CodeStub object called.
961 // Try to generate the stub code if necessary. Do not perform a GC
962 // but instead return a retry after GC failure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000963 MUST_USE_RESULT MaybeObject* TryCallRuntime(const Runtime::Function* f,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000964 int num_arguments);
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000965
ager@chromium.org9085a012009-05-11 19:22:57 +0000966 // Convenience function: Same as above, but takes the fid instead.
967 void CallRuntime(Runtime::FunctionId id, int num_arguments);
968
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000969 // Convenience function: Same as above, but takes the fid instead.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000970 MUST_USE_RESULT MaybeObject* TryCallRuntime(Runtime::FunctionId id,
971 int num_arguments);
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000972
ager@chromium.org5c838252010-02-19 08:53:10 +0000973 // Convenience function: call an external reference.
974 void CallExternalReference(const ExternalReference& ext,
975 int num_arguments);
976
ager@chromium.org9085a012009-05-11 19:22:57 +0000977 // Tail call of a runtime routine (jump).
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000978 // Like JumpToExternalReference, but also takes care of passing the number
979 // of parameters.
980 void TailCallExternalReference(const ExternalReference& ext,
981 int num_arguments,
982 int result_size);
983
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000984 MUST_USE_RESULT MaybeObject* TryTailCallExternalReference(
985 const ExternalReference& ext, int num_arguments, int result_size);
986
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000987 // Convenience function: tail call a runtime routine (jump).
988 void TailCallRuntime(Runtime::FunctionId fid,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000989 int num_arguments,
990 int result_size);
ager@chromium.org9085a012009-05-11 19:22:57 +0000991
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000992 MUST_USE_RESULT MaybeObject* TryTailCallRuntime(Runtime::FunctionId fid,
993 int num_arguments,
994 int result_size);
995
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000996 // Jump to a runtime routine.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000997 void JumpToExternalReference(const ExternalReference& ext, int result_size);
ager@chromium.org9085a012009-05-11 19:22:57 +0000998
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000999 // Jump to a runtime routine.
1000 MaybeObject* TryJumpToExternalReference(const ExternalReference& ext,
1001 int result_size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001002
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001003 // Prepares stack to put arguments (aligns and so on).
1004 // WIN64 calling convention requires to put the pointer to the return value
1005 // slot into rcx (rcx must be preserverd until TryCallApiFunctionAndReturn).
1006 // Saves context (rsi). Clobbers rax. Allocates arg_stack_space * kPointerSize
1007 // inside the exit frame (not GCed) accessible via StackSpaceOperand.
1008 void PrepareCallApiFunction(int arg_stack_space);
1009
1010 // Calls an API function. Allocates HandleScope, extracts
1011 // returned value from handle and propagates exceptions.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001012 // Clobbers r14, r15, rbx and caller-save registers. Restores context.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001013 // On return removes stack_space * kPointerSize (GCed).
1014 MUST_USE_RESULT MaybeObject* TryCallApiFunctionAndReturn(
1015 ApiFunction* function, int stack_space);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001016
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001017 // Before calling a C-function from generated code, align arguments on stack.
1018 // After aligning the frame, arguments must be stored in esp[0], esp[4],
1019 // etc., not pushed. The argument count assumes all arguments are word sized.
1020 // The number of slots reserved for arguments depends on platform. On Windows
1021 // stack slots are reserved for the arguments passed in registers. On other
1022 // platforms stack slots are only reserved for the arguments actually passed
1023 // on the stack.
1024 void PrepareCallCFunction(int num_arguments);
1025
1026 // Calls a C function and cleans up the space for arguments allocated
1027 // by PrepareCallCFunction. The called function is not allowed to trigger a
1028 // garbage collection, since that might move the code and invalidate the
1029 // return address (unless this is somehow accounted for by the called
1030 // function).
1031 void CallCFunction(ExternalReference function, int num_arguments);
1032 void CallCFunction(Register function, int num_arguments);
1033
1034 // Calculate the number of stack slots to reserve for arguments when calling a
1035 // C function.
1036 int ArgumentStackSlotsForCFunctionCall(int num_arguments);
ager@chromium.org9085a012009-05-11 19:22:57 +00001037
1038 // ---------------------------------------------------------------------------
1039 // Utilities
1040
1041 void Ret();
1042
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001043 // Return and drop arguments from stack, where the number of arguments
1044 // may be bigger than 2^16 - 1. Requires a scratch register.
1045 void Ret(int bytes_dropped, Register scratch);
1046
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001047 Handle<Object> CodeObject() {
1048 ASSERT(!code_object_.is_null());
1049 return code_object_;
1050 }
ager@chromium.org9085a012009-05-11 19:22:57 +00001051
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001052 // Copy length bytes from source to destination.
1053 // Uses scratch register internally (if you have a low-eight register
1054 // free, do use it, otherwise kScratchRegister will be used).
1055 // The min_length is a minimum limit on the value that length will have.
1056 // The algorithm has some special cases that might be omitted if the string
1057 // is known to always be long.
1058 void CopyBytes(Register destination,
1059 Register source,
1060 Register length,
1061 int min_length = 0,
1062 Register scratch = kScratchRegister);
1063
ager@chromium.org9085a012009-05-11 19:22:57 +00001064
1065 // ---------------------------------------------------------------------------
1066 // StatsCounter support
1067
1068 void SetCounter(StatsCounter* counter, int value);
1069 void IncrementCounter(StatsCounter* counter, int value);
1070 void DecrementCounter(StatsCounter* counter, int value);
1071
1072
1073 // ---------------------------------------------------------------------------
1074 // Debugging
1075
1076 // Calls Abort(msg) if the condition cc is not satisfied.
1077 // Use --debug_code to enable.
1078 void Assert(Condition cc, const char* msg);
1079
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001080 void AssertFastElements(Register elements);
1081
ager@chromium.org9085a012009-05-11 19:22:57 +00001082 // Like Assert(), but always enabled.
1083 void Check(Condition cc, const char* msg);
1084
1085 // Print a message to stdout and abort execution.
1086 void Abort(const char* msg);
1087
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001088 // Check that the stack is aligned.
1089 void CheckStackAlignment();
1090
ager@chromium.org9085a012009-05-11 19:22:57 +00001091 // Verify restrictions about code generated in stubs.
1092 void set_generating_stub(bool value) { generating_stub_ = value; }
1093 bool generating_stub() { return generating_stub_; }
1094 void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
1095 bool allow_stub_calls() { return allow_stub_calls_; }
1096
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001097 static int SafepointRegisterStackIndex(Register reg) {
1098 return SafepointRegisterStackIndex(reg.code());
1099 }
1100
ager@chromium.org9085a012009-05-11 19:22:57 +00001101 private:
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001102 // Order general registers are pushed by Pushad.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001103 // rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r14, r15.
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001104 static int kSafepointPushRegisterIndices[Register::kNumRegisters];
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001105 static const int kNumSafepointSavedRegisters = 11;
1106
ager@chromium.org9085a012009-05-11 19:22:57 +00001107 bool generating_stub_;
1108 bool allow_stub_calls_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001109 bool root_array_available_;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001110
1111 // Returns a register holding the smi value. The register MUST NOT be
1112 // modified. It may be the "smi 1 constant" register.
1113 Register GetSmiConstant(Smi* value);
1114
1115 // Moves the smi value to the destination register.
1116 void LoadSmiConstant(Register dst, Smi* value);
1117
ager@chromium.org5c838252010-02-19 08:53:10 +00001118 // This handle will be patched with the code object on installation.
1119 Handle<Object> code_object_;
ager@chromium.org9085a012009-05-11 19:22:57 +00001120
1121 // Helper functions for generating invokes.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001122 template <typename LabelType>
ager@chromium.org9085a012009-05-11 19:22:57 +00001123 void InvokePrologue(const ParameterCount& expected,
1124 const ParameterCount& actual,
1125 Handle<Code> code_constant,
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001126 Register code_register,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001127 LabelType* done,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001128 InvokeFlag flag,
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001129 const CallWrapper& call_wrapper);
ager@chromium.org9085a012009-05-11 19:22:57 +00001130
ager@chromium.org9085a012009-05-11 19:22:57 +00001131 // Activation support.
1132 void EnterFrame(StackFrame::Type type);
1133 void LeaveFrame(StackFrame::Type type);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001134
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001135 void EnterExitFramePrologue(bool save_rax);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001136
1137 // Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack
1138 // accessible via StackSpaceOperand.
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001139 void EnterExitFrameEpilogue(int arg_stack_space, bool save_doubles);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001140
1141 void LeaveExitFrameEpilogue();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001142
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001143 // Allocation support helpers.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001144 // Loads the top of new-space into the result register.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001145 // Otherwise the address of the new-space top is loaded into scratch (if
1146 // scratch is valid), and the new-space top is loaded into result.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001147 void LoadAllocationTopHelper(Register result,
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001148 Register scratch,
ager@chromium.orga1645e22009-09-09 19:27:10 +00001149 AllocationFlags flags);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001150 // Update allocation top with value in result_end register.
1151 // If scratch is valid, it contains the address of the allocation top.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001152 void UpdateAllocationTopHelper(Register result_end, Register scratch);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001153
1154 // Helper for PopHandleScope. Allowed to perform a GC and returns
1155 // NULL if gc_allowed. Does not perform a GC if !gc_allowed, and
1156 // possibly returns a failure object indicating an allocation failure.
1157 Object* PopHandleScopeHelper(Register saved,
1158 Register scratch,
1159 bool gc_allowed);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001160
1161
1162 // Compute memory operands for safepoint stack slots.
1163 Operand SafepointRegisterSlot(Register reg);
1164 static int SafepointRegisterStackIndex(int reg_code) {
1165 return kNumSafepointRegisters - kSafepointPushRegisterIndices[reg_code] - 1;
1166 }
1167
1168 // Needs access to SafepointRegisterStackIndex for optimized frame
1169 // traversal.
1170 friend class OptimizedFrame;
ager@chromium.org9085a012009-05-11 19:22:57 +00001171};
1172
1173
ager@chromium.org4af710e2009-09-15 12:20:11 +00001174// The code patcher is used to patch (typically) small parts of code e.g. for
1175// debugging and other types of instrumentation. When using the code patcher
1176// the exact number of bytes specified must be emitted. Is not legal to emit
1177// relocation information. If any of these constraints are violated it causes
1178// an assertion.
1179class CodePatcher {
1180 public:
1181 CodePatcher(byte* address, int size);
1182 virtual ~CodePatcher();
1183
1184 // Macro assembler to emit code.
1185 MacroAssembler* masm() { return &masm_; }
1186
1187 private:
1188 byte* address_; // The address of the code being patched.
1189 int size_; // Number of bytes of the expected patch size.
1190 MacroAssembler masm_; // Macro assembler used to generate the code.
1191};
1192
1193
ager@chromium.org9085a012009-05-11 19:22:57 +00001194// -----------------------------------------------------------------------------
1195// Static helper functions.
1196
1197// Generate an Operand for loading a field from an object.
1198static inline Operand FieldOperand(Register object, int offset) {
1199 return Operand(object, offset - kHeapObjectTag);
1200}
1201
1202
1203// Generate an Operand for loading an indexed field from an object.
1204static inline Operand FieldOperand(Register object,
1205 Register index,
1206 ScaleFactor scale,
1207 int offset) {
1208 return Operand(object, index, scale, offset - kHeapObjectTag);
1209}
1210
1211
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001212static inline Operand ContextOperand(Register context, int index) {
1213 return Operand(context, Context::SlotOffset(index));
1214}
1215
1216
1217static inline Operand GlobalObjectOperand() {
1218 return ContextOperand(rsi, Context::GLOBAL_INDEX);
1219}
1220
1221
1222// Provides access to exit frame stack space (not GCed).
1223static inline Operand StackSpaceOperand(int index) {
1224#ifdef _WIN64
1225 const int kShaddowSpace = 4;
1226 return Operand(rsp, (index + kShaddowSpace) * kPointerSize);
1227#else
1228 return Operand(rsp, index * kPointerSize);
1229#endif
1230}
1231
1232
1233
ager@chromium.org9085a012009-05-11 19:22:57 +00001234#ifdef GENERATED_CODE_COVERAGE
1235extern void LogGeneratedCodeCoverage(const char* file_line);
1236#define CODE_COVERAGE_STRINGIFY(x) #x
1237#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
1238#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
1239#define ACCESS_MASM(masm) { \
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001240 byte* x64_coverage_function = \
ager@chromium.org9085a012009-05-11 19:22:57 +00001241 reinterpret_cast<byte*>(FUNCTION_ADDR(LogGeneratedCodeCoverage)); \
1242 masm->pushfd(); \
1243 masm->pushad(); \
1244 masm->push(Immediate(reinterpret_cast<int>(&__FILE_LINE__))); \
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001245 masm->call(x64_coverage_function, RelocInfo::RUNTIME_ENTRY); \
ager@chromium.org9085a012009-05-11 19:22:57 +00001246 masm->pop(rax); \
1247 masm->popad(); \
1248 masm->popfd(); \
1249 } \
1250 masm->
1251#else
1252#define ACCESS_MASM(masm) masm->
1253#endif
1254
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001255// -----------------------------------------------------------------------------
1256// Template implementations.
1257
1258static int kSmiShift = kSmiTagSize + kSmiShiftSize;
1259
1260
1261template <typename LabelType>
1262void MacroAssembler::SmiNeg(Register dst,
1263 Register src,
1264 LabelType* on_smi_result) {
1265 if (dst.is(src)) {
1266 ASSERT(!dst.is(kScratchRegister));
1267 movq(kScratchRegister, src);
1268 neg(dst); // Low 32 bits are retained as zero by negation.
1269 // Test if result is zero or Smi::kMinValue.
1270 cmpq(dst, kScratchRegister);
1271 j(not_equal, on_smi_result);
1272 movq(src, kScratchRegister);
1273 } else {
1274 movq(dst, src);
1275 neg(dst);
1276 cmpq(dst, src);
1277 // If the result is zero or Smi::kMinValue, negation failed to create a smi.
1278 j(not_equal, on_smi_result);
1279 }
1280}
1281
1282
1283template <typename LabelType>
1284void MacroAssembler::SmiAdd(Register dst,
1285 Register src1,
1286 Register src2,
1287 LabelType* on_not_smi_result) {
1288 ASSERT_NOT_NULL(on_not_smi_result);
1289 ASSERT(!dst.is(src2));
1290 if (dst.is(src1)) {
1291 movq(kScratchRegister, src1);
1292 addq(kScratchRegister, src2);
1293 j(overflow, on_not_smi_result);
1294 movq(dst, kScratchRegister);
1295 } else {
1296 movq(dst, src1);
1297 addq(dst, src2);
1298 j(overflow, on_not_smi_result);
1299 }
1300}
1301
1302
1303template <typename LabelType>
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001304void MacroAssembler::SmiAdd(Register dst,
1305 Register src1,
1306 const Operand& src2,
1307 LabelType* on_not_smi_result) {
1308 ASSERT_NOT_NULL(on_not_smi_result);
1309 if (dst.is(src1)) {
1310 movq(kScratchRegister, src1);
1311 addq(kScratchRegister, src2);
1312 j(overflow, on_not_smi_result);
1313 movq(dst, kScratchRegister);
1314 } else {
1315 ASSERT(!src2.AddressUsesRegister(dst));
1316 movq(dst, src1);
1317 addq(dst, src2);
1318 j(overflow, on_not_smi_result);
1319 }
1320}
1321
1322
1323template <typename LabelType>
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001324void MacroAssembler::SmiSub(Register dst,
1325 Register src1,
1326 Register src2,
1327 LabelType* on_not_smi_result) {
1328 ASSERT_NOT_NULL(on_not_smi_result);
1329 ASSERT(!dst.is(src2));
1330 if (dst.is(src1)) {
1331 cmpq(dst, src2);
1332 j(overflow, on_not_smi_result);
1333 subq(dst, src2);
1334 } else {
1335 movq(dst, src1);
1336 subq(dst, src2);
1337 j(overflow, on_not_smi_result);
1338 }
1339}
1340
1341
1342template <typename LabelType>
1343void MacroAssembler::SmiSub(Register dst,
1344 Register src1,
1345 const Operand& src2,
1346 LabelType* on_not_smi_result) {
1347 ASSERT_NOT_NULL(on_not_smi_result);
1348 if (dst.is(src1)) {
1349 movq(kScratchRegister, src2);
1350 cmpq(src1, kScratchRegister);
1351 j(overflow, on_not_smi_result);
1352 subq(src1, kScratchRegister);
1353 } else {
1354 movq(dst, src1);
1355 subq(dst, src2);
1356 j(overflow, on_not_smi_result);
1357 }
1358}
1359
1360
1361template <typename LabelType>
1362void MacroAssembler::SmiMul(Register dst,
1363 Register src1,
1364 Register src2,
1365 LabelType* on_not_smi_result) {
1366 ASSERT(!dst.is(src2));
1367 ASSERT(!dst.is(kScratchRegister));
1368 ASSERT(!src1.is(kScratchRegister));
1369 ASSERT(!src2.is(kScratchRegister));
1370
1371 if (dst.is(src1)) {
1372 NearLabel failure, zero_correct_result;
1373 movq(kScratchRegister, src1); // Create backup for later testing.
1374 SmiToInteger64(dst, src1);
1375 imul(dst, src2);
1376 j(overflow, &failure);
1377
1378 // Check for negative zero result. If product is zero, and one
1379 // argument is negative, go to slow case.
1380 NearLabel correct_result;
1381 testq(dst, dst);
1382 j(not_zero, &correct_result);
1383
1384 movq(dst, kScratchRegister);
1385 xor_(dst, src2);
1386 j(positive, &zero_correct_result); // Result was positive zero.
1387
1388 bind(&failure); // Reused failure exit, restores src1.
1389 movq(src1, kScratchRegister);
1390 jmp(on_not_smi_result);
1391
1392 bind(&zero_correct_result);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001393 Set(dst, 0);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001394
1395 bind(&correct_result);
1396 } else {
1397 SmiToInteger64(dst, src1);
1398 imul(dst, src2);
1399 j(overflow, on_not_smi_result);
1400 // Check for negative zero result. If product is zero, and one
1401 // argument is negative, go to slow case.
1402 NearLabel correct_result;
1403 testq(dst, dst);
1404 j(not_zero, &correct_result);
1405 // One of src1 and src2 is zero, the check whether the other is
1406 // negative.
1407 movq(kScratchRegister, src1);
1408 xor_(kScratchRegister, src2);
1409 j(negative, on_not_smi_result);
1410 bind(&correct_result);
1411 }
1412}
1413
1414
1415template <typename LabelType>
1416void MacroAssembler::SmiTryAddConstant(Register dst,
1417 Register src,
1418 Smi* constant,
1419 LabelType* on_not_smi_result) {
1420 // Does not assume that src is a smi.
1421 ASSERT_EQ(static_cast<int>(1), static_cast<int>(kSmiTagMask));
1422 ASSERT_EQ(0, kSmiTag);
1423 ASSERT(!dst.is(kScratchRegister));
1424 ASSERT(!src.is(kScratchRegister));
1425
1426 JumpIfNotSmi(src, on_not_smi_result);
1427 Register tmp = (dst.is(src) ? kScratchRegister : dst);
1428 LoadSmiConstant(tmp, constant);
1429 addq(tmp, src);
1430 j(overflow, on_not_smi_result);
1431 if (dst.is(src)) {
1432 movq(dst, tmp);
1433 }
1434}
1435
1436
1437template <typename LabelType>
1438void MacroAssembler::SmiAddConstant(Register dst,
1439 Register src,
1440 Smi* constant,
1441 LabelType* on_not_smi_result) {
1442 if (constant->value() == 0) {
1443 if (!dst.is(src)) {
1444 movq(dst, src);
1445 }
1446 } else if (dst.is(src)) {
1447 ASSERT(!dst.is(kScratchRegister));
1448
1449 LoadSmiConstant(kScratchRegister, constant);
1450 addq(kScratchRegister, src);
1451 j(overflow, on_not_smi_result);
1452 movq(dst, kScratchRegister);
1453 } else {
1454 LoadSmiConstant(dst, constant);
1455 addq(dst, src);
1456 j(overflow, on_not_smi_result);
1457 }
1458}
1459
1460
1461template <typename LabelType>
1462void MacroAssembler::SmiSubConstant(Register dst,
1463 Register src,
1464 Smi* constant,
1465 LabelType* on_not_smi_result) {
1466 if (constant->value() == 0) {
1467 if (!dst.is(src)) {
1468 movq(dst, src);
1469 }
1470 } else if (dst.is(src)) {
1471 ASSERT(!dst.is(kScratchRegister));
1472 if (constant->value() == Smi::kMinValue) {
1473 // Subtracting min-value from any non-negative value will overflow.
1474 // We test the non-negativeness before doing the subtraction.
1475 testq(src, src);
1476 j(not_sign, on_not_smi_result);
1477 LoadSmiConstant(kScratchRegister, constant);
1478 subq(dst, kScratchRegister);
1479 } else {
1480 // Subtract by adding the negation.
1481 LoadSmiConstant(kScratchRegister, Smi::FromInt(-constant->value()));
1482 addq(kScratchRegister, dst);
1483 j(overflow, on_not_smi_result);
1484 movq(dst, kScratchRegister);
1485 }
1486 } else {
1487 if (constant->value() == Smi::kMinValue) {
1488 // Subtracting min-value from any non-negative value will overflow.
1489 // We test the non-negativeness before doing the subtraction.
1490 testq(src, src);
1491 j(not_sign, on_not_smi_result);
1492 LoadSmiConstant(dst, constant);
1493 // Adding and subtracting the min-value gives the same result, it only
1494 // differs on the overflow bit, which we don't check here.
1495 addq(dst, src);
1496 } else {
1497 // Subtract by adding the negation.
1498 LoadSmiConstant(dst, Smi::FromInt(-(constant->value())));
1499 addq(dst, src);
1500 j(overflow, on_not_smi_result);
1501 }
1502 }
1503}
1504
1505
1506template <typename LabelType>
1507void MacroAssembler::SmiDiv(Register dst,
1508 Register src1,
1509 Register src2,
1510 LabelType* on_not_smi_result) {
1511 ASSERT(!src1.is(kScratchRegister));
1512 ASSERT(!src2.is(kScratchRegister));
1513 ASSERT(!dst.is(kScratchRegister));
1514 ASSERT(!src2.is(rax));
1515 ASSERT(!src2.is(rdx));
1516 ASSERT(!src1.is(rdx));
1517
1518 // Check for 0 divisor (result is +/-Infinity).
1519 NearLabel positive_divisor;
1520 testq(src2, src2);
1521 j(zero, on_not_smi_result);
1522
1523 if (src1.is(rax)) {
1524 movq(kScratchRegister, src1);
1525 }
1526 SmiToInteger32(rax, src1);
1527 // We need to rule out dividing Smi::kMinValue by -1, since that would
1528 // overflow in idiv and raise an exception.
1529 // We combine this with negative zero test (negative zero only happens
1530 // when dividing zero by a negative number).
1531
1532 // We overshoot a little and go to slow case if we divide min-value
1533 // by any negative value, not just -1.
1534 NearLabel safe_div;
1535 testl(rax, Immediate(0x7fffffff));
1536 j(not_zero, &safe_div);
1537 testq(src2, src2);
1538 if (src1.is(rax)) {
1539 j(positive, &safe_div);
1540 movq(src1, kScratchRegister);
1541 jmp(on_not_smi_result);
1542 } else {
1543 j(negative, on_not_smi_result);
1544 }
1545 bind(&safe_div);
1546
1547 SmiToInteger32(src2, src2);
1548 // Sign extend src1 into edx:eax.
1549 cdq();
1550 idivl(src2);
1551 Integer32ToSmi(src2, src2);
1552 // Check that the remainder is zero.
1553 testl(rdx, rdx);
1554 if (src1.is(rax)) {
1555 NearLabel smi_result;
1556 j(zero, &smi_result);
1557 movq(src1, kScratchRegister);
1558 jmp(on_not_smi_result);
1559 bind(&smi_result);
1560 } else {
1561 j(not_zero, on_not_smi_result);
1562 }
1563 if (!dst.is(src1) && src1.is(rax)) {
1564 movq(src1, kScratchRegister);
1565 }
1566 Integer32ToSmi(dst, rax);
1567}
1568
1569
1570template <typename LabelType>
1571void MacroAssembler::SmiMod(Register dst,
1572 Register src1,
1573 Register src2,
1574 LabelType* on_not_smi_result) {
1575 ASSERT(!dst.is(kScratchRegister));
1576 ASSERT(!src1.is(kScratchRegister));
1577 ASSERT(!src2.is(kScratchRegister));
1578 ASSERT(!src2.is(rax));
1579 ASSERT(!src2.is(rdx));
1580 ASSERT(!src1.is(rdx));
1581 ASSERT(!src1.is(src2));
1582
1583 testq(src2, src2);
1584 j(zero, on_not_smi_result);
1585
1586 if (src1.is(rax)) {
1587 movq(kScratchRegister, src1);
1588 }
1589 SmiToInteger32(rax, src1);
1590 SmiToInteger32(src2, src2);
1591
1592 // Test for the edge case of dividing Smi::kMinValue by -1 (will overflow).
1593 NearLabel safe_div;
1594 cmpl(rax, Immediate(Smi::kMinValue));
1595 j(not_equal, &safe_div);
1596 cmpl(src2, Immediate(-1));
1597 j(not_equal, &safe_div);
1598 // Retag inputs and go slow case.
1599 Integer32ToSmi(src2, src2);
1600 if (src1.is(rax)) {
1601 movq(src1, kScratchRegister);
1602 }
1603 jmp(on_not_smi_result);
1604 bind(&safe_div);
1605
1606 // Sign extend eax into edx:eax.
1607 cdq();
1608 idivl(src2);
1609 // Restore smi tags on inputs.
1610 Integer32ToSmi(src2, src2);
1611 if (src1.is(rax)) {
1612 movq(src1, kScratchRegister);
1613 }
1614 // Check for a negative zero result. If the result is zero, and the
1615 // dividend is negative, go slow to return a floating point negative zero.
1616 NearLabel smi_result;
1617 testl(rdx, rdx);
1618 j(not_zero, &smi_result);
1619 testq(src1, src1);
1620 j(negative, on_not_smi_result);
1621 bind(&smi_result);
1622 Integer32ToSmi(dst, rdx);
1623}
1624
1625
1626template <typename LabelType>
1627void MacroAssembler::SmiShiftLogicalRightConstant(
1628 Register dst, Register src, int shift_value, LabelType* on_not_smi_result) {
1629 // Logic right shift interprets its result as an *unsigned* number.
1630 if (dst.is(src)) {
1631 UNIMPLEMENTED(); // Not used.
1632 } else {
1633 movq(dst, src);
1634 if (shift_value == 0) {
1635 testq(dst, dst);
1636 j(negative, on_not_smi_result);
1637 }
1638 shr(dst, Immediate(shift_value + kSmiShift));
1639 shl(dst, Immediate(kSmiShift));
1640 }
1641}
1642
1643
1644template <typename LabelType>
1645void MacroAssembler::SmiShiftLogicalRight(Register dst,
1646 Register src1,
1647 Register src2,
1648 LabelType* on_not_smi_result) {
1649 ASSERT(!dst.is(kScratchRegister));
1650 ASSERT(!src1.is(kScratchRegister));
1651 ASSERT(!src2.is(kScratchRegister));
1652 ASSERT(!dst.is(rcx));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001653 // dst and src1 can be the same, because the one case that bails out
1654 // is a shift by 0, which leaves dst, and therefore src1, unchanged.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001655 NearLabel result_ok;
1656 if (src1.is(rcx) || src2.is(rcx)) {
1657 movq(kScratchRegister, rcx);
1658 }
1659 if (!dst.is(src1)) {
1660 movq(dst, src1);
1661 }
1662 SmiToInteger32(rcx, src2);
1663 orl(rcx, Immediate(kSmiShift));
1664 shr_cl(dst); // Shift is rcx modulo 0x1f + 32.
1665 shl(dst, Immediate(kSmiShift));
1666 testq(dst, dst);
1667 if (src1.is(rcx) || src2.is(rcx)) {
1668 NearLabel positive_result;
1669 j(positive, &positive_result);
1670 if (src1.is(rcx)) {
1671 movq(src1, kScratchRegister);
1672 } else {
1673 movq(src2, kScratchRegister);
1674 }
1675 jmp(on_not_smi_result);
1676 bind(&positive_result);
1677 } else {
1678 j(negative, on_not_smi_result); // src2 was zero and src1 negative.
1679 }
1680}
1681
1682
1683template <typename LabelType>
1684void MacroAssembler::SelectNonSmi(Register dst,
1685 Register src1,
1686 Register src2,
1687 LabelType* on_not_smis) {
1688 ASSERT(!dst.is(kScratchRegister));
1689 ASSERT(!src1.is(kScratchRegister));
1690 ASSERT(!src2.is(kScratchRegister));
1691 ASSERT(!dst.is(src1));
1692 ASSERT(!dst.is(src2));
1693 // Both operands must not be smis.
1694#ifdef DEBUG
1695 if (allow_stub_calls()) { // Check contains a stub call.
1696 Condition not_both_smis = NegateCondition(CheckBothSmi(src1, src2));
1697 Check(not_both_smis, "Both registers were smis in SelectNonSmi.");
1698 }
1699#endif
1700 ASSERT_EQ(0, kSmiTag);
1701 ASSERT_EQ(0, Smi::FromInt(0));
1702 movl(kScratchRegister, Immediate(kSmiTagMask));
1703 and_(kScratchRegister, src1);
1704 testl(kScratchRegister, src2);
1705 // If non-zero then both are smis.
1706 j(not_zero, on_not_smis);
1707
1708 // Exactly one operand is a smi.
1709 ASSERT_EQ(1, static_cast<int>(kSmiTagMask));
1710 // kScratchRegister still holds src1 & kSmiTag, which is either zero or one.
1711 subq(kScratchRegister, Immediate(1));
1712 // If src1 is a smi, then scratch register all 1s, else it is all 0s.
1713 movq(dst, src1);
1714 xor_(dst, src2);
1715 and_(dst, kScratchRegister);
1716 // If src1 is a smi, dst holds src1 ^ src2, else it is zero.
1717 xor_(dst, src1);
1718 // If src1 is a smi, dst is src2, else it is src1, i.e., the non-smi.
1719}
1720
1721
1722template <typename LabelType>
1723void MacroAssembler::JumpIfSmi(Register src, LabelType* on_smi) {
1724 ASSERT_EQ(0, kSmiTag);
1725 Condition smi = CheckSmi(src);
1726 j(smi, on_smi);
1727}
1728
1729
1730template <typename LabelType>
1731void MacroAssembler::JumpIfNotSmi(Register src, LabelType* on_not_smi) {
1732 Condition smi = CheckSmi(src);
1733 j(NegateCondition(smi), on_not_smi);
1734}
1735
1736
1737template <typename LabelType>
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00001738void MacroAssembler::JumpUnlessNonNegativeSmi(
1739 Register src, LabelType* on_not_smi_or_negative) {
1740 Condition non_negative_smi = CheckNonNegativeSmi(src);
1741 j(NegateCondition(non_negative_smi), on_not_smi_or_negative);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001742}
1743
1744
1745template <typename LabelType>
1746void MacroAssembler::JumpIfSmiEqualsConstant(Register src,
1747 Smi* constant,
1748 LabelType* on_equals) {
1749 SmiCompare(src, constant);
1750 j(equal, on_equals);
1751}
1752
1753
1754template <typename LabelType>
1755void MacroAssembler::JumpIfNotValidSmiValue(Register src,
1756 LabelType* on_invalid) {
1757 Condition is_valid = CheckInteger32ValidSmiValue(src);
1758 j(NegateCondition(is_valid), on_invalid);
1759}
1760
1761
1762template <typename LabelType>
1763void MacroAssembler::JumpIfUIntNotValidSmiValue(Register src,
1764 LabelType* on_invalid) {
1765 Condition is_valid = CheckUInteger32ValidSmiValue(src);
1766 j(NegateCondition(is_valid), on_invalid);
1767}
1768
1769
1770template <typename LabelType>
1771void MacroAssembler::JumpIfNotBothSmi(Register src1,
1772 Register src2,
1773 LabelType* on_not_both_smi) {
1774 Condition both_smi = CheckBothSmi(src1, src2);
1775 j(NegateCondition(both_smi), on_not_both_smi);
1776}
1777
1778
1779template <typename LabelType>
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00001780void MacroAssembler::JumpUnlessBothNonNegativeSmi(Register src1,
1781 Register src2,
1782 LabelType* on_not_both_smi) {
1783 Condition both_smi = CheckBothNonNegativeSmi(src1, src2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001784 j(NegateCondition(both_smi), on_not_both_smi);
1785}
1786
1787
1788template <typename LabelType>
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001789void MacroAssembler::SmiOrIfSmis(Register dst, Register src1, Register src2,
1790 LabelType* on_not_smis) {
1791 if (dst.is(src1) || dst.is(src2)) {
1792 ASSERT(!src1.is(kScratchRegister));
1793 ASSERT(!src2.is(kScratchRegister));
1794 movq(kScratchRegister, src1);
1795 or_(kScratchRegister, src2);
1796 JumpIfNotSmi(kScratchRegister, on_not_smis);
1797 movq(dst, kScratchRegister);
1798 } else {
1799 movq(dst, src1);
1800 or_(dst, src2);
1801 JumpIfNotSmi(dst, on_not_smis);
1802 }
1803}
1804
1805
1806template <typename LabelType>
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001807void MacroAssembler::JumpIfNotString(Register object,
1808 Register object_map,
1809 LabelType* not_string) {
1810 Condition is_smi = CheckSmi(object);
1811 j(is_smi, not_string);
1812 CmpObjectType(object, FIRST_NONSTRING_TYPE, object_map);
1813 j(above_equal, not_string);
1814}
1815
1816
1817template <typename LabelType>
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001818void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register first_object,
1819 Register second_object,
1820 Register scratch1,
1821 Register scratch2,
1822 LabelType* on_fail) {
1823 // Check that both objects are not smis.
1824 Condition either_smi = CheckEitherSmi(first_object, second_object);
1825 j(either_smi, on_fail);
1826
1827 // Load instance type for both strings.
1828 movq(scratch1, FieldOperand(first_object, HeapObject::kMapOffset));
1829 movq(scratch2, FieldOperand(second_object, HeapObject::kMapOffset));
1830 movzxbl(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset));
1831 movzxbl(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset));
1832
1833 // Check that both are flat ascii strings.
1834 ASSERT(kNotStringTag != 0);
1835 const int kFlatAsciiStringMask =
1836 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
1837 const int kFlatAsciiStringTag = ASCII_STRING_TYPE;
1838
1839 andl(scratch1, Immediate(kFlatAsciiStringMask));
1840 andl(scratch2, Immediate(kFlatAsciiStringMask));
1841 // Interleave the bits to check both scratch1 and scratch2 in one test.
1842 ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
1843 lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
1844 cmpl(scratch1,
1845 Immediate(kFlatAsciiStringTag + (kFlatAsciiStringTag << 3)));
1846 j(not_equal, on_fail);
1847}
1848
1849
1850template <typename LabelType>
1851void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii(
1852 Register instance_type,
1853 Register scratch,
1854 LabelType *failure) {
1855 if (!scratch.is(instance_type)) {
1856 movl(scratch, instance_type);
1857 }
1858
1859 const int kFlatAsciiStringMask =
1860 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
1861
1862 andl(scratch, Immediate(kFlatAsciiStringMask));
1863 cmpl(scratch, Immediate(kStringTag | kSeqStringTag | kAsciiStringTag));
1864 j(not_equal, failure);
1865}
1866
1867
1868template <typename LabelType>
1869void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialAscii(
1870 Register first_object_instance_type,
1871 Register second_object_instance_type,
1872 Register scratch1,
1873 Register scratch2,
1874 LabelType* on_fail) {
1875 // Load instance type for both strings.
1876 movq(scratch1, first_object_instance_type);
1877 movq(scratch2, second_object_instance_type);
1878
1879 // Check that both are flat ascii strings.
1880 ASSERT(kNotStringTag != 0);
1881 const int kFlatAsciiStringMask =
1882 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
1883 const int kFlatAsciiStringTag = ASCII_STRING_TYPE;
1884
1885 andl(scratch1, Immediate(kFlatAsciiStringMask));
1886 andl(scratch2, Immediate(kFlatAsciiStringMask));
1887 // Interleave the bits to check both scratch1 and scratch2 in one test.
1888 ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
1889 lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
1890 cmpl(scratch1,
1891 Immediate(kFlatAsciiStringTag + (kFlatAsciiStringTag << 3)));
1892 j(not_equal, on_fail);
1893}
1894
1895
1896template <typename LabelType>
1897void MacroAssembler::InNewSpace(Register object,
1898 Register scratch,
1899 Condition cc,
1900 LabelType* branch) {
1901 if (Serializer::enabled()) {
1902 // Can't do arithmetic on external references if it might get serialized.
1903 // The mask isn't really an address. We load it as an external reference in
1904 // case the size of the new space is different between the snapshot maker
1905 // and the running system.
1906 if (scratch.is(object)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001907 movq(kScratchRegister, ExternalReference::new_space_mask(isolate()));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001908 and_(scratch, kScratchRegister);
1909 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001910 movq(scratch, ExternalReference::new_space_mask(isolate()));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001911 and_(scratch, object);
1912 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001913 movq(kScratchRegister, ExternalReference::new_space_start(isolate()));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001914 cmpq(scratch, kScratchRegister);
1915 j(cc, branch);
1916 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001917 ASSERT(is_int32(static_cast<int64_t>(HEAP->NewSpaceMask())));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001918 intptr_t new_space_start =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001919 reinterpret_cast<intptr_t>(HEAP->NewSpaceStart());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001920 movq(kScratchRegister, -new_space_start, RelocInfo::NONE);
1921 if (scratch.is(object)) {
1922 addq(scratch, kScratchRegister);
1923 } else {
1924 lea(scratch, Operand(object, kScratchRegister, times_1, 0));
1925 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001926 and_(scratch, Immediate(static_cast<int32_t>(HEAP->NewSpaceMask())));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001927 j(cc, branch);
1928 }
1929}
1930
1931
1932template <typename LabelType>
1933void MacroAssembler::InvokePrologue(const ParameterCount& expected,
1934 const ParameterCount& actual,
1935 Handle<Code> code_constant,
1936 Register code_register,
1937 LabelType* done,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001938 InvokeFlag flag,
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001939 const CallWrapper& call_wrapper) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001940 bool definitely_matches = false;
1941 NearLabel invoke;
1942 if (expected.is_immediate()) {
1943 ASSERT(actual.is_immediate());
1944 if (expected.immediate() == actual.immediate()) {
1945 definitely_matches = true;
1946 } else {
1947 Set(rax, actual.immediate());
1948 if (expected.immediate() ==
1949 SharedFunctionInfo::kDontAdaptArgumentsSentinel) {
1950 // Don't worry about adapting arguments for built-ins that
1951 // don't want that done. Skip adaption code by making it look
1952 // like we have a match between expected and actual number of
1953 // arguments.
1954 definitely_matches = true;
1955 } else {
1956 Set(rbx, expected.immediate());
1957 }
1958 }
1959 } else {
1960 if (actual.is_immediate()) {
1961 // Expected is in register, actual is immediate. This is the
1962 // case when we invoke function values without going through the
1963 // IC mechanism.
1964 cmpq(expected.reg(), Immediate(actual.immediate()));
1965 j(equal, &invoke);
1966 ASSERT(expected.reg().is(rbx));
1967 Set(rax, actual.immediate());
1968 } else if (!expected.reg().is(actual.reg())) {
1969 // Both expected and actual are in (different) registers. This
1970 // is the case when we invoke functions using call and apply.
1971 cmpq(expected.reg(), actual.reg());
1972 j(equal, &invoke);
1973 ASSERT(actual.reg().is(rax));
1974 ASSERT(expected.reg().is(rbx));
1975 }
1976 }
1977
1978 if (!definitely_matches) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001979 Handle<Code> adaptor = isolate()->builtins()->ArgumentsAdaptorTrampoline();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001980 if (!code_constant.is_null()) {
1981 movq(rdx, code_constant, RelocInfo::EMBEDDED_OBJECT);
1982 addq(rdx, Immediate(Code::kHeaderSize - kHeapObjectTag));
1983 } else if (!code_register.is(rdx)) {
1984 movq(rdx, code_register);
1985 }
1986
1987 if (flag == CALL_FUNCTION) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001988 call_wrapper.BeforeCall(CallSize(adaptor));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001989 Call(adaptor, RelocInfo::CODE_TARGET);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001990 call_wrapper.AfterCall();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001991 jmp(done);
1992 } else {
1993 Jump(adaptor, RelocInfo::CODE_TARGET);
1994 }
1995 bind(&invoke);
1996 }
1997}
1998
ager@chromium.org9085a012009-05-11 19:22:57 +00001999
2000} } // namespace v8::internal
2001
2002#endif // V8_X64_MACRO_ASSEMBLER_X64_H_