blob: a6d782e44d92b52c9a985493d6ecbde03331311b [file] [log] [blame]
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
ager@chromium.org5ec48922009-05-05 07:25:34 +000028#ifndef V8_IA32_MACRO_ASSEMBLER_IA32_H_
29#define V8_IA32_MACRO_ASSEMBLER_IA32_H_
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000030
31#include "assembler.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000032#include "frames.h"
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000033#include "v8globals.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000034
kasperl@chromium.org71affb52009-05-26 05:44:31 +000035namespace v8 {
36namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000038// Convenience for platform-independent signatures. We do not normally
39// distinguish memory operands from other operands on ia32.
40typedef Operand MemOperand;
41
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000042enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET };
43enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
44
45
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +000046enum RegisterValueType {
47 REGISTER_VALUE_IS_SMI,
48 REGISTER_VALUE_IS_INT32
49};
50
51
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000052bool AreAliased(Register r1, Register r2, Register r3, Register r4);
53
54
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055// MacroAssembler implements a collection of frequently used macros.
56class MacroAssembler: public Assembler {
57 public:
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000058 // The isolate parameter can be NULL if the macro assembler should
59 // not use isolate-dependent functionality. In this case, it's the
60 // responsibility of the caller to never invoke such function on the
61 // macro assembler.
62 MacroAssembler(Isolate* isolate, void* buffer, int size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
danno@chromium.org59400602013-08-13 17:09:37 +000064 // Operations on roots in the root-array.
65 void LoadRoot(Register destination, Heap::RootListIndex index);
66 void StoreRoot(Register source, Register scratch, Heap::RootListIndex index);
67 void CompareRoot(Register with, Register scratch, Heap::RootListIndex index);
68 // These methods can only be used with constant roots (i.e. non-writable
69 // and not in new space).
70 void CompareRoot(Register with, Heap::RootListIndex index);
71 void CompareRoot(const Operand& with, Heap::RootListIndex index);
72
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073 // ---------------------------------------------------------------------------
74 // GC Support
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000075 enum RememberedSetFinalAction {
76 kReturnAtEnd,
77 kFallThroughAtEnd
78 };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000079
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000080 // Record in the remembered set the fact that we have a pointer to new space
81 // at the address pointed to by the addr register. Only works if addr is not
82 // in new space.
83 void RememberedSetHelper(Register object, // Used for debug code.
84 Register addr,
85 Register scratch,
86 SaveFPRegsMode save_fp,
87 RememberedSetFinalAction and_then);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000088
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000089 void CheckPageFlag(Register object,
90 Register scratch,
91 int mask,
92 Condition cc,
93 Label* condition_met,
94 Label::Distance condition_met_distance = Label::kFar);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000095
mmassi@chromium.org7028c052012-06-13 11:51:58 +000096 void CheckPageFlagForMap(
97 Handle<Map> map,
98 int mask,
99 Condition cc,
100 Label* condition_met,
101 Label::Distance condition_met_distance = Label::kFar);
102
danno@chromium.orgf005df62013-04-30 16:36:45 +0000103 void CheckMapDeprecated(Handle<Map> map,
104 Register scratch,
105 Label* if_deprecated);
106
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000107 // Check if object is in new space. Jumps if the object is not in new space.
108 // The register scratch can be object itself, but scratch will be clobbered.
109 void JumpIfNotInNewSpace(Register object,
110 Register scratch,
111 Label* branch,
112 Label::Distance distance = Label::kFar) {
113 InNewSpace(object, scratch, zero, branch, distance);
114 }
115
116 // Check if object is in new space. Jumps if the object is in new space.
117 // The register scratch can be object itself, but it will be clobbered.
118 void JumpIfInNewSpace(Register object,
119 Register scratch,
120 Label* branch,
121 Label::Distance distance = Label::kFar) {
122 InNewSpace(object, scratch, not_zero, branch, distance);
123 }
124
125 // Check if an object has a given incremental marking color. Also uses ecx!
126 void HasColor(Register object,
127 Register scratch0,
128 Register scratch1,
129 Label* has_color,
130 Label::Distance has_color_distance,
131 int first_bit,
132 int second_bit);
133
134 void JumpIfBlack(Register object,
135 Register scratch0,
136 Register scratch1,
137 Label* on_black,
138 Label::Distance on_black_distance = Label::kFar);
139
140 // Checks the color of an object. If the object is already grey or black
141 // then we just fall through, since it is already live. If it is white and
142 // we can determine that it doesn't need to be scanned, then we just mark it
143 // black and fall through. For the rest we jump to the label so the
144 // incremental marker can fix its assumptions.
145 void EnsureNotWhite(Register object,
146 Register scratch1,
147 Register scratch2,
148 Label* object_is_white_and_not_data,
149 Label::Distance distance);
150
151 // Notify the garbage collector that we wrote a pointer into an object.
152 // |object| is the object being stored into, |value| is the object being
153 // stored. value and scratch registers are clobbered by the operation.
154 // The offset is the offset from the start of the object, not the offset from
155 // the tagged HeapObject pointer. For use with FieldOperand(reg, off).
156 void RecordWriteField(
157 Register object,
158 int offset,
159 Register value,
160 Register scratch,
161 SaveFPRegsMode save_fp,
162 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
163 SmiCheck smi_check = INLINE_SMI_CHECK);
164
165 // As above, but the offset has the tag presubtracted. For use with
166 // Operand(reg, off).
167 void RecordWriteContextSlot(
168 Register context,
169 int offset,
170 Register value,
171 Register scratch,
172 SaveFPRegsMode save_fp,
173 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
174 SmiCheck smi_check = INLINE_SMI_CHECK) {
175 RecordWriteField(context,
176 offset + kHeapObjectTag,
177 value,
178 scratch,
179 save_fp,
180 remembered_set_action,
181 smi_check);
182 }
183
184 // Notify the garbage collector that we wrote a pointer into a fixed array.
185 // |array| is the array being stored into, |value| is the
186 // object being stored. |index| is the array index represented as a
187 // Smi. All registers are clobbered by the operation RecordWriteArray
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000188 // filters out smis so it does not update the write barrier if the
189 // value is a smi.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000190 void RecordWriteArray(
191 Register array,
192 Register value,
193 Register index,
194 SaveFPRegsMode save_fp,
195 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
196 SmiCheck smi_check = INLINE_SMI_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000197
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000198 // For page containing |object| mark region covering |address|
199 // dirty. |object| is the object being stored into, |value| is the
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000200 // object being stored. The address and value registers are clobbered by the
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000201 // operation. RecordWrite filters out smis so it does not update the
202 // write barrier if the value is a smi.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000203 void RecordWrite(
204 Register object,
205 Register address,
206 Register value,
207 SaveFPRegsMode save_fp,
208 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
209 SmiCheck smi_check = INLINE_SMI_CHECK);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000210
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000211 // For page containing |object| mark the region covering the object's map
212 // dirty. |object| is the object being stored into, |map| is the Map object
213 // that was stored.
214 void RecordWriteForMap(
215 Register object,
216 Handle<Map> map,
217 Register scratch1,
218 Register scratch2,
219 SaveFPRegsMode save_fp);
220
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000221#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222 // ---------------------------------------------------------------------------
223 // Debugger Support
224
ager@chromium.org5c838252010-02-19 08:53:10 +0000225 void DebugBreak();
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000226#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000227
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000228 // Enter specific kind of exit frame. Expects the number of
229 // arguments in register eax and sets up the number of arguments in
230 // register edi and the pointer to the first argument in register
231 // esi.
232 void EnterExitFrame(bool save_doubles);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000233
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000234 void EnterApiExitFrame(int argc);
ager@chromium.org236ad962008-09-25 09:45:57 +0000235
236 // Leave the current exit frame. Expects the return value in
237 // register eax:edx (untouched) and the pointer to the first
238 // argument in register esi.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000239 void LeaveExitFrame(bool save_doubles);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000240
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000241 // Leave the current exit frame. Expects the return value in
242 // register eax (untouched).
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000243 void LeaveApiExitFrame(bool restore_context);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000244
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000245 // Find the function context up the context chain.
246 void LoadContext(Register dst, int context_chain_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000247
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +0000248 // Conditionally load the cached Array transitioned map of type
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000249 // transitioned_kind from the native context if the map in register
250 // map_in_out is the cached Array map in the native context of
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +0000251 // expected_kind.
252 void LoadTransitionedArrayMapConditional(
253 ElementsKind expected_kind,
254 ElementsKind transitioned_kind,
255 Register map_in_out,
256 Register scratch,
257 Label* no_map_match);
258
259 // Load the initial map for new Arrays from a JSFunction.
260 void LoadInitialArrayMap(Register function_in,
261 Register scratch,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000262 Register map_out,
263 bool can_have_holes);
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000264
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000265 void LoadGlobalContext(Register global_context);
266
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000267 // Load the global function with the given index.
268 void LoadGlobalFunction(int index, Register function);
269
270 // Load the initial map from the global function. The registers
271 // function and map can be the same.
272 void LoadGlobalFunctionInitialMap(Register function, Register map);
273
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000274 // Push and pop the registers that can hold pointers.
275 void PushSafepointRegisters() { pushad(); }
276 void PopSafepointRegisters() { popad(); }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000277 // Store the value in register/immediate src in the safepoint
278 // register stack slot for register dst.
279 void StoreToSafepointRegisterSlot(Register dst, Register src);
280 void StoreToSafepointRegisterSlot(Register dst, Immediate src);
281 void LoadFromSafepointRegisterSlot(Register dst, Register src);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000282
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000283 void LoadHeapObject(Register result, Handle<HeapObject> object);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000284 void CmpHeapObject(Register reg, Handle<HeapObject> object);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000285 void PushHeapObject(Handle<HeapObject> object);
286
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000287 void LoadObject(Register result, Handle<Object> object) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000288 AllowDeferredHandleDereference heap_object_check;
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000289 if (object->IsHeapObject()) {
290 LoadHeapObject(result, Handle<HeapObject>::cast(object));
291 } else {
292 Set(result, Immediate(object));
293 }
294 }
295
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000296 void CmpObject(Register reg, Handle<Object> object) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000297 AllowDeferredHandleDereference heap_object_check;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000298 if (object->IsHeapObject()) {
299 CmpHeapObject(reg, Handle<HeapObject>::cast(object));
300 } else {
301 cmp(reg, Immediate(object));
302 }
303 }
304
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000305 // ---------------------------------------------------------------------------
306 // JavaScript invokes
307
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000308 // Set up call kind marking in ecx. The method takes ecx as an
danno@chromium.org40cb8782011-05-25 07:58:50 +0000309 // explicit first parameter to make the code more readable at the
310 // call sites.
311 void SetCallKind(Register dst, CallKind kind);
312
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000313 // Invoke the JavaScript function code by either calling or jumping.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000314 void InvokeCode(Register code,
315 const ParameterCount& expected,
316 const ParameterCount& actual,
317 InvokeFlag flag,
318 const CallWrapper& call_wrapper,
319 CallKind call_kind) {
320 InvokeCode(Operand(code), expected, actual, flag, call_wrapper, call_kind);
321 }
322
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000323 void InvokeCode(const Operand& code,
324 const ParameterCount& expected,
325 const ParameterCount& actual,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000326 InvokeFlag flag,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000327 const CallWrapper& call_wrapper,
328 CallKind call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000329
330 void InvokeCode(Handle<Code> code,
331 const ParameterCount& expected,
332 const ParameterCount& actual,
ager@chromium.org236ad962008-09-25 09:45:57 +0000333 RelocInfo::Mode rmode,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000334 InvokeFlag flag,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000335 const CallWrapper& call_wrapper,
336 CallKind call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000337
338 // Invoke the JavaScript function in the given register. Changes the
339 // current context to the context in the function before invoking.
340 void InvokeFunction(Register function,
341 const ParameterCount& actual,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000342 InvokeFlag flag,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000343 const CallWrapper& call_wrapper,
344 CallKind call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000346 void InvokeFunction(Handle<JSFunction> function,
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000347 const ParameterCount& expected,
ager@chromium.org5c838252010-02-19 08:53:10 +0000348 const ParameterCount& actual,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000349 InvokeFlag flag,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000350 const CallWrapper& call_wrapper,
351 CallKind call_kind);
ager@chromium.org5c838252010-02-19 08:53:10 +0000352
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000353 // Invoke specified builtin JavaScript function. Adds an entry to
354 // the unresolved list if the name does not resolve.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000355 void InvokeBuiltin(Builtins::JavaScript id,
356 InvokeFlag flag,
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +0000357 const CallWrapper& call_wrapper = NullCallWrapper());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000358
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000359 // Store the function for the given builtin in the target register.
360 void GetBuiltinFunction(Register target, Builtins::JavaScript id);
361
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362 // Store the code object for the given builtin in the target register.
363 void GetBuiltinEntry(Register target, Builtins::JavaScript id);
364
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000365 // Expression support
366 void Set(Register dst, const Immediate& x);
367 void Set(const Operand& dst, const Immediate& x);
368
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000369 // cvtsi2sd instruction only writes to the low 64-bit of dst register, which
370 // hinders register renaming and makes dependence chains longer. So we use
371 // xorps to clear the dst register before cvtsi2sd to solve this issue.
372 void Cvtsi2sd(XMMRegister dst, Register src) { Cvtsi2sd(dst, Operand(src)); }
373 void Cvtsi2sd(XMMRegister dst, const Operand& src);
374
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000375 // Support for constant splitting.
376 bool IsUnsafeImmediate(const Immediate& x);
377 void SafeSet(Register dst, const Immediate& x);
378 void SafePush(const Immediate& x);
379
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000380 // Compare object type for heap object.
381 // Incoming register is heap_object and outgoing register is map.
382 void CmpObjectType(Register heap_object, InstanceType type, Register map);
383
384 // Compare instance type for map.
385 void CmpInstanceType(Register map, InstanceType type);
386
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000387 // Check if a map for a JSObject indicates that the object has fast elements.
388 // Jump to the specified label if it does not.
389 void CheckFastElements(Register map,
390 Label* fail,
391 Label::Distance distance = Label::kFar);
392
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000393 // Check if a map for a JSObject indicates that the object can have both smi
394 // and HeapObject elements. Jump to the specified label if it does not.
395 void CheckFastObjectElements(Register map,
396 Label* fail,
397 Label::Distance distance = Label::kFar);
398
399 // Check if a map for a JSObject indicates that the object has fast smi only
400 // elements. Jump to the specified label if it does not.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000401 void CheckFastSmiElements(Register map,
402 Label* fail,
403 Label::Distance distance = Label::kFar);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000404
405 // Check to see if maybe_number can be stored as a double in
406 // FastDoubleElements. If it can, store it at the index specified by key in
407 // the FastDoubleElements array elements, otherwise jump to fail.
408 void StoreNumberToDoubleElements(Register maybe_number,
409 Register elements,
410 Register key,
411 Register scratch1,
412 XMMRegister scratch2,
413 Label* fail,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000414 bool specialize_for_processor,
415 int offset = 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000416
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000417 // Compare an object's map with the specified map and its transitioned
418 // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. FLAGS are set with
419 // result of map compare. If multiple map compares are required, the compare
420 // sequences branches to early_success.
421 void CompareMap(Register obj,
422 Handle<Map> map,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000423 Label* early_success);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000424
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000425 // Check if the map of an object is equal to a specified map and branch to
426 // label if not. Skip the smi check if not required (object is known to be a
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000427 // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000428 // against maps that are ElementsKind transition maps of the specified map.
ager@chromium.org5c838252010-02-19 08:53:10 +0000429 void CheckMap(Register obj,
430 Handle<Map> map,
431 Label* fail,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000432 SmiCheckType smi_check_type);
ager@chromium.org5c838252010-02-19 08:53:10 +0000433
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000434 // Check if the map of an object is equal to a specified map and branch to a
435 // specified target if equal. Skip the smi check if not required (object is
436 // known to be a heap object)
437 void DispatchMap(Register obj,
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000438 Register unused,
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000439 Handle<Map> map,
440 Handle<Code> success,
441 SmiCheckType smi_check_type);
442
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000443 // Check if the object in register heap_object is a string. Afterwards the
444 // register map contains the object map and the register instance_type
445 // contains the instance_type. The registers map and instance_type can be the
446 // same in which case it contains the instance type afterwards. Either of the
447 // registers map and instance_type can be the same as heap_object.
448 Condition IsObjectStringType(Register heap_object,
449 Register map,
450 Register instance_type);
451
ulan@chromium.org750145a2013-03-07 15:14:13 +0000452 // Check if the object in register heap_object is a name. Afterwards the
453 // register map contains the object map and the register instance_type
454 // contains the instance_type. The registers map and instance_type can be the
455 // same in which case it contains the instance type afterwards. Either of the
456 // registers map and instance_type can be the same as heap_object.
457 Condition IsObjectNameType(Register heap_object,
458 Register map,
459 Register instance_type);
460
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000461 // Check if a heap object's type is in the JSObject range, not including
462 // JSFunction. The object's map will be loaded in the map register.
463 // Any or all of the three registers may be the same.
464 // The contents of the scratch register will always be overwritten.
465 void IsObjectJSObjectType(Register heap_object,
466 Register map,
467 Register scratch,
468 Label* fail);
469
470 // The contents of the scratch register will be overwritten.
471 void IsInstanceJSObjectType(Register map, Register scratch, Label* fail);
472
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000473 // FCmp is similar to integer cmp, but requires unsigned
474 // jcc instructions (je, ja, jae, jb, jbe, je, and jz).
475 void FCmp();
476
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000477 void ClampUint8(Register reg);
478
479 void ClampDoubleToUint8(XMMRegister input_reg,
480 XMMRegister scratch_reg,
481 Register result_reg);
482
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000483 void SlowTruncateToI(Register result_reg, Register input_reg,
484 int offset = HeapNumber::kValueOffset - kHeapObjectTag);
485
486 void TruncateHeapNumberToI(Register result_reg, Register input_reg);
487 void TruncateDoubleToI(Register result_reg, XMMRegister input_reg);
488 void TruncateX87TOSToI(Register result_reg);
489
490 void DoubleToI(Register result_reg, XMMRegister input_reg,
491 XMMRegister scratch, MinusZeroMode minus_zero_mode,
492 Label* conversion_failed, Label::Distance dst = Label::kFar);
493 void X87TOSToI(Register result_reg, MinusZeroMode minus_zero_mode,
494 Label* conversion_failed, Label::Distance dst = Label::kFar);
495
496 void TaggedToI(Register result_reg, Register input_reg, XMMRegister temp,
497 MinusZeroMode minus_zero_mode, Label* lost_precision);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000498
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000499 // Smi tagging support.
500 void SmiTag(Register reg) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000501 STATIC_ASSERT(kSmiTag == 0);
502 STATIC_ASSERT(kSmiTagSize == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000503 add(reg, reg);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000504 }
505 void SmiUntag(Register reg) {
506 sar(reg, kSmiTagSize);
507 }
508
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000509 // Modifies the register even if it does not contain a Smi!
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000510 void SmiUntag(Register reg, Label* is_smi) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000511 STATIC_ASSERT(kSmiTagSize == 1);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000512 sar(reg, kSmiTagSize);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000513 STATIC_ASSERT(kSmiTag == 0);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000514 j(not_carry, is_smi);
515 }
516
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000517 void LoadUint32(XMMRegister dst, Register src, XMMRegister scratch);
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +0000518 void LoadUint32NoSSE2(Register src);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000519
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000520 // Jump the register contains a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000521 inline void JumpIfSmi(Register value,
522 Label* smi_label,
523 Label::Distance distance = Label::kFar) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000524 test(value, Immediate(kSmiTagMask));
whesse@chromium.org7b260152011-06-20 15:33:18 +0000525 j(zero, smi_label, distance);
526 }
527 // Jump if the operand is a smi.
528 inline void JumpIfSmi(Operand value,
529 Label* smi_label,
530 Label::Distance distance = Label::kFar) {
531 test(value, Immediate(kSmiTagMask));
532 j(zero, smi_label, distance);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000533 }
534 // Jump if register contain a non-smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000535 inline void JumpIfNotSmi(Register value,
536 Label* not_smi_label,
537 Label::Distance distance = Label::kFar) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000538 test(value, Immediate(kSmiTagMask));
whesse@chromium.org7b260152011-06-20 15:33:18 +0000539 j(not_zero, not_smi_label, distance);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000540 }
541
danno@chromium.org40cb8782011-05-25 07:58:50 +0000542 void LoadInstanceDescriptors(Register map, Register descriptors);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000543 void EnumLength(Register dst, Register map);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +0000544 void NumberOfOwnDescriptors(Register dst, Register map);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000545
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000546 template<typename Field>
547 void DecodeField(Register reg) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +0000548 static const int shift = Field::kShift;
549 static const int mask = (Field::kMask >> Field::kShift) << kSmiTagSize;
550 sar(reg, shift);
551 and_(reg, Immediate(mask));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000552 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000553 void LoadPowerOf2(XMMRegister dst, Register scratch, int power);
554
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000555 // Abort execution if argument is not a number, enabled via --debug-code.
556 void AssertNumber(Register object);
ager@chromium.org5c838252010-02-19 08:53:10 +0000557
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000558 // Abort execution if argument is not a smi, enabled via --debug-code.
559 void AssertSmi(Register object);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000560
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000561 // Abort execution if argument is a smi, enabled via --debug-code.
562 void AssertNotSmi(Register object);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000563
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000564 // Abort execution if argument is not a string, enabled via --debug-code.
565 void AssertString(Register object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000566
ulan@chromium.org750145a2013-03-07 15:14:13 +0000567 // Abort execution if argument is not a name, enabled via --debug-code.
568 void AssertName(Register object);
569
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000570 // ---------------------------------------------------------------------------
571 // Exception handling
572
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000573 // Push a new try handler and link it into try handler chain.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000574 void PushTryHandler(StackHandler::Kind kind, int handler_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000575
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000576 // Unlink the stack handler on top of the stack from the try handler chain.
577 void PopTryHandler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000578
ulan@chromium.org65a89c22012-02-14 11:46:07 +0000579 // Throw to the top handler in the try hander chain.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000580 void Throw(Register value);
581
ulan@chromium.org65a89c22012-02-14 11:46:07 +0000582 // Throw past all JS frames to the top JS entry frame.
583 void ThrowUncatchable(Register value);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000584
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000585 // ---------------------------------------------------------------------------
586 // Inline caching support
587
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000588 // Generate code for checking access rights - used for security checks
589 // on access to global objects across environments. The holder register
590 // is left untouched, but the scratch register is clobbered.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000591 void CheckAccessGlobalProxy(Register holder_reg,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000592 Register scratch1,
593 Register scratch2,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000594 Label* miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000595
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000596 void GetNumberHash(Register r0, Register scratch);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000597
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000598 void LoadFromNumberDictionary(Label* miss,
599 Register elements,
600 Register key,
601 Register r0,
602 Register r1,
603 Register r2,
604 Register result);
605
606
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000607 // ---------------------------------------------------------------------------
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000608 // Allocation support
609
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000610 // Allocate an object in new space or old pointer space. If the given space
611 // is exhausted control continues at the gc_required label. The allocated
612 // object is returned in result and end of the new object is returned in
613 // result_end. The register scratch can be passed as no_reg in which case
614 // an additional object reference will be added to the reloc info. The
615 // returned pointers in result and result_end have not yet been tagged as
616 // heap objects. If result_contains_top_on_entry is true the content of
617 // result is known to be the allocation top on entry (could be result_end
618 // from a previous call). If result_contains_top_on_entry is true scratch
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000619 // should be no_reg as it is never used.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000620 void Allocate(int object_size,
621 Register result,
622 Register result_end,
623 Register scratch,
624 Label* gc_required,
625 AllocationFlags flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000626
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000627 void Allocate(int header_size,
628 ScaleFactor element_size,
629 Register element_count,
630 RegisterValueType element_count_type,
631 Register result,
632 Register result_end,
633 Register scratch,
634 Label* gc_required,
635 AllocationFlags flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000636
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000637 void Allocate(Register object_size,
638 Register result,
639 Register result_end,
640 Register scratch,
641 Label* gc_required,
642 AllocationFlags flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000643
644 // Undo allocation in new space. The object passed and objects allocated after
645 // it will no longer be allocated. Make sure that no pointers are left to the
646 // object(s) no longer allocated as they would be invalid when allocation is
647 // un-done.
648 void UndoAllocationInNewSpace(Register object);
649
ager@chromium.org3811b432009-10-28 14:53:37 +0000650 // Allocate a heap number in new space with undefined value. The
651 // register scratch2 can be passed as no_reg; the others must be
652 // valid registers. Returns tagged pointer in result register, or
653 // jumps to gc_required if new space is full.
654 void AllocateHeapNumber(Register result,
655 Register scratch1,
656 Register scratch2,
657 Label* gc_required);
658
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000659 // Allocate a sequential string. All the header fields of the string object
660 // are initialized.
661 void AllocateTwoByteString(Register result,
662 Register length,
663 Register scratch1,
664 Register scratch2,
665 Register scratch3,
666 Label* gc_required);
667 void AllocateAsciiString(Register result,
668 Register length,
669 Register scratch1,
670 Register scratch2,
671 Register scratch3,
672 Label* gc_required);
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000673 void AllocateAsciiString(Register result,
674 int length,
675 Register scratch1,
676 Register scratch2,
677 Label* gc_required);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000678
679 // Allocate a raw cons string object. Only the map field of the result is
680 // initialized.
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000681 void AllocateTwoByteConsString(Register result,
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000682 Register scratch1,
683 Register scratch2,
684 Label* gc_required);
685 void AllocateAsciiConsString(Register result,
686 Register scratch1,
687 Register scratch2,
688 Label* gc_required);
689
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000690 // Allocate a raw sliced string object. Only the map field of the result is
691 // initialized.
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000692 void AllocateTwoByteSlicedString(Register result,
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000693 Register scratch1,
694 Register scratch2,
695 Label* gc_required);
696 void AllocateAsciiSlicedString(Register result,
697 Register scratch1,
698 Register scratch2,
699 Label* gc_required);
700
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000701 // Copy memory, byte-by-byte, from source to destination. Not optimized for
702 // long or aligned copies.
703 // The contents of index and scratch are destroyed.
704 void CopyBytes(Register source,
705 Register destination,
706 Register length,
707 Register scratch);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000708
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000709 // Initialize fields with filler values. Fields starting at |start_offset|
710 // not including end_offset are overwritten with the value in |filler|. At
711 // the end the loop, |start_offset| takes the value of |end_offset|.
712 void InitializeFieldsWithFiller(Register start_offset,
713 Register end_offset,
714 Register filler);
715
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000716 // ---------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000717 // Support functions.
718
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000719 // Check a boolean-bit of a Smi field.
720 void BooleanBitTest(Register object, int field_offset, int bit_index);
721
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000722 // Check if result is zero and op is negative.
723 void NegativeZeroTest(Register result, Register op, Label* then_label);
724
725 // Check if result is zero and any of op1 and op2 are negative.
726 // Register scratch is destroyed, and it must be different from op2.
727 void NegativeZeroTest(Register result, Register op1, Register op2,
728 Register scratch, Label* then_label);
729
ager@chromium.org7c537e22008-10-16 08:43:32 +0000730 // Try to get function prototype of a function and puts the value in
731 // the result register. Checks that the function really is a
732 // function and jumps to the miss label if the fast checks fail. The
733 // function register will be untouched; the other registers may be
734 // clobbered.
735 void TryGetFunctionPrototype(Register function,
736 Register result,
737 Register scratch,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000738 Label* miss,
739 bool miss_on_bound_function = false);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000740
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000741 // Generates code for reporting that an illegal operation has
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000742 // occurred.
743 void IllegalOperation(int num_arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000744
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000745 // Picks out an array index from the hash field.
746 // Register use:
747 // hash - holds the index's hash. Clobbered.
748 // index - holds the overwritten index on exit.
749 void IndexFromHash(Register hash, Register index);
750
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000751 // ---------------------------------------------------------------------------
752 // Runtime calls
753
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000754 // Call a code stub. Generate the code if necessary.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000755 void CallStub(CodeStub* stub, TypeFeedbackId ast_id = TypeFeedbackId::None());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000756
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000757 // Tail call a code stub (jump). Generate the code if necessary.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000758 void TailCallStub(CodeStub* stub);
759
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000760 // Return from a code stub after popping its arguments.
761 void StubReturn(int argc);
762
763 // Call a runtime routine.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000764 void CallRuntime(const Runtime::Function* f,
765 int num_arguments,
766 SaveFPRegsMode save_doubles = kDontSaveFPRegs);
767 void CallRuntimeSaveDoubles(Runtime::FunctionId id) {
768 const Runtime::Function* function = Runtime::FunctionForId(id);
769 CallRuntime(function, function->nargs, kSaveFPRegs);
770 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000771
772 // Convenience function: Same as above, but takes the fid instead.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000773 void CallRuntime(Runtime::FunctionId id, int num_arguments) {
774 CallRuntime(Runtime::FunctionForId(id), num_arguments);
775 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000776
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000777 // Convenience function: call an external reference.
778 void CallExternalReference(ExternalReference ref, int num_arguments);
779
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000780 // Tail call of a runtime routine (jump).
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000781 // Like JumpToExternalReference, but also takes care of passing the number
782 // of parameters.
783 void TailCallExternalReference(const ExternalReference& ext,
784 int num_arguments,
785 int result_size);
786
787 // Convenience function: tail call a runtime routine (jump).
788 void TailCallRuntime(Runtime::FunctionId fid,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000789 int num_arguments,
790 int result_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000791
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000792 // Before calling a C-function from generated code, align arguments on stack.
793 // After aligning the frame, arguments must be stored in esp[0], esp[4],
794 // etc., not pushed. The argument count assumes all arguments are word sized.
795 // Some compilers/platforms require the stack to be aligned when calling
796 // C++ code.
797 // Needs a scratch register to do some arithmetic. This register will be
798 // trashed.
799 void PrepareCallCFunction(int num_arguments, Register scratch);
800
801 // Calls a C function and cleans up the space for arguments allocated
802 // by PrepareCallCFunction. The called function is not allowed to trigger a
803 // garbage collection, since that might move the code and invalidate the
804 // return address (unless this is somehow accounted for by the called
805 // function).
806 void CallCFunction(ExternalReference function, int num_arguments);
807 void CallCFunction(Register function, int num_arguments);
808
lrn@chromium.org303ada72010-10-27 09:33:13 +0000809 // Prepares stack to put arguments (aligns and so on). Reserves
810 // space for return value if needed (assumes the return value is a handle).
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000811 // Arguments must be stored in ApiParameterOperand(0), ApiParameterOperand(1)
812 // etc. Saves context (esi). If space was reserved for return value then
813 // stores the pointer to the reserved slot into esi.
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000814 void PrepareCallApiFunction(int argc);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000815
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000816 // Calls an API function. Allocates HandleScope, extracts returned value
817 // from handle and propagates exceptions. Clobbers ebx, edi and
818 // caller-save registers. Restores context. On return removes
819 // stack_space * kPointerSize (GCed).
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000820 void CallApiFunctionAndReturn(Address function_address,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000821 Address thunk_address,
822 Operand thunk_last_arg,
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000823 int stack_space,
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000824 Operand return_value_operand,
825 Operand* context_restore_operand);
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +0000826
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000827 // Jump to a runtime routine.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000828 void JumpToExternalReference(const ExternalReference& ext);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000829
ager@chromium.org236ad962008-09-25 09:45:57 +0000830 // ---------------------------------------------------------------------------
831 // Utilities
832
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000833 void Ret();
834
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000835 // Return and drop arguments from stack, where the number of arguments
836 // may be bigger than 2^16 - 1. Requires a scratch register.
837 void Ret(int bytes_dropped, Register scratch);
838
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000839 // Emit code to discard a non-negative number of pointer-sized elements
840 // from the stack, clobbering only the esp register.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000841 void Drop(int element_count);
842
843 void Call(Label* target) { call(target); }
danno@chromium.org59400602013-08-13 17:09:37 +0000844 void Push(Register src) { push(src); }
845 void Pop(Register dst) { pop(dst); }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000846
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000847 // Emit call to the code we are currently generating.
848 void CallSelf() {
849 Handle<Code> self(reinterpret_cast<Code**>(CodeObject().location()));
850 call(self, RelocInfo::CODE_TARGET);
851 }
852
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000853 // Move if the registers are not identical.
854 void Move(Register target, Register source);
855
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000856 // Push a handle value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000857 void Push(Handle<Object> handle) { push(Immediate(handle)); }
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000858 void Push(Smi* smi) { Push(Handle<Smi>(smi, isolate())); }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000859
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000860 Handle<Object> CodeObject() {
861 ASSERT(!code_object_.is_null());
862 return code_object_;
863 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000864
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000865 // Insert code to verify that the x87 stack has the specified depth (0-7)
866 void VerifyX87StackDepth(uint32_t depth);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000867
868 // ---------------------------------------------------------------------------
869 // StatsCounter support
870
871 void SetCounter(StatsCounter* counter, int value);
872 void IncrementCounter(StatsCounter* counter, int value);
873 void DecrementCounter(StatsCounter* counter, int value);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000874 void IncrementCounter(Condition cc, StatsCounter* counter, int value);
875 void DecrementCounter(Condition cc, StatsCounter* counter, int value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000876
877
878 // ---------------------------------------------------------------------------
879 // Debugging
880
881 // Calls Abort(msg) if the condition cc is not satisfied.
882 // Use --debug_code to enable.
danno@chromium.org59400602013-08-13 17:09:37 +0000883 void Assert(Condition cc, BailoutReason reason);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000884
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000885 void AssertFastElements(Register elements);
886
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000887 // Like Assert(), but always enabled.
danno@chromium.org59400602013-08-13 17:09:37 +0000888 void Check(Condition cc, BailoutReason reason);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000889
890 // Print a message to stdout and abort execution.
danno@chromium.org59400602013-08-13 17:09:37 +0000891 void Abort(BailoutReason reason);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000892
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000893 // Check that the stack is aligned.
894 void CheckStackAlignment();
895
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000896 // Verify restrictions about code generated in stubs.
897 void set_generating_stub(bool value) { generating_stub_ = value; }
898 bool generating_stub() { return generating_stub_; }
kasper.lund7276f142008-07-30 08:49:36 +0000899 void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
900 bool allow_stub_calls() { return allow_stub_calls_; }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000901 void set_has_frame(bool value) { has_frame_ = value; }
902 bool has_frame() { return has_frame_; }
903 inline bool AllowThisStubCall(CodeStub* stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000904
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000905 // ---------------------------------------------------------------------------
906 // String utilities.
907
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000908 // Generate code to do a lookup in the number string cache. If the number in
909 // the register object is found in the cache the generated code falls through
910 // with the result in the result register. The object and the result register
911 // can be the same. If the number is not found in the cache the code jumps to
912 // the label not_found with only the content of register object unchanged.
913 void LookupNumberStringCache(Register object,
914 Register result,
915 Register scratch1,
916 Register scratch2,
917 Label* not_found);
918
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000919 // Check whether the instance type represents a flat ASCII string. Jump to the
ager@chromium.org5c838252010-02-19 08:53:10 +0000920 // label if not. If the instance type can be scratched specify same register
921 // for both instance type and scratch.
922 void JumpIfInstanceTypeIsNotSequentialAscii(Register instance_type,
923 Register scratch,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000924 Label* on_not_flat_ascii_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000925
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000926 // Checks if both objects are sequential ASCII strings, and jumps to label
927 // if either is not.
928 void JumpIfNotBothSequentialAsciiStrings(Register object1,
929 Register object2,
930 Register scratch1,
931 Register scratch2,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000932 Label* on_not_flat_ascii_strings);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000933
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000934 // Checks if the given register or operand is a unique name
935 void JumpIfNotUniqueName(Register reg, Label* not_unique_name,
936 Label::Distance distance = Label::kFar) {
937 JumpIfNotUniqueName(Operand(reg), not_unique_name, distance);
938 }
939
940 void JumpIfNotUniqueName(Operand operand, Label* not_unique_name,
941 Label::Distance distance = Label::kFar);
942
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000943 static int SafepointRegisterStackIndex(Register reg) {
944 return SafepointRegisterStackIndex(reg.code());
945 }
946
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000947 // Activation support.
948 void EnterFrame(StackFrame::Type type);
949 void LeaveFrame(StackFrame::Type type);
950
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +0000951 // Expects object in eax and returns map with validated enum cache
952 // in eax. Assumes that any other register can be used as a scratch.
953 void CheckEnumCache(Label* call_runtime);
954
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000955 // AllocationMemento support. Arrays may have an associated
956 // AllocationMemento object that can be checked for in order to pretransition
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000957 // to another type.
958 // On entry, receiver_reg should point to the array object.
959 // scratch_reg gets clobbered.
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +0000960 // If allocation info is present, conditional code is set to equal.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000961 void TestJSArrayForAllocationMemento(Register receiver_reg,
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +0000962 Register scratch_reg,
963 Label* no_memento_found);
964
965 void JumpIfJSArrayHasAllocationMemento(Register receiver_reg,
966 Register scratch_reg,
967 Label* memento_found) {
968 Label no_memento_found;
969 TestJSArrayForAllocationMemento(receiver_reg, scratch_reg,
970 &no_memento_found);
971 j(equal, memento_found);
972 bind(&no_memento_found);
973 }
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000974
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000975 private:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000976 bool generating_stub_;
kasper.lund7276f142008-07-30 08:49:36 +0000977 bool allow_stub_calls_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000978 bool has_frame_;
ager@chromium.org5c838252010-02-19 08:53:10 +0000979 // This handle will be patched with the code object on installation.
980 Handle<Object> code_object_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000981
982 // Helper functions for generating invokes.
983 void InvokePrologue(const ParameterCount& expected,
984 const ParameterCount& actual,
985 Handle<Code> code_constant,
986 const Operand& code_operand,
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000987 Label* done,
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000988 bool* definitely_mismatches,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000989 InvokeFlag flag,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000990 Label::Distance done_distance,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000991 const CallWrapper& call_wrapper = NullCallWrapper(),
992 CallKind call_kind = CALL_AS_METHOD);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000993
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000994 void EnterExitFramePrologue();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000995 void EnterExitFrameEpilogue(int argc, bool save_doubles);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000996
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000997 void LeaveExitFrameEpilogue(bool restore_context);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000998
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000999 // Allocation support helpers.
1000 void LoadAllocationTopHelper(Register result,
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001001 Register scratch,
ager@chromium.orga1645e22009-09-09 19:27:10 +00001002 AllocationFlags flags);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001003
1004 void UpdateAllocationTopHelper(Register result_end,
1005 Register scratch,
1006 AllocationFlags flags);
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001007
1008 // Helper for PopHandleScope. Allowed to perform a GC and returns
1009 // NULL if gc_allowed. Does not perform a GC if !gc_allowed, and
1010 // possibly returns a failure object indicating an allocation failure.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001011 MUST_USE_RESULT MaybeObject* PopHandleScopeHelper(Register saved,
1012 Register scratch,
1013 bool gc_allowed);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001014
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001015 // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace.
1016 void InNewSpace(Register object,
1017 Register scratch,
1018 Condition cc,
1019 Label* condition_met,
1020 Label::Distance condition_met_distance = Label::kFar);
1021
1022 // Helper for finding the mark bits for an address. Afterwards, the
1023 // bitmap register points at the word with the mark bits and the mask
1024 // the position of the first bit. Uses ecx as scratch and leaves addr_reg
1025 // unchanged.
1026 inline void GetMarkBits(Register addr_reg,
1027 Register bitmap_reg,
1028 Register mask_reg);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001029
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001030 // Helper for throwing exceptions. Compute a handler address and jump to
1031 // it. See the implementation for register usage.
1032 void JumpToHandlerEntry();
1033
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001034 // Compute memory operands for safepoint stack slots.
1035 Operand SafepointRegisterSlot(Register reg);
1036 static int SafepointRegisterStackIndex(int reg_code);
1037
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001038 // Needs access to SafepointRegisterStackIndex for compiled frame
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001039 // traversal.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001040 friend class StandardFrame;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001041};
1042
1043
1044// The code patcher is used to patch (typically) small parts of code e.g. for
1045// debugging and other types of instrumentation. When using the code patcher
1046// the exact number of bytes specified must be emitted. Is not legal to emit
1047// relocation information. If any of these constraints are violated it causes
1048// an assertion.
1049class CodePatcher {
1050 public:
1051 CodePatcher(byte* address, int size);
1052 virtual ~CodePatcher();
1053
1054 // Macro assembler to emit code.
1055 MacroAssembler* masm() { return &masm_; }
1056
1057 private:
1058 byte* address_; // The address of the code being patched.
1059 int size_; // Number of bytes of the expected patch size.
1060 MacroAssembler masm_; // Macro assembler used to generate the code.
1061};
1062
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001063
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001064// -----------------------------------------------------------------------------
1065// Static helper functions.
1066
1067// Generate an Operand for loading a field from an object.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001068inline Operand FieldOperand(Register object, int offset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001069 return Operand(object, offset - kHeapObjectTag);
1070}
1071
1072
kasper.lund7276f142008-07-30 08:49:36 +00001073// Generate an Operand for loading an indexed field from an object.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001074inline Operand FieldOperand(Register object,
1075 Register index,
1076 ScaleFactor scale,
1077 int offset) {
kasper.lund7276f142008-07-30 08:49:36 +00001078 return Operand(object, index, scale, offset - kHeapObjectTag);
1079}
1080
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001081
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001082inline Operand ContextOperand(Register context, int index) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001083 return Operand(context, Context::SlotOffset(index));
1084}
1085
1086
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001087inline Operand GlobalObjectOperand() {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001088 return ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001089}
1090
1091
lrn@chromium.org303ada72010-10-27 09:33:13 +00001092// Generates an Operand for saving parameters after PrepareCallApiFunction.
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001093Operand ApiParameterOperand(int index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001094
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001095
1096#ifdef GENERATED_CODE_COVERAGE
1097extern void LogGeneratedCodeCoverage(const char* file_line);
1098#define CODE_COVERAGE_STRINGIFY(x) #x
1099#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
1100#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
1101#define ACCESS_MASM(masm) { \
1102 byte* ia32_coverage_function = \
1103 reinterpret_cast<byte*>(FUNCTION_ADDR(LogGeneratedCodeCoverage)); \
1104 masm->pushfd(); \
1105 masm->pushad(); \
1106 masm->push(Immediate(reinterpret_cast<int>(&__FILE_LINE__))); \
1107 masm->call(ia32_coverage_function, RelocInfo::RUNTIME_ENTRY); \
1108 masm->pop(eax); \
1109 masm->popad(); \
1110 masm->popfd(); \
1111 } \
1112 masm->
1113#else
1114#define ACCESS_MASM(masm) masm->
1115#endif
1116
1117
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118} } // namespace v8::internal
1119
ager@chromium.org5ec48922009-05-05 07:25:34 +00001120#endif // V8_IA32_MACRO_ASSEMBLER_IA32_H_