aboutsummaryrefslogtreecommitdiff
path: root/src/x64/macro-assembler-x64.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/x64/macro-assembler-x64.cc')
-rw-r--r--src/x64/macro-assembler-x64.cc376
1 files changed, 56 insertions, 320 deletions
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 8d70f540..b75b38eb 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -8,11 +8,14 @@
#include "src/base/division-by-constant.h"
#include "src/bootstrapper.h"
#include "src/codegen.h"
+#include "src/counters.h"
#include "src/debug/debug.h"
-#include "src/heap/heap.h"
+#include "src/heap/heap-inl.h"
+#include "src/objects-inl.h"
#include "src/register-configuration.h"
#include "src/x64/assembler-x64.h"
-#include "src/x64/macro-assembler-x64.h"
+
+#include "src/x64/macro-assembler-x64.h" // Cannot be the first include.
namespace v8 {
namespace internal {
@@ -1570,6 +1573,11 @@ void MacroAssembler::JumpIfNotSmi(Register src,
j(NegateCondition(smi), on_not_smi, near_jump);
}
+void MacroAssembler::JumpIfNotSmi(Operand src, Label* on_not_smi,
+ Label::Distance near_jump) {
+ Condition smi = CheckSmi(src);
+ j(NegateCondition(smi), on_not_smi, near_jump);
+}
void MacroAssembler::JumpUnlessNonNegativeSmi(
Register src, Label* on_not_smi_or_negative,
@@ -2460,10 +2468,19 @@ void MacroAssembler::Push(Smi* source) {
intptr_t smi = reinterpret_cast<intptr_t>(source);
if (is_int32(smi)) {
Push(Immediate(static_cast<int32_t>(smi)));
- } else {
- Register constant = GetSmiConstant(source);
- Push(constant);
+ return;
}
+ int first_byte_set = base::bits::CountTrailingZeros64(smi) / 8;
+ int last_byte_set = (63 - base::bits::CountLeadingZeros64(smi)) / 8;
+ if (first_byte_set == last_byte_set && kPointerSize == kInt64Size) {
+ // This sequence has only 7 bytes, compared to the 12 bytes below.
+ Push(Immediate(0));
+ movb(Operand(rsp, first_byte_set),
+ Immediate(static_cast<int8_t>(smi >> (8 * first_byte_set))));
+ return;
+ }
+ Register constant = GetSmiConstant(source);
+ Push(constant);
}
@@ -2540,30 +2557,15 @@ void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(
andl(scratch1, Immediate(kFlatOneByteStringMask));
andl(scratch2, Immediate(kFlatOneByteStringMask));
// Interleave the bits to check both scratch1 and scratch2 in one test.
- DCHECK_EQ(0, kFlatOneByteStringMask & (kFlatOneByteStringMask << 3));
- leap(scratch1, Operand(scratch1, scratch2, times_8, 0));
+ const int kShift = 8;
+ DCHECK_EQ(0, kFlatOneByteStringMask & (kFlatOneByteStringMask << kShift));
+ shlp(scratch2, Immediate(kShift));
+ orp(scratch1, scratch2);
cmpl(scratch1,
- Immediate(kFlatOneByteStringTag + (kFlatOneByteStringTag << 3)));
+ Immediate(kFlatOneByteStringTag + (kFlatOneByteStringTag << kShift)));
j(not_equal, on_fail, near_jump);
}
-
-void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte(
- Register instance_type, Register scratch, Label* failure,
- Label::Distance near_jump) {
- if (!scratch.is(instance_type)) {
- movl(scratch, instance_type);
- }
-
- const int kFlatOneByteStringMask =
- kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
-
- andl(scratch, Immediate(kFlatOneByteStringMask));
- cmpl(scratch, Immediate(kStringTag | kSeqStringTag | kOneByteStringTag));
- j(not_equal, failure, near_jump);
-}
-
-
void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte(
Register first_object_instance_type, Register second_object_instance_type,
Register scratch1, Register scratch2, Label* on_fail,
@@ -3663,66 +3665,6 @@ void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
Immediate(static_cast<int8_t>(type)));
}
-void MacroAssembler::CheckFastObjectElements(Register map,
- Label* fail,
- Label::Distance distance) {
- STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
- STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
- STATIC_ASSERT(FAST_ELEMENTS == 2);
- STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
- cmpb(FieldOperand(map, Map::kBitField2Offset),
- Immediate(Map::kMaximumBitField2FastHoleySmiElementValue));
- j(below_equal, fail, distance);
- cmpb(FieldOperand(map, Map::kBitField2Offset),
- Immediate(Map::kMaximumBitField2FastHoleyElementValue));
- j(above, fail, distance);
-}
-
-
-void MacroAssembler::CheckFastSmiElements(Register map,
- Label* fail,
- Label::Distance distance) {
- STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
- STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
- cmpb(FieldOperand(map, Map::kBitField2Offset),
- Immediate(Map::kMaximumBitField2FastHoleySmiElementValue));
- j(above, fail, distance);
-}
-
-
-void MacroAssembler::StoreNumberToDoubleElements(
- Register maybe_number,
- Register elements,
- Register index,
- XMMRegister xmm_scratch,
- Label* fail,
- int elements_offset) {
- Label smi_value, done;
-
- JumpIfSmi(maybe_number, &smi_value, Label::kNear);
-
- CheckMap(maybe_number,
- isolate()->factory()->heap_number_map(),
- fail,
- DONT_DO_SMI_CHECK);
-
- // Double value, turn potential sNaN into qNaN.
- Move(xmm_scratch, 1.0);
- mulsd(xmm_scratch, FieldOperand(maybe_number, HeapNumber::kValueOffset));
- jmp(&done, Label::kNear);
-
- bind(&smi_value);
- // Value is a smi. convert to a double and store.
- // Preserve original value.
- SmiToInteger32(kScratchRegister, maybe_number);
- Cvtlsi2sd(xmm_scratch, kScratchRegister);
- bind(&done);
- Movsd(FieldOperand(elements, index, times_8,
- FixedDoubleArray::kHeaderSize - elements_offset),
- xmm_scratch);
-}
-
-
void MacroAssembler::CompareMap(Register obj, Handle<Map> map) {
Cmp(FieldOperand(obj, HeapObject::kMapOffset), map);
}
@@ -4099,32 +4041,6 @@ void MacroAssembler::GetMapConstructor(Register result, Register map,
bind(&done);
}
-
-void MacroAssembler::TryGetFunctionPrototype(Register function, Register result,
- Label* miss) {
- // Get the prototype or initial map from the function.
- movp(result,
- FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
-
- // If the prototype or initial map is the hole, don't return it and
- // simply miss the cache instead. This will allow us to allocate a
- // prototype object on-demand in the runtime system.
- CompareRoot(result, Heap::kTheHoleValueRootIndex);
- j(equal, miss);
-
- // If the function does not have an initial map, we're done.
- Label done;
- CmpObjectType(result, MAP_TYPE, kScratchRegister);
- j(not_equal, &done, Label::kNear);
-
- // Get the prototype from the initial map.
- movp(result, FieldOperand(result, Map::kPrototypeOffset));
-
- // All done.
- bind(&done);
-}
-
-
void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
if (FLAG_native_code_counters && counter->Enabled()) {
Operand counter_operand = ExternalOperand(ExternalReference(counter));
@@ -4158,14 +4074,14 @@ void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
}
}
-
-void MacroAssembler::DebugBreak() {
- Set(rax, 0); // No arguments.
- LoadAddress(rbx,
- ExternalReference(Runtime::kHandleDebuggerStatement, isolate()));
- CEntryStub ces(isolate(), 1);
- DCHECK(AllowThisStubCall(&ces));
- Call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT);
+void MacroAssembler::MaybeDropFrames() {
+ // Check whether we need to drop frames to restart a function on the stack.
+ ExternalReference restart_fp =
+ ExternalReference::debug_restart_fp_address(isolate());
+ Load(rbx, restart_fp);
+ testp(rbx, rbx);
+ j(not_zero, isolate()->builtins()->FrameDropperTrampoline(),
+ RelocInfo::CODE_TARGET);
}
void MacroAssembler::PrepareForTailCall(const ParameterCount& callee_args_count,
@@ -4286,8 +4202,8 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
DCHECK(function.is(rdi));
DCHECK_IMPLIES(new_target.is_valid(), new_target.is(rdx));
- if (call_wrapper.NeedsDebugStepCheck()) {
- FloodFunctionIfStepping(function, new_target, expected, actual);
+ if (call_wrapper.NeedsDebugHookCheck()) {
+ CheckDebugHook(function, new_target, expected, actual);
}
// Clear the new.target register if not given.
@@ -4367,6 +4283,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
DCHECK(actual.reg().is(rax));
DCHECK(expected.reg().is(rbx));
} else {
+ definitely_matches = true;
Move(rax, actual.reg());
}
}
@@ -4387,17 +4304,15 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
}
}
-
-void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target,
- const ParameterCount& expected,
- const ParameterCount& actual) {
- Label skip_flooding;
- ExternalReference last_step_action =
- ExternalReference::debug_last_step_action_address(isolate());
- Operand last_step_action_operand = ExternalOperand(last_step_action);
- STATIC_ASSERT(StepFrame > StepIn);
- cmpb(last_step_action_operand, Immediate(StepIn));
- j(less, &skip_flooding);
+void MacroAssembler::CheckDebugHook(Register fun, Register new_target,
+ const ParameterCount& expected,
+ const ParameterCount& actual) {
+ Label skip_hook;
+ ExternalReference debug_hook_active =
+ ExternalReference::debug_hook_on_function_call_address(isolate());
+ Operand debug_hook_active_operand = ExternalOperand(debug_hook_active);
+ cmpb(debug_hook_active_operand, Immediate(0));
+ j(equal, &skip_hook);
{
FrameScope frame(this,
has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
@@ -4414,7 +4329,7 @@ void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target,
}
Push(fun);
Push(fun);
- CallRuntime(Runtime::kDebugPrepareStepInIfStepping);
+ CallRuntime(Runtime::kDebugOnFunctionCall);
Pop(fun);
if (new_target.is_valid()) {
Pop(new_target);
@@ -4428,13 +4343,13 @@ void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target,
SmiToInteger64(expected.reg(), expected.reg());
}
}
- bind(&skip_flooding);
+ bind(&skip_hook);
}
void MacroAssembler::StubPrologue(StackFrame::Type type) {
pushq(rbp); // Caller's frame pointer.
movp(rbp, rsp);
- Push(Smi::FromInt(type));
+ Push(Immediate(StackFrame::TypeToMarker(type)));
}
void MacroAssembler::Prologue(bool code_pre_aging) {
@@ -4453,11 +4368,10 @@ void MacroAssembler::Prologue(bool code_pre_aging) {
}
}
-
-void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) {
+void MacroAssembler::EmitLoadFeedbackVector(Register vector) {
movp(vector, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
- movp(vector, FieldOperand(vector, JSFunction::kLiteralsOffset));
- movp(vector, FieldOperand(vector, LiteralsArray::kFeedbackVectorOffset));
+ movp(vector, FieldOperand(vector, JSFunction::kFeedbackVectorOffset));
+ movp(vector, FieldOperand(vector, Cell::kValueOffset));
}
@@ -4471,7 +4385,7 @@ void MacroAssembler::EnterFrame(StackFrame::Type type,
void MacroAssembler::EnterFrame(StackFrame::Type type) {
pushq(rbp);
movp(rbp, rsp);
- Push(Smi::FromInt(type));
+ Push(Immediate(StackFrame::TypeToMarker(type)));
if (type == StackFrame::INTERNAL) {
Move(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT);
Push(kScratchRegister);
@@ -4488,9 +4402,8 @@ void MacroAssembler::EnterFrame(StackFrame::Type type) {
void MacroAssembler::LeaveFrame(StackFrame::Type type) {
if (emit_debug_code()) {
- Move(kScratchRegister, Smi::FromInt(type));
cmpp(Operand(rbp, CommonFrameConstants::kContextOrFrameTypeOffset),
- kScratchRegister);
+ Immediate(StackFrame::TypeToMarker(type)));
Check(equal, kStackFrameTypesMustMatch);
}
movp(rsp, rbp);
@@ -4529,7 +4442,7 @@ void MacroAssembler::EnterExitFramePrologue(bool save_rax,
movp(rbp, rsp);
// Reserve room for entry stack pointer and push the code object.
- Push(Smi::FromInt(frame_type));
+ Push(Immediate(StackFrame::TypeToMarker(frame_type)));
DCHECK_EQ(-2 * kPointerSize, ExitFrameConstants::kSPOffset);
Push(Immediate(0)); // Saved entry sp, patched before call.
Move(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT);
@@ -4958,125 +4871,6 @@ void MacroAssembler::AllocateHeapNumber(Register result,
movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
}
-
-void MacroAssembler::AllocateTwoByteString(Register result,
- Register length,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- Label* gc_required) {
- // Calculate the number of bytes needed for the characters in the string while
- // observing object alignment.
- const int kHeaderAlignment = SeqTwoByteString::kHeaderSize &
- kObjectAlignmentMask;
- DCHECK(kShortSize == 2);
- // scratch1 = length * 2 + kObjectAlignmentMask.
- leap(scratch1, Operand(length, length, times_1, kObjectAlignmentMask +
- kHeaderAlignment));
- andp(scratch1, Immediate(~kObjectAlignmentMask));
- if (kHeaderAlignment > 0) {
- subp(scratch1, Immediate(kHeaderAlignment));
- }
-
- // Allocate two byte string in new space.
- Allocate(SeqTwoByteString::kHeaderSize, times_1, scratch1, result, scratch2,
- scratch3, gc_required, NO_ALLOCATION_FLAGS);
-
- // Set the map, length and hash field.
- LoadRoot(kScratchRegister, Heap::kStringMapRootIndex);
- movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
- Integer32ToSmi(scratch1, length);
- movp(FieldOperand(result, String::kLengthOffset), scratch1);
- movp(FieldOperand(result, String::kHashFieldOffset),
- Immediate(String::kEmptyHashField));
-}
-
-
-void MacroAssembler::AllocateOneByteString(Register result, Register length,
- Register scratch1, Register scratch2,
- Register scratch3,
- Label* gc_required) {
- // Calculate the number of bytes needed for the characters in the string while
- // observing object alignment.
- const int kHeaderAlignment = SeqOneByteString::kHeaderSize &
- kObjectAlignmentMask;
- movl(scratch1, length);
- DCHECK(kCharSize == 1);
- addp(scratch1, Immediate(kObjectAlignmentMask + kHeaderAlignment));
- andp(scratch1, Immediate(~kObjectAlignmentMask));
- if (kHeaderAlignment > 0) {
- subp(scratch1, Immediate(kHeaderAlignment));
- }
-
- // Allocate one-byte string in new space.
- Allocate(SeqOneByteString::kHeaderSize, times_1, scratch1, result, scratch2,
- scratch3, gc_required, NO_ALLOCATION_FLAGS);
-
- // Set the map, length and hash field.
- LoadRoot(kScratchRegister, Heap::kOneByteStringMapRootIndex);
- movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
- Integer32ToSmi(scratch1, length);
- movp(FieldOperand(result, String::kLengthOffset), scratch1);
- movp(FieldOperand(result, String::kHashFieldOffset),
- Immediate(String::kEmptyHashField));
-}
-
-
-void MacroAssembler::AllocateTwoByteConsString(Register result,
- Register scratch1,
- Register scratch2,
- Label* gc_required) {
- // Allocate heap number in new space.
- Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
- NO_ALLOCATION_FLAGS);
-
- // Set the map. The other fields are left uninitialized.
- LoadRoot(kScratchRegister, Heap::kConsStringMapRootIndex);
- movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
-}
-
-
-void MacroAssembler::AllocateOneByteConsString(Register result,
- Register scratch1,
- Register scratch2,
- Label* gc_required) {
- Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
- NO_ALLOCATION_FLAGS);
-
- // Set the map. The other fields are left uninitialized.
- LoadRoot(kScratchRegister, Heap::kConsOneByteStringMapRootIndex);
- movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
-}
-
-
-void MacroAssembler::AllocateTwoByteSlicedString(Register result,
- Register scratch1,
- Register scratch2,
- Label* gc_required) {
- // Allocate heap number in new space.
- Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
- NO_ALLOCATION_FLAGS);
-
- // Set the map. The other fields are left uninitialized.
- LoadRoot(kScratchRegister, Heap::kSlicedStringMapRootIndex);
- movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
-}
-
-
-void MacroAssembler::AllocateOneByteSlicedString(Register result,
- Register scratch1,
- Register scratch2,
- Label* gc_required) {
- // Allocate heap number in new space.
- Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
- NO_ALLOCATION_FLAGS);
-
- // Set the map. The other fields are left uninitialized.
- LoadRoot(kScratchRegister, Heap::kSlicedOneByteStringMapRootIndex);
- movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
-}
-
-
void MacroAssembler::AllocateJSValue(Register result, Register constructor,
Register value, Register scratch,
Label* gc_required) {
@@ -5137,28 +4931,6 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
}
}
-
-void MacroAssembler::LoadTransitionedArrayMapConditional(
- ElementsKind expected_kind,
- ElementsKind transitioned_kind,
- Register map_in_out,
- Register scratch,
- Label* no_map_match) {
- DCHECK(IsFastElementsKind(expected_kind));
- DCHECK(IsFastElementsKind(transitioned_kind));
-
- // Check that the function's map is the same as the expected cached map.
- movp(scratch, NativeContextOperand());
- cmpp(map_in_out,
- ContextOperand(scratch, Context::ArrayMapIndex(expected_kind)));
- j(not_equal, no_map_match);
-
- // Use the transitioned cached map.
- movp(map_in_out,
- ContextOperand(scratch, Context::ArrayMapIndex(transitioned_kind)));
-}
-
-
#ifdef _WIN64
static const int kRegisterPassedArguments = 4;
#else
@@ -5501,42 +5273,6 @@ void MacroAssembler::TestJSArrayForAllocationMemento(
Heap::kAllocationMementoMapRootIndex);
}
-
-void MacroAssembler::JumpIfDictionaryInPrototypeChain(
- Register object,
- Register scratch0,
- Register scratch1,
- Label* found) {
- DCHECK(!(scratch0.is(kScratchRegister) && scratch1.is(kScratchRegister)));
- DCHECK(!scratch1.is(scratch0));
- Register current = scratch0;
- Label loop_again, end;
-
- movp(current, object);
- movp(current, FieldOperand(current, HeapObject::kMapOffset));
- movp(current, FieldOperand(current, Map::kPrototypeOffset));
- CompareRoot(current, Heap::kNullValueRootIndex);
- j(equal, &end);
-
- // Loop based on the map going up the prototype chain.
- bind(&loop_again);
- movp(current, FieldOperand(current, HeapObject::kMapOffset));
- STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE);
- STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
- CmpInstanceType(current, JS_OBJECT_TYPE);
- j(below, found);
- movp(scratch1, FieldOperand(current, Map::kBitField2Offset));
- DecodeField<Map::ElementsKindBits>(scratch1);
- cmpp(scratch1, Immediate(DICTIONARY_ELEMENTS));
- j(equal, found);
- movp(current, FieldOperand(current, Map::kPrototypeOffset));
- CompareRoot(current, Heap::kNullValueRootIndex);
- j(not_equal, &loop_again);
-
- bind(&end);
-}
-
-
void MacroAssembler::TruncatingDiv(Register dividend, int32_t divisor) {
DCHECK(!dividend.is(rax));
DCHECK(!dividend.is(rdx));