Upgrade V8 to version 4.9.385.28
https://chromium.googlesource.com/v8/v8/+/4.9.385.28
FPIIM-449
Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 5b897de..9952eb3 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -2,33 +2,30 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "src/v8.h"
-
#if V8_TARGET_ARCH_X64
#include "src/base/bits.h"
#include "src/base/division-by-constant.h"
#include "src/bootstrapper.h"
#include "src/codegen.h"
-#include "src/cpu-profiler.h"
-#include "src/debug.h"
+#include "src/debug/debug.h"
#include "src/heap/heap.h"
-#include "src/isolate-inl.h"
-#include "src/serialize.h"
+#include "src/register-configuration.h"
#include "src/x64/assembler-x64.h"
#include "src/x64/macro-assembler-x64.h"
namespace v8 {
namespace internal {
-MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size)
+MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size,
+ CodeObjectRequired create_code_object)
: Assembler(arg_isolate, buffer, size),
generating_stub_(false),
has_frame_(false),
root_array_available_(true) {
- if (isolate() != NULL) {
- code_object_ = Handle<Object>(isolate()->heap()->undefined_value(),
- isolate());
+ if (create_code_object == CodeObjectRequired::kYes) {
+ code_object_ =
+ Handle<Object>::New(isolate()->heap()->undefined_value(), isolate());
}
}
@@ -177,6 +174,7 @@
void MacroAssembler::StoreRoot(Register source, Heap::RootListIndex index) {
+ DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
DCHECK(root_array_available_);
movp(Operand(kRootRegister, (index << kPointerSizeLog2) - kRootRegisterBias),
source);
@@ -664,246 +662,48 @@
}
-void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
- int num_arguments,
- int result_size) {
+void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
// ----------- S t a t e -------------
// -- rsp[0] : return address
// -- rsp[8] : argument num_arguments - 1
// ...
// -- rsp[8 * num_arguments] : argument 0 (receiver)
+ //
+ // For runtime functions with variable arguments:
+ // -- rax : number of arguments
// -----------------------------------
- // TODO(1236192): Most runtime routines don't need the number of
- // arguments passed in because it is constant. At some point we
- // should remove this need and make the runtime routine entry code
- // smarter.
- Set(rax, num_arguments);
- JumpToExternalReference(ext, result_size);
-}
-
-
-void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
- int num_arguments,
- int result_size) {
- TailCallExternalReference(ExternalReference(fid, isolate()),
- num_arguments,
- result_size);
-}
-
-
-static int Offset(ExternalReference ref0, ExternalReference ref1) {
- int64_t offset = (ref0.address() - ref1.address());
- // Check that fits into int.
- DCHECK(static_cast<int>(offset) == offset);
- return static_cast<int>(offset);
-}
-
-
-void MacroAssembler::PrepareCallApiFunction(int arg_stack_space) {
- EnterApiExitFrame(arg_stack_space);
-}
-
-
-void MacroAssembler::CallApiFunctionAndReturn(
- Register function_address,
- ExternalReference thunk_ref,
- Register thunk_last_arg,
- int stack_space,
- Operand return_value_operand,
- Operand* context_restore_operand) {
- Label prologue;
- Label promote_scheduled_exception;
- Label exception_handled;
- Label delete_allocated_handles;
- Label leave_exit_frame;
- Label write_back;
-
- Factory* factory = isolate()->factory();
- ExternalReference next_address =
- ExternalReference::handle_scope_next_address(isolate());
- const int kNextOffset = 0;
- const int kLimitOffset = Offset(
- ExternalReference::handle_scope_limit_address(isolate()),
- next_address);
- const int kLevelOffset = Offset(
- ExternalReference::handle_scope_level_address(isolate()),
- next_address);
- ExternalReference scheduled_exception_address =
- ExternalReference::scheduled_exception_address(isolate());
-
- DCHECK(rdx.is(function_address) || r8.is(function_address));
- // Allocate HandleScope in callee-save registers.
- Register prev_next_address_reg = r14;
- Register prev_limit_reg = rbx;
- Register base_reg = r15;
- Move(base_reg, next_address);
- movp(prev_next_address_reg, Operand(base_reg, kNextOffset));
- movp(prev_limit_reg, Operand(base_reg, kLimitOffset));
- addl(Operand(base_reg, kLevelOffset), Immediate(1));
-
- if (FLAG_log_timer_events) {
- FrameScope frame(this, StackFrame::MANUAL);
- PushSafepointRegisters();
- PrepareCallCFunction(1);
- LoadAddress(arg_reg_1, ExternalReference::isolate_address(isolate()));
- CallCFunction(ExternalReference::log_enter_external_function(isolate()), 1);
- PopSafepointRegisters();
+ const Runtime::Function* function = Runtime::FunctionForId(fid);
+ DCHECK_EQ(1, function->result_size);
+ if (function->nargs >= 0) {
+ Set(rax, function->nargs);
}
-
-
- Label profiler_disabled;
- Label end_profiler_check;
- Move(rax, ExternalReference::is_profiling_address(isolate()));
- cmpb(Operand(rax, 0), Immediate(0));
- j(zero, &profiler_disabled);
-
- // Third parameter is the address of the actual getter function.
- Move(thunk_last_arg, function_address);
- Move(rax, thunk_ref);
- jmp(&end_profiler_check);
-
- bind(&profiler_disabled);
- // Call the api function!
- Move(rax, function_address);
-
- bind(&end_profiler_check);
-
- // Call the api function!
- call(rax);
-
- if (FLAG_log_timer_events) {
- FrameScope frame(this, StackFrame::MANUAL);
- PushSafepointRegisters();
- PrepareCallCFunction(1);
- LoadAddress(arg_reg_1, ExternalReference::isolate_address(isolate()));
- CallCFunction(ExternalReference::log_leave_external_function(isolate()), 1);
- PopSafepointRegisters();
- }
-
- // Load the value from ReturnValue
- movp(rax, return_value_operand);
- bind(&prologue);
-
- // No more valid handles (the result handle was the last one). Restore
- // previous handle scope.
- subl(Operand(base_reg, kLevelOffset), Immediate(1));
- movp(Operand(base_reg, kNextOffset), prev_next_address_reg);
- cmpp(prev_limit_reg, Operand(base_reg, kLimitOffset));
- j(not_equal, &delete_allocated_handles);
- bind(&leave_exit_frame);
-
- // Check if the function scheduled an exception.
- Move(rsi, scheduled_exception_address);
- Cmp(Operand(rsi, 0), factory->the_hole_value());
- j(not_equal, &promote_scheduled_exception);
- bind(&exception_handled);
-
-#if ENABLE_EXTRA_CHECKS
- // Check if the function returned a valid JavaScript value.
- Label ok;
- Register return_value = rax;
- Register map = rcx;
-
- JumpIfSmi(return_value, &ok, Label::kNear);
- movp(map, FieldOperand(return_value, HeapObject::kMapOffset));
-
- CmpInstanceType(map, FIRST_NONSTRING_TYPE);
- j(below, &ok, Label::kNear);
-
- CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
- j(above_equal, &ok, Label::kNear);
-
- CompareRoot(map, Heap::kHeapNumberMapRootIndex);
- j(equal, &ok, Label::kNear);
-
- CompareRoot(return_value, Heap::kUndefinedValueRootIndex);
- j(equal, &ok, Label::kNear);
-
- CompareRoot(return_value, Heap::kTrueValueRootIndex);
- j(equal, &ok, Label::kNear);
-
- CompareRoot(return_value, Heap::kFalseValueRootIndex);
- j(equal, &ok, Label::kNear);
-
- CompareRoot(return_value, Heap::kNullValueRootIndex);
- j(equal, &ok, Label::kNear);
-
- Abort(kAPICallReturnedInvalidObject);
-
- bind(&ok);
-#endif
-
- bool restore_context = context_restore_operand != NULL;
- if (restore_context) {
- movp(rsi, *context_restore_operand);
- }
- LeaveApiExitFrame(!restore_context);
- ret(stack_space * kPointerSize);
-
- bind(&promote_scheduled_exception);
- {
- FrameScope frame(this, StackFrame::INTERNAL);
- CallRuntime(Runtime::kPromoteScheduledException, 0);
- }
- jmp(&exception_handled);
-
- // HandleScope limit has changed. Delete allocated extensions.
- bind(&delete_allocated_handles);
- movp(Operand(base_reg, kLimitOffset), prev_limit_reg);
- movp(prev_limit_reg, rax);
- LoadAddress(arg_reg_1, ExternalReference::isolate_address(isolate()));
- LoadAddress(rax,
- ExternalReference::delete_handle_scope_extensions(isolate()));
- call(rax);
- movp(rax, prev_limit_reg);
- jmp(&leave_exit_frame);
+ JumpToExternalReference(ExternalReference(fid, isolate()));
}
-void MacroAssembler::JumpToExternalReference(const ExternalReference& ext,
- int result_size) {
+void MacroAssembler::JumpToExternalReference(const ExternalReference& ext) {
// Set the entry point and jump to the C entry runtime stub.
LoadAddress(rbx, ext);
- CEntryStub ces(isolate(), result_size);
+ CEntryStub ces(isolate(), 1);
jmp(ces.GetCode(), RelocInfo::CODE_TARGET);
}
-void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
- InvokeFlag flag,
+void MacroAssembler::InvokeBuiltin(int native_context_index, InvokeFlag flag,
const CallWrapper& call_wrapper) {
// You can't call a builtin without a valid frame.
DCHECK(flag == JUMP_FUNCTION || has_frame());
- // Rely on the assertion to check that the number of provided
- // arguments match the expected number of arguments. Fake a
- // parameter count to avoid emitting code to do the check.
+ // Fake a parameter count to avoid emitting code to do the check.
ParameterCount expected(0);
- GetBuiltinEntry(rdx, id);
- InvokeCode(rdx, expected, expected, flag, call_wrapper);
+ LoadNativeContextSlot(native_context_index, rdi);
+ InvokeFunctionCode(rdi, no_reg, expected, expected, flag, call_wrapper);
}
-void MacroAssembler::GetBuiltinFunction(Register target,
- Builtins::JavaScript id) {
- // Load the builtins object into target register.
- movp(target, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
- movp(target, FieldOperand(target, GlobalObject::kBuiltinsOffset));
- movp(target, FieldOperand(target,
- JSBuiltinsObject::OffsetOfFunctionWithId(id)));
-}
-
-
-void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
- DCHECK(!target.is(rdi));
- // Load the JavaScript builtin function from the builtins object.
- GetBuiltinFunction(rdi, id);
- movp(target, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
-}
-
-
-#define REG(Name) { kRegister_ ## Name ## _Code }
+#define REG(Name) \
+ { Register::kCode_##Name }
static const Register saved_regs[] = {
REG(rax), REG(rcx), REG(rdx), REG(rbx), REG(rbp), REG(rsi), REG(rdi), REG(r8),
@@ -933,7 +733,7 @@
subp(rsp, Immediate(kDoubleSize * XMMRegister::kMaxNumRegisters));
for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
XMMRegister reg = XMMRegister::from_code(i);
- movsd(Operand(rsp, i * kDoubleSize), reg);
+ Movsd(Operand(rsp, i * kDoubleSize), reg);
}
}
}
@@ -946,7 +746,7 @@
if (fp_mode == kSaveFPRegs) {
for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
XMMRegister reg = XMMRegister::from_code(i);
- movsd(reg, Operand(rsp, i * kDoubleSize));
+ Movsd(reg, Operand(rsp, i * kDoubleSize));
}
addp(rsp, Immediate(kDoubleSize * XMMRegister::kMaxNumRegisters));
}
@@ -959,15 +759,222 @@
}
+void MacroAssembler::Cvtss2sd(XMMRegister dst, XMMRegister src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vcvtss2sd(dst, src, src);
+ } else {
+ cvtss2sd(dst, src);
+ }
+}
+
+
+void MacroAssembler::Cvtss2sd(XMMRegister dst, const Operand& src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vcvtss2sd(dst, dst, src);
+ } else {
+ cvtss2sd(dst, src);
+ }
+}
+
+
+void MacroAssembler::Cvtsd2ss(XMMRegister dst, XMMRegister src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vcvtsd2ss(dst, src, src);
+ } else {
+ cvtsd2ss(dst, src);
+ }
+}
+
+
+void MacroAssembler::Cvtsd2ss(XMMRegister dst, const Operand& src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vcvtsd2ss(dst, dst, src);
+ } else {
+ cvtsd2ss(dst, src);
+ }
+}
+
+
void MacroAssembler::Cvtlsi2sd(XMMRegister dst, Register src) {
- xorps(dst, dst);
- cvtlsi2sd(dst, src);
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vxorpd(dst, dst, dst);
+ vcvtlsi2sd(dst, dst, src);
+ } else {
+ xorpd(dst, dst);
+ cvtlsi2sd(dst, src);
+ }
}
void MacroAssembler::Cvtlsi2sd(XMMRegister dst, const Operand& src) {
- xorps(dst, dst);
- cvtlsi2sd(dst, src);
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vxorpd(dst, dst, dst);
+ vcvtlsi2sd(dst, dst, src);
+ } else {
+ xorpd(dst, dst);
+ cvtlsi2sd(dst, src);
+ }
+}
+
+
+void MacroAssembler::Cvtqsi2ss(XMMRegister dst, Register src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vxorps(dst, dst, dst);
+ vcvtqsi2ss(dst, dst, src);
+ } else {
+ xorps(dst, dst);
+ cvtqsi2ss(dst, src);
+ }
+}
+
+
+void MacroAssembler::Cvtqsi2ss(XMMRegister dst, const Operand& src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vxorps(dst, dst, dst);
+ vcvtqsi2ss(dst, dst, src);
+ } else {
+ xorps(dst, dst);
+ cvtqsi2ss(dst, src);
+ }
+}
+
+
+void MacroAssembler::Cvtqsi2sd(XMMRegister dst, Register src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vxorpd(dst, dst, dst);
+ vcvtqsi2sd(dst, dst, src);
+ } else {
+ xorpd(dst, dst);
+ cvtqsi2sd(dst, src);
+ }
+}
+
+
+void MacroAssembler::Cvtqsi2sd(XMMRegister dst, const Operand& src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vxorpd(dst, dst, dst);
+ vcvtqsi2sd(dst, dst, src);
+ } else {
+ xorpd(dst, dst);
+ cvtqsi2sd(dst, src);
+ }
+}
+
+
+void MacroAssembler::Cvtqui2ss(XMMRegister dst, Register src, Register tmp) {
+ Label msb_set_src;
+ Label jmp_return;
+ testq(src, src);
+ j(sign, &msb_set_src, Label::kNear);
+ Cvtqsi2ss(dst, src);
+ jmp(&jmp_return, Label::kNear);
+ bind(&msb_set_src);
+ movq(tmp, src);
+ shrq(src, Immediate(1));
+ // Recover the least significant bit to avoid rounding errors.
+ andq(tmp, Immediate(1));
+ orq(src, tmp);
+ Cvtqsi2ss(dst, src);
+ addss(dst, dst);
+ bind(&jmp_return);
+}
+
+
+void MacroAssembler::Cvtqui2sd(XMMRegister dst, Register src, Register tmp) {
+ Label msb_set_src;
+ Label jmp_return;
+ testq(src, src);
+ j(sign, &msb_set_src, Label::kNear);
+ Cvtqsi2sd(dst, src);
+ jmp(&jmp_return, Label::kNear);
+ bind(&msb_set_src);
+ movq(tmp, src);
+ shrq(src, Immediate(1));
+ andq(tmp, Immediate(1));
+ orq(src, tmp);
+ Cvtqsi2sd(dst, src);
+ addsd(dst, dst);
+ bind(&jmp_return);
+}
+
+
+void MacroAssembler::Cvtsd2si(Register dst, XMMRegister src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vcvtsd2si(dst, src);
+ } else {
+ cvtsd2si(dst, src);
+ }
+}
+
+
+void MacroAssembler::Cvttsd2si(Register dst, XMMRegister src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vcvttsd2si(dst, src);
+ } else {
+ cvttsd2si(dst, src);
+ }
+}
+
+
+void MacroAssembler::Cvttsd2si(Register dst, const Operand& src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vcvttsd2si(dst, src);
+ } else {
+ cvttsd2si(dst, src);
+ }
+}
+
+
+void MacroAssembler::Cvttss2siq(Register dst, XMMRegister src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vcvttss2siq(dst, src);
+ } else {
+ cvttss2siq(dst, src);
+ }
+}
+
+
+void MacroAssembler::Cvttss2siq(Register dst, const Operand& src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vcvttss2siq(dst, src);
+ } else {
+ cvttss2siq(dst, src);
+ }
+}
+
+
+void MacroAssembler::Cvttsd2siq(Register dst, XMMRegister src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vcvttsd2siq(dst, src);
+ } else {
+ cvttsd2siq(dst, src);
+ }
+}
+
+
+void MacroAssembler::Cvttsd2siq(Register dst, const Operand& src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vcvttsd2siq(dst, src);
+ } else {
+ cvttsd2siq(dst, src);
+ }
}
@@ -1084,71 +1091,24 @@
Register MacroAssembler::GetSmiConstant(Smi* source) {
+ STATIC_ASSERT(kSmiTag == 0);
int value = source->value();
if (value == 0) {
xorl(kScratchRegister, kScratchRegister);
return kScratchRegister;
}
- if (value == 1) {
- return kSmiConstantRegister;
- }
LoadSmiConstant(kScratchRegister, source);
return kScratchRegister;
}
void MacroAssembler::LoadSmiConstant(Register dst, Smi* source) {
- if (emit_debug_code()) {
- Move(dst, Smi::FromInt(kSmiConstantRegisterValue),
- Assembler::RelocInfoNone());
- cmpp(dst, kSmiConstantRegister);
- Assert(equal, kUninitializedKSmiConstantRegister);
- }
+ STATIC_ASSERT(kSmiTag == 0);
int value = source->value();
if (value == 0) {
xorl(dst, dst);
- return;
- }
- bool negative = value < 0;
- unsigned int uvalue = negative ? -value : value;
-
- switch (uvalue) {
- case 9:
- leap(dst,
- Operand(kSmiConstantRegister, kSmiConstantRegister, times_8, 0));
- break;
- case 8:
- xorl(dst, dst);
- leap(dst, Operand(dst, kSmiConstantRegister, times_8, 0));
- break;
- case 4:
- xorl(dst, dst);
- leap(dst, Operand(dst, kSmiConstantRegister, times_4, 0));
- break;
- case 5:
- leap(dst,
- Operand(kSmiConstantRegister, kSmiConstantRegister, times_4, 0));
- break;
- case 3:
- leap(dst,
- Operand(kSmiConstantRegister, kSmiConstantRegister, times_2, 0));
- break;
- case 2:
- leap(dst,
- Operand(kSmiConstantRegister, kSmiConstantRegister, times_1, 0));
- break;
- case 1:
- movp(dst, kSmiConstantRegister);
- break;
- case 0:
- UNREACHABLE();
- return;
- default:
- Move(dst, source, Assembler::RelocInfoNone());
- return;
- }
- if (negative) {
- negp(dst);
+ } else {
+ Move(dst, source, Assembler::RelocInfoNone());
}
}
@@ -1442,14 +1402,6 @@
}
-Condition MacroAssembler::CheckIsMinSmi(Register src) {
- DCHECK(!src.is(kScratchRegister));
- // If we overflow by subtracting one, it's the minimal smi value.
- cmpp(src, kSmiConstantRegister);
- return overflow;
-}
-
-
Condition MacroAssembler::CheckInteger32ValidSmiValue(Register src) {
if (SmiValuesAre32Bits()) {
// A 32-bit integer value can always be converted to a smi.
@@ -1588,43 +1540,11 @@
return;
} else if (dst.is(src)) {
DCHECK(!dst.is(kScratchRegister));
- switch (constant->value()) {
- case 1:
- addp(dst, kSmiConstantRegister);
- return;
- case 2:
- leap(dst, Operand(src, kSmiConstantRegister, times_2, 0));
- return;
- case 4:
- leap(dst, Operand(src, kSmiConstantRegister, times_4, 0));
- return;
- case 8:
- leap(dst, Operand(src, kSmiConstantRegister, times_8, 0));
- return;
- default:
- Register constant_reg = GetSmiConstant(constant);
- addp(dst, constant_reg);
- return;
- }
+ Register constant_reg = GetSmiConstant(constant);
+ addp(dst, constant_reg);
} else {
- switch (constant->value()) {
- case 1:
- leap(dst, Operand(src, kSmiConstantRegister, times_1, 0));
- return;
- case 2:
- leap(dst, Operand(src, kSmiConstantRegister, times_2, 0));
- return;
- case 4:
- leap(dst, Operand(src, kSmiConstantRegister, times_4, 0));
- return;
- case 8:
- leap(dst, Operand(src, kSmiConstantRegister, times_8, 0));
- return;
- default:
- LoadSmiConstant(dst, constant);
- addp(dst, src);
- return;
- }
+ LoadSmiConstant(dst, constant);
+ addp(dst, src);
}
}
@@ -1642,10 +1562,8 @@
}
-void MacroAssembler::SmiAddConstant(Register dst,
- Register src,
- Smi* constant,
- SmiOperationExecutionMode mode,
+void MacroAssembler::SmiAddConstant(Register dst, Register src, Smi* constant,
+ SmiOperationConstraints constraints,
Label* bailout_label,
Label::Distance near_jump) {
if (constant->value() == 0) {
@@ -1656,12 +1574,12 @@
DCHECK(!dst.is(kScratchRegister));
LoadSmiConstant(kScratchRegister, constant);
addp(dst, kScratchRegister);
- if (mode.Contains(BAILOUT_ON_NO_OVERFLOW)) {
+ if (constraints & SmiOperationConstraint::kBailoutOnNoOverflow) {
j(no_overflow, bailout_label, near_jump);
- DCHECK(mode.Contains(PRESERVE_SOURCE_REGISTER));
+ DCHECK(constraints & SmiOperationConstraint::kPreserveSourceRegister);
subp(dst, kScratchRegister);
- } else if (mode.Contains(BAILOUT_ON_OVERFLOW)) {
- if (mode.Contains(PRESERVE_SOURCE_REGISTER)) {
+ } else if (constraints & SmiOperationConstraint::kBailoutOnOverflow) {
+ if (constraints & SmiOperationConstraint::kPreserveSourceRegister) {
Label done;
j(no_overflow, &done, Label::kNear);
subp(dst, kScratchRegister);
@@ -1672,11 +1590,11 @@
j(overflow, bailout_label, near_jump);
}
} else {
- CHECK(mode.IsEmpty());
+ UNREACHABLE();
}
} else {
- DCHECK(mode.Contains(PRESERVE_SOURCE_REGISTER));
- DCHECK(mode.Contains(BAILOUT_ON_OVERFLOW));
+ DCHECK(constraints & SmiOperationConstraint::kPreserveSourceRegister);
+ DCHECK(constraints & SmiOperationConstraint::kBailoutOnOverflow);
LoadSmiConstant(dst, constant);
addp(dst, src);
j(overflow, bailout_label, near_jump);
@@ -1708,10 +1626,8 @@
}
-void MacroAssembler::SmiSubConstant(Register dst,
- Register src,
- Smi* constant,
- SmiOperationExecutionMode mode,
+void MacroAssembler::SmiSubConstant(Register dst, Register src, Smi* constant,
+ SmiOperationConstraints constraints,
Label* bailout_label,
Label::Distance near_jump) {
if (constant->value() == 0) {
@@ -1722,12 +1638,12 @@
DCHECK(!dst.is(kScratchRegister));
LoadSmiConstant(kScratchRegister, constant);
subp(dst, kScratchRegister);
- if (mode.Contains(BAILOUT_ON_NO_OVERFLOW)) {
+ if (constraints & SmiOperationConstraint::kBailoutOnNoOverflow) {
j(no_overflow, bailout_label, near_jump);
- DCHECK(mode.Contains(PRESERVE_SOURCE_REGISTER));
+ DCHECK(constraints & SmiOperationConstraint::kPreserveSourceRegister);
addp(dst, kScratchRegister);
- } else if (mode.Contains(BAILOUT_ON_OVERFLOW)) {
- if (mode.Contains(PRESERVE_SOURCE_REGISTER)) {
+ } else if (constraints & SmiOperationConstraint::kBailoutOnOverflow) {
+ if (constraints & SmiOperationConstraint::kPreserveSourceRegister) {
Label done;
j(no_overflow, &done, Label::kNear);
addp(dst, kScratchRegister);
@@ -1738,11 +1654,11 @@
j(overflow, bailout_label, near_jump);
}
} else {
- CHECK(mode.IsEmpty());
+ UNREACHABLE();
}
} else {
- DCHECK(mode.Contains(PRESERVE_SOURCE_REGISTER));
- DCHECK(mode.Contains(BAILOUT_ON_OVERFLOW));
+ DCHECK(constraints & SmiOperationConstraint::kPreserveSourceRegister);
+ DCHECK(constraints & SmiOperationConstraint::kBailoutOnOverflow);
if (constant->value() == Smi::kMinValue) {
DCHECK(!dst.is(kScratchRegister));
movp(dst, src);
@@ -2367,7 +2283,7 @@
Check(not_both_smis, kBothRegistersWereSmisInSelectNonSmi);
#endif
STATIC_ASSERT(kSmiTag == 0);
- DCHECK_EQ(0, Smi::FromInt(0));
+ DCHECK_EQ(static_cast<Smi*>(0), Smi::FromInt(0));
movl(kScratchRegister, Immediate(kSmiTagMask));
andp(kScratchRegister, src1);
testl(kScratchRegister, src2);
@@ -2516,90 +2432,6 @@
// ----------------------------------------------------------------------------
-void MacroAssembler::LookupNumberStringCache(Register object,
- Register result,
- Register scratch1,
- Register scratch2,
- Label* not_found) {
- // Use of registers. Register result is used as a temporary.
- Register number_string_cache = result;
- Register mask = scratch1;
- Register scratch = scratch2;
-
- // Load the number string cache.
- LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex);
-
- // Make the hash mask from the length of the number string cache. It
- // contains two elements (number and string) for each cache entry.
- SmiToInteger32(
- mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset));
- shrl(mask, Immediate(1));
- subp(mask, Immediate(1)); // Make mask.
-
- // Calculate the entry in the number string cache. The hash value in the
- // number string cache for smis is just the smi value, and the hash for
- // doubles is the xor of the upper and lower words. See
- // Heap::GetNumberStringCache.
- Label is_smi;
- Label load_result_from_cache;
- JumpIfSmi(object, &is_smi);
- CheckMap(object,
- isolate()->factory()->heap_number_map(),
- not_found,
- DONT_DO_SMI_CHECK);
-
- STATIC_ASSERT(8 == kDoubleSize);
- movl(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4));
- xorp(scratch, FieldOperand(object, HeapNumber::kValueOffset));
- andp(scratch, mask);
- // Each entry in string cache consists of two pointer sized fields,
- // but times_twice_pointer_size (multiplication by 16) scale factor
- // is not supported by addrmode on x64 platform.
- // So we have to premultiply entry index before lookup.
- shlp(scratch, Immediate(kPointerSizeLog2 + 1));
-
- Register index = scratch;
- Register probe = mask;
- movp(probe,
- FieldOperand(number_string_cache,
- index,
- times_1,
- FixedArray::kHeaderSize));
- JumpIfSmi(probe, not_found);
- movsd(xmm0, FieldOperand(object, HeapNumber::kValueOffset));
- ucomisd(xmm0, FieldOperand(probe, HeapNumber::kValueOffset));
- j(parity_even, not_found); // Bail out if NaN is involved.
- j(not_equal, not_found); // The cache did not contain this value.
- jmp(&load_result_from_cache);
-
- bind(&is_smi);
- SmiToInteger32(scratch, object);
- andp(scratch, mask);
- // Each entry in string cache consists of two pointer sized fields,
- // but times_twice_pointer_size (multiplication by 16) scale factor
- // is not supported by addrmode on x64 platform.
- // So we have to premultiply entry index before lookup.
- shlp(scratch, Immediate(kPointerSizeLog2 + 1));
-
- // Check if the entry is the smi we are looking for.
- cmpp(object,
- FieldOperand(number_string_cache,
- index,
- times_1,
- FixedArray::kHeaderSize));
- j(not_equal, not_found);
-
- // Get the result from the cache.
- bind(&load_result_from_cache);
- movp(result,
- FieldOperand(number_string_cache,
- index,
- times_1,
- FixedArray::kHeaderSize + kPointerSize));
- IncrementCounter(isolate()->counters()->number_to_string_native(), 1);
-}
-
-
void MacroAssembler::JumpIfNotString(Register object,
Register object_map,
Label* not_string,
@@ -2745,55 +2577,272 @@
void MacroAssembler::Move(XMMRegister dst, uint32_t src) {
if (src == 0) {
- xorps(dst, dst);
+ Xorpd(dst, dst);
} else {
- unsigned cnt = base::bits::CountPopulation32(src);
- unsigned nlz = base::bits::CountLeadingZeros32(src);
- unsigned ntz = base::bits::CountTrailingZeros32(src);
- if (nlz + cnt + ntz == 32) {
- pcmpeqd(dst, dst);
- if (ntz == 0) {
- psrld(dst, 32 - cnt);
- } else {
- pslld(dst, 32 - cnt);
- if (nlz != 0) psrld(dst, nlz);
- }
+ unsigned pop = base::bits::CountPopulation32(src);
+ DCHECK_NE(0u, pop);
+ if (pop == 32) {
+ Pcmpeqd(dst, dst);
} else {
movl(kScratchRegister, Immediate(src));
- movq(dst, kScratchRegister);
+ Movq(dst, kScratchRegister);
}
}
}
void MacroAssembler::Move(XMMRegister dst, uint64_t src) {
- uint32_t lower = static_cast<uint32_t>(src);
- uint32_t upper = static_cast<uint32_t>(src >> 32);
- if (upper == 0) {
- Move(dst, lower);
+ if (src == 0) {
+ Xorpd(dst, dst);
} else {
- unsigned cnt = base::bits::CountPopulation64(src);
unsigned nlz = base::bits::CountLeadingZeros64(src);
unsigned ntz = base::bits::CountTrailingZeros64(src);
- if (nlz + cnt + ntz == 64) {
- pcmpeqd(dst, dst);
- if (ntz == 0) {
- psrlq(dst, 64 - cnt);
- } else {
- psllq(dst, 64 - cnt);
- if (nlz != 0) psrlq(dst, nlz);
- }
- } else if (lower == 0) {
- Move(dst, upper);
- psllq(dst, 32);
+ unsigned pop = base::bits::CountPopulation64(src);
+ DCHECK_NE(0u, pop);
+ if (pop == 64) {
+ Pcmpeqd(dst, dst);
+ } else if (pop + ntz == 64) {
+ Pcmpeqd(dst, dst);
+ Psllq(dst, ntz);
+ } else if (pop + nlz == 64) {
+ Pcmpeqd(dst, dst);
+ Psrlq(dst, nlz);
} else {
- movq(kScratchRegister, src);
- movq(dst, kScratchRegister);
+ uint32_t lower = static_cast<uint32_t>(src);
+ uint32_t upper = static_cast<uint32_t>(src >> 32);
+ if (upper == 0) {
+ Move(dst, lower);
+ } else {
+ movq(kScratchRegister, src);
+ Movq(dst, kScratchRegister);
+ }
}
}
}
+void MacroAssembler::Movaps(XMMRegister dst, XMMRegister src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vmovaps(dst, src);
+ } else {
+ movaps(dst, src);
+ }
+}
+
+
+void MacroAssembler::Movapd(XMMRegister dst, XMMRegister src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vmovapd(dst, src);
+ } else {
+ movapd(dst, src);
+ }
+}
+
+
+void MacroAssembler::Movsd(XMMRegister dst, XMMRegister src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vmovsd(dst, dst, src);
+ } else {
+ movsd(dst, src);
+ }
+}
+
+
+void MacroAssembler::Movsd(XMMRegister dst, const Operand& src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vmovsd(dst, src);
+ } else {
+ movsd(dst, src);
+ }
+}
+
+
+void MacroAssembler::Movsd(const Operand& dst, XMMRegister src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vmovsd(dst, src);
+ } else {
+ movsd(dst, src);
+ }
+}
+
+
+void MacroAssembler::Movss(XMMRegister dst, XMMRegister src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vmovss(dst, dst, src);
+ } else {
+ movss(dst, src);
+ }
+}
+
+
+void MacroAssembler::Movss(XMMRegister dst, const Operand& src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vmovss(dst, src);
+ } else {
+ movss(dst, src);
+ }
+}
+
+
+void MacroAssembler::Movss(const Operand& dst, XMMRegister src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vmovss(dst, src);
+ } else {
+ movss(dst, src);
+ }
+}
+
+
+void MacroAssembler::Movd(XMMRegister dst, Register src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vmovd(dst, src);
+ } else {
+ movd(dst, src);
+ }
+}
+
+
+void MacroAssembler::Movd(XMMRegister dst, const Operand& src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vmovd(dst, src);
+ } else {
+ movd(dst, src);
+ }
+}
+
+
+void MacroAssembler::Movd(Register dst, XMMRegister src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vmovd(dst, src);
+ } else {
+ movd(dst, src);
+ }
+}
+
+
+void MacroAssembler::Movq(XMMRegister dst, Register src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vmovq(dst, src);
+ } else {
+ movq(dst, src);
+ }
+}
+
+
+void MacroAssembler::Movq(Register dst, XMMRegister src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vmovq(dst, src);
+ } else {
+ movq(dst, src);
+ }
+}
+
+
+void MacroAssembler::Movmskpd(Register dst, XMMRegister src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vmovmskpd(dst, src);
+ } else {
+ movmskpd(dst, src);
+ }
+}
+
+
+void MacroAssembler::Roundss(XMMRegister dst, XMMRegister src,
+ RoundingMode mode) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vroundss(dst, dst, src, mode);
+ } else {
+ roundss(dst, src, mode);
+ }
+}
+
+
+void MacroAssembler::Roundsd(XMMRegister dst, XMMRegister src,
+ RoundingMode mode) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vroundsd(dst, dst, src, mode);
+ } else {
+ roundsd(dst, src, mode);
+ }
+}
+
+
+void MacroAssembler::Sqrtsd(XMMRegister dst, XMMRegister src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vsqrtsd(dst, dst, src);
+ } else {
+ sqrtsd(dst, src);
+ }
+}
+
+
+void MacroAssembler::Sqrtsd(XMMRegister dst, const Operand& src) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vsqrtsd(dst, dst, src);
+ } else {
+ sqrtsd(dst, src);
+ }
+}
+
+
+void MacroAssembler::Ucomiss(XMMRegister src1, XMMRegister src2) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vucomiss(src1, src2);
+ } else {
+ ucomiss(src1, src2);
+ }
+}
+
+
+void MacroAssembler::Ucomiss(XMMRegister src1, const Operand& src2) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vucomiss(src1, src2);
+ } else {
+ ucomiss(src1, src2);
+ }
+}
+
+
+void MacroAssembler::Ucomisd(XMMRegister src1, XMMRegister src2) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vucomisd(src1, src2);
+ } else {
+ ucomisd(src1, src2);
+ }
+}
+
+
+void MacroAssembler::Ucomisd(XMMRegister src1, const Operand& src2) {
+ if (CpuFeatures::IsSupported(AVX)) {
+ CpuFeatureScope scope(this, AVX);
+ vucomisd(src1, src2);
+ } else {
+ ucomisd(src1, src2);
+ }
+}
+
+
void MacroAssembler::Cmp(Register dst, Handle<Object> source) {
AllowDeferredHandleDereference smi_check;
if (source->IsSmi()) {
@@ -2859,10 +2908,15 @@
}
-void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
- Label* miss) {
+void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) {
Move(value, cell, RelocInfo::EMBEDDED_OBJECT);
movp(value, FieldOperand(value, WeakCell::kValueOffset));
+}
+
+
+void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
+ Label* miss) {
+ GetWeakValue(value, cell);
JumpIfSmi(value, miss);
}
@@ -2958,15 +3012,13 @@
popq(dst);
} else {
Register scratch = dst.AddressUsesRegister(kScratchRegister)
- ? kSmiConstantRegister : kScratchRegister;
+ ? kRootRegister : kScratchRegister;
movp(scratch, Operand(rsp, 0));
movp(dst, scratch);
leal(rsp, Operand(rsp, 4));
- if (scratch.is(kSmiConstantRegister)) {
- // Restore kSmiConstantRegister.
- movp(kSmiConstantRegister,
- reinterpret_cast<void*>(Smi::FromInt(kSmiConstantRegisterValue)),
- Assembler::RelocInfoNone());
+ if (scratch.is(kRootRegister)) {
+ // Restore kRootRegister.
+ InitializeRootRegister();
}
}
}
@@ -3061,7 +3113,7 @@
void MacroAssembler::Call(const Operand& op) {
- if (kPointerSize == kInt64Size) {
+ if (kPointerSize == kInt64Size && !CpuFeatures::IsSupported(ATOM)) {
call(op);
} else {
movp(kScratchRegister, op);
@@ -3097,6 +3149,213 @@
}
+void MacroAssembler::Pextrd(Register dst, XMMRegister src, int8_t imm8) {
+ if (imm8 == 0) {
+ Movd(dst, src);
+ return;
+ }
+ DCHECK_EQ(1, imm8);
+ if (CpuFeatures::IsSupported(SSE4_1)) {
+ CpuFeatureScope sse_scope(this, SSE4_1);
+ pextrd(dst, src, imm8);
+ return;
+ }
+ movq(dst, src);
+ shrq(dst, Immediate(32));
+}
+
+
+void MacroAssembler::Pinsrd(XMMRegister dst, Register src, int8_t imm8) {
+ if (CpuFeatures::IsSupported(SSE4_1)) {
+ CpuFeatureScope sse_scope(this, SSE4_1);
+ pinsrd(dst, src, imm8);
+ return;
+ }
+ Movd(xmm0, src);
+ if (imm8 == 1) {
+ punpckldq(dst, xmm0);
+ } else {
+ DCHECK_EQ(0, imm8);
+ Movss(dst, xmm0);
+ }
+}
+
+
+void MacroAssembler::Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8) {
+ DCHECK(imm8 == 0 || imm8 == 1);
+ if (CpuFeatures::IsSupported(SSE4_1)) {
+ CpuFeatureScope sse_scope(this, SSE4_1);
+ pinsrd(dst, src, imm8);
+ return;
+ }
+ Movd(xmm0, src);
+ if (imm8 == 1) {
+ punpckldq(dst, xmm0);
+ } else {
+ DCHECK_EQ(0, imm8);
+ Movss(dst, xmm0);
+ }
+}
+
+
+void MacroAssembler::Lzcntl(Register dst, Register src) {
+ if (CpuFeatures::IsSupported(LZCNT)) {
+ CpuFeatureScope scope(this, LZCNT);
+ lzcntl(dst, src);
+ return;
+ }
+ Label not_zero_src;
+ bsrl(dst, src);
+ j(not_zero, ¬_zero_src, Label::kNear);
+ Set(dst, 63); // 63^31 == 32
+ bind(¬_zero_src);
+ xorl(dst, Immediate(31)); // for x in [0..31], 31^x == 31 - x
+}
+
+
+void MacroAssembler::Lzcntl(Register dst, const Operand& src) {
+ if (CpuFeatures::IsSupported(LZCNT)) {
+ CpuFeatureScope scope(this, LZCNT);
+ lzcntl(dst, src);
+ return;
+ }
+ Label not_zero_src;
+ bsrl(dst, src);
+ j(not_zero, ¬_zero_src, Label::kNear);
+ Set(dst, 63); // 63^31 == 32
+ bind(¬_zero_src);
+ xorl(dst, Immediate(31)); // for x in [0..31], 31^x == 31 - x
+}
+
+
+void MacroAssembler::Lzcntq(Register dst, Register src) {
+ if (CpuFeatures::IsSupported(LZCNT)) {
+ CpuFeatureScope scope(this, LZCNT);
+ lzcntq(dst, src);
+ return;
+ }
+ Label not_zero_src;
+ bsrq(dst, src);
+ j(not_zero, ¬_zero_src, Label::kNear);
+ Set(dst, 127); // 127^63 == 64
+ bind(¬_zero_src);
+ xorl(dst, Immediate(63)); // for x in [0..63], 63^x == 63 - x
+}
+
+
+void MacroAssembler::Lzcntq(Register dst, const Operand& src) {
+ if (CpuFeatures::IsSupported(LZCNT)) {
+ CpuFeatureScope scope(this, LZCNT);
+ lzcntq(dst, src);
+ return;
+ }
+ Label not_zero_src;
+ bsrq(dst, src);
+ j(not_zero, ¬_zero_src, Label::kNear);
+ Set(dst, 127); // 127^63 == 64
+ bind(¬_zero_src);
+ xorl(dst, Immediate(63)); // for x in [0..63], 63^x == 63 - x
+}
+
+
+void MacroAssembler::Tzcntq(Register dst, Register src) {
+ if (CpuFeatures::IsSupported(BMI1)) {
+ CpuFeatureScope scope(this, BMI1);
+ tzcntq(dst, src);
+ return;
+ }
+ Label not_zero_src;
+ bsfq(dst, src);
+ j(not_zero, ¬_zero_src, Label::kNear);
+ // Define the result of tzcnt(0) separately, because bsf(0) is undefined.
+ Set(dst, 64);
+ bind(¬_zero_src);
+}
+
+
+void MacroAssembler::Tzcntq(Register dst, const Operand& src) {
+ if (CpuFeatures::IsSupported(BMI1)) {
+ CpuFeatureScope scope(this, BMI1);
+ tzcntq(dst, src);
+ return;
+ }
+ Label not_zero_src;
+ bsfq(dst, src);
+ j(not_zero, ¬_zero_src, Label::kNear);
+ // Define the result of tzcnt(0) separately, because bsf(0) is undefined.
+ Set(dst, 64);
+ bind(¬_zero_src);
+}
+
+
+void MacroAssembler::Tzcntl(Register dst, Register src) {
+ if (CpuFeatures::IsSupported(BMI1)) {
+ CpuFeatureScope scope(this, BMI1);
+ tzcntl(dst, src);
+ return;
+ }
+ Label not_zero_src;
+ bsfl(dst, src);
+ j(not_zero, ¬_zero_src, Label::kNear);
+ Set(dst, 32); // The result of tzcnt is 32 if src = 0.
+ bind(¬_zero_src);
+}
+
+
+void MacroAssembler::Tzcntl(Register dst, const Operand& src) {
+ if (CpuFeatures::IsSupported(BMI1)) {
+ CpuFeatureScope scope(this, BMI1);
+ tzcntl(dst, src);
+ return;
+ }
+ Label not_zero_src;
+ bsfl(dst, src);
+ j(not_zero, ¬_zero_src, Label::kNear);
+ Set(dst, 32); // The result of tzcnt is 32 if src = 0.
+ bind(¬_zero_src);
+}
+
+
+void MacroAssembler::Popcntl(Register dst, Register src) {
+ if (CpuFeatures::IsSupported(POPCNT)) {
+ CpuFeatureScope scope(this, POPCNT);
+ popcntl(dst, src);
+ return;
+ }
+ UNREACHABLE();
+}
+
+
+void MacroAssembler::Popcntl(Register dst, const Operand& src) {
+ if (CpuFeatures::IsSupported(POPCNT)) {
+ CpuFeatureScope scope(this, POPCNT);
+ popcntl(dst, src);
+ return;
+ }
+ UNREACHABLE();
+}
+
+
+void MacroAssembler::Popcntq(Register dst, Register src) {
+ if (CpuFeatures::IsSupported(POPCNT)) {
+ CpuFeatureScope scope(this, POPCNT);
+ popcntq(dst, src);
+ return;
+ }
+ UNREACHABLE();
+}
+
+
+void MacroAssembler::Popcntq(Register dst, const Operand& src) {
+ if (CpuFeatures::IsSupported(POPCNT)) {
+ CpuFeatureScope scope(this, POPCNT);
+ popcntq(dst, src);
+ return;
+ }
+ UNREACHABLE();
+}
+
+
void MacroAssembler::Pushad() {
Push(rax);
Push(rcx);
@@ -3109,11 +3368,11 @@
Push(r9);
// r10 is kScratchRegister.
Push(r11);
- // r12 is kSmiConstantRegister.
+ Push(r12);
// r13 is kRootRegister.
Push(r14);
Push(r15);
- STATIC_ASSERT(11 == kNumSafepointSavedRegisters);
+ STATIC_ASSERT(12 == kNumSafepointSavedRegisters);
// Use lea for symmetry with Popad.
int sp_delta =
(kNumSafepointRegisters - kNumSafepointSavedRegisters) * kPointerSize;
@@ -3128,6 +3387,7 @@
leap(rsp, Operand(rsp, sp_delta));
Pop(r15);
Pop(r14);
+ Pop(r12);
Pop(r11);
Pop(r9);
Pop(r8);
@@ -3161,10 +3421,10 @@
7,
-1,
8,
- -1,
- -1,
9,
- 10
+ -1,
+ 10,
+ 11
};
@@ -3189,46 +3449,21 @@
}
-void MacroAssembler::PushTryHandler(StackHandler::Kind kind,
- int handler_index) {
+void MacroAssembler::PushStackHandler() {
// Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize +
- kFPOnStackSize);
+ STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
- STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
-
- // We will build up the handler from the bottom by pushing on the stack.
- // First push the frame pointer and context.
- if (kind == StackHandler::JS_ENTRY) {
- // The frame pointer does not point to a JS frame so we save NULL for
- // rbp. We expect the code throwing an exception to check rbp before
- // dereferencing it to restore the context.
- pushq(Immediate(0)); // NULL frame pointer.
- Push(Smi::FromInt(0)); // No context.
- } else {
- pushq(rbp);
- Push(rsi);
- }
-
- // Push the state and the code object.
- unsigned state =
- StackHandler::IndexField::encode(handler_index) |
- StackHandler::KindField::encode(kind);
- Push(Immediate(state));
- Push(CodeObject());
// Link the current handler as the next handler.
ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
Push(ExternalOperand(handler_address));
+
// Set this new handler as the current one.
movp(ExternalOperand(handler_address), rsp);
}
-void MacroAssembler::PopTryHandler() {
+void MacroAssembler::PopStackHandler() {
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
Pop(ExternalOperand(handler_address));
@@ -3236,106 +3471,6 @@
}
-void MacroAssembler::JumpToHandlerEntry() {
- // Compute the handler entry address and jump to it. The handler table is
- // a fixed array of (smi-tagged) code offsets.
- // rax = exception, rdi = code object, rdx = state.
- movp(rbx, FieldOperand(rdi, Code::kHandlerTableOffset));
- shrp(rdx, Immediate(StackHandler::kKindWidth));
- movp(rdx,
- FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize));
- SmiToInteger64(rdx, rdx);
- leap(rdi, FieldOperand(rdi, rdx, times_1, Code::kHeaderSize));
- jmp(rdi);
-}
-
-
-void MacroAssembler::Throw(Register value) {
- // Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize +
- kFPOnStackSize);
- STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
- STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
-
- // The exception is expected in rax.
- if (!value.is(rax)) {
- movp(rax, value);
- }
- // Drop the stack pointer to the top of the top handler.
- ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
- movp(rsp, ExternalOperand(handler_address));
- // Restore the next handler.
- Pop(ExternalOperand(handler_address));
-
- // Remove the code object and state, compute the handler address in rdi.
- Pop(rdi); // Code object.
- Pop(rdx); // Offset and state.
-
- // Restore the context and frame pointer.
- Pop(rsi); // Context.
- popq(rbp); // Frame pointer.
-
- // If the handler is a JS frame, restore the context to the frame.
- // (kind == ENTRY) == (rbp == 0) == (rsi == 0), so we could test either
- // rbp or rsi.
- Label skip;
- testp(rsi, rsi);
- j(zero, &skip, Label::kNear);
- movp(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
- bind(&skip);
-
- JumpToHandlerEntry();
-}
-
-
-void MacroAssembler::ThrowUncatchable(Register value) {
- // Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize +
- kFPOnStackSize);
- STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
- STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
-
- // The exception is expected in rax.
- if (!value.is(rax)) {
- movp(rax, value);
- }
- // Drop the stack pointer to the top of the top stack handler.
- ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
- Load(rsp, handler_address);
-
- // Unwind the handlers until the top ENTRY handler is found.
- Label fetch_next, check_kind;
- jmp(&check_kind, Label::kNear);
- bind(&fetch_next);
- movp(rsp, Operand(rsp, StackHandlerConstants::kNextOffset));
-
- bind(&check_kind);
- STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
- testl(Operand(rsp, StackHandlerConstants::kStateOffset),
- Immediate(StackHandler::KindField::kMask));
- j(not_zero, &fetch_next);
-
- // Set the top handler address to next handler past the top ENTRY handler.
- Pop(ExternalOperand(handler_address));
-
- // Remove the code object and state, compute the handler address in rdi.
- Pop(rdi); // Code object.
- Pop(rdx); // Offset and state.
-
- // Clear the context pointer and frame pointer (0 was saved in the handler).
- Pop(rsi);
- popq(rbp);
-
- JumpToHandlerEntry();
-}
-
-
void MacroAssembler::Ret() {
ret(0);
}
@@ -3420,7 +3555,7 @@
XMMRegister xmm_scratch,
Label* fail,
int elements_offset) {
- Label smi_value, is_nan, maybe_nan, not_nan, have_double_value, done;
+ Label smi_value, done;
JumpIfSmi(maybe_number, &smi_value, Label::kNear);
@@ -3429,44 +3564,20 @@
fail,
DONT_DO_SMI_CHECK);
- // Double value, canonicalize NaN.
- uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32);
- cmpl(FieldOperand(maybe_number, offset),
- Immediate(kNaNOrInfinityLowerBoundUpper32));
- j(greater_equal, &maybe_nan, Label::kNear);
-
- bind(¬_nan);
- movsd(xmm_scratch, FieldOperand(maybe_number, HeapNumber::kValueOffset));
- bind(&have_double_value);
- movsd(FieldOperand(elements, index, times_8,
- FixedDoubleArray::kHeaderSize - elements_offset),
- xmm_scratch);
- jmp(&done);
-
- bind(&maybe_nan);
- // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise
- // it's an Infinity, and the non-NaN code path applies.
- j(greater, &is_nan, Label::kNear);
- cmpl(FieldOperand(maybe_number, HeapNumber::kValueOffset), Immediate(0));
- j(zero, ¬_nan);
- bind(&is_nan);
- // Convert all NaNs to the same canonical NaN value when they are stored in
- // the double array.
- Set(kScratchRegister,
- bit_cast<uint64_t>(
- FixedDoubleArray::canonical_not_the_hole_nan_as_double()));
- movq(xmm_scratch, kScratchRegister);
- jmp(&have_double_value, Label::kNear);
+ // 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);
- movsd(FieldOperand(elements, index, times_8,
+ bind(&done);
+ Movsd(FieldOperand(elements, index, times_8,
FixedDoubleArray::kHeaderSize - elements_offset),
xmm_scratch);
- bind(&done);
}
@@ -3503,8 +3614,8 @@
Register result_reg) {
Label done;
Label conv_failure;
- xorps(temp_xmm_reg, temp_xmm_reg);
- cvtsd2si(result_reg, input_reg);
+ Xorpd(temp_xmm_reg, temp_xmm_reg);
+ Cvtsd2si(result_reg, input_reg);
testl(result_reg, Immediate(0xFFFFFF00));
j(zero, &done, Label::kNear);
cmpl(result_reg, Immediate(1));
@@ -3516,7 +3627,7 @@
jmp(&done, Label::kNear);
bind(&conv_failure);
Set(result_reg, 0);
- ucomisd(input_reg, temp_xmm_reg);
+ Ucomisd(input_reg, temp_xmm_reg);
j(below, &done, Label::kNear);
Set(result_reg, 255);
bind(&done);
@@ -3529,7 +3640,7 @@
cmpq(src, Immediate(0xffffffff));
Assert(below_equal, kInputGPRIsExpectedToHaveUpper32Cleared);
}
- cvtqsi2sd(dst, src);
+ Cvtqsi2sd(dst, src);
}
@@ -3544,15 +3655,15 @@
void MacroAssembler::TruncateHeapNumberToI(Register result_reg,
Register input_reg) {
Label done;
- movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
- cvttsd2siq(result_reg, xmm0);
+ Movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
+ Cvttsd2siq(result_reg, xmm0);
cmpq(result_reg, Immediate(1));
j(no_overflow, &done, Label::kNear);
// Slow case.
if (input_reg.is(result_reg)) {
subp(rsp, Immediate(kDoubleSize));
- movsd(MemOperand(rsp, 0), xmm0);
+ Movsd(MemOperand(rsp, 0), xmm0);
SlowTruncateToI(result_reg, rsp, 0);
addp(rsp, Immediate(kDoubleSize));
} else {
@@ -3568,12 +3679,12 @@
void MacroAssembler::TruncateDoubleToI(Register result_reg,
XMMRegister input_reg) {
Label done;
- cvttsd2siq(result_reg, input_reg);
+ Cvttsd2siq(result_reg, input_reg);
cmpq(result_reg, Immediate(1));
j(no_overflow, &done, Label::kNear);
subp(rsp, Immediate(kDoubleSize));
- movsd(MemOperand(rsp, 0), input_reg);
+ Movsd(MemOperand(rsp, 0), input_reg);
SlowTruncateToI(result_reg, rsp, 0);
addp(rsp, Immediate(kDoubleSize));
@@ -3588,9 +3699,9 @@
MinusZeroMode minus_zero_mode,
Label* lost_precision, Label* is_nan,
Label* minus_zero, Label::Distance dst) {
- cvttsd2si(result_reg, input_reg);
+ Cvttsd2si(result_reg, input_reg);
Cvtlsi2sd(xmm0, result_reg);
- ucomisd(xmm0, input_reg);
+ Ucomisd(xmm0, input_reg);
j(not_equal, lost_precision, dst);
j(parity_even, is_nan, dst); // NaN.
if (minus_zero_mode == FAIL_ON_MINUS_ZERO) {
@@ -3599,7 +3710,7 @@
// only have to test if we got -0 as an input.
testl(result_reg, result_reg);
j(not_zero, &done, Label::kNear);
- movmskpd(result_reg, input_reg);
+ Movmskpd(result_reg, input_reg);
// Bit 0 contains the sign of the double in input_reg.
// If input was positive, we are ok and return 0, otherwise
// jump to minus_zero.
@@ -3630,6 +3741,18 @@
}
+void MacroAssembler::LoadAccessor(Register dst, Register holder,
+ int accessor_index,
+ AccessorComponent accessor) {
+ movp(dst, FieldOperand(holder, HeapObject::kMapOffset));
+ LoadInstanceDescriptors(dst, dst);
+ movp(dst, FieldOperand(dst, DescriptorArray::GetValueOffset(accessor_index)));
+ int offset = accessor == ACCESSOR_GETTER ? AccessorPair::kGetterOffset
+ : AccessorPair::kSetterOffset;
+ movp(dst, FieldOperand(dst, offset));
+}
+
+
void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
Register scratch2, Handle<WeakCell> cell,
Handle<Code> success,
@@ -3718,6 +3841,30 @@
}
+void MacroAssembler::AssertFunction(Register object) {
+ if (emit_debug_code()) {
+ testb(object, Immediate(kSmiTagMask));
+ Check(not_equal, kOperandIsASmiAndNotAFunction);
+ Push(object);
+ CmpObjectType(object, JS_FUNCTION_TYPE, object);
+ Pop(object);
+ Check(equal, kOperandIsNotAFunction);
+ }
+}
+
+
+void MacroAssembler::AssertBoundFunction(Register object) {
+ if (emit_debug_code()) {
+ testb(object, Immediate(kSmiTagMask));
+ Check(not_equal, kOperandIsASmiAndNotABoundFunction);
+ Push(object);
+ CmpObjectType(object, JS_BOUND_FUNCTION_TYPE, object);
+ Pop(object);
+ Check(equal, kOperandIsNotABoundFunction);
+ }
+}
+
+
void MacroAssembler::AssertUndefinedOrAllocationSite(Register object) {
if (emit_debug_code()) {
Label done_checking;
@@ -3765,35 +3912,22 @@
}
-void MacroAssembler::TryGetFunctionPrototype(Register function,
- Register result,
- Label* miss,
- bool miss_on_bound_function) {
- Label non_instance;
- if (miss_on_bound_function) {
- // Check that the receiver isn't a smi.
- testl(function, Immediate(kSmiTagMask));
- j(zero, miss);
+void MacroAssembler::GetMapConstructor(Register result, Register map,
+ Register temp) {
+ Label done, loop;
+ movp(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset));
+ bind(&loop);
+ JumpIfSmi(result, &done, Label::kNear);
+ CmpObjectType(result, MAP_TYPE, temp);
+ j(not_equal, &done, Label::kNear);
+ movp(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset));
+ jmp(&loop);
+ bind(&done);
+}
- // Check that the function really is a function.
- CmpObjectType(function, JS_FUNCTION_TYPE, result);
- j(not_equal, miss);
- movp(kScratchRegister,
- FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
- // It's not smi-tagged (stored in the top half of a smi-tagged 8-byte
- // field).
- TestBitSharedFunctionInfoSpecialField(kScratchRegister,
- SharedFunctionInfo::kCompilerHintsOffset,
- SharedFunctionInfo::kBoundFunction);
- j(not_zero, miss);
-
- // Make sure that the function has an instance prototype.
- testb(FieldOperand(result, Map::kBitFieldOffset),
- Immediate(1 << Map::kHasNonInstancePrototype));
- j(not_zero, &non_instance, Label::kNear);
- }
-
+void MacroAssembler::TryGetFunctionPrototype(Register function, Register result,
+ Label* miss) {
// Get the prototype or initial map from the function.
movp(result,
FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
@@ -3812,15 +3946,6 @@
// Get the prototype from the initial map.
movp(result, FieldOperand(result, Map::kPrototypeOffset));
- if (miss_on_bound_function) {
- jmp(&done, Label::kNear);
-
- // Non-instance prototype: Fetch prototype from constructor field
- // in initial map.
- bind(&non_instance);
- movp(result, FieldOperand(result, Map::kConstructorOffset));
- }
-
// All done.
bind(&done);
}
@@ -3862,33 +3987,83 @@
void MacroAssembler::DebugBreak() {
Set(rax, 0); // No arguments.
- LoadAddress(rbx, ExternalReference(Runtime::kDebugBreak, isolate()));
+ LoadAddress(rbx,
+ ExternalReference(Runtime::kHandleDebuggerStatement, isolate()));
CEntryStub ces(isolate(), 1);
DCHECK(AllowThisStubCall(&ces));
- Call(ces.GetCode(), RelocInfo::DEBUG_BREAK);
+ Call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT);
}
-void MacroAssembler::InvokeCode(Register code,
- const ParameterCount& expected,
- const ParameterCount& actual,
- InvokeFlag flag,
- const CallWrapper& call_wrapper) {
+void MacroAssembler::InvokeFunction(Register function,
+ Register new_target,
+ const ParameterCount& actual,
+ InvokeFlag flag,
+ const CallWrapper& call_wrapper) {
+ movp(rbx, FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
+ LoadSharedFunctionInfoSpecialField(
+ rbx, rbx, SharedFunctionInfo::kFormalParameterCountOffset);
+
+ ParameterCount expected(rbx);
+ InvokeFunction(function, new_target, expected, actual, flag, call_wrapper);
+}
+
+
+void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
+ const ParameterCount& expected,
+ const ParameterCount& actual,
+ InvokeFlag flag,
+ const CallWrapper& call_wrapper) {
+ Move(rdi, function);
+ InvokeFunction(rdi, no_reg, expected, actual, flag, call_wrapper);
+}
+
+
+void MacroAssembler::InvokeFunction(Register function,
+ Register new_target,
+ const ParameterCount& expected,
+ const ParameterCount& actual,
+ InvokeFlag flag,
+ const CallWrapper& call_wrapper) {
+ DCHECK(function.is(rdi));
+ movp(rsi, FieldOperand(function, JSFunction::kContextOffset));
+ InvokeFunctionCode(rdi, new_target, expected, actual, flag, call_wrapper);
+}
+
+
+void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
+ const ParameterCount& expected,
+ const ParameterCount& actual,
+ InvokeFlag flag,
+ const CallWrapper& call_wrapper) {
// You can't call a function without a valid frame.
DCHECK(flag == JUMP_FUNCTION || has_frame());
+ DCHECK(function.is(rdi));
+ DCHECK_IMPLIES(new_target.is_valid(), new_target.is(rdx));
+
+ if (call_wrapper.NeedsDebugStepCheck()) {
+ FloodFunctionIfStepping(function, new_target, expected, actual);
+ }
+
+ // Clear the new.target register if not given.
+ if (!new_target.is_valid()) {
+ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
+ }
Label done;
bool definitely_mismatches = false;
InvokePrologue(expected,
actual,
- Handle<Code>::null(),
- code,
&done,
&definitely_mismatches,
flag,
Label::kNear,
call_wrapper);
if (!definitely_mismatches) {
+ // We call indirectly through the code field in the function to
+ // allow recompilation to take effect without changing any of the
+ // call sites.
+ Operand code = FieldOperand(function, JSFunction::kCodeEntryOffset);
if (flag == CALL_FUNCTION) {
call_wrapper.BeforeCall(CallSize(code));
call(code);
@@ -3902,59 +4077,8 @@
}
-void MacroAssembler::InvokeFunction(Register function,
- const ParameterCount& actual,
- InvokeFlag flag,
- const CallWrapper& call_wrapper) {
- // You can't call a function without a valid frame.
- DCHECK(flag == JUMP_FUNCTION || has_frame());
-
- DCHECK(function.is(rdi));
- movp(rdx, FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
- movp(rsi, FieldOperand(function, JSFunction::kContextOffset));
- LoadSharedFunctionInfoSpecialField(rbx, rdx,
- SharedFunctionInfo::kFormalParameterCountOffset);
- // Advances rdx to the end of the Code object header, to the start of
- // the executable code.
- movp(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
-
- ParameterCount expected(rbx);
- InvokeCode(rdx, expected, actual, flag, call_wrapper);
-}
-
-
-void MacroAssembler::InvokeFunction(Register function,
- const ParameterCount& expected,
- const ParameterCount& actual,
- InvokeFlag flag,
- const CallWrapper& call_wrapper) {
- // You can't call a function without a valid frame.
- DCHECK(flag == JUMP_FUNCTION || has_frame());
-
- DCHECK(function.is(rdi));
- movp(rsi, FieldOperand(function, JSFunction::kContextOffset));
- // Advances rdx to the end of the Code object header, to the start of
- // the executable code.
- movp(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
-
- InvokeCode(rdx, expected, actual, flag, call_wrapper);
-}
-
-
-void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
- const ParameterCount& expected,
- const ParameterCount& actual,
- InvokeFlag flag,
- const CallWrapper& call_wrapper) {
- Move(rdi, function);
- InvokeFunction(rdi, expected, actual, flag, call_wrapper);
-}
-
-
void MacroAssembler::InvokePrologue(const ParameterCount& expected,
const ParameterCount& actual,
- Handle<Code> code_constant,
- Register code_register,
Label* done,
bool* definitely_mismatches,
InvokeFlag flag,
@@ -3965,10 +4089,10 @@
Label invoke;
if (expected.is_immediate()) {
DCHECK(actual.is_immediate());
+ Set(rax, actual.immediate());
if (expected.immediate() == actual.immediate()) {
definitely_matches = true;
} else {
- Set(rax, actual.immediate());
if (expected.immediate() ==
SharedFunctionInfo::kDontAdaptArgumentsSentinel) {
// Don't worry about adapting arguments for built-ins that
@@ -3986,10 +4110,10 @@
// Expected is in register, actual is immediate. This is the
// case when we invoke function values without going through the
// IC mechanism.
+ Set(rax, actual.immediate());
cmpp(expected.reg(), Immediate(actual.immediate()));
j(equal, &invoke, Label::kNear);
DCHECK(expected.reg().is(rbx));
- Set(rax, actual.immediate());
} else if (!expected.reg().is(actual.reg())) {
// Both expected and actual are in (different) registers. This
// is the case when we invoke functions using call and apply.
@@ -3997,18 +4121,13 @@
j(equal, &invoke, Label::kNear);
DCHECK(actual.reg().is(rax));
DCHECK(expected.reg().is(rbx));
+ } else {
+ Move(rax, actual.reg());
}
}
if (!definitely_matches) {
Handle<Code> adaptor = isolate()->builtins()->ArgumentsAdaptorTrampoline();
- if (!code_constant.is_null()) {
- Move(rdx, code_constant, RelocInfo::EMBEDDED_OBJECT);
- addp(rdx, Immediate(Code::kHeaderSize - kHeapObjectTag));
- } else if (!code_register.is(rdx)) {
- movp(rdx, code_register);
- }
-
if (flag == CALL_FUNCTION) {
call_wrapper.BeforeCall(CallSize(adaptor));
Call(adaptor, RelocInfo::CODE_TARGET);
@@ -4024,6 +4143,49 @@
}
+void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target,
+ const ParameterCount& expected,
+ const ParameterCount& actual) {
+ Label skip_flooding;
+ ExternalReference step_in_enabled =
+ ExternalReference::debug_step_in_enabled_address(isolate());
+ Operand step_in_enabled_operand = ExternalOperand(step_in_enabled);
+ cmpb(step_in_enabled_operand, Immediate(0));
+ j(equal, &skip_flooding);
+ {
+ FrameScope frame(this,
+ has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
+ if (expected.is_reg()) {
+ Integer32ToSmi(expected.reg(), expected.reg());
+ Push(expected.reg());
+ }
+ if (actual.is_reg()) {
+ Integer32ToSmi(actual.reg(), actual.reg());
+ Push(actual.reg());
+ }
+ if (new_target.is_valid()) {
+ Push(new_target);
+ }
+ Push(fun);
+ Push(fun);
+ CallRuntime(Runtime::kDebugPrepareStepInIfStepping, 1);
+ Pop(fun);
+ if (new_target.is_valid()) {
+ Pop(new_target);
+ }
+ if (actual.is_reg()) {
+ Pop(actual.reg());
+ SmiToInteger64(actual.reg(), actual.reg());
+ }
+ if (expected.is_reg()) {
+ Pop(expected.reg());
+ SmiToInteger64(expected.reg(), expected.reg());
+ }
+ }
+ bind(&skip_flooding);
+}
+
+
void MacroAssembler::StubPrologue() {
pushq(rbp); // Caller's frame pointer.
movp(rbp, rsp);
@@ -4049,6 +4211,13 @@
}
+void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) {
+ movp(vector, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
+ movp(vector, FieldOperand(vector, JSFunction::kSharedFunctionInfoOffset));
+ movp(vector, FieldOperand(vector, SharedFunctionInfo::kFeedbackVectorOffset));
+}
+
+
void MacroAssembler::EnterFrame(StackFrame::Type type,
bool load_constant_pool_pointer_reg) {
// Out-of-line constant pool not implemented on x64.
@@ -4119,13 +4288,16 @@
#endif
// Optionally save all XMM registers.
if (save_doubles) {
- int space = XMMRegister::kMaxNumAllocatableRegisters * kDoubleSize +
- arg_stack_space * kRegisterSize;
+ int space = XMMRegister::kMaxNumRegisters * kDoubleSize +
+ arg_stack_space * kRegisterSize;
subp(rsp, Immediate(space));
int offset = -2 * kPointerSize;
- for (int i = 0; i < XMMRegister::NumAllocatableRegisters(); i++) {
- XMMRegister reg = XMMRegister::FromAllocationIndex(i);
- movsd(Operand(rbp, offset - ((i + 1) * kDoubleSize)), reg);
+ const RegisterConfiguration* config =
+ RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT);
+ for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
+ DoubleRegister reg =
+ DoubleRegister::from_code(config->GetAllocatableDoubleCode(i));
+ Movsd(Operand(rbp, offset - ((i + 1) * kDoubleSize)), reg);
}
} else if (arg_stack_space > 0) {
subp(rsp, Immediate(arg_stack_space * kRegisterSize));
@@ -4162,25 +4334,34 @@
}
-void MacroAssembler::LeaveExitFrame(bool save_doubles) {
+void MacroAssembler::LeaveExitFrame(bool save_doubles, bool pop_arguments) {
// Registers:
// r15 : argv
if (save_doubles) {
int offset = -2 * kPointerSize;
- for (int i = 0; i < XMMRegister::NumAllocatableRegisters(); i++) {
- XMMRegister reg = XMMRegister::FromAllocationIndex(i);
- movsd(reg, Operand(rbp, offset - ((i + 1) * kDoubleSize)));
+ const RegisterConfiguration* config =
+ RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT);
+ for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
+ DoubleRegister reg =
+ DoubleRegister::from_code(config->GetAllocatableDoubleCode(i));
+ Movsd(reg, Operand(rbp, offset - ((i + 1) * kDoubleSize)));
}
}
- // Get the return address from the stack and restore the frame pointer.
- movp(rcx, Operand(rbp, kFPOnStackSize));
- movp(rbp, Operand(rbp, 0 * kPointerSize));
- // Drop everything up to and including the arguments and the receiver
- // from the caller stack.
- leap(rsp, Operand(r15, 1 * kPointerSize));
+ if (pop_arguments) {
+ // Get the return address from the stack and restore the frame pointer.
+ movp(rcx, Operand(rbp, kFPOnStackSize));
+ movp(rbp, Operand(rbp, 0 * kPointerSize));
- PushReturnAddressFrom(rcx);
+ // Drop everything up to and including the arguments and the receiver
+ // from the caller stack.
+ leap(rsp, Operand(r15, 1 * kPointerSize));
+
+ PushReturnAddressFrom(rcx);
+ } else {
+ // Otherwise just leave the exit frame.
+ leave();
+ }
LeaveExitFrameEpilogue(true);
}
@@ -4229,10 +4410,7 @@
Check(not_equal, kWeShouldNotHaveAnEmptyLexicalContext);
}
// Load the native context of the current context.
- int offset =
- Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
- movp(scratch, FieldOperand(scratch, offset));
- movp(scratch, FieldOperand(scratch, GlobalObject::kNativeContextOffset));
+ movp(scratch, ContextOperand(scratch, Context::NATIVE_CONTEXT_INDEX));
// Check the context is a native context.
if (emit_debug_code()) {
@@ -4313,6 +4491,7 @@
movl(scratch, r0);
shrl(scratch, Immediate(16));
xorl(r0, scratch);
+ andl(r0, Immediate(0x3fffffff));
}
@@ -4384,7 +4563,7 @@
// Check that the value is a field property.
const int kDetailsOffset =
SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
- DCHECK_EQ(FIELD, 0);
+ DCHECK_EQ(DATA, 0);
Test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
Smi::FromInt(PropertyDetails::TypeField::kMask));
j(not_zero, miss);
@@ -4439,7 +4618,6 @@
// Align the next allocation. Storing the filler map without checking top
// is safe in new-space because the limit of the heap is aligned there.
DCHECK(kPointerSize * 2 == kDoubleSize);
- DCHECK((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
// Make sure scratch is not clobbered by this function as it might be
// used in UpdateAllocationTopHelper later.
@@ -4447,7 +4625,7 @@
Label aligned;
testl(result, Immediate(kDoubleAlignmentMask));
j(zero, &aligned, Label::kNear);
- if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
+ if ((flags & PRETENURE) != 0) {
ExternalReference allocation_limit =
AllocationUtils::GetAllocationLimitReference(isolate(), flags);
cmpp(result, ExternalOperand(allocation_limit));
@@ -4611,21 +4789,6 @@
}
-void MacroAssembler::UndoAllocationInNewSpace(Register object) {
- ExternalReference new_space_allocation_top =
- ExternalReference::new_space_allocation_top_address(isolate());
-
- // Make sure the object has no tag before resetting top.
- andp(object, Immediate(~kHeapObjectTagMask));
- Operand top_operand = ExternalOperand(new_space_allocation_top);
-#ifdef DEBUG
- cmpp(object, top_operand);
- Check(below, kUndoAllocationOfNonAllocatedMemory);
-#endif
- movp(top_operand, object);
-}
-
-
void MacroAssembler::AllocateHeapNumber(Register result,
Register scratch,
Label* gc_required,
@@ -4777,6 +4940,27 @@
}
+void MacroAssembler::AllocateJSValue(Register result, Register constructor,
+ Register value, Register scratch,
+ Label* gc_required) {
+ DCHECK(!result.is(constructor));
+ DCHECK(!result.is(scratch));
+ DCHECK(!result.is(value));
+
+ // Allocate JSValue in new space.
+ Allocate(JSValue::kSize, result, scratch, no_reg, gc_required, TAG_OBJECT);
+
+ // Initialize the JSValue.
+ LoadGlobalFunctionInitialMap(constructor, scratch);
+ movp(FieldOperand(result, HeapObject::kMapOffset), scratch);
+ LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex);
+ movp(FieldOperand(result, JSObject::kPropertiesOffset), scratch);
+ movp(FieldOperand(result, JSObject::kElementsOffset), scratch);
+ movp(FieldOperand(result, JSValue::kValueOffset), value);
+ STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
+}
+
+
// Copy memory, byte-by-byte, from source to destination. Not optimized for
// long or aligned copies. The contents of scratch and length are destroyed.
// Destination is incremented by length, source, length and scratch are
@@ -4863,17 +5047,17 @@
}
-void MacroAssembler::InitializeFieldsWithFiller(Register start_offset,
- Register end_offset,
+void MacroAssembler::InitializeFieldsWithFiller(Register current_address,
+ Register end_address,
Register filler) {
Label loop, entry;
jmp(&entry);
bind(&loop);
- movp(Operand(start_offset, 0), filler);
- addp(start_offset, Immediate(kPointerSize));
+ movp(Operand(current_address, 0), filler);
+ addp(current_address, Immediate(kPointerSize));
bind(&entry);
- cmpp(start_offset, end_offset);
- j(less, &loop);
+ cmpp(current_address, end_address);
+ j(below, &loop);
}
@@ -4909,24 +5093,18 @@
Register map_in_out,
Register scratch,
Label* no_map_match) {
- // Load the global or builtins object from the current context.
- movp(scratch,
- Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
- movp(scratch, FieldOperand(scratch, GlobalObject::kNativeContextOffset));
+ DCHECK(IsFastElementsKind(expected_kind));
+ DCHECK(IsFastElementsKind(transitioned_kind));
// Check that the function's map is the same as the expected cached map.
- movp(scratch, Operand(scratch,
- Context::SlotOffset(Context::JS_ARRAY_MAPS_INDEX)));
-
- int offset = expected_kind * kPointerSize +
- FixedArrayBase::kHeaderSize;
- cmpp(map_in_out, FieldOperand(scratch, offset));
+ movp(scratch, NativeContextOperand());
+ cmpp(map_in_out,
+ ContextOperand(scratch, Context::ArrayMapIndex(expected_kind)));
j(not_equal, no_map_match);
// Use the transitioned cached map.
- offset = transitioned_kind * kPointerSize +
- FixedArrayBase::kHeaderSize;
- movp(map_in_out, FieldOperand(scratch, offset));
+ movp(map_in_out,
+ ContextOperand(scratch, Context::ArrayMapIndex(transitioned_kind)));
}
@@ -4936,14 +5114,10 @@
static const int kRegisterPassedArguments = 6;
#endif
-void MacroAssembler::LoadGlobalFunction(int index, Register function) {
- // Load the global or builtins object from the current context.
- movp(function,
- Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
- // Load the native context from the global or builtins object.
- movp(function, FieldOperand(function, GlobalObject::kNativeContextOffset));
- // Load the function from the native context.
- movp(function, Operand(function, Context::SlotOffset(index)));
+
+void MacroAssembler::LoadNativeContextSlot(int index, Register dst) {
+ movp(dst, NativeContextOperand());
+ movp(dst, ContextOperand(dst, index));
}
@@ -5082,10 +5256,10 @@
#endif
-CodePatcher::CodePatcher(byte* address, int size)
+CodePatcher::CodePatcher(Isolate* isolate, byte* address, int size)
: address_(address),
size_(size),
- masm_(NULL, address, size + Assembler::kGap) {
+ masm_(isolate, address, size + Assembler::kGap, CodeObjectRequired::kNo) {
// Create a new macro assembler pointing to the address of the code to patch.
// The size is adjusted with kGap on order for the assembler to generate size
// bytes of instructions without failing with buffer size constraints.
@@ -5095,7 +5269,7 @@
CodePatcher::~CodePatcher() {
// Indicate that code has changed.
- CpuFeatures::FlushICache(address_, size_);
+ Assembler::FlushICache(masm_.isolate(), address_, size_);
// Check that the code was patched as expected.
DCHECK(masm_.pc_ == address_ + size_);
@@ -5133,45 +5307,19 @@
Label* on_black,
Label::Distance on_black_distance) {
DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, rcx));
+
GetMarkBits(object, bitmap_scratch, mask_scratch);
- DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0);
+ DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
// The mask_scratch register contains a 1 at the position of the first bit
- // and a 0 at all other positions, including the position of the second bit.
+ // and a 1 at a position of the second bit. All other positions are zero.
movp(rcx, mask_scratch);
- // Make rcx into a mask that covers both marking bits using the operation
- // rcx = mask | (mask << 1).
- leap(rcx, Operand(mask_scratch, mask_scratch, times_2, 0));
- // Note that we are using a 4-byte aligned 8-byte load.
andp(rcx, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
cmpp(mask_scratch, rcx);
j(equal, on_black, on_black_distance);
}
-// Detect some, but not all, common pointer-free objects. This is used by the
-// incremental write barrier which doesn't care about oddballs (they are always
-// marked black immediately so this code is not hit).
-void MacroAssembler::JumpIfDataObject(
- Register value,
- Register scratch,
- Label* not_data_object,
- Label::Distance not_data_object_distance) {
- Label is_data_object;
- movp(scratch, FieldOperand(value, HeapObject::kMapOffset));
- CompareRoot(scratch, Heap::kHeapNumberMapRootIndex);
- j(equal, &is_data_object, Label::kNear);
- DCHECK(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1);
- DCHECK(kNotStringTag == 0x80 && kIsNotStringMask == 0x80);
- // If it's a string and it's not a cons string then it's an object containing
- // no GC pointers.
- testb(FieldOperand(scratch, Map::kInstanceTypeOffset),
- Immediate(kIsIndirectStringMask | kIsNotStringMask));
- j(not_zero, not_data_object, not_data_object_distance);
- bind(&is_data_object);
-}
-
-
void MacroAssembler::GetMarkBits(Register addr_reg,
Register bitmap_reg,
Register mask_reg) {
@@ -5191,104 +5339,27 @@
movp(rcx, addr_reg);
shrl(rcx, Immediate(kPointerSizeLog2));
andp(rcx, Immediate((1 << Bitmap::kBitsPerCellLog2) - 1));
- movl(mask_reg, Immediate(1));
+ movl(mask_reg, Immediate(3));
shlp_cl(mask_reg);
}
-void MacroAssembler::EnsureNotWhite(
- Register value,
- Register bitmap_scratch,
- Register mask_scratch,
- Label* value_is_white_and_not_data,
- Label::Distance distance) {
+void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch,
+ Register mask_scratch, Label* value_is_white,
+ Label::Distance distance) {
DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, rcx));
GetMarkBits(value, bitmap_scratch, mask_scratch);
// If the value is black or grey we don't need to do anything.
DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
- DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0);
- DCHECK(strcmp(Marking::kGreyBitPattern, "11") == 0);
+ DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
+ DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0);
DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
- Label done;
-
// Since both black and grey have a 1 in the first position and white does
// not have a 1 there we only need to check one bit.
testp(Operand(bitmap_scratch, MemoryChunk::kHeaderSize), mask_scratch);
- j(not_zero, &done, Label::kNear);
-
- if (emit_debug_code()) {
- // Check for impossible bit pattern.
- Label ok;
- Push(mask_scratch);
- // shl. May overflow making the check conservative.
- addp(mask_scratch, mask_scratch);
- testp(Operand(bitmap_scratch, MemoryChunk::kHeaderSize), mask_scratch);
- j(zero, &ok, Label::kNear);
- int3();
- bind(&ok);
- Pop(mask_scratch);
- }
-
- // Value is white. We check whether it is data that doesn't need scanning.
- // Currently only checks for HeapNumber and non-cons strings.
- Register map = rcx; // Holds map while checking type.
- Register length = rcx; // Holds length of object after checking type.
- Label not_heap_number;
- Label is_data_object;
-
- // Check for heap-number
- movp(map, FieldOperand(value, HeapObject::kMapOffset));
- CompareRoot(map, Heap::kHeapNumberMapRootIndex);
- j(not_equal, ¬_heap_number, Label::kNear);
- movp(length, Immediate(HeapNumber::kSize));
- jmp(&is_data_object, Label::kNear);
-
- bind(¬_heap_number);
- // Check for strings.
- DCHECK(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1);
- DCHECK(kNotStringTag == 0x80 && kIsNotStringMask == 0x80);
- // If it's a string and it's not a cons string then it's an object containing
- // no GC pointers.
- Register instance_type = rcx;
- movzxbl(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
- testb(instance_type, Immediate(kIsIndirectStringMask | kIsNotStringMask));
- j(not_zero, value_is_white_and_not_data);
- // It's a non-indirect (non-cons and non-slice) string.
- // If it's external, the length is just ExternalString::kSize.
- // Otherwise it's String::kHeaderSize + string->length() * (1 or 2).
- Label not_external;
- // External strings are the only ones with the kExternalStringTag bit
- // set.
- DCHECK_EQ(0, kSeqStringTag & kExternalStringTag);
- DCHECK_EQ(0, kConsStringTag & kExternalStringTag);
- testb(instance_type, Immediate(kExternalStringTag));
- j(zero, ¬_external, Label::kNear);
- movp(length, Immediate(ExternalString::kSize));
- jmp(&is_data_object, Label::kNear);
-
- bind(¬_external);
- // Sequential string, either Latin1 or UC16.
- DCHECK(kOneByteStringTag == 0x04);
- andp(length, Immediate(kStringEncodingMask));
- xorp(length, Immediate(kStringEncodingMask));
- addp(length, Immediate(0x04));
- // Value now either 4 (if Latin1) or 8 (if UC16), i.e. char-size shifted by 2.
- imulp(length, FieldOperand(value, String::kLengthOffset));
- shrp(length, Immediate(2 + kSmiTagSize + kSmiShiftSize));
- addp(length, Immediate(SeqString::kHeaderSize + kObjectAlignmentMask));
- andp(length, Immediate(~kObjectAlignmentMask));
-
- bind(&is_data_object);
- // Value is a data object, and it is white. Mark it black. Since we know
- // that the object is white we can make it black by flipping one bit.
- orp(Operand(bitmap_scratch, MemoryChunk::kHeaderSize), mask_scratch);
-
- andp(bitmap_scratch, Immediate(~Page::kPageAlignmentMask));
- addl(Operand(bitmap_scratch, MemoryChunk::kLiveBytesOffset), length);
-
- bind(&done);
+ j(zero, value_is_white, distance);
}
@@ -5366,13 +5437,21 @@
DCHECK(!(scratch0.is(kScratchRegister) && scratch1.is(kScratchRegister)));
DCHECK(!scratch1.is(scratch0));
Register current = scratch0;
- Label loop_again;
+ 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));
@@ -5380,6 +5459,8 @@
movp(current, FieldOperand(current, Map::kPrototypeOffset));
CompareRoot(current, Heap::kNullValueRootIndex);
j(not_equal, &loop_again);
+
+ bind(&end);
}
@@ -5400,6 +5481,7 @@
}
-} } // namespace v8::internal
+} // namespace internal
+} // namespace v8
#endif // V8_TARGET_ARCH_X64