blob: 42b7eb15a02f330806937042c633abaae020eab5 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_X87_MACRO_ASSEMBLER_X87_H_
6#define V8_X87_MACRO_ASSEMBLER_X87_H_
7
8#include "src/assembler.h"
9#include "src/bailout-reason.h"
10#include "src/frames.h"
11#include "src/globals.h"
12
13namespace v8 {
14namespace internal {
15
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016// Give alias names to registers for calling conventions.
17const Register kReturnRegister0 = {Register::kCode_eax};
18const Register kReturnRegister1 = {Register::kCode_edx};
Ben Murdoch097c5b22016-05-18 11:27:45 +010019const Register kReturnRegister2 = {Register::kCode_edi};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000020const Register kJSFunctionRegister = {Register::kCode_edi};
21const Register kContextRegister = {Register::kCode_esi};
Ben Murdochc5610432016-08-08 18:44:38 +010022const Register kAllocateSizeRegister = {Register::kCode_edx};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000023const Register kInterpreterAccumulatorRegister = {Register::kCode_eax};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000024const Register kInterpreterBytecodeOffsetRegister = {Register::kCode_ecx};
25const Register kInterpreterBytecodeArrayRegister = {Register::kCode_edi};
Ben Murdochc5610432016-08-08 18:44:38 +010026const Register kInterpreterDispatchTableRegister = {Register::kCode_esi};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000027const Register kJavaScriptCallArgCountRegister = {Register::kCode_eax};
28const Register kJavaScriptCallNewTargetRegister = {Register::kCode_edx};
29const Register kRuntimeCallFunctionRegister = {Register::kCode_ebx};
30const Register kRuntimeCallArgCountRegister = {Register::kCode_eax};
31
32// Spill slots used by interpreter dispatch calling convention.
33const int kInterpreterDispatchTableSpillSlot = -1;
34
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035// Convenience for platform-independent signatures. We do not normally
36// distinguish memory operands from other operands on ia32.
37typedef Operand MemOperand;
38
39enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET };
40enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
41enum PointersToHereCheck {
42 kPointersToHereMaybeInteresting,
43 kPointersToHereAreAlwaysInteresting
44};
45
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000046enum RegisterValueType { REGISTER_VALUE_IS_SMI, REGISTER_VALUE_IS_INT32 };
Ben Murdochb8a8cc12014-11-26 15:28:44 +000047
Ben Murdochda12d292016-06-02 14:46:10 +010048enum class ReturnAddressState { kOnStack, kNotOnStack };
49
Ben Murdochb8a8cc12014-11-26 15:28:44 +000050#ifdef DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000051bool AreAliased(Register reg1, Register reg2, Register reg3 = no_reg,
52 Register reg4 = no_reg, Register reg5 = no_reg,
53 Register reg6 = no_reg, Register reg7 = no_reg,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054 Register reg8 = no_reg);
55#endif
56
Ben Murdochb8a8cc12014-11-26 15:28:44 +000057// MacroAssembler implements a collection of frequently used macros.
58class MacroAssembler: public Assembler {
59 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000060 MacroAssembler(Isolate* isolate, void* buffer, int size,
61 CodeObjectRequired create_code_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000062
63 void Load(Register dst, const Operand& src, Representation r);
64 void Store(Register src, const Operand& dst, Representation r);
65
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000066 // Load a register with a long value as efficiently as possible.
67 void Set(Register dst, int32_t x) {
68 if (x == 0) {
69 xor_(dst, dst);
70 } else {
71 mov(dst, Immediate(x));
72 }
73 }
74 void Set(const Operand& dst, int32_t x) { mov(dst, Immediate(x)); }
75
Ben Murdochb8a8cc12014-11-26 15:28:44 +000076 // Operations on roots in the root-array.
77 void LoadRoot(Register destination, Heap::RootListIndex index);
78 void StoreRoot(Register source, Register scratch, Heap::RootListIndex index);
79 void CompareRoot(Register with, Register scratch, Heap::RootListIndex index);
80 // These methods can only be used with constant roots (i.e. non-writable
81 // and not in new space).
82 void CompareRoot(Register with, Heap::RootListIndex index);
83 void CompareRoot(const Operand& with, Heap::RootListIndex index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000084 void PushRoot(Heap::RootListIndex index);
85
86 // Compare the object in a register to a value and jump if they are equal.
87 void JumpIfRoot(Register with, Heap::RootListIndex index, Label* if_equal,
88 Label::Distance if_equal_distance = Label::kFar) {
89 CompareRoot(with, index);
90 j(equal, if_equal, if_equal_distance);
91 }
92 void JumpIfRoot(const Operand& with, Heap::RootListIndex index,
93 Label* if_equal,
94 Label::Distance if_equal_distance = Label::kFar) {
95 CompareRoot(with, index);
96 j(equal, if_equal, if_equal_distance);
97 }
98
99 // Compare the object in a register to a value and jump if they are not equal.
100 void JumpIfNotRoot(Register with, Heap::RootListIndex index,
101 Label* if_not_equal,
102 Label::Distance if_not_equal_distance = Label::kFar) {
103 CompareRoot(with, index);
104 j(not_equal, if_not_equal, if_not_equal_distance);
105 }
106 void JumpIfNotRoot(const Operand& with, Heap::RootListIndex index,
107 Label* if_not_equal,
108 Label::Distance if_not_equal_distance = Label::kFar) {
109 CompareRoot(with, index);
110 j(not_equal, if_not_equal, if_not_equal_distance);
111 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000112
Ben Murdoch097c5b22016-05-18 11:27:45 +0100113 // These functions do not arrange the registers in any particular order so
114 // they are not useful for calls that can cause a GC. The caller can
115 // exclude up to 3 registers that do not need to be saved and restored.
116 void PushCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg,
117 Register exclusion2 = no_reg,
118 Register exclusion3 = no_reg);
119 void PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg,
120 Register exclusion2 = no_reg,
121 Register exclusion3 = no_reg);
122
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000123 // ---------------------------------------------------------------------------
124 // GC Support
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000125 enum RememberedSetFinalAction { kReturnAtEnd, kFallThroughAtEnd };
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000126
127 // Record in the remembered set the fact that we have a pointer to new space
128 // at the address pointed to by the addr register. Only works if addr is not
129 // in new space.
130 void RememberedSetHelper(Register object, // Used for debug code.
131 Register addr, Register scratch,
132 SaveFPRegsMode save_fp,
133 RememberedSetFinalAction and_then);
134
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000135 void CheckPageFlag(Register object, Register scratch, int mask, Condition cc,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000136 Label* condition_met,
137 Label::Distance condition_met_distance = Label::kFar);
138
139 void CheckPageFlagForMap(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000140 Handle<Map> map, int mask, Condition cc, Label* condition_met,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141 Label::Distance condition_met_distance = Label::kFar);
142
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000143 // Check if object is in new space. Jumps if the object is not in new space.
144 // The register scratch can be object itself, but scratch will be clobbered.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000145 void JumpIfNotInNewSpace(Register object, Register scratch, Label* branch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000146 Label::Distance distance = Label::kFar) {
147 InNewSpace(object, scratch, zero, branch, distance);
148 }
149
150 // Check if object is in new space. Jumps if the object is in new space.
151 // The register scratch can be object itself, but it will be clobbered.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152 void JumpIfInNewSpace(Register object, Register scratch, Label* branch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000153 Label::Distance distance = Label::kFar) {
154 InNewSpace(object, scratch, not_zero, branch, distance);
155 }
156
157 // Check if an object has a given incremental marking color. Also uses ecx!
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000158 void HasColor(Register object, Register scratch0, Register scratch1,
159 Label* has_color, Label::Distance has_color_distance,
160 int first_bit, int second_bit);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000162 void JumpIfBlack(Register object, Register scratch0, Register scratch1,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000163 Label* on_black,
164 Label::Distance on_black_distance = Label::kFar);
165
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000166 // Checks the color of an object. If the object is white we jump to the
167 // incremental marker.
168 void JumpIfWhite(Register value, Register scratch1, Register scratch2,
169 Label* value_is_white, Label::Distance distance);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000170
171 // Notify the garbage collector that we wrote a pointer into an object.
172 // |object| is the object being stored into, |value| is the object being
173 // stored. value and scratch registers are clobbered by the operation.
174 // The offset is the offset from the start of the object, not the offset from
175 // the tagged HeapObject pointer. For use with FieldOperand(reg, off).
176 void RecordWriteField(
177 Register object, int offset, Register value, Register scratch,
178 SaveFPRegsMode save_fp,
179 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
180 SmiCheck smi_check = INLINE_SMI_CHECK,
181 PointersToHereCheck pointers_to_here_check_for_value =
182 kPointersToHereMaybeInteresting);
183
184 // As above, but the offset has the tag presubtracted. For use with
185 // Operand(reg, off).
186 void RecordWriteContextSlot(
187 Register context, int offset, Register value, Register scratch,
188 SaveFPRegsMode save_fp,
189 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
190 SmiCheck smi_check = INLINE_SMI_CHECK,
191 PointersToHereCheck pointers_to_here_check_for_value =
192 kPointersToHereMaybeInteresting) {
193 RecordWriteField(context, offset + kHeapObjectTag, value, scratch, save_fp,
194 remembered_set_action, smi_check,
195 pointers_to_here_check_for_value);
196 }
197
198 // Notify the garbage collector that we wrote a pointer into a fixed array.
199 // |array| is the array being stored into, |value| is the
200 // object being stored. |index| is the array index represented as a
201 // Smi. All registers are clobbered by the operation RecordWriteArray
202 // filters out smis so it does not update the write barrier if the
203 // value is a smi.
204 void RecordWriteArray(
205 Register array, Register value, Register index, SaveFPRegsMode save_fp,
206 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
207 SmiCheck smi_check = INLINE_SMI_CHECK,
208 PointersToHereCheck pointers_to_here_check_for_value =
209 kPointersToHereMaybeInteresting);
210
211 // For page containing |object| mark region covering |address|
212 // dirty. |object| is the object being stored into, |value| is the
213 // object being stored. The address and value registers are clobbered by the
214 // operation. RecordWrite filters out smis so it does not update the
215 // write barrier if the value is a smi.
216 void RecordWrite(
217 Register object, Register address, Register value, SaveFPRegsMode save_fp,
218 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
219 SmiCheck smi_check = INLINE_SMI_CHECK,
220 PointersToHereCheck pointers_to_here_check_for_value =
221 kPointersToHereMaybeInteresting);
222
Ben Murdoch097c5b22016-05-18 11:27:45 +0100223 // Notify the garbage collector that we wrote a code entry into a
224 // JSFunction. Only scratch is clobbered by the operation.
225 void RecordWriteCodeEntryField(Register js_function, Register code_entry,
226 Register scratch);
227
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000228 // For page containing |object| mark the region covering the object's map
229 // dirty. |object| is the object being stored into, |map| is the Map object
230 // that was stored.
231 void RecordWriteForMap(Register object, Handle<Map> map, Register scratch1,
232 Register scratch2, SaveFPRegsMode save_fp);
233
234 // ---------------------------------------------------------------------------
235 // Debugger Support
236
237 void DebugBreak();
238
239 // Generates function and stub prologue code.
Ben Murdochda12d292016-06-02 14:46:10 +0100240 void StubPrologue(StackFrame::Type type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000241 void Prologue(bool code_pre_aging);
242
243 // Enter specific kind of exit frame. Expects the number of
244 // arguments in register eax and sets up the number of arguments in
245 // register edi and the pointer to the first argument in register
246 // esi.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100247 void EnterExitFrame(int argc, bool save_doubles);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000248
249 void EnterApiExitFrame(int argc);
250
251 // Leave the current exit frame. Expects the return value in
252 // register eax:edx (untouched) and the pointer to the first
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000253 // argument in register esi (if pop_arguments == true).
254 void LeaveExitFrame(bool save_doubles, bool pop_arguments = true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000255
256 // Leave the current exit frame. Expects the return value in
257 // register eax (untouched).
258 void LeaveApiExitFrame(bool restore_context);
259
260 // Find the function context up the context chain.
261 void LoadContext(Register dst, int context_chain_length);
262
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000263 // Load the global proxy from the current context.
264 void LoadGlobalProxy(Register dst);
265
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000266 // Conditionally load the cached Array transitioned map of type
267 // transitioned_kind from the native context if the map in register
268 // map_in_out is the cached Array map in the native context of
269 // expected_kind.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000270 void LoadTransitionedArrayMapConditional(ElementsKind expected_kind,
271 ElementsKind transitioned_kind,
272 Register map_in_out,
273 Register scratch,
274 Label* no_map_match);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000275
276 // Load the global function with the given index.
277 void LoadGlobalFunction(int index, Register function);
278
279 // Load the initial map from the global function. The registers
280 // function and map can be the same.
281 void LoadGlobalFunctionInitialMap(Register function, Register map);
282
283 // Push and pop the registers that can hold pointers.
284 void PushSafepointRegisters() { pushad(); }
285 void PopSafepointRegisters() { popad(); }
286 // Store the value in register/immediate src in the safepoint
287 // register stack slot for register dst.
288 void StoreToSafepointRegisterSlot(Register dst, Register src);
289 void StoreToSafepointRegisterSlot(Register dst, Immediate src);
290 void LoadFromSafepointRegisterSlot(Register dst, Register src);
291
Ben Murdoch097c5b22016-05-18 11:27:45 +0100292 // Nop, because x87 does not have a root register.
293 void InitializeRootRegister() {}
294
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000295 void LoadHeapObject(Register result, Handle<HeapObject> object);
296 void CmpHeapObject(Register reg, Handle<HeapObject> object);
297 void PushHeapObject(Handle<HeapObject> object);
298
299 void LoadObject(Register result, Handle<Object> object) {
300 AllowDeferredHandleDereference heap_object_check;
301 if (object->IsHeapObject()) {
302 LoadHeapObject(result, Handle<HeapObject>::cast(object));
303 } else {
304 Move(result, Immediate(object));
305 }
306 }
307
308 void CmpObject(Register reg, Handle<Object> object) {
309 AllowDeferredHandleDereference heap_object_check;
310 if (object->IsHeapObject()) {
311 CmpHeapObject(reg, Handle<HeapObject>::cast(object));
312 } else {
313 cmp(reg, Immediate(object));
314 }
315 }
316
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400317 void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318 void GetWeakValue(Register value, Handle<WeakCell> cell);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400319 void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
320
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000321 // ---------------------------------------------------------------------------
322 // JavaScript invokes
323
Ben Murdochda12d292016-06-02 14:46:10 +0100324 // Removes current frame and its arguments from the stack preserving
325 // the arguments and a return address pushed to the stack for the next call.
326 // |ra_state| defines whether return address is already pushed to stack or
327 // not. Both |callee_args_count| and |caller_args_count_reg| do not include
328 // receiver. |callee_args_count| is not modified, |caller_args_count_reg|
329 // is trashed. |number_of_temp_values_after_return_address| specifies
330 // the number of words pushed to the stack after the return address. This is
331 // to allow "allocation" of scratch registers that this function requires
332 // by saving their values on the stack.
333 void PrepareForTailCall(const ParameterCount& callee_args_count,
334 Register caller_args_count_reg, Register scratch0,
335 Register scratch1, ReturnAddressState ra_state,
336 int number_of_temp_values_after_return_address);
337
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000338 // Invoke the JavaScript function code by either calling or jumping.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000339
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000340 void InvokeFunctionCode(Register function, Register new_target,
341 const ParameterCount& expected,
342 const ParameterCount& actual, InvokeFlag flag,
343 const CallWrapper& call_wrapper);
344
345 void FloodFunctionIfStepping(Register fun, Register new_target,
346 const ParameterCount& expected,
347 const ParameterCount& actual);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000348
349 // Invoke the JavaScript function in the given register. Changes the
350 // current context to the context in the function before invoking.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000351 void InvokeFunction(Register function, Register new_target,
352 const ParameterCount& actual, InvokeFlag flag,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000353 const CallWrapper& call_wrapper);
354
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000355 void InvokeFunction(Register function, const ParameterCount& expected,
356 const ParameterCount& actual, InvokeFlag flag,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000357 const CallWrapper& call_wrapper);
358
359 void InvokeFunction(Handle<JSFunction> function,
360 const ParameterCount& expected,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000361 const ParameterCount& actual, InvokeFlag flag,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000362 const CallWrapper& call_wrapper);
363
Ben Murdochda12d292016-06-02 14:46:10 +0100364 void ShlPair(Register high, Register low, uint8_t imm8);
365 void ShlPair_cl(Register high, Register low);
366 void ShrPair(Register high, Register low, uint8_t imm8);
367 void ShrPair_cl(Register high, Register src);
368 void SarPair(Register high, Register low, uint8_t imm8);
369 void SarPair_cl(Register high, Register low);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000370
371 // Expression support
372 // Support for constant splitting.
373 bool IsUnsafeImmediate(const Immediate& x);
374 void SafeMove(Register dst, const Immediate& x);
375 void SafePush(const Immediate& x);
376
377 // Compare object type for heap object.
378 // Incoming register is heap_object and outgoing register is map.
379 void CmpObjectType(Register heap_object, InstanceType type, Register map);
380
381 // Compare instance type for map.
382 void CmpInstanceType(Register map, InstanceType type);
383
384 // Check if a map for a JSObject indicates that the object has fast elements.
385 // Jump to the specified label if it does not.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000386 void CheckFastElements(Register map, Label* fail,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000387 Label::Distance distance = Label::kFar);
388
389 // Check if a map for a JSObject indicates that the object can have both smi
390 // and HeapObject elements. Jump to the specified label if it does not.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000391 void CheckFastObjectElements(Register map, Label* fail,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000392 Label::Distance distance = Label::kFar);
393
394 // Check if a map for a JSObject indicates that the object has fast smi only
395 // elements. Jump to the specified label if it does not.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000396 void CheckFastSmiElements(Register map, Label* fail,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000397 Label::Distance distance = Label::kFar);
398
399 // Check to see if maybe_number can be stored as a double in
400 // FastDoubleElements. If it can, store it at the index specified by key in
401 // the FastDoubleElements array elements, otherwise jump to fail.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000402 void StoreNumberToDoubleElements(Register maybe_number, Register elements,
403 Register key, Register scratch, Label* fail,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000404 int offset = 0);
405
406 // Compare an object's map with the specified map.
407 void CompareMap(Register obj, Handle<Map> map);
408
409 // Check if the map of an object is equal to a specified map and branch to
410 // label if not. Skip the smi check if not required (object is known to be a
411 // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match
412 // against maps that are ElementsKind transition maps of the specified map.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000413 void CheckMap(Register obj, Handle<Map> map, Label* fail,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000414 SmiCheckType smi_check_type);
415
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400416 // Check if the map of an object is equal to a specified weak map and branch
417 // to a specified target if equal. Skip the smi check if not required
418 // (object is known to be a heap object)
419 void DispatchWeakMap(Register obj, Register scratch1, Register scratch2,
420 Handle<WeakCell> cell, Handle<Code> success,
421 SmiCheckType smi_check_type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000422
423 // Check if the object in register heap_object is a string. Afterwards the
424 // register map contains the object map and the register instance_type
425 // contains the instance_type. The registers map and instance_type can be the
426 // same in which case it contains the instance type afterwards. Either of the
427 // registers map and instance_type can be the same as heap_object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000428 Condition IsObjectStringType(Register heap_object, Register map,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000429 Register instance_type);
430
431 // Check if the object in register heap_object is a name. Afterwards the
432 // register map contains the object map and the register instance_type
433 // contains the instance_type. The registers map and instance_type can be the
434 // same in which case it contains the instance type afterwards. Either of the
435 // registers map and instance_type can be the same as heap_object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000436 Condition IsObjectNameType(Register heap_object, Register map,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000437 Register instance_type);
438
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000439 // FCmp is similar to integer cmp, but requires unsigned
440 // jcc instructions (je, ja, jae, jb, jbe, je, and jz).
441 void FCmp();
442 void FXamMinusZero();
443 void FXamSign();
444 void X87CheckIA();
445 void X87SetRC(int rc);
446 void X87SetFPUCW(int cw);
447
448 void ClampUint8(Register reg);
449 void ClampTOSToUint8(Register result_reg);
450
451 void SlowTruncateToI(Register result_reg, Register input_reg,
452 int offset = HeapNumber::kValueOffset - kHeapObjectTag);
453
454 void TruncateHeapNumberToI(Register result_reg, Register input_reg);
455 void TruncateX87TOSToI(Register result_reg);
456
457 void X87TOSToI(Register result_reg, MinusZeroMode minus_zero_mode,
458 Label* lost_precision, Label* is_nan, Label* minus_zero,
459 Label::Distance dst = Label::kFar);
460
461 // Smi tagging support.
462 void SmiTag(Register reg) {
463 STATIC_ASSERT(kSmiTag == 0);
464 STATIC_ASSERT(kSmiTagSize == 1);
465 add(reg, reg);
466 }
467 void SmiUntag(Register reg) {
468 sar(reg, kSmiTagSize);
469 }
470
471 // Modifies the register even if it does not contain a Smi!
472 void SmiUntag(Register reg, Label* is_smi) {
473 STATIC_ASSERT(kSmiTagSize == 1);
474 sar(reg, kSmiTagSize);
475 STATIC_ASSERT(kSmiTag == 0);
476 j(not_carry, is_smi);
477 }
478
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400479 void LoadUint32NoSSE2(Register src) {
480 LoadUint32NoSSE2(Operand(src));
481 }
482 void LoadUint32NoSSE2(const Operand& src);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000483
484 // Jump the register contains a smi.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000485 inline void JumpIfSmi(Register value, Label* smi_label,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000486 Label::Distance distance = Label::kFar) {
487 test(value, Immediate(kSmiTagMask));
488 j(zero, smi_label, distance);
489 }
490 // Jump if the operand is a smi.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000491 inline void JumpIfSmi(Operand value, Label* smi_label,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000492 Label::Distance distance = Label::kFar) {
493 test(value, Immediate(kSmiTagMask));
494 j(zero, smi_label, distance);
495 }
496 // Jump if register contain a non-smi.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000497 inline void JumpIfNotSmi(Register value, Label* not_smi_label,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000498 Label::Distance distance = Label::kFar) {
499 test(value, Immediate(kSmiTagMask));
500 j(not_zero, not_smi_label, distance);
501 }
502
Ben Murdochc5610432016-08-08 18:44:38 +0100503 // Jump if the value cannot be represented by a smi.
504 inline void JumpIfNotValidSmiValue(Register value, Register scratch,
505 Label* on_invalid,
506 Label::Distance distance = Label::kFar) {
507 mov(scratch, value);
508 add(scratch, Immediate(0x40000000U));
509 j(sign, on_invalid, distance);
510 }
511
512 // Jump if the unsigned integer value cannot be represented by a smi.
513 inline void JumpIfUIntNotValidSmiValue(
514 Register value, Label* on_invalid,
515 Label::Distance distance = Label::kFar) {
516 cmp(value, Immediate(0x40000000U));
517 j(above_equal, on_invalid, distance);
518 }
519
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000520 void LoadInstanceDescriptors(Register map, Register descriptors);
521 void EnumLength(Register dst, Register map);
522 void NumberOfOwnDescriptors(Register dst, Register map);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000523 void LoadAccessor(Register dst, Register holder, int accessor_index,
524 AccessorComponent accessor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000525
526 template<typename Field>
527 void DecodeField(Register reg) {
528 static const int shift = Field::kShift;
529 static const int mask = Field::kMask >> Field::kShift;
530 if (shift != 0) {
531 sar(reg, shift);
532 }
533 and_(reg, Immediate(mask));
534 }
535
536 template<typename Field>
537 void DecodeFieldToSmi(Register reg) {
538 static const int shift = Field::kShift;
539 static const int mask = (Field::kMask >> Field::kShift) << kSmiTagSize;
540 STATIC_ASSERT((mask & (0x80000000u >> (kSmiTagSize - 1))) == 0);
541 STATIC_ASSERT(kSmiTag == 0);
542 if (shift < kSmiTagSize) {
543 shl(reg, kSmiTagSize - shift);
544 } else if (shift > kSmiTagSize) {
545 sar(reg, shift - kSmiTagSize);
546 }
547 and_(reg, Immediate(mask));
548 }
549
550 // Abort execution if argument is not a number, enabled via --debug-code.
551 void AssertNumber(Register object);
Ben Murdochda12d292016-06-02 14:46:10 +0100552 void AssertNotNumber(Register object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000553
554 // Abort execution if argument is not a smi, enabled via --debug-code.
555 void AssertSmi(Register object);
556
557 // Abort execution if argument is a smi, enabled via --debug-code.
558 void AssertNotSmi(Register object);
559
560 // Abort execution if argument is not a string, enabled via --debug-code.
561 void AssertString(Register object);
562
563 // Abort execution if argument is not a name, enabled via --debug-code.
564 void AssertName(Register object);
565
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000566 // Abort execution if argument is not a JSFunction, enabled via --debug-code.
567 void AssertFunction(Register object);
568
569 // Abort execution if argument is not a JSBoundFunction,
570 // enabled via --debug-code.
571 void AssertBoundFunction(Register object);
572
Ben Murdochc5610432016-08-08 18:44:38 +0100573 // Abort execution if argument is not a JSGeneratorObject,
574 // enabled via --debug-code.
575 void AssertGeneratorObject(Register object);
576
Ben Murdoch097c5b22016-05-18 11:27:45 +0100577 // Abort execution if argument is not a JSReceiver, enabled via --debug-code.
578 void AssertReceiver(Register object);
579
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000580 // Abort execution if argument is not undefined or an AllocationSite, enabled
581 // via --debug-code.
582 void AssertUndefinedOrAllocationSite(Register object);
583
584 // ---------------------------------------------------------------------------
585 // Exception handling
586
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000587 // Push a new stack handler and link it into stack handler chain.
588 void PushStackHandler();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000589
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000590 // Unlink the stack handler on top of the stack from the stack handler chain.
591 void PopStackHandler();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000592
593 // ---------------------------------------------------------------------------
594 // Inline caching support
595
596 // Generate code for checking access rights - used for security checks
597 // on access to global objects across environments. The holder register
598 // is left untouched, but the scratch register is clobbered.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000599 void CheckAccessGlobalProxy(Register holder_reg, Register scratch1,
600 Register scratch2, Label* miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000601
602 void GetNumberHash(Register r0, Register scratch);
603
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000604 void LoadFromNumberDictionary(Label* miss, Register elements, Register key,
605 Register r0, Register r1, Register r2,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000606 Register result);
607
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000608 // ---------------------------------------------------------------------------
609 // Allocation support
610
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000611 // Allocate an object in new space or old space. If the given space
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000612 // is exhausted control continues at the gc_required label. The allocated
613 // object is returned in result and end of the new object is returned in
614 // result_end. The register scratch can be passed as no_reg in which case
615 // an additional object reference will be added to the reloc info. The
616 // returned pointers in result and result_end have not yet been tagged as
617 // heap objects. If result_contains_top_on_entry is true the content of
618 // result is known to be the allocation top on entry (could be result_end
619 // from a previous call). If result_contains_top_on_entry is true scratch
620 // should be no_reg as it is never used.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000621 void Allocate(int object_size, Register result, Register result_end,
622 Register scratch, Label* gc_required, AllocationFlags flags);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000623
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000624 void Allocate(int header_size, ScaleFactor element_size,
625 Register element_count, RegisterValueType element_count_type,
626 Register result, Register result_end, Register scratch,
627 Label* gc_required, AllocationFlags flags);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000628
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000629 void Allocate(Register object_size, Register result, Register result_end,
630 Register scratch, Label* gc_required, AllocationFlags flags);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000631
Ben Murdochc5610432016-08-08 18:44:38 +0100632 // FastAllocate is right now only used for folded allocations. It just
633 // increments the top pointer without checking against limit. This can only
634 // be done if it was proved earlier that the allocation will succeed.
635 void FastAllocate(int object_size, Register result, Register result_end,
636 AllocationFlags flags);
637 void FastAllocate(Register object_size, Register result, Register result_end,
638 AllocationFlags flags);
639
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000640 // Allocate a heap number in new space with undefined value. The
641 // register scratch2 can be passed as no_reg; the others must be
642 // valid registers. Returns tagged pointer in result register, or
643 // jumps to gc_required if new space is full.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000644 void AllocateHeapNumber(Register result, Register scratch1, Register scratch2,
645 Label* gc_required, MutableMode mode = IMMUTABLE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000646
647 // Allocate a sequential string. All the header fields of the string object
648 // are initialized.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000649 void AllocateTwoByteString(Register result, Register length,
650 Register scratch1, Register scratch2,
651 Register scratch3, Label* gc_required);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000652 void AllocateOneByteString(Register result, Register length,
653 Register scratch1, Register scratch2,
654 Register scratch3, Label* gc_required);
655 void AllocateOneByteString(Register result, int length, Register scratch1,
656 Register scratch2, Label* gc_required);
657
658 // Allocate a raw cons string object. Only the map field of the result is
659 // initialized.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000660 void AllocateTwoByteConsString(Register result, Register scratch1,
661 Register scratch2, Label* gc_required);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000662 void AllocateOneByteConsString(Register result, Register scratch1,
663 Register scratch2, Label* gc_required);
664
665 // Allocate a raw sliced string object. Only the map field of the result is
666 // initialized.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000667 void AllocateTwoByteSlicedString(Register result, Register scratch1,
668 Register scratch2, Label* gc_required);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000669 void AllocateOneByteSlicedString(Register result, Register scratch1,
670 Register scratch2, Label* gc_required);
671
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000672 // Allocate and initialize a JSValue wrapper with the specified {constructor}
673 // and {value}.
674 void AllocateJSValue(Register result, Register constructor, Register value,
675 Register scratch, Label* gc_required);
676
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000677 // Copy memory, byte-by-byte, from source to destination. Not optimized for
678 // long or aligned copies.
679 // The contents of index and scratch are destroyed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000680 void CopyBytes(Register source, Register destination, Register length,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000681 Register scratch);
682
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000683 // Initialize fields with filler values. Fields starting at |current_address|
684 // not including |end_address| are overwritten with the value in |filler|. At
685 // the end the loop, |current_address| takes the value of |end_address|.
686 void InitializeFieldsWithFiller(Register current_address,
687 Register end_address, Register filler);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000688
689 // ---------------------------------------------------------------------------
690 // Support functions.
691
692 // Check a boolean-bit of a Smi field.
693 void BooleanBitTest(Register object, int field_offset, int bit_index);
694
695 // Check if result is zero and op is negative.
696 void NegativeZeroTest(Register result, Register op, Label* then_label);
697
698 // Check if result is zero and any of op1 and op2 are negative.
699 // Register scratch is destroyed, and it must be different from op2.
700 void NegativeZeroTest(Register result, Register op1, Register op2,
701 Register scratch, Label* then_label);
702
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000703 // Machine code version of Map::GetConstructor().
704 // |temp| holds |result|'s map when done.
705 void GetMapConstructor(Register result, Register map, Register temp);
706
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000707 // Try to get function prototype of a function and puts the value in
708 // the result register. Checks that the function really is a
709 // function and jumps to the miss label if the fast checks fail. The
710 // function register will be untouched; the other registers may be
711 // clobbered.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000712 void TryGetFunctionPrototype(Register function, Register result,
713 Register scratch, Label* miss);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000714
715 // Picks out an array index from the hash field.
716 // Register use:
717 // hash - holds the index's hash. Clobbered.
718 // index - holds the overwritten index on exit.
719 void IndexFromHash(Register hash, Register index);
720
721 // ---------------------------------------------------------------------------
722 // Runtime calls
723
724 // Call a code stub. Generate the code if necessary.
725 void CallStub(CodeStub* stub, TypeFeedbackId ast_id = TypeFeedbackId::None());
726
727 // Tail call a code stub (jump). Generate the code if necessary.
728 void TailCallStub(CodeStub* stub);
729
730 // Return from a code stub after popping its arguments.
731 void StubReturn(int argc);
732
733 // Call a runtime routine.
734 void CallRuntime(const Runtime::Function* f, int num_arguments,
735 SaveFPRegsMode save_doubles = kDontSaveFPRegs);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000736 void CallRuntimeSaveDoubles(Runtime::FunctionId fid) {
737 const Runtime::Function* function = Runtime::FunctionForId(fid);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000738 CallRuntime(function, function->nargs, kSaveFPRegs);
739 }
740
741 // Convenience function: Same as above, but takes the fid instead.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000742 void CallRuntime(Runtime::FunctionId fid,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000743 SaveFPRegsMode save_doubles = kDontSaveFPRegs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000744 const Runtime::Function* function = Runtime::FunctionForId(fid);
745 CallRuntime(function, function->nargs, save_doubles);
746 }
747
748 // Convenience function: Same as above, but takes the fid instead.
749 void CallRuntime(Runtime::FunctionId fid, int num_arguments,
750 SaveFPRegsMode save_doubles = kDontSaveFPRegs) {
751 CallRuntime(Runtime::FunctionForId(fid), num_arguments, save_doubles);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000752 }
753
754 // Convenience function: call an external reference.
755 void CallExternalReference(ExternalReference ref, int num_arguments);
756
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000757 // Convenience function: tail call a runtime routine (jump).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000758 void TailCallRuntime(Runtime::FunctionId fid);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000759
760 // Before calling a C-function from generated code, align arguments on stack.
761 // After aligning the frame, arguments must be stored in esp[0], esp[4],
762 // etc., not pushed. The argument count assumes all arguments are word sized.
763 // Some compilers/platforms require the stack to be aligned when calling
764 // C++ code.
765 // Needs a scratch register to do some arithmetic. This register will be
766 // trashed.
767 void PrepareCallCFunction(int num_arguments, Register scratch);
768
769 // Calls a C function and cleans up the space for arguments allocated
770 // by PrepareCallCFunction. The called function is not allowed to trigger a
771 // garbage collection, since that might move the code and invalidate the
772 // return address (unless this is somehow accounted for by the called
773 // function).
774 void CallCFunction(ExternalReference function, int num_arguments);
775 void CallCFunction(Register function, int num_arguments);
776
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000777 // Jump to a runtime routine.
778 void JumpToExternalReference(const ExternalReference& ext);
779
780 // ---------------------------------------------------------------------------
781 // Utilities
782
783 void Ret();
784
785 // Return and drop arguments from stack, where the number of arguments
786 // may be bigger than 2^16 - 1. Requires a scratch register.
787 void Ret(int bytes_dropped, Register scratch);
788
789 // Emit code to discard a non-negative number of pointer-sized elements
790 // from the stack, clobbering only the esp register.
791 void Drop(int element_count);
792
793 void Call(Label* target) { call(target); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000794 void Call(Handle<Code> target, RelocInfo::Mode rmode) { call(target, rmode); }
795 void Jump(Handle<Code> target, RelocInfo::Mode rmode) { jmp(target, rmode); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000796 void Push(Register src) { push(src); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000797 void Push(const Operand& src) { push(src); }
798 void Push(Immediate value) { push(value); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000799 void Pop(Register dst) { pop(dst); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000800 void Pop(const Operand& dst) { pop(dst); }
801 void PushReturnAddressFrom(Register src) { push(src); }
802 void PopReturnAddressTo(Register dst) { pop(dst); }
803
804 void Lzcnt(Register dst, Register src) { Lzcnt(dst, Operand(src)); }
805 void Lzcnt(Register dst, const Operand& src);
806
807 void Tzcnt(Register dst, Register src) { Tzcnt(dst, Operand(src)); }
808 void Tzcnt(Register dst, const Operand& src);
809
810 void Popcnt(Register dst, Register src) { Popcnt(dst, Operand(src)); }
811 void Popcnt(Register dst, const Operand& src);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000812
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000813 // Move if the registers are not identical.
814 void Move(Register target, Register source);
815
816 // Move a constant into a destination using the most efficient encoding.
817 void Move(Register dst, const Immediate& x);
818 void Move(const Operand& dst, const Immediate& x);
819
Ben Murdochda12d292016-06-02 14:46:10 +0100820 void Move(Register dst, Handle<Object> handle) { LoadObject(dst, handle); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000821 void Move(Register dst, Smi* source) { Move(dst, Immediate(source)); }
822
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000823 // Push a handle value.
824 void Push(Handle<Object> handle) { push(Immediate(handle)); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000825 void Push(Smi* smi) { Push(Immediate(smi)); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000826
827 Handle<Object> CodeObject() {
828 DCHECK(!code_object_.is_null());
829 return code_object_;
830 }
831
832 // Insert code to verify that the x87 stack has the specified depth (0-7)
833 void VerifyX87StackDepth(uint32_t depth);
834
835 // Emit code for a truncating division by a constant. The dividend register is
836 // unchanged, the result is in edx, and eax gets clobbered.
837 void TruncatingDiv(Register dividend, int32_t divisor);
838
839 // ---------------------------------------------------------------------------
840 // StatsCounter support
841
842 void SetCounter(StatsCounter* counter, int value);
843 void IncrementCounter(StatsCounter* counter, int value);
844 void DecrementCounter(StatsCounter* counter, int value);
845 void IncrementCounter(Condition cc, StatsCounter* counter, int value);
846 void DecrementCounter(Condition cc, StatsCounter* counter, int value);
847
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000848 // ---------------------------------------------------------------------------
849 // Debugging
850
851 // Calls Abort(msg) if the condition cc is not satisfied.
852 // Use --debug_code to enable.
853 void Assert(Condition cc, BailoutReason reason);
854
855 void AssertFastElements(Register elements);
856
857 // Like Assert(), but always enabled.
858 void Check(Condition cc, BailoutReason reason);
859
860 // Print a message to stdout and abort execution.
861 void Abort(BailoutReason reason);
862
863 // Check that the stack is aligned.
864 void CheckStackAlignment();
865
866 // Verify restrictions about code generated in stubs.
867 void set_generating_stub(bool value) { generating_stub_ = value; }
868 bool generating_stub() { return generating_stub_; }
869 void set_has_frame(bool value) { has_frame_ = value; }
870 bool has_frame() { return has_frame_; }
871 inline bool AllowThisStubCall(CodeStub* stub);
872
873 // ---------------------------------------------------------------------------
874 // String utilities.
875
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000876 // Check whether the instance type represents a flat one-byte string. Jump to
877 // the label if not. If the instance type can be scratched specify same
878 // register for both instance type and scratch.
879 void JumpIfInstanceTypeIsNotSequentialOneByte(
880 Register instance_type, Register scratch,
881 Label* on_not_flat_one_byte_string);
882
883 // Checks if both objects are sequential one-byte strings, and jumps to label
884 // if either is not.
885 void JumpIfNotBothSequentialOneByteStrings(
886 Register object1, Register object2, Register scratch1, Register scratch2,
887 Label* on_not_flat_one_byte_strings);
888
889 // Checks if the given register or operand is a unique name
890 void JumpIfNotUniqueNameInstanceType(Register reg, Label* not_unique_name,
891 Label::Distance distance = Label::kFar) {
892 JumpIfNotUniqueNameInstanceType(Operand(reg), not_unique_name, distance);
893 }
894
895 void JumpIfNotUniqueNameInstanceType(Operand operand, Label* not_unique_name,
896 Label::Distance distance = Label::kFar);
897
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000898 void EmitSeqStringSetCharCheck(Register string, Register index,
899 Register value, uint32_t encoding_mask);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000900
901 static int SafepointRegisterStackIndex(Register reg) {
902 return SafepointRegisterStackIndex(reg.code());
903 }
904
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000905 // Load the type feedback vector from a JavaScript frame.
906 void EmitLoadTypeFeedbackVector(Register vector);
907
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000908 // Activation support.
909 void EnterFrame(StackFrame::Type type);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400910 void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000911 void LeaveFrame(StackFrame::Type type);
912
913 // Expects object in eax and returns map with validated enum cache
914 // in eax. Assumes that any other register can be used as a scratch.
915 void CheckEnumCache(Label* call_runtime);
916
917 // AllocationMemento support. Arrays may have an associated
918 // AllocationMemento object that can be checked for in order to pretransition
919 // to another type.
920 // On entry, receiver_reg should point to the array object.
921 // scratch_reg gets clobbered.
922 // If allocation info is present, conditional code is set to equal.
923 void TestJSArrayForAllocationMemento(Register receiver_reg,
924 Register scratch_reg,
925 Label* no_memento_found);
926
927 void JumpIfJSArrayHasAllocationMemento(Register receiver_reg,
928 Register scratch_reg,
929 Label* memento_found) {
930 Label no_memento_found;
931 TestJSArrayForAllocationMemento(receiver_reg, scratch_reg,
932 &no_memento_found);
933 j(equal, memento_found);
934 bind(&no_memento_found);
935 }
936
937 // Jumps to found label if a prototype map has dictionary elements.
938 void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0,
939 Register scratch1, Label* found);
940
941 private:
942 bool generating_stub_;
943 bool has_frame_;
944 // This handle will be patched with the code object on installation.
945 Handle<Object> code_object_;
946
947 // Helper functions for generating invokes.
948 void InvokePrologue(const ParameterCount& expected,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000949 const ParameterCount& actual, Label* done,
950 bool* definitely_mismatches, InvokeFlag flag,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000951 Label::Distance done_distance,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000952 const CallWrapper& call_wrapper);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000953
954 void EnterExitFramePrologue();
955 void EnterExitFrameEpilogue(int argc, bool save_doubles);
956
957 void LeaveExitFrameEpilogue(bool restore_context);
958
959 // Allocation support helpers.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000960 void LoadAllocationTopHelper(Register result, Register scratch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000961 AllocationFlags flags);
962
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000963 void UpdateAllocationTopHelper(Register result_end, Register scratch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000964 AllocationFlags flags);
965
966 // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000967 void InNewSpace(Register object, Register scratch, Condition cc,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000968 Label* condition_met,
969 Label::Distance condition_met_distance = Label::kFar);
970
971 // Helper for finding the mark bits for an address. Afterwards, the
972 // bitmap register points at the word with the mark bits and the mask
973 // the position of the first bit. Uses ecx as scratch and leaves addr_reg
974 // unchanged.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000975 inline void GetMarkBits(Register addr_reg, Register bitmap_reg,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000976 Register mask_reg);
977
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000978 // Compute memory operands for safepoint stack slots.
979 Operand SafepointRegisterSlot(Register reg);
980 static int SafepointRegisterStackIndex(int reg_code);
981
982 // Needs access to SafepointRegisterStackIndex for compiled frame
983 // traversal.
984 friend class StandardFrame;
985};
986
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000987// The code patcher is used to patch (typically) small parts of code e.g. for
988// debugging and other types of instrumentation. When using the code patcher
989// the exact number of bytes specified must be emitted. Is not legal to emit
990// relocation information. If any of these constraints are violated it causes
991// an assertion.
992class CodePatcher {
993 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000994 CodePatcher(Isolate* isolate, byte* address, int size);
995 ~CodePatcher();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000996
997 // Macro assembler to emit code.
998 MacroAssembler* masm() { return &masm_; }
999
1000 private:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001001 byte* address_; // The address of the code being patched.
1002 int size_; // Number of bytes of the expected patch size.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001003 MacroAssembler masm_; // Macro assembler used to generate the code.
1004};
1005
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001006// -----------------------------------------------------------------------------
1007// Static helper functions.
1008
1009// Generate an Operand for loading a field from an object.
1010inline Operand FieldOperand(Register object, int offset) {
1011 return Operand(object, offset - kHeapObjectTag);
1012}
1013
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001014// Generate an Operand for loading an indexed field from an object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001015inline Operand FieldOperand(Register object, Register index, ScaleFactor scale,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001016 int offset) {
1017 return Operand(object, index, scale, offset - kHeapObjectTag);
1018}
1019
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001020inline Operand FixedArrayElementOperand(Register array, Register index_as_smi,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001021 int additional_offset = 0) {
1022 int offset = FixedArray::kHeaderSize + additional_offset * kPointerSize;
1023 return FieldOperand(array, index_as_smi, times_half_pointer_size, offset);
1024}
1025
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001026inline Operand ContextOperand(Register context, int index) {
1027 return Operand(context, Context::SlotOffset(index));
1028}
1029
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001030inline Operand ContextOperand(Register context, Register index) {
1031 return Operand(context, index, times_pointer_size, Context::SlotOffset(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001032}
1033
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001034inline Operand NativeContextOperand() {
1035 return ContextOperand(esi, Context::NATIVE_CONTEXT_INDEX);
1036}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001037
1038#ifdef GENERATED_CODE_COVERAGE
1039extern void LogGeneratedCodeCoverage(const char* file_line);
1040#define CODE_COVERAGE_STRINGIFY(x) #x
1041#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
1042#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
1043#define ACCESS_MASM(masm) { \
1044 byte* ia32_coverage_function = \
1045 reinterpret_cast<byte*>(FUNCTION_ADDR(LogGeneratedCodeCoverage)); \
1046 masm->pushfd(); \
1047 masm->pushad(); \
1048 masm->push(Immediate(reinterpret_cast<int>(&__FILE_LINE__))); \
1049 masm->call(ia32_coverage_function, RelocInfo::RUNTIME_ENTRY); \
1050 masm->pop(eax); \
1051 masm->popad(); \
1052 masm->popfd(); \
1053 } \
1054 masm->
1055#else
1056#define ACCESS_MASM(masm) masm->
1057#endif
1058
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001059} // namespace internal
1060} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001061
1062#endif // V8_X87_MACRO_ASSEMBLER_X87_H_