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/ppc/macro-assembler-ppc.cc b/src/ppc/macro-assembler-ppc.cc
index 0b3d729..9cd35ab 100644
--- a/src/ppc/macro-assembler-ppc.cc
+++ b/src/ppc/macro-assembler-ppc.cc
@@ -5,29 +5,29 @@
#include <assert.h> // For assert
#include <limits.h> // For LONG_MIN, LONG_MAX.
-#include "src/v8.h"
-
#if V8_TARGET_ARCH_PPC
#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/isolate-inl.h"
+#include "src/debug/debug.h"
+#include "src/register-configuration.h"
#include "src/runtime/runtime.h"
+#include "src/ppc/macro-assembler-ppc.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) {
- if (isolate() != NULL) {
+ if (create_code_object == CodeObjectRequired::kYes) {
code_object_ =
- Handle<Object>(isolate()->heap()->undefined_value(), isolate());
+ Handle<Object>::New(isolate()->heap()->undefined_value(), isolate());
}
}
@@ -105,7 +105,7 @@
int MacroAssembler::CallSize(Address target, RelocInfo::Mode rmode,
Condition cond) {
Operand mov_operand = Operand(reinterpret_cast<intptr_t>(target), rmode);
- return (2 + instructions_required_for_mov(mov_operand)) * kInstrSize;
+ return (2 + instructions_required_for_mov(ip, mov_operand)) * kInstrSize;
}
@@ -177,26 +177,13 @@
}
-void MacroAssembler::Ret(Condition cond) {
- DCHECK(cond == al);
- blr();
-}
-
-
-void MacroAssembler::Drop(int count, Condition cond) {
- DCHECK(cond == al);
+void MacroAssembler::Drop(int count) {
if (count > 0) {
Add(sp, sp, count * kPointerSize, r0);
}
}
-void MacroAssembler::Ret(int drop, Condition cond) {
- Drop(drop, cond);
- Ret(cond);
-}
-
-
void MacroAssembler::Call(Label* target) { b(target, SetLK); }
@@ -238,30 +225,59 @@
}
-void MacroAssembler::MultiPush(RegList regs) {
+void MacroAssembler::MultiPush(RegList regs, Register location) {
int16_t num_to_push = NumberOfBitsSet(regs);
int16_t stack_offset = num_to_push * kPointerSize;
- subi(sp, sp, Operand(stack_offset));
- for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
+ subi(location, location, Operand(stack_offset));
+ for (int16_t i = Register::kNumRegisters - 1; i >= 0; i--) {
if ((regs & (1 << i)) != 0) {
stack_offset -= kPointerSize;
- StoreP(ToRegister(i), MemOperand(sp, stack_offset));
+ StoreP(ToRegister(i), MemOperand(location, stack_offset));
}
}
}
-void MacroAssembler::MultiPop(RegList regs) {
+void MacroAssembler::MultiPop(RegList regs, Register location) {
int16_t stack_offset = 0;
- for (int16_t i = 0; i < kNumRegisters; i++) {
+ for (int16_t i = 0; i < Register::kNumRegisters; i++) {
if ((regs & (1 << i)) != 0) {
- LoadP(ToRegister(i), MemOperand(sp, stack_offset));
+ LoadP(ToRegister(i), MemOperand(location, stack_offset));
stack_offset += kPointerSize;
}
}
- addi(sp, sp, Operand(stack_offset));
+ addi(location, location, Operand(stack_offset));
+}
+
+
+void MacroAssembler::MultiPushDoubles(RegList dregs, Register location) {
+ int16_t num_to_push = NumberOfBitsSet(dregs);
+ int16_t stack_offset = num_to_push * kDoubleSize;
+
+ subi(location, location, Operand(stack_offset));
+ for (int16_t i = DoubleRegister::kNumRegisters - 1; i >= 0; i--) {
+ if ((dregs & (1 << i)) != 0) {
+ DoubleRegister dreg = DoubleRegister::from_code(i);
+ stack_offset -= kDoubleSize;
+ stfd(dreg, MemOperand(location, stack_offset));
+ }
+ }
+}
+
+
+void MacroAssembler::MultiPopDoubles(RegList dregs, Register location) {
+ int16_t stack_offset = 0;
+
+ for (int16_t i = 0; i < DoubleRegister::kNumRegisters; i++) {
+ if ((dregs & (1 << i)) != 0) {
+ DoubleRegister dreg = DoubleRegister::from_code(i);
+ lfd(dreg, MemOperand(location, stack_offset));
+ stack_offset += kDoubleSize;
+ }
+ }
+ addi(location, location, Operand(stack_offset));
}
@@ -274,6 +290,7 @@
void MacroAssembler::StoreRoot(Register source, Heap::RootListIndex index,
Condition cond) {
+ DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
DCHECK(cond == al);
StoreP(source, MemOperand(kRootRegister, index << kPointerSizeLog2), r0);
}
@@ -497,7 +514,7 @@
beq(&done, cr0);
} else {
DCHECK(and_then == kReturnAtEnd);
- beq(&done, cr0);
+ Ret(eq, cr0);
}
mflr(r0);
push(r0);
@@ -514,40 +531,44 @@
void MacroAssembler::PushFixedFrame(Register marker_reg) {
mflr(r0);
-#if V8_OOL_CONSTANT_POOL
- if (marker_reg.is_valid()) {
- Push(r0, fp, kConstantPoolRegister, cp, marker_reg);
+ if (FLAG_enable_embedded_constant_pool) {
+ if (marker_reg.is_valid()) {
+ Push(r0, fp, kConstantPoolRegister, cp, marker_reg);
+ } else {
+ Push(r0, fp, kConstantPoolRegister, cp);
+ }
} else {
- Push(r0, fp, kConstantPoolRegister, cp);
+ if (marker_reg.is_valid()) {
+ Push(r0, fp, cp, marker_reg);
+ } else {
+ Push(r0, fp, cp);
+ }
}
-#else
- if (marker_reg.is_valid()) {
- Push(r0, fp, cp, marker_reg);
- } else {
- Push(r0, fp, cp);
- }
-#endif
}
void MacroAssembler::PopFixedFrame(Register marker_reg) {
-#if V8_OOL_CONSTANT_POOL
- if (marker_reg.is_valid()) {
- Pop(r0, fp, kConstantPoolRegister, cp, marker_reg);
+ if (FLAG_enable_embedded_constant_pool) {
+ if (marker_reg.is_valid()) {
+ Pop(r0, fp, kConstantPoolRegister, cp, marker_reg);
+ } else {
+ Pop(r0, fp, kConstantPoolRegister, cp);
+ }
} else {
- Pop(r0, fp, kConstantPoolRegister, cp);
+ if (marker_reg.is_valid()) {
+ Pop(r0, fp, cp, marker_reg);
+ } else {
+ Pop(r0, fp, cp);
+ }
}
-#else
- if (marker_reg.is_valid()) {
- Pop(r0, fp, cp, marker_reg);
- } else {
- Pop(r0, fp, cp);
- }
-#endif
mtlr(r0);
}
+const RegList MacroAssembler::kSafepointSavedRegisters = Register::kAllocatable;
+const int MacroAssembler::kNumSafepointSavedRegisters =
+ Register::kNumAllocatable;
+
// Push and pop all registers that can hold pointers.
void MacroAssembler::PushSafepointRegisters() {
// Safepoints expect a block of kNumSafepointRegisters values on the
@@ -605,7 +626,9 @@
MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
// General purpose registers are pushed last on the stack.
- int doubles_size = DoubleRegister::NumAllocatableRegisters() * kDoubleSize;
+ const RegisterConfiguration* config =
+ RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT);
+ int doubles_size = config->num_allocatable_double_registers() * kDoubleSize;
int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
return MemOperand(sp, doubles_size + register_offset);
}
@@ -613,26 +636,8 @@
void MacroAssembler::CanonicalizeNaN(const DoubleRegister dst,
const DoubleRegister src) {
- Label done;
-
- // Test for NaN
- fcmpu(src, src);
-
- if (dst.is(src)) {
- bordered(&done);
- } else {
- Label is_nan;
- bunordered(&is_nan);
- fmr(dst, src);
- b(&done);
- bind(&is_nan);
- }
-
- // Replace with canonical NaN.
- double nan_value = FixedDoubleArray::canonical_not_the_hole_nan_as_double();
- LoadDoubleLiteral(dst, nan_value, r0);
-
- bind(&done);
+ // Turn potential sNaN into qNaN.
+ fsub(dst, src, kDoubleRegZero);
}
@@ -654,11 +659,40 @@
const Register src,
const Register int_scratch) {
MovIntToDouble(dst, src, int_scratch);
- fcfid(dst, dst);
- frsp(dst, dst);
+ fcfids(dst, dst);
}
+#if V8_TARGET_ARCH_PPC64
+void MacroAssembler::ConvertInt64ToDouble(Register src,
+ DoubleRegister double_dst) {
+ MovInt64ToDouble(double_dst, src);
+ fcfid(double_dst, double_dst);
+}
+
+
+void MacroAssembler::ConvertUnsignedInt64ToFloat(Register src,
+ DoubleRegister double_dst) {
+ MovInt64ToDouble(double_dst, src);
+ fcfidus(double_dst, double_dst);
+}
+
+
+void MacroAssembler::ConvertUnsignedInt64ToDouble(Register src,
+ DoubleRegister double_dst) {
+ MovInt64ToDouble(double_dst, src);
+ fcfidu(double_dst, double_dst);
+}
+
+
+void MacroAssembler::ConvertInt64ToFloat(Register src,
+ DoubleRegister double_dst) {
+ MovInt64ToDouble(double_dst, src);
+ fcfids(double_dst, double_dst);
+}
+#endif
+
+
void MacroAssembler::ConvertDoubleToInt64(const DoubleRegister double_input,
#if !V8_TARGET_ARCH_PPC64
const Register dst_hi,
@@ -681,46 +715,64 @@
dst, double_dst);
}
-
-#if V8_OOL_CONSTANT_POOL
-void MacroAssembler::LoadConstantPoolPointerRegister(
- CodeObjectAccessMethod access_method, int ip_code_entry_delta) {
- Register base;
- int constant_pool_offset = Code::kConstantPoolOffset - Code::kHeaderSize;
- if (access_method == CAN_USE_IP) {
- base = ip;
- constant_pool_offset += ip_code_entry_delta;
+#if V8_TARGET_ARCH_PPC64
+void MacroAssembler::ConvertDoubleToUnsignedInt64(
+ const DoubleRegister double_input, const Register dst,
+ const DoubleRegister double_dst, FPRoundingMode rounding_mode) {
+ if (rounding_mode == kRoundToZero) {
+ fctiduz(double_dst, double_input);
} else {
- DCHECK(access_method == CONSTRUCT_INTERNAL_REFERENCE);
- base = kConstantPoolRegister;
- ConstantPoolUnavailableScope constant_pool_unavailable(this);
-
- // CheckBuffer() is called too frequently. This will pre-grow
- // the buffer if needed to avoid spliting the relocation and instructions
- EnsureSpaceFor(kMovInstructionsNoConstantPool * kInstrSize);
-
- uintptr_t code_start = reinterpret_cast<uintptr_t>(pc_) - pc_offset();
- mov(base, Operand(code_start, RelocInfo::INTERNAL_REFERENCE));
+ SetRoundingMode(rounding_mode);
+ fctidu(double_dst, double_input);
+ ResetRoundingMode();
}
- LoadP(kConstantPoolRegister, MemOperand(base, constant_pool_offset));
+
+ MovDoubleToInt64(dst, double_dst);
}
#endif
-void MacroAssembler::StubPrologue(int prologue_offset) {
+void MacroAssembler::LoadConstantPoolPointerRegisterFromCodeTargetAddress(
+ Register code_target_address) {
+ lwz(kConstantPoolRegister,
+ MemOperand(code_target_address,
+ Code::kConstantPoolOffset - Code::kHeaderSize));
+ add(kConstantPoolRegister, kConstantPoolRegister, code_target_address);
+}
+
+
+void MacroAssembler::LoadConstantPoolPointerRegister(Register base,
+ int code_start_delta) {
+ add_label_offset(kConstantPoolRegister, base, ConstantPoolPosition(),
+ code_start_delta);
+}
+
+
+void MacroAssembler::LoadConstantPoolPointerRegister() {
+ mov_label_addr(kConstantPoolRegister, ConstantPoolPosition());
+}
+
+
+void MacroAssembler::StubPrologue(Register base, int prologue_offset) {
LoadSmiLiteral(r11, Smi::FromInt(StackFrame::STUB));
PushFixedFrame(r11);
// Adjust FP to point to saved FP.
addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
-#if V8_OOL_CONSTANT_POOL
- // ip contains prologue address
- LoadConstantPoolPointerRegister(CAN_USE_IP, -prologue_offset);
- set_ool_constant_pool_available(true);
-#endif
+ if (FLAG_enable_embedded_constant_pool) {
+ if (!base.is(no_reg)) {
+ // base contains prologue address
+ LoadConstantPoolPointerRegister(base, -prologue_offset);
+ } else {
+ LoadConstantPoolPointerRegister();
+ }
+ set_constant_pool_available(true);
+ }
}
-void MacroAssembler::Prologue(bool code_pre_aging, int prologue_offset) {
+void MacroAssembler::Prologue(bool code_pre_aging, Register base,
+ int prologue_offset) {
+ DCHECK(!base.is(no_reg));
{
PredictableCodeSizeScope predictible_code_size_scope(
this, kNoCodeAgeSequenceLength);
@@ -749,22 +801,28 @@
}
}
}
-#if V8_OOL_CONSTANT_POOL
- // ip contains prologue address
- LoadConstantPoolPointerRegister(CAN_USE_IP, -prologue_offset);
- set_ool_constant_pool_available(true);
-#endif
+ if (FLAG_enable_embedded_constant_pool) {
+ // base contains prologue address
+ LoadConstantPoolPointerRegister(base, -prologue_offset);
+ set_constant_pool_available(true);
+ }
+}
+
+
+void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) {
+ LoadP(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+ LoadP(vector, FieldMemOperand(vector, JSFunction::kSharedFunctionInfoOffset));
+ LoadP(vector,
+ FieldMemOperand(vector, SharedFunctionInfo::kFeedbackVectorOffset));
}
void MacroAssembler::EnterFrame(StackFrame::Type type,
bool load_constant_pool_pointer_reg) {
- if (FLAG_enable_ool_constant_pool && load_constant_pool_pointer_reg) {
+ if (FLAG_enable_embedded_constant_pool && load_constant_pool_pointer_reg) {
PushFixedFrame();
-#if V8_OOL_CONSTANT_POOL
// This path should not rely on ip containing code entry.
- LoadConstantPoolPointerRegister(CONSTRUCT_INTERNAL_REFERENCE);
-#endif
+ LoadConstantPoolPointerRegister();
LoadSmiLiteral(ip, Smi::FromInt(type));
push(ip);
} else {
@@ -780,24 +838,23 @@
int MacroAssembler::LeaveFrame(StackFrame::Type type, int stack_adjustment) {
-#if V8_OOL_CONSTANT_POOL
ConstantPoolUnavailableScope constant_pool_unavailable(this);
-#endif
// r3: preserved
// r4: preserved
// r5: preserved
// Drop the execution stack down to the frame pointer and restore
- // the caller frame pointer, return address and constant pool pointer.
+ // the caller's state.
int frame_ends;
LoadP(r0, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
LoadP(ip, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
-#if V8_OOL_CONSTANT_POOL
- const int exitOffset = ExitFrameConstants::kConstantPoolOffset;
- const int standardOffset = StandardFrameConstants::kConstantPoolOffset;
- const int offset = ((type == StackFrame::EXIT) ? exitOffset : standardOffset);
- LoadP(kConstantPoolRegister, MemOperand(fp, offset));
-#endif
+ if (FLAG_enable_embedded_constant_pool) {
+ const int exitOffset = ExitFrameConstants::kConstantPoolOffset;
+ const int standardOffset = StandardFrameConstants::kConstantPoolOffset;
+ const int offset =
+ ((type == StackFrame::EXIT) ? exitOffset : standardOffset);
+ LoadP(kConstantPoolRegister, MemOperand(fp, offset));
+ }
mtlr(r0);
frame_ends = pc_offset();
Add(sp, fp, StandardFrameConstants::kCallerSPOffset + stack_adjustment, r0);
@@ -844,10 +901,10 @@
li(r8, Operand::Zero());
StoreP(r8, MemOperand(fp, ExitFrameConstants::kSPOffset));
}
-#if V8_OOL_CONSTANT_POOL
- StoreP(kConstantPoolRegister,
- MemOperand(fp, ExitFrameConstants::kConstantPoolOffset));
-#endif
+ if (FLAG_enable_embedded_constant_pool) {
+ StoreP(kConstantPoolRegister,
+ MemOperand(fp, ExitFrameConstants::kConstantPoolOffset));
+ }
mov(r8, Operand(CodeObject()));
StoreP(r8, MemOperand(fp, ExitFrameConstants::kCodeOffset));
@@ -859,10 +916,10 @@
// Optionally save all volatile double registers.
if (save_doubles) {
- SaveFPRegs(sp, 0, DoubleRegister::kNumVolatileRegisters);
+ MultiPushDoubles(kCallerSavedDoubles);
// Note that d0 will be accessible at
// fp - ExitFrameConstants::kFrameSize -
- // kNumVolatileRegisters * kDoubleSize,
+ // kNumCallerSavedDoubles * kDoubleSize,
// since the sp slot and code slot were pushed after the fp.
}
@@ -915,18 +972,17 @@
void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
- bool restore_context) {
-#if V8_OOL_CONSTANT_POOL
+ bool restore_context,
+ bool argument_count_is_length) {
ConstantPoolUnavailableScope constant_pool_unavailable(this);
-#endif
// Optionally restore all double registers.
if (save_doubles) {
// Calculate the stack location of the saved doubles and restore them.
- const int kNumRegs = DoubleRegister::kNumVolatileRegisters;
+ const int kNumRegs = kNumCallerSavedDoubles;
const int offset =
(ExitFrameConstants::kFrameSize + kNumRegs * kDoubleSize);
addi(r6, fp, Operand(-offset));
- RestoreFPRegs(r6, 0, kNumRegs);
+ MultiPopDoubles(kCallerSavedDoubles, r6);
}
// Clear top frame.
@@ -948,7 +1004,9 @@
LeaveFrame(StackFrame::EXIT);
if (argument_count.is_valid()) {
- ShiftLeftImm(argument_count, argument_count, Operand(kPointerSizeLog2));
+ if (!argument_count_is_length) {
+ ShiftLeftImm(argument_count, argument_count, Operand(kPointerSizeLog2));
+ }
add(sp, sp, argument_count);
}
}
@@ -965,9 +1023,7 @@
void MacroAssembler::InvokePrologue(const ParameterCount& expected,
- const ParameterCount& actual,
- Handle<Code> code_constant,
- Register code_reg, Label* done,
+ const ParameterCount& actual, Label* done,
bool* definitely_mismatches,
InvokeFlag flag,
const CallWrapper& call_wrapper) {
@@ -988,15 +1044,13 @@
// ARM has some sanity checks as per below, considering add them for PPC
// DCHECK(actual.is_immediate() || actual.reg().is(r3));
// DCHECK(expected.is_immediate() || expected.reg().is(r5));
- // DCHECK((!code_constant.is_null() && code_reg.is(no_reg))
- // || code_reg.is(r6));
if (expected.is_immediate()) {
DCHECK(actual.is_immediate());
+ mov(r3, Operand(actual.immediate()));
if (expected.immediate() == actual.immediate()) {
definitely_matches = true;
} else {
- mov(r3, Operand(actual.immediate()));
const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
if (expected.immediate() == sentinel) {
// Don't worry about adapting arguments for builtins that
@@ -1011,9 +1065,9 @@
}
} else {
if (actual.is_immediate()) {
+ mov(r3, Operand(actual.immediate()));
cmpi(expected.reg(), Operand(actual.immediate()));
beq(®ular_invoke);
- mov(r3, Operand(actual.immediate()));
} else {
cmp(expected.reg(), actual.reg());
beq(®ular_invoke);
@@ -1021,11 +1075,6 @@
}
if (!definitely_matches) {
- if (!code_constant.is_null()) {
- mov(r6, Operand(code_constant));
- addi(r6, r6, Operand(Code::kHeaderSize - kHeapObjectTag));
- }
-
Handle<Code> adaptor = isolate()->builtins()->ArgumentsAdaptorTrampoline();
if (flag == CALL_FUNCTION) {
call_wrapper.BeforeCall(CallSize(adaptor));
@@ -1042,17 +1091,78 @@
}
-void MacroAssembler::InvokeCode(Register code, const ParameterCount& expected,
- const ParameterCount& actual, InvokeFlag flag,
- const CallWrapper& call_wrapper) {
+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());
+ mov(r7, Operand(step_in_enabled));
+ lbz(r7, MemOperand(r7));
+ cmpi(r7, Operand::Zero());
+ beq(&skip_flooding);
+ {
+ FrameScope frame(this,
+ has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
+ if (expected.is_reg()) {
+ SmiTag(expected.reg());
+ Push(expected.reg());
+ }
+ if (actual.is_reg()) {
+ SmiTag(actual.reg());
+ Push(actual.reg());
+ }
+ if (new_target.is_valid()) {
+ Push(new_target);
+ }
+ Push(fun, fun);
+ CallRuntime(Runtime::kDebugPrepareStepInIfStepping, 1);
+ Pop(fun);
+ if (new_target.is_valid()) {
+ Pop(new_target);
+ }
+ if (actual.is_reg()) {
+ Pop(actual.reg());
+ SmiUntag(actual.reg());
+ }
+ if (expected.is_reg()) {
+ Pop(expected.reg());
+ SmiUntag(expected.reg());
+ }
+ }
+ bind(&skip_flooding);
+}
+
+
+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(r4));
+ DCHECK_IMPLIES(new_target.is_valid(), new_target.is(r6));
+
+ if (call_wrapper.NeedsDebugStepCheck()) {
+ FloodFunctionIfStepping(function, new_target, expected, actual);
+ }
+
+ // Clear the new.target register if not given.
+ if (!new_target.is_valid()) {
+ LoadRoot(r6, Heap::kUndefinedValueRootIndex);
+ }
Label done;
bool definitely_mismatches = false;
- InvokePrologue(expected, actual, Handle<Code>::null(), code, &done,
- &definitely_mismatches, flag, call_wrapper);
+ InvokePrologue(expected, actual, &done, &definitely_mismatches, flag,
+ 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.
+ Register code = ip;
+ LoadP(code, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
if (flag == CALL_FUNCTION) {
call_wrapper.BeforeCall(CallSize(code));
CallJSEntry(code);
@@ -1069,7 +1179,8 @@
}
-void MacroAssembler::InvokeFunction(Register fun, const ParameterCount& actual,
+void MacroAssembler::InvokeFunction(Register fun, Register new_target,
+ const ParameterCount& actual,
InvokeFlag flag,
const CallWrapper& call_wrapper) {
// You can't call a function without a valid frame.
@@ -1079,20 +1190,19 @@
DCHECK(fun.is(r4));
Register expected_reg = r5;
- Register code_reg = ip;
+ Register temp_reg = r7;
- LoadP(code_reg, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
+ LoadP(temp_reg, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
LoadWordArith(expected_reg,
FieldMemOperand(
- code_reg, SharedFunctionInfo::kFormalParameterCountOffset));
+ temp_reg, SharedFunctionInfo::kFormalParameterCountOffset));
#if !defined(V8_TARGET_ARCH_PPC64)
SmiUntag(expected_reg);
#endif
- LoadP(code_reg, FieldMemOperand(r4, JSFunction::kCodeEntryOffset));
ParameterCount expected(expected_reg);
- InvokeCode(code_reg, expected, actual, flag, call_wrapper);
+ InvokeFunctionCode(fun, new_target, expected, actual, flag, call_wrapper);
}
@@ -1110,11 +1220,7 @@
// Get the function and setup the context.
LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
- // We call indirectly through the code field in the function to
- // allow recompilation to take effect without changing any of the
- // call sites.
- LoadP(ip, FieldMemOperand(r4, JSFunction::kCodeEntryOffset));
- InvokeCode(ip, expected, actual, flag, call_wrapper);
+ InvokeFunctionCode(r4, no_reg, expected, actual, flag, call_wrapper);
}
@@ -1128,23 +1234,6 @@
}
-void MacroAssembler::IsObjectJSObjectType(Register heap_object, Register map,
- Register scratch, Label* fail) {
- LoadP(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
- IsInstanceJSObjectType(map, scratch, fail);
-}
-
-
-void MacroAssembler::IsInstanceJSObjectType(Register map, Register scratch,
- Label* fail) {
- lbz(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
- cmpi(scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
- blt(fail);
- cmpi(scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
- bgt(fail);
-}
-
-
void MacroAssembler::IsObjectJSStringType(Register object, Register scratch,
Label* fail) {
DCHECK(kNotStringTag != 0);
@@ -1167,172 +1256,40 @@
void MacroAssembler::DebugBreak() {
li(r3, Operand::Zero());
- mov(r4, Operand(ExternalReference(Runtime::kDebugBreak, isolate())));
+ mov(r4,
+ Operand(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::PushTryHandler(StackHandler::Kind kind,
- int handler_index) {
+void MacroAssembler::PushStackHandler() {
// Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
-
- // For the JSEntry handler, we must preserve r1-r7, r0,r8-r15 are available.
- // We want the stack to look like
- // sp -> NextOffset
- // CodeObject
- // state
- // context
- // frame pointer
// Link the current handler as the next handler.
+ // Preserve r3-r7.
mov(r8, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
LoadP(r0, MemOperand(r8));
- StorePU(r0, MemOperand(sp, -StackHandlerConstants::kSize));
+ push(r0);
+
// Set this new handler as the current one.
StoreP(sp, MemOperand(r8));
-
- if (kind == StackHandler::JS_ENTRY) {
- li(r8, Operand::Zero()); // NULL frame pointer.
- StoreP(r8, MemOperand(sp, StackHandlerConstants::kFPOffset));
- LoadSmiLiteral(r8, Smi::FromInt(0)); // Indicates no context.
- StoreP(r8, MemOperand(sp, StackHandlerConstants::kContextOffset));
- } else {
- // still not sure if fp is right
- StoreP(fp, MemOperand(sp, StackHandlerConstants::kFPOffset));
- StoreP(cp, MemOperand(sp, StackHandlerConstants::kContextOffset));
- }
- unsigned state = StackHandler::IndexField::encode(handler_index) |
- StackHandler::KindField::encode(kind);
- LoadIntLiteral(r8, state);
- StoreP(r8, MemOperand(sp, StackHandlerConstants::kStateOffset));
- mov(r8, Operand(CodeObject()));
- StoreP(r8, MemOperand(sp, StackHandlerConstants::kCodeOffset));
}
-void MacroAssembler::PopTryHandler() {
+void MacroAssembler::PopStackHandler() {
+ STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
+
pop(r4);
mov(ip, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
- addi(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
StoreP(r4, MemOperand(ip));
}
-// PPC - make use of ip as a temporary register
-void MacroAssembler::JumpToHandlerEntry() {
-// Compute the handler entry address and jump to it. The handler table is
-// a fixed array of (smi-tagged) code offsets.
-// r3 = exception, r4 = code object, r5 = state.
-#if V8_OOL_CONSTANT_POOL
- ConstantPoolUnavailableScope constant_pool_unavailable(this);
- LoadP(kConstantPoolRegister, FieldMemOperand(r4, Code::kConstantPoolOffset));
-#endif
- LoadP(r6, FieldMemOperand(r4, Code::kHandlerTableOffset)); // Handler table.
- addi(r6, r6, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- srwi(r5, r5, Operand(StackHandler::kKindWidth)); // Handler index.
- slwi(ip, r5, Operand(kPointerSizeLog2));
- add(ip, r6, ip);
- LoadP(r5, MemOperand(ip)); // Smi-tagged offset.
- addi(r4, r4, Operand(Code::kHeaderSize - kHeapObjectTag)); // Code start.
- SmiUntag(ip, r5);
- add(r0, r4, ip);
- mtctr(r0);
- bctr();
-}
-
-
-void MacroAssembler::Throw(Register value) {
- // Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 5 * 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);
- Label skip;
-
- // The exception is expected in r3.
- if (!value.is(r3)) {
- mr(r3, value);
- }
- // Drop the stack pointer to the top of the top handler.
- mov(r6, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
- LoadP(sp, MemOperand(r6));
- // Restore the next handler.
- pop(r5);
- StoreP(r5, MemOperand(r6));
-
- // Get the code object (r4) and state (r5). Restore the context and frame
- // pointer.
- pop(r4);
- pop(r5);
- pop(cp);
- pop(fp);
-
- // If the handler is a JS frame, restore the context to the frame.
- // (kind == ENTRY) == (fp == 0) == (cp == 0), so we could test either fp
- // or cp.
- cmpi(cp, Operand::Zero());
- beq(&skip);
- StoreP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
- bind(&skip);
-
- JumpToHandlerEntry();
-}
-
-
-void MacroAssembler::ThrowUncatchable(Register value) {
- // Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
- 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 r3.
- if (!value.is(r3)) {
- mr(r3, value);
- }
- // Drop the stack pointer to the top of the top stack handler.
- mov(r6, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
- LoadP(sp, MemOperand(r6));
-
- // Unwind the handlers until the ENTRY handler is found.
- Label fetch_next, check_kind;
- b(&check_kind);
- bind(&fetch_next);
- LoadP(sp, MemOperand(sp, StackHandlerConstants::kNextOffset));
-
- bind(&check_kind);
- STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
- LoadP(r5, MemOperand(sp, StackHandlerConstants::kStateOffset));
- andi(r0, r5, Operand(StackHandler::KindField::kMask));
- bne(&fetch_next, cr0);
-
- // Set the top handler address to next handler past the top ENTRY handler.
- pop(r5);
- StoreP(r5, MemOperand(r6));
- // Get the code object (r4) and state (r5). Clear the context and frame
- // pointer (0 was saved in the handler).
- pop(r4);
- pop(r5);
- pop(cp);
- pop(fp);
-
- JumpToHandlerEntry();
-}
-
-
void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
Register scratch, Label* miss) {
Label same_contexts;
@@ -1350,10 +1307,7 @@
#endif
// Load the native context of the current context.
- int offset =
- Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
- LoadP(scratch, FieldMemOperand(scratch, offset));
- LoadP(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset));
+ LoadP(scratch, ContextMemOperand(scratch, Context::NATIVE_CONTEXT_INDEX));
// Check the context is a native context.
if (emit_debug_code()) {
@@ -1444,6 +1398,8 @@
// hash = hash ^ (hash >> 16);
srwi(scratch, t0, Operand(16));
xor_(t0, t0, scratch);
+ // hash & 0x3fffffff
+ ExtractBitRange(t0, t0, 29, 0);
}
@@ -1515,7 +1471,7 @@
SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
LoadP(t1, FieldMemOperand(t2, kDetailsOffset));
LoadSmiLiteral(ip, Smi::FromInt(PropertyDetails::TypeField::kMask));
- DCHECK_EQ(FIELD, 0);
+ DCHECK_EQ(DATA, 0);
and_(r0, t1, ip, SetRC);
bne(miss, cr0);
@@ -1541,11 +1497,7 @@
return;
}
- DCHECK(!result.is(scratch1));
- DCHECK(!result.is(scratch2));
- DCHECK(!scratch1.is(scratch2));
- DCHECK(!scratch1.is(ip));
- DCHECK(!scratch2.is(ip));
+ DCHECK(!AreAliased(result, scratch1, scratch2, ip));
// Make object size into bytes.
if ((flags & SIZE_IN_WORDS) != 0) {
@@ -1564,45 +1516,44 @@
DCHECK((limit - top) == kPointerSize);
// Set up allocation top address register.
- Register topaddr = scratch1;
- mov(topaddr, Operand(allocation_top));
-
+ Register top_address = scratch1;
// This code stores a temporary value in ip. This is OK, as the code below
// does not need ip for implicit literal generation.
+ Register alloc_limit = ip;
+ Register result_end = scratch2;
+ mov(top_address, Operand(allocation_top));
+
if ((flags & RESULT_CONTAINS_TOP) == 0) {
// Load allocation top into result and allocation limit into ip.
- LoadP(result, MemOperand(topaddr));
- LoadP(ip, MemOperand(topaddr, kPointerSize));
+ LoadP(result, MemOperand(top_address));
+ LoadP(alloc_limit, MemOperand(top_address, kPointerSize));
} else {
if (emit_debug_code()) {
- // Assert that result actually contains top on entry. ip is used
- // immediately below so this use of ip does not cause difference with
- // respect to register content between debug and release mode.
- LoadP(ip, MemOperand(topaddr));
- cmp(result, ip);
+ // Assert that result actually contains top on entry.
+ LoadP(alloc_limit, MemOperand(top_address));
+ cmp(result, alloc_limit);
Check(eq, kUnexpectedAllocationTop);
}
- // Load allocation limit into ip. Result already contains allocation top.
- LoadP(ip, MemOperand(topaddr, limit - top), r0);
+ // Load allocation limit. Result already contains allocation top.
+ LoadP(alloc_limit, MemOperand(top_address, limit - top));
}
if ((flags & DOUBLE_ALIGNMENT) != 0) {
// 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((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
#if V8_TARGET_ARCH_PPC64
STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
#else
STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
- andi(scratch2, result, Operand(kDoubleAlignmentMask));
+ andi(result_end, result, Operand(kDoubleAlignmentMask));
Label aligned;
beq(&aligned, cr0);
- if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
- cmpl(result, ip);
+ if ((flags & PRETENURE) != 0) {
+ cmpl(result, alloc_limit);
bge(gc_required);
}
- mov(scratch2, Operand(isolate()->factory()->one_pointer_filler_map()));
- stw(scratch2, MemOperand(result));
+ mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
+ stw(result_end, MemOperand(result));
addi(result, result, Operand(kDoubleSize / 2));
bind(&aligned);
#endif
@@ -1610,17 +1561,17 @@
// Calculate new top and bail out if new space is exhausted. Use result
// to calculate the new top.
- sub(r0, ip, result);
+ sub(r0, alloc_limit, result);
if (is_int16(object_size)) {
cmpi(r0, Operand(object_size));
blt(gc_required);
- addi(scratch2, result, Operand(object_size));
+ addi(result_end, result, Operand(object_size));
} else {
- Cmpi(r0, Operand(object_size), scratch2);
+ Cmpi(r0, Operand(object_size), result_end);
blt(gc_required);
- add(scratch2, result, scratch2);
+ add(result_end, result, result_end);
}
- StoreP(scratch2, MemOperand(topaddr));
+ StoreP(result_end, MemOperand(top_address));
// Tag object if requested.
if ((flags & TAG_OBJECT) != 0) {
@@ -1630,28 +1581,24 @@
void MacroAssembler::Allocate(Register object_size, Register result,
- Register scratch1, Register scratch2,
+ Register result_end, Register scratch,
Label* gc_required, AllocationFlags flags) {
if (!FLAG_inline_new) {
if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
li(result, Operand(0x7091));
- li(scratch1, Operand(0x7191));
- li(scratch2, Operand(0x7291));
+ li(scratch, Operand(0x7191));
+ li(result_end, Operand(0x7291));
}
b(gc_required);
return;
}
- // Assert that the register arguments are different and that none of
- // them are ip. ip is used explicitly in the code generated below.
- DCHECK(!result.is(scratch1));
- DCHECK(!result.is(scratch2));
- DCHECK(!scratch1.is(scratch2));
- DCHECK(!object_size.is(ip));
- DCHECK(!result.is(ip));
- DCHECK(!scratch1.is(ip));
- DCHECK(!scratch2.is(ip));
+ // |object_size| and |result_end| may overlap if the DOUBLE_ALIGNMENT flag
+ // is not specified. Other registers must not overlap.
+ DCHECK(!AreAliased(object_size, result, scratch, ip));
+ DCHECK(!AreAliased(result_end, result, scratch, ip));
+ DCHECK((flags & DOUBLE_ALIGNMENT) == 0 || !object_size.is(result_end));
// Check relative positions of allocation top and limit addresses.
ExternalReference allocation_top =
@@ -1662,46 +1609,44 @@
intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
DCHECK((limit - top) == kPointerSize);
- // Set up allocation top address.
- Register topaddr = scratch1;
- mov(topaddr, Operand(allocation_top));
-
+ // Set up allocation top address and allocation limit registers.
+ Register top_address = scratch;
// This code stores a temporary value in ip. This is OK, as the code below
// does not need ip for implicit literal generation.
+ Register alloc_limit = ip;
+ mov(top_address, Operand(allocation_top));
+
if ((flags & RESULT_CONTAINS_TOP) == 0) {
- // Load allocation top into result and allocation limit into ip.
- LoadP(result, MemOperand(topaddr));
- LoadP(ip, MemOperand(topaddr, kPointerSize));
+ // Load allocation top into result and allocation limit into alloc_limit..
+ LoadP(result, MemOperand(top_address));
+ LoadP(alloc_limit, MemOperand(top_address, kPointerSize));
} else {
if (emit_debug_code()) {
- // Assert that result actually contains top on entry. ip is used
- // immediately below so this use of ip does not cause difference with
- // respect to register content between debug and release mode.
- LoadP(ip, MemOperand(topaddr));
- cmp(result, ip);
+ // Assert that result actually contains top on entry.
+ LoadP(alloc_limit, MemOperand(top_address));
+ cmp(result, alloc_limit);
Check(eq, kUnexpectedAllocationTop);
}
- // Load allocation limit into ip. Result already contains allocation top.
- LoadP(ip, MemOperand(topaddr, limit - top));
+ // Load allocation limit. Result already contains allocation top.
+ LoadP(alloc_limit, MemOperand(top_address, limit - top));
}
if ((flags & DOUBLE_ALIGNMENT) != 0) {
// 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((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
#if V8_TARGET_ARCH_PPC64
STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
#else
STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
- andi(scratch2, result, Operand(kDoubleAlignmentMask));
+ andi(result_end, result, Operand(kDoubleAlignmentMask));
Label aligned;
beq(&aligned, cr0);
- if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
- cmpl(result, ip);
+ if ((flags & PRETENURE) != 0) {
+ cmpl(result, alloc_limit);
bge(gc_required);
}
- mov(scratch2, Operand(isolate()->factory()->one_pointer_filler_map()));
- stw(scratch2, MemOperand(result));
+ mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
+ stw(result_end, MemOperand(result));
addi(result, result, Operand(kDoubleSize / 2));
bind(&aligned);
#endif
@@ -1710,24 +1655,24 @@
// Calculate new top and bail out if new space is exhausted. Use result
// to calculate the new top. Object size may be in words so a shift is
// required to get the number of bytes.
- sub(r0, ip, result);
+ sub(r0, alloc_limit, result);
if ((flags & SIZE_IN_WORDS) != 0) {
- ShiftLeftImm(scratch2, object_size, Operand(kPointerSizeLog2));
- cmp(r0, scratch2);
+ ShiftLeftImm(result_end, object_size, Operand(kPointerSizeLog2));
+ cmp(r0, result_end);
blt(gc_required);
- add(scratch2, result, scratch2);
+ add(result_end, result, result_end);
} else {
cmp(r0, object_size);
blt(gc_required);
- add(scratch2, result, object_size);
+ add(result_end, result, object_size);
}
// Update allocation top. result temporarily holds the new top.
if (emit_debug_code()) {
- andi(r0, scratch2, Operand(kObjectAlignmentMask));
+ andi(r0, result_end, Operand(kObjectAlignmentMask));
Check(eq, kUnalignedAllocationInNewSpace, cr0);
}
- StoreP(scratch2, MemOperand(topaddr));
+ StoreP(result_end, MemOperand(top_address));
// Tag object if requested.
if ((flags & TAG_OBJECT) != 0) {
@@ -1736,28 +1681,6 @@
}
-void MacroAssembler::UndoAllocationInNewSpace(Register object,
- Register scratch) {
- ExternalReference new_space_allocation_top =
- ExternalReference::new_space_allocation_top_address(isolate());
-
- // Make sure the object has no tag before resetting top.
- mov(r0, Operand(~kHeapObjectTagMask));
- and_(object, object, r0);
-// was.. and_(object, object, Operand(~kHeapObjectTagMask));
-#ifdef DEBUG
- // Check that the object un-allocated is below the current top.
- mov(scratch, Operand(new_space_allocation_top));
- LoadP(scratch, MemOperand(scratch));
- cmp(object, scratch);
- Check(lt, kUndoAllocationOfNonAllocatedMemory);
-#endif
- // Write the address of the object to un-allocate as the current top.
- mov(scratch, Operand(new_space_allocation_top));
- StoreP(object, MemOperand(scratch));
-}
-
-
void MacroAssembler::AllocateTwoByteString(Register result, Register length,
Register scratch1, Register scratch2,
Register scratch3,
@@ -1861,20 +1784,6 @@
}
-void MacroAssembler::CheckObjectTypeRange(Register object, Register map,
- InstanceType min_type,
- InstanceType max_type,
- Label* false_label) {
- STATIC_ASSERT(Map::kInstanceTypeOffset < 4096);
- STATIC_ASSERT(LAST_TYPE < 256);
- LoadP(map, FieldMemOperand(object, HeapObject::kMapOffset));
- lbz(ip, FieldMemOperand(map, Map::kInstanceTypeOffset));
- subi(ip, ip, Operand(min_type));
- cmpli(ip, Operand(max_type - min_type));
- bgt(false_label);
-}
-
-
void MacroAssembler::CompareInstanceType(Register map, Register type_reg,
InstanceType type) {
STATIC_ASSERT(Map::kInstanceTypeOffset < 4096);
@@ -1932,6 +1841,7 @@
Register value_reg, Register key_reg, Register elements_reg,
Register scratch1, DoubleRegister double_scratch, Label* fail,
int elements_offset) {
+ DCHECK(!AreAliased(value_reg, key_reg, elements_reg, scratch1));
Label smi_value, store;
// Handle smi values specially.
@@ -1942,7 +1852,7 @@
DONT_DO_SMI_CHECK);
lfd(double_scratch, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
- // Force a canonical NaN.
+ // Double value, turn potential sNaN into qNaN.
CanonicalizeNaN(double_scratch);
b(&store);
@@ -1967,23 +1877,26 @@
DCHECK(!overflow_dst.is(left));
DCHECK(!overflow_dst.is(right));
+ bool left_is_right = left.is(right);
+ RCBit xorRC = left_is_right ? SetRC : LeaveRC;
+
// C = A+B; C overflows if A/B have same sign and C has diff sign than A
if (dst.is(left)) {
mr(scratch, left); // Preserve left.
add(dst, left, right); // Left is overwritten.
- xor_(scratch, dst, scratch); // Original left.
- xor_(overflow_dst, dst, right);
+ xor_(overflow_dst, dst, scratch, xorRC); // Original left.
+ if (!left_is_right) xor_(scratch, dst, right);
} else if (dst.is(right)) {
mr(scratch, right); // Preserve right.
add(dst, left, right); // Right is overwritten.
- xor_(scratch, dst, scratch); // Original right.
- xor_(overflow_dst, dst, left);
+ xor_(overflow_dst, dst, left, xorRC);
+ if (!left_is_right) xor_(scratch, dst, scratch); // Original right.
} else {
add(dst, left, right);
- xor_(overflow_dst, dst, left);
- xor_(scratch, dst, right);
+ xor_(overflow_dst, dst, left, xorRC);
+ if (!left_is_right) xor_(scratch, dst, right);
}
- and_(overflow_dst, scratch, overflow_dst, SetRC);
+ if (!left_is_right) and_(overflow_dst, scratch, overflow_dst, SetRC);
}
@@ -2085,53 +1998,58 @@
}
-void MacroAssembler::DispatchMap(Register obj, Register scratch,
- Handle<Map> map, Handle<Code> success,
- SmiCheckType smi_check_type) {
+void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
+ Register scratch2, Handle<WeakCell> cell,
+ Handle<Code> success,
+ SmiCheckType smi_check_type) {
Label fail;
if (smi_check_type == DO_SMI_CHECK) {
JumpIfSmi(obj, &fail);
}
- LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
- mov(r0, Operand(map));
- cmp(scratch, r0);
- bne(&fail);
- Jump(success, RelocInfo::CODE_TARGET, al);
+ LoadP(scratch1, FieldMemOperand(obj, HeapObject::kMapOffset));
+ CmpWeakValue(scratch1, cell, scratch2);
+ Jump(success, RelocInfo::CODE_TARGET, eq);
bind(&fail);
}
+void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
+ Register scratch, CRegister cr) {
+ mov(scratch, Operand(cell));
+ LoadP(scratch, FieldMemOperand(scratch, WeakCell::kValueOffset));
+ cmp(value, scratch, cr);
+}
+
+
+void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) {
+ mov(value, Operand(cell));
+ LoadP(value, FieldMemOperand(value, WeakCell::kValueOffset));
+}
+
+
+void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
+ Label* miss) {
+ GetWeakValue(value, cell);
+ JumpIfSmi(value, miss);
+}
+
+
+void MacroAssembler::GetMapConstructor(Register result, Register map,
+ Register temp, Register temp2) {
+ Label done, loop;
+ LoadP(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset));
+ bind(&loop);
+ JumpIfSmi(result, &done);
+ CompareObjectType(result, temp, temp2, MAP_TYPE);
+ bne(&done);
+ LoadP(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset));
+ b(&loop);
+ bind(&done);
+}
+
+
void MacroAssembler::TryGetFunctionPrototype(Register function, Register result,
- Register scratch, Label* miss,
- bool miss_on_bound_function) {
- Label non_instance;
- if (miss_on_bound_function) {
- // Check that the receiver isn't a smi.
- JumpIfSmi(function, miss);
-
- // Check that the function really is a function. Load map into result reg.
- CompareObjectType(function, result, scratch, JS_FUNCTION_TYPE);
- bne(miss);
-
- LoadP(scratch,
- FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
- lwz(scratch,
- FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset));
- TestBit(scratch,
-#if V8_TARGET_ARCH_PPC64
- SharedFunctionInfo::kBoundFunction,
-#else
- SharedFunctionInfo::kBoundFunction + kSmiTagSize,
-#endif
- r0);
- bne(miss, cr0);
-
- // Make sure that the function has an instance prototype.
- lbz(scratch, FieldMemOperand(result, Map::kBitFieldOffset));
- andi(r0, scratch, Operand(1 << Map::kHasNonInstancePrototype));
- bne(&non_instance, cr0);
- }
-
+ Register scratch, Label* miss) {
// Get the prototype or initial map from the function.
LoadP(result,
FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
@@ -2151,15 +2069,6 @@
// Get the prototype from the initial map.
LoadP(result, FieldMemOperand(result, Map::kPrototypeOffset));
- if (miss_on_bound_function) {
- b(&done);
-
- // Non-instance prototype: Fetch prototype from constructor field
- // in initial map.
- bind(&non_instance);
- LoadP(result, FieldMemOperand(result, Map::kConstructorOffset));
- }
-
// All done.
bind(&done);
}
@@ -2177,138 +2086,6 @@
}
-static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
- return ref0.address() - ref1.address();
-}
-
-
-void MacroAssembler::CallApiFunctionAndReturn(
- Register function_address, ExternalReference thunk_ref, int stack_space,
- MemOperand return_value_operand, MemOperand* context_restore_operand) {
- ExternalReference next_address =
- ExternalReference::handle_scope_next_address(isolate());
- const int kNextOffset = 0;
- const int kLimitOffset = AddressOffset(
- ExternalReference::handle_scope_limit_address(isolate()), next_address);
- const int kLevelOffset = AddressOffset(
- ExternalReference::handle_scope_level_address(isolate()), next_address);
-
- DCHECK(function_address.is(r4) || function_address.is(r5));
- Register scratch = r6;
-
- Label profiler_disabled;
- Label end_profiler_check;
- mov(scratch, Operand(ExternalReference::is_profiling_address(isolate())));
- lbz(scratch, MemOperand(scratch, 0));
- cmpi(scratch, Operand::Zero());
- beq(&profiler_disabled);
-
- // Additional parameter is the address of the actual callback.
- mov(scratch, Operand(thunk_ref));
- jmp(&end_profiler_check);
-
- bind(&profiler_disabled);
- mr(scratch, function_address);
- bind(&end_profiler_check);
-
- // Allocate HandleScope in callee-save registers.
- // r17 - next_address
- // r14 - next_address->kNextOffset
- // r15 - next_address->kLimitOffset
- // r16 - next_address->kLevelOffset
- mov(r17, Operand(next_address));
- LoadP(r14, MemOperand(r17, kNextOffset));
- LoadP(r15, MemOperand(r17, kLimitOffset));
- lwz(r16, MemOperand(r17, kLevelOffset));
- addi(r16, r16, Operand(1));
- stw(r16, MemOperand(r17, kLevelOffset));
-
- if (FLAG_log_timer_events) {
- FrameScope frame(this, StackFrame::MANUAL);
- PushSafepointRegisters();
- PrepareCallCFunction(1, r3);
- mov(r3, Operand(ExternalReference::isolate_address(isolate())));
- CallCFunction(ExternalReference::log_enter_external_function(isolate()), 1);
- PopSafepointRegisters();
- }
-
- // Native call returns to the DirectCEntry stub which redirects to the
- // return address pushed on stack (could have moved after GC).
- // DirectCEntry stub itself is generated early and never moves.
- DirectCEntryStub stub(isolate());
- stub.GenerateCall(this, scratch);
-
- if (FLAG_log_timer_events) {
- FrameScope frame(this, StackFrame::MANUAL);
- PushSafepointRegisters();
- PrepareCallCFunction(1, r3);
- mov(r3, Operand(ExternalReference::isolate_address(isolate())));
- CallCFunction(ExternalReference::log_leave_external_function(isolate()), 1);
- PopSafepointRegisters();
- }
-
- Label promote_scheduled_exception;
- Label exception_handled;
- Label delete_allocated_handles;
- Label leave_exit_frame;
- Label return_value_loaded;
-
- // load value from ReturnValue
- LoadP(r3, return_value_operand);
- bind(&return_value_loaded);
- // No more valid handles (the result handle was the last one). Restore
- // previous handle scope.
- StoreP(r14, MemOperand(r17, kNextOffset));
- if (emit_debug_code()) {
- lwz(r4, MemOperand(r17, kLevelOffset));
- cmp(r4, r16);
- Check(eq, kUnexpectedLevelAfterReturnFromApiCall);
- }
- subi(r16, r16, Operand(1));
- stw(r16, MemOperand(r17, kLevelOffset));
- LoadP(r0, MemOperand(r17, kLimitOffset));
- cmp(r15, r0);
- bne(&delete_allocated_handles);
-
- // Check if the function scheduled an exception.
- bind(&leave_exit_frame);
- LoadRoot(r14, Heap::kTheHoleValueRootIndex);
- mov(r15, Operand(ExternalReference::scheduled_exception_address(isolate())));
- LoadP(r15, MemOperand(r15));
- cmp(r14, r15);
- bne(&promote_scheduled_exception);
- bind(&exception_handled);
-
- bool restore_context = context_restore_operand != NULL;
- if (restore_context) {
- LoadP(cp, *context_restore_operand);
- }
- // LeaveExitFrame expects unwind space to be in a register.
- mov(r14, Operand(stack_space));
- LeaveExitFrame(false, r14, !restore_context);
- blr();
-
- bind(&promote_scheduled_exception);
- {
- FrameScope frame(this, StackFrame::INTERNAL);
- CallExternalReference(
- ExternalReference(Runtime::kPromoteScheduledException, isolate()), 0);
- }
- jmp(&exception_handled);
-
- // HandleScope limit has changed. Delete allocated extensions.
- bind(&delete_allocated_handles);
- StoreP(r15, MemOperand(r17, kLimitOffset));
- mr(r14, r3);
- PrepareCallCFunction(1, r15);
- mov(r3, Operand(ExternalReference::isolate_address(isolate())));
- CallCFunction(ExternalReference::delete_handle_scope_extensions(isolate()),
- 1);
- mr(r3, r14);
- b(&leave_exit_frame);
-}
-
-
bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
return has_frame_ || !stub->SometimesSetsUpAFrame();
}
@@ -2352,7 +2129,7 @@
result, double_scratch);
#if V8_TARGET_ARCH_PPC64
- TestIfInt32(result, scratch, r0);
+ TestIfInt32(result, r0);
#else
TestIfInt32(scratch, result, r0);
#endif
@@ -2389,7 +2166,7 @@
// Test for overflow
#if V8_TARGET_ARCH_PPC64
- TestIfInt32(result, scratch, r0);
+ TestIfInt32(result, r0);
#else
TestIfInt32(scratch, result, r0);
#endif
@@ -2409,7 +2186,9 @@
DoubleRegister double_input,
Label* done) {
DoubleRegister double_scratch = kScratchDoubleReg;
+#if !V8_TARGET_ARCH_PPC64
Register scratch = ip;
+#endif
ConvertDoubleToInt64(double_input,
#if !V8_TARGET_ARCH_PPC64
@@ -2419,7 +2198,7 @@
// Test for overflow
#if V8_TARGET_ARCH_PPC64
- TestIfInt32(result, scratch, r0);
+ TestIfInt32(result, r0);
#else
TestIfInt32(scratch, result, r0);
#endif
@@ -2539,22 +2318,13 @@
}
-void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
- int num_arguments,
- int result_size) {
- // 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.
- mov(r3, Operand(num_arguments));
- JumpToExternalReference(ext);
-}
-
-
-void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid, int num_arguments,
- int result_size) {
- TailCallExternalReference(ExternalReference(fid, isolate()), num_arguments,
- result_size);
+void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
+ const Runtime::Function* function = Runtime::FunctionForId(fid);
+ DCHECK_EQ(1, function->result_size);
+ if (function->nargs >= 0) {
+ mov(r3, Operand(function->nargs));
+ }
+ JumpToExternalReference(ExternalReference(fid, isolate()));
}
@@ -2565,41 +2335,15 @@
}
-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());
- GetBuiltinEntry(ip, id);
- if (flag == CALL_FUNCTION) {
- call_wrapper.BeforeCall(CallSize(ip));
- CallJSEntry(ip);
- call_wrapper.AfterCall();
- } else {
- DCHECK(flag == JUMP_FUNCTION);
- JumpToJSEntry(ip);
- }
-}
-
-
-void MacroAssembler::GetBuiltinFunction(Register target,
- Builtins::JavaScript id) {
- // Load the builtins object into target register.
- LoadP(target,
- MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
- LoadP(target, FieldMemOperand(target, GlobalObject::kBuiltinsOffset));
- // Load the JavaScript builtin function from the builtins object.
- LoadP(target,
- FieldMemOperand(target, JSBuiltinsObject::OffsetOfFunctionWithId(id)),
- r0);
-}
-
-
-void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
- DCHECK(!target.is(r4));
- GetBuiltinFunction(r4, id);
- // Load the code entry point from the builtins object.
- LoadP(target, FieldMemOperand(r4, JSFunction::kCodeEntryOffset));
+ // Fake a parameter count to avoid emitting code to do the check.
+ ParameterCount expected(0);
+ LoadNativeContextSlot(native_context_index, r4);
+ InvokeFunctionCode(r4, no_reg, expected, expected, flag, call_wrapper);
}
@@ -2724,34 +2468,24 @@
void MacroAssembler::LoadTransitionedArrayMapConditional(
ElementsKind expected_kind, ElementsKind transitioned_kind,
Register map_in_out, Register scratch, Label* no_map_match) {
- // Load the global or builtins object from the current context.
- LoadP(scratch,
- MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
- LoadP(scratch, FieldMemOperand(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.
- LoadP(scratch,
- MemOperand(scratch, Context::SlotOffset(Context::JS_ARRAY_MAPS_INDEX)));
- size_t offset = expected_kind * kPointerSize + FixedArrayBase::kHeaderSize;
- LoadP(scratch, FieldMemOperand(scratch, offset));
- cmp(map_in_out, scratch);
+ LoadP(scratch, NativeContextMemOperand());
+ LoadP(ip, ContextMemOperand(scratch, Context::ArrayMapIndex(expected_kind)));
+ cmp(map_in_out, ip);
bne(no_map_match);
// Use the transitioned cached map.
- offset = transitioned_kind * kPointerSize + FixedArrayBase::kHeaderSize;
- LoadP(map_in_out, FieldMemOperand(scratch, offset));
+ LoadP(map_in_out,
+ ContextMemOperand(scratch, Context::ArrayMapIndex(transitioned_kind)));
}
-void MacroAssembler::LoadGlobalFunction(int index, Register function) {
- // Load the global or builtins object from the current context.
- LoadP(function,
- MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
- // Load the native context from the global or builtins object.
- LoadP(function,
- FieldMemOperand(function, GlobalObject::kNativeContextOffset));
- // Load the function from the native context.
- LoadP(function, MemOperand(function, Context::SlotOffset(index)), r0);
+void MacroAssembler::LoadNativeContextSlot(int index, Register dst) {
+ LoadP(dst, NativeContextMemOperand());
+ LoadP(dst, ContextMemOperand(dst, index));
}
@@ -2820,7 +2554,6 @@
void MacroAssembler::JumpIfNotBothSmi(Register reg1, Register reg2,
Label* on_not_both_smi) {
STATIC_ASSERT(kSmiTag == 0);
- DCHECK_EQ(1, static_cast<int>(kSmiTagMask));
orx(r0, reg1, reg2, LeaveRC);
JumpIfNotSmi(r0, on_not_both_smi);
}
@@ -2829,8 +2562,7 @@
void MacroAssembler::UntagAndJumpIfSmi(Register dst, Register src,
Label* smi_case) {
STATIC_ASSERT(kSmiTag == 0);
- STATIC_ASSERT(kSmiTagSize == 1);
- TestBit(src, 0, r0);
+ TestBitRange(src, kSmiTagSize - 1, 0, r0);
SmiUntag(dst, src);
beq(smi_case, cr0);
}
@@ -2839,8 +2571,7 @@
void MacroAssembler::UntagAndJumpIfNotSmi(Register dst, Register src,
Label* non_smi_case) {
STATIC_ASSERT(kSmiTag == 0);
- STATIC_ASSERT(kSmiTagSize == 1);
- TestBit(src, 0, r0);
+ TestBitRange(src, kSmiTagSize - 1, 0, r0);
SmiUntag(dst, src);
bne(non_smi_case, cr0);
}
@@ -2900,6 +2631,32 @@
}
+void MacroAssembler::AssertFunction(Register object) {
+ if (emit_debug_code()) {
+ STATIC_ASSERT(kSmiTag == 0);
+ TestIfSmi(object, r0);
+ Check(ne, kOperandIsASmiAndNotAFunction, cr0);
+ push(object);
+ CompareObjectType(object, object, object, JS_FUNCTION_TYPE);
+ pop(object);
+ Check(eq, kOperandIsNotAFunction);
+ }
+}
+
+
+void MacroAssembler::AssertBoundFunction(Register object) {
+ if (emit_debug_code()) {
+ STATIC_ASSERT(kSmiTag == 0);
+ TestIfSmi(object, r0);
+ Check(ne, kOperandIsASmiAndNotABoundFunction, cr0);
+ push(object);
+ CompareObjectType(object, object, object, JS_BOUND_FUNCTION_TYPE);
+ pop(object);
+ Check(eq, kOperandIsNotABoundFunction);
+ }
+}
+
+
void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
Register scratch) {
if (emit_debug_code()) {
@@ -2934,78 +2691,6 @@
}
-void MacroAssembler::LookupNumberStringCache(Register object, Register result,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- Label* not_found) {
- // Use of registers. Register result is used as a temporary.
- Register number_string_cache = result;
- Register mask = scratch3;
-
- // 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.
- LoadP(mask, FieldMemOperand(number_string_cache, FixedArray::kLengthOffset));
- // Divide length by two (length is a smi).
- ShiftRightArithImm(mask, mask, kSmiTagSize + kSmiShiftSize + 1);
- subi(mask, mask, Operand(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, scratch1, Heap::kHeapNumberMapRootIndex, not_found,
- DONT_DO_SMI_CHECK);
-
- STATIC_ASSERT(8 == kDoubleSize);
- lwz(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
- lwz(scratch2, FieldMemOperand(object, HeapNumber::kMantissaOffset));
- xor_(scratch1, scratch1, scratch2);
- and_(scratch1, scratch1, mask);
-
- // Calculate address of entry in string cache: each entry consists
- // of two pointer sized fields.
- ShiftLeftImm(scratch1, scratch1, Operand(kPointerSizeLog2 + 1));
- add(scratch1, number_string_cache, scratch1);
-
- Register probe = mask;
- LoadP(probe, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
- JumpIfSmi(probe, not_found);
- lfd(d0, FieldMemOperand(object, HeapNumber::kValueOffset));
- lfd(d1, FieldMemOperand(probe, HeapNumber::kValueOffset));
- fcmpu(d0, d1);
- bne(not_found); // The cache did not contain this value.
- b(&load_result_from_cache);
-
- bind(&is_smi);
- Register scratch = scratch1;
- SmiUntag(scratch, object);
- and_(scratch, mask, scratch);
- // Calculate address of entry in string cache: each entry consists
- // of two pointer sized fields.
- ShiftLeftImm(scratch, scratch, Operand(kPointerSizeLog2 + 1));
- add(scratch, number_string_cache, scratch);
-
- // Check if the entry is the smi we are looking for.
- LoadP(probe, FieldMemOperand(scratch, FixedArray::kHeaderSize));
- cmp(object, probe);
- bne(not_found);
-
- // Get the result from the cache.
- bind(&load_result_from_cache);
- LoadP(result,
- FieldMemOperand(scratch, FixedArray::kHeaderSize + kPointerSize));
- IncrementCounter(isolate()->counters()->number_to_string_native(), 1,
- scratch1, scratch2);
-}
-
-
void MacroAssembler::JumpIfNonSmisNotBothSequentialOneByteStrings(
Register first, Register second, Register scratch1, Register scratch2,
Label* failure) {
@@ -3082,29 +2767,25 @@
}
-// Copies a fixed number of fields of heap objects from src to dst.
-void MacroAssembler::CopyFields(Register dst, Register src, RegList temps,
- int field_count) {
- // At least one bit set in the first 15 registers.
- DCHECK((temps & ((1 << 15) - 1)) != 0);
- DCHECK((temps & dst.bit()) == 0);
- DCHECK((temps & src.bit()) == 0);
- // Primitive implementation using only one temporary register.
+void MacroAssembler::AllocateJSValue(Register result, Register constructor,
+ Register value, Register scratch1,
+ Register scratch2, Label* gc_required) {
+ DCHECK(!result.is(constructor));
+ DCHECK(!result.is(scratch1));
+ DCHECK(!result.is(scratch2));
+ DCHECK(!result.is(value));
- Register tmp = no_reg;
- // Find a temp register in temps list.
- for (int i = 0; i < 15; i++) {
- if ((temps & (1 << i)) != 0) {
- tmp.set_code(i);
- break;
- }
- }
- DCHECK(!tmp.is(no_reg));
+ // Allocate JSValue in new space.
+ Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required, TAG_OBJECT);
- for (int i = 0; i < field_count; i++) {
- LoadP(tmp, FieldMemOperand(src, i * kPointerSize), r0);
- StoreP(tmp, FieldMemOperand(dst, i * kPointerSize), r0);
- }
+ // Initialize the JSValue.
+ LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2);
+ StoreP(scratch1, FieldMemOperand(result, HeapObject::kMapOffset), r0);
+ LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
+ StoreP(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset), r0);
+ StoreP(scratch1, FieldMemOperand(result, JSObject::kElementsOffset), r0);
+ StoreP(value, FieldMemOperand(result, JSValue::kValueOffset), r0);
+ STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
}
@@ -3215,51 +2896,29 @@
}
-void MacroAssembler::InitializeNFieldsWithFiller(Register start_offset,
+void MacroAssembler::InitializeNFieldsWithFiller(Register current_address,
Register count,
Register filler) {
Label loop;
mtctr(count);
bind(&loop);
- StoreP(filler, MemOperand(start_offset));
- addi(start_offset, start_offset, Operand(kPointerSize));
+ StoreP(filler, MemOperand(current_address));
+ addi(current_address, current_address, Operand(kPointerSize));
bdnz(&loop);
}
-void MacroAssembler::InitializeFieldsWithFiller(Register start_offset,
- Register end_offset,
+void MacroAssembler::InitializeFieldsWithFiller(Register current_address,
+ Register end_address,
Register filler) {
Label done;
- sub(r0, end_offset, start_offset, LeaveOE, SetRC);
+ sub(r0, end_address, current_address, LeaveOE, SetRC);
beq(&done, cr0);
ShiftRightImm(r0, r0, Operand(kPointerSizeLog2));
- InitializeNFieldsWithFiller(start_offset, r0, filler);
+ InitializeNFieldsWithFiller(current_address, r0, filler);
bind(&done);
}
-void MacroAssembler::SaveFPRegs(Register location, int first, int count) {
- DCHECK(count > 0);
- int cur = first;
- subi(location, location, Operand(count * kDoubleSize));
- for (int i = 0; i < count; i++) {
- DoubleRegister reg = DoubleRegister::from_code(cur++);
- stfd(reg, MemOperand(location, i * kDoubleSize));
- }
-}
-
-
-void MacroAssembler::RestoreFPRegs(Register location, int first, int count) {
- DCHECK(count > 0);
- int cur = first + count - 1;
- for (int i = count - 1; i >= 0; i--) {
- DoubleRegister reg = DoubleRegister::from_code(cur--);
- lfd(reg, MemOperand(location, i * kDoubleSize));
- }
- addi(location, location, Operand(count * kDoubleSize));
-}
-
-
void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte(
Register first, Register second, Register scratch1, Register scratch2,
Label* failure) {
@@ -3431,17 +3090,16 @@
// Just call directly. The function called cannot cause a GC, or
// allow preemption, so the return address in the link register
// stays correct.
+ Register dest = function;
#if ABI_USES_FUNCTION_DESCRIPTORS && !defined(USE_SIMULATOR)
// AIX uses a function descriptor. When calling C code be aware
// of this descriptor and pick up values from it
LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(function, kPointerSize));
LoadP(ip, MemOperand(function, 0));
- Register dest = ip;
-#elif ABI_TOC_ADDRESSABILITY_VIA_IP
+ dest = ip;
+#elif ABI_CALL_VIA_IP
Move(ip, function);
- Register dest = ip;
-#else
- Register dest = function;
+ dest = ip;
#endif
Call(dest);
@@ -3493,184 +3151,32 @@
}
-void MacroAssembler::SetRelocatedValue(Register location, Register scratch,
- Register new_value) {
- lwz(scratch, MemOperand(location));
+void MacroAssembler::DecodeConstantPoolOffset(Register result,
+ Register location) {
+ Label overflow_access, done;
+ DCHECK(!AreAliased(result, location, r0));
-#if V8_OOL_CONSTANT_POOL
- if (emit_debug_code()) {
-// Check that the instruction sequence is a load from the constant pool
-#if V8_TARGET_ARCH_PPC64
- And(scratch, scratch, Operand(kOpcodeMask | (0x1f * B16)));
- Cmpi(scratch, Operand(ADDI), r0);
- Check(eq, kTheInstructionShouldBeALi);
- lwz(scratch, MemOperand(location, kInstrSize));
-#endif
- ExtractBitMask(scratch, scratch, 0x1f * B16);
- cmpi(scratch, Operand(kConstantPoolRegister.code()));
- Check(eq, kTheInstructionToPatchShouldBeALoadFromConstantPool);
- // Scratch was clobbered. Restore it.
- lwz(scratch, MemOperand(location));
- }
- // Get the address of the constant and patch it.
- andi(scratch, scratch, Operand(kImm16Mask));
- StorePX(new_value, MemOperand(kConstantPoolRegister, scratch));
-#else
- // This code assumes a FIXED_SEQUENCE for lis/ori
+ // Determine constant pool access type
+ // Caller has already placed the instruction word at location in result.
+ ExtractBitRange(r0, result, 31, 26);
+ cmpi(r0, Operand(ADDIS >> 26));
+ beq(&overflow_access);
- // At this point scratch is a lis instruction.
- if (emit_debug_code()) {
- And(scratch, scratch, Operand(kOpcodeMask | (0x1f * B16)));
- Cmpi(scratch, Operand(ADDIS), r0);
- Check(eq, kTheInstructionToPatchShouldBeALis);
- lwz(scratch, MemOperand(location));
- }
-
-// insert new high word into lis instruction
-#if V8_TARGET_ARCH_PPC64
- srdi(ip, new_value, Operand(32));
- rlwimi(scratch, ip, 16, 16, 31);
-#else
- rlwimi(scratch, new_value, 16, 16, 31);
-#endif
-
- stw(scratch, MemOperand(location));
-
- lwz(scratch, MemOperand(location, kInstrSize));
- // scratch is now ori.
- if (emit_debug_code()) {
- And(scratch, scratch, Operand(kOpcodeMask));
- Cmpi(scratch, Operand(ORI), r0);
- Check(eq, kTheInstructionShouldBeAnOri);
- lwz(scratch, MemOperand(location, kInstrSize));
- }
-
-// insert new low word into ori instruction
-#if V8_TARGET_ARCH_PPC64
- rlwimi(scratch, ip, 0, 16, 31);
-#else
- rlwimi(scratch, new_value, 0, 16, 31);
-#endif
- stw(scratch, MemOperand(location, kInstrSize));
-
-#if V8_TARGET_ARCH_PPC64
- if (emit_debug_code()) {
- lwz(scratch, MemOperand(location, 2 * kInstrSize));
- // scratch is now sldi.
- And(scratch, scratch, Operand(kOpcodeMask | kExt5OpcodeMask));
- Cmpi(scratch, Operand(EXT5 | RLDICR), r0);
- Check(eq, kTheInstructionShouldBeASldi);
- }
-
- lwz(scratch, MemOperand(location, 3 * kInstrSize));
- // scratch is now ori.
- if (emit_debug_code()) {
- And(scratch, scratch, Operand(kOpcodeMask));
- Cmpi(scratch, Operand(ORIS), r0);
- Check(eq, kTheInstructionShouldBeAnOris);
- lwz(scratch, MemOperand(location, 3 * kInstrSize));
- }
-
- rlwimi(scratch, new_value, 16, 16, 31);
- stw(scratch, MemOperand(location, 3 * kInstrSize));
-
- lwz(scratch, MemOperand(location, 4 * kInstrSize));
- // scratch is now ori.
- if (emit_debug_code()) {
- And(scratch, scratch, Operand(kOpcodeMask));
- Cmpi(scratch, Operand(ORI), r0);
- Check(eq, kTheInstructionShouldBeAnOri);
- lwz(scratch, MemOperand(location, 4 * kInstrSize));
- }
- rlwimi(scratch, new_value, 0, 16, 31);
- stw(scratch, MemOperand(location, 4 * kInstrSize));
-#endif
-
-// Update the I-cache so the new lis and addic can be executed.
-#if V8_TARGET_ARCH_PPC64
- FlushICache(location, 5 * kInstrSize, scratch);
-#else
- FlushICache(location, 2 * kInstrSize, scratch);
-#endif
-#endif
-}
-
-
-void MacroAssembler::GetRelocatedValue(Register location, Register result,
- Register scratch) {
- lwz(result, MemOperand(location));
-
-#if V8_OOL_CONSTANT_POOL
- if (emit_debug_code()) {
-// Check that the instruction sequence is a load from the constant pool
-#if V8_TARGET_ARCH_PPC64
- And(result, result, Operand(kOpcodeMask | (0x1f * B16)));
- Cmpi(result, Operand(ADDI), r0);
- Check(eq, kTheInstructionShouldBeALi);
- lwz(result, MemOperand(location, kInstrSize));
-#endif
- ExtractBitMask(result, result, 0x1f * B16);
- cmpi(result, Operand(kConstantPoolRegister.code()));
- Check(eq, kTheInstructionToPatchShouldBeALoadFromConstantPool);
- lwz(result, MemOperand(location));
- }
- // Get the address of the constant and retrieve it.
+ // Regular constant pool access
+ // extract the load offset
andi(result, result, Operand(kImm16Mask));
- LoadPX(result, MemOperand(kConstantPoolRegister, result));
-#else
- // This code assumes a FIXED_SEQUENCE for lis/ori
- if (emit_debug_code()) {
- And(result, result, Operand(kOpcodeMask | (0x1f * B16)));
- Cmpi(result, Operand(ADDIS), r0);
- Check(eq, kTheInstructionShouldBeALis);
- lwz(result, MemOperand(location));
- }
+ b(&done);
- // result now holds a lis instruction. Extract the immediate.
- slwi(result, result, Operand(16));
+ bind(&overflow_access);
+ // Overflow constant pool access
+ // shift addis immediate
+ slwi(r0, result, Operand(16));
+ // sign-extend and add the load offset
+ lwz(result, MemOperand(location, kInstrSize));
+ extsh(result, result);
+ add(result, r0, result);
- lwz(scratch, MemOperand(location, kInstrSize));
- if (emit_debug_code()) {
- And(scratch, scratch, Operand(kOpcodeMask));
- Cmpi(scratch, Operand(ORI), r0);
- Check(eq, kTheInstructionShouldBeAnOri);
- lwz(scratch, MemOperand(location, kInstrSize));
- }
- // Copy the low 16bits from ori instruction into result
- rlwimi(result, scratch, 0, 16, 31);
-
-#if V8_TARGET_ARCH_PPC64
- if (emit_debug_code()) {
- lwz(scratch, MemOperand(location, 2 * kInstrSize));
- // scratch is now sldi.
- And(scratch, scratch, Operand(kOpcodeMask | kExt5OpcodeMask));
- Cmpi(scratch, Operand(EXT5 | RLDICR), r0);
- Check(eq, kTheInstructionShouldBeASldi);
- }
-
- lwz(scratch, MemOperand(location, 3 * kInstrSize));
- // scratch is now ori.
- if (emit_debug_code()) {
- And(scratch, scratch, Operand(kOpcodeMask));
- Cmpi(scratch, Operand(ORIS), r0);
- Check(eq, kTheInstructionShouldBeAnOris);
- lwz(scratch, MemOperand(location, 3 * kInstrSize));
- }
- sldi(result, result, Operand(16));
- rldimi(result, scratch, 0, 48);
-
- lwz(scratch, MemOperand(location, 4 * kInstrSize));
- // scratch is now ori.
- if (emit_debug_code()) {
- And(scratch, scratch, Operand(kOpcodeMask));
- Cmpi(scratch, Operand(ORI), r0);
- Check(eq, kTheInstructionShouldBeAnOri);
- lwz(scratch, MemOperand(location, 4 * kInstrSize));
- }
- sldi(result, result, Operand(16));
- rldimi(result, scratch, 0, 48);
-#endif
-#endif
+ bind(&done);
}
@@ -3693,21 +3199,10 @@
}
-void MacroAssembler::CheckMapDeprecated(Handle<Map> map, Register scratch,
- Label* if_deprecated) {
- if (map->CanBeDeprecated()) {
- mov(scratch, Operand(map));
- lwz(scratch, FieldMemOperand(scratch, Map::kBitField3Offset));
- ExtractBitMask(scratch, scratch, Map::Deprecated::kMask, SetRC);
- bne(if_deprecated, cr0);
- }
-}
-
-
void MacroAssembler::JumpIfBlack(Register object, Register scratch0,
Register scratch1, Label* on_black) {
- HasColor(object, scratch0, scratch1, on_black, 1, 0); // kBlackBitPattern.
- DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0);
+ HasColor(object, scratch0, scratch1, on_black, 1, 1); // kBlackBitPattern.
+ DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
}
@@ -3740,27 +3235,6 @@
}
-// 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 is_data_object;
- LoadP(scratch, FieldMemOperand(value, HeapObject::kMapOffset));
- CompareRoot(scratch, Heap::kHeapNumberMapRootIndex);
- beq(&is_data_object);
- 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.
- lbz(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
- STATIC_ASSERT((kIsIndirectStringMask | kIsNotStringMask) == 0x81);
- andi(scratch, scratch, Operand(kIsIndirectStringMask | kIsNotStringMask));
- bne(not_data_object, cr0);
- bind(&is_data_object);
-}
-
-
void MacroAssembler::GetMarkBits(Register addr_reg, Register bitmap_reg,
Register mask_reg) {
DCHECK(!AreAliased(addr_reg, bitmap_reg, mask_reg, no_reg));
@@ -3777,117 +3251,23 @@
}
-void MacroAssembler::EnsureNotWhite(Register value, Register bitmap_scratch,
- Register mask_scratch,
- Register load_scratch,
- Label* value_is_white_and_not_data) {
+void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch,
+ Register mask_scratch, Register load_scratch,
+ Label* value_is_white) {
DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ip));
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.
lwz(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
and_(r0, mask_scratch, load_scratch, SetRC);
- bne(&done, cr0);
-
- if (emit_debug_code()) {
- // Check for impossible bit pattern.
- Label ok;
- // LSL may overflow, making the check conservative.
- slwi(r0, mask_scratch, Operand(1));
- and_(r0, load_scratch, r0, SetRC);
- beq(&ok, cr0);
- stop("Impossible marking bit pattern");
- bind(&ok);
- }
-
- // 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 = load_scratch; // Holds map while checking type.
- Register length = load_scratch; // Holds length of object after testing type.
- Label is_data_object, maybe_string_object, is_string_object, is_encoded;
-#if V8_TARGET_ARCH_PPC64
- Label length_computed;
-#endif
-
-
- // Check for heap-number
- LoadP(map, FieldMemOperand(value, HeapObject::kMapOffset));
- CompareRoot(map, Heap::kHeapNumberMapRootIndex);
- bne(&maybe_string_object);
- li(length, Operand(HeapNumber::kSize));
- b(&is_data_object);
- bind(&maybe_string_object);
-
- // 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 = load_scratch;
- lbz(instance_type, FieldMemOperand(map, Map::kInstanceTypeOffset));
- andi(r0, instance_type, Operand(kIsIndirectStringMask | kIsNotStringMask));
- bne(value_is_white_and_not_data, cr0);
- // 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).
- // External strings are the only ones with the kExternalStringTag bit
- // set.
- DCHECK_EQ(0, kSeqStringTag & kExternalStringTag);
- DCHECK_EQ(0, kConsStringTag & kExternalStringTag);
- andi(r0, instance_type, Operand(kExternalStringTag));
- beq(&is_string_object, cr0);
- li(length, Operand(ExternalString::kSize));
- b(&is_data_object);
- bind(&is_string_object);
-
- // Sequential string, either Latin1 or UC16.
- // For Latin1 (char-size of 1) we untag the smi to get the length.
- // For UC16 (char-size of 2):
- // - (32-bit) we just leave the smi tag in place, thereby getting
- // the length multiplied by 2.
- // - (64-bit) we compute the offset in the 2-byte array
- DCHECK(kOneByteStringTag == 4 && kStringEncodingMask == 4);
- LoadP(ip, FieldMemOperand(value, String::kLengthOffset));
- andi(r0, instance_type, Operand(kStringEncodingMask));
- beq(&is_encoded, cr0);
- SmiUntag(ip);
-#if V8_TARGET_ARCH_PPC64
- b(&length_computed);
-#endif
- bind(&is_encoded);
-#if V8_TARGET_ARCH_PPC64
- SmiToShortArrayOffset(ip, ip);
- bind(&length_computed);
-#else
- DCHECK(kSmiShift == 1);
-#endif
- addi(length, ip, Operand(SeqString::kHeaderSize + kObjectAlignmentMask));
- li(r0, Operand(~kObjectAlignmentMask));
- and_(length, length, r0);
-
- 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.
- lwz(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
- orx(ip, ip, mask_scratch);
- stw(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
-
- mov(ip, Operand(~Page::kPageAlignmentMask));
- and_(bitmap_scratch, bitmap_scratch, ip);
- lwz(ip, MemOperand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
- add(ip, ip, length);
- stw(ip, MemOperand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
-
- bind(&done);
+ beq(value_is_white, cr0);
}
@@ -3896,28 +3276,38 @@
// if input_value > 255, output_value is 255
// otherwise output_value is the input_value
void MacroAssembler::ClampUint8(Register output_reg, Register input_reg) {
- Label done, negative_label, overflow_label;
int satval = (1 << 8) - 1;
- cmpi(input_reg, Operand::Zero());
- blt(&negative_label);
+ if (CpuFeatures::IsSupported(ISELECT)) {
+ // set to 0 if negative
+ cmpi(input_reg, Operand::Zero());
+ isel(lt, output_reg, r0, input_reg);
- cmpi(input_reg, Operand(satval));
- bgt(&overflow_label);
- if (!output_reg.is(input_reg)) {
- mr(output_reg, input_reg);
+ // set to satval if > satval
+ li(r0, Operand(satval));
+ cmpi(output_reg, Operand(satval));
+ isel(lt, output_reg, output_reg, r0);
+ } else {
+ Label done, negative_label, overflow_label;
+ cmpi(input_reg, Operand::Zero());
+ blt(&negative_label);
+
+ cmpi(input_reg, Operand(satval));
+ bgt(&overflow_label);
+ if (!output_reg.is(input_reg)) {
+ mr(output_reg, input_reg);
+ }
+ b(&done);
+
+ bind(&negative_label);
+ li(output_reg, Operand::Zero()); // set to 0 if negative
+ b(&done);
+
+ bind(&overflow_label); // set to satval if > satval
+ li(output_reg, Operand(satval));
+
+ bind(&done);
}
- b(&done);
-
- bind(&negative_label);
- li(output_reg, Operand::Zero()); // set to 0 if negative
- b(&done);
-
-
- bind(&overflow_label); // set to satval if > satval
- li(output_reg, Operand(satval));
-
- bind(&done);
}
@@ -3982,6 +3372,20 @@
}
+void MacroAssembler::LoadAccessor(Register dst, Register holder,
+ int accessor_index,
+ AccessorComponent accessor) {
+ LoadP(dst, FieldMemOperand(holder, HeapObject::kMapOffset));
+ LoadInstanceDescriptors(dst, dst);
+ LoadP(dst,
+ FieldMemOperand(dst, DescriptorArray::GetValueOffset(accessor_index)));
+ const int getterOffset = AccessorPair::kGetterOffset;
+ const int setterOffset = AccessorPair::kSetterOffset;
+ int offset = ((accessor == ACCESSOR_GETTER) ? getterOffset : setterOffset);
+ LoadP(dst, FieldMemOperand(dst, offset));
+}
+
+
void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) {
Register empty_fixed_array_value = r9;
LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
@@ -4043,22 +3447,17 @@
void MacroAssembler::LoadDoubleLiteral(DoubleRegister result, double value,
Register scratch) {
-#if V8_OOL_CONSTANT_POOL
- // TODO(mbrandy): enable extended constant pool usage for doubles.
- // See ARM commit e27ab337 for a reference.
- if (is_ool_constant_pool_available() && !is_constant_pool_full()) {
- RelocInfo rinfo(pc_, value);
- ConstantPoolAddEntry(rinfo);
-#if V8_TARGET_ARCH_PPC64
- // We use 2 instruction sequence here for consistency with mov.
- li(scratch, Operand::Zero());
- lfdx(result, MemOperand(kConstantPoolRegister, scratch));
-#else
- lfd(result, MemOperand(kConstantPoolRegister, 0));
-#endif
+ if (FLAG_enable_embedded_constant_pool && is_constant_pool_available() &&
+ !(scratch.is(r0) && ConstantPoolAccessIsInOverflow())) {
+ ConstantPoolEntry::Access access = ConstantPoolAddEntry(value);
+ if (access == ConstantPoolEntry::OVERFLOWED) {
+ addis(scratch, kConstantPoolRegister, Operand::Zero());
+ lfd(result, MemOperand(scratch, 0));
+ } else {
+ lfd(result, MemOperand(kConstantPoolRegister, 0));
+ }
return;
}
-#endif
// avoid gcc strict aliasing error using union cast
union {
@@ -4195,6 +3594,46 @@
#endif
+void MacroAssembler::InsertDoubleLow(DoubleRegister dst, Register src,
+ Register scratch) {
+#if V8_TARGET_ARCH_PPC64
+ if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
+ mffprd(scratch, dst);
+ rldimi(scratch, src, 0, 32);
+ mtfprd(dst, scratch);
+ return;
+ }
+#endif
+
+ subi(sp, sp, Operand(kDoubleSize));
+ stfd(dst, MemOperand(sp));
+ stw(src, MemOperand(sp, Register::kMantissaOffset));
+ nop(GROUP_ENDING_NOP); // LHS/RAW optimization
+ lfd(dst, MemOperand(sp));
+ addi(sp, sp, Operand(kDoubleSize));
+}
+
+
+void MacroAssembler::InsertDoubleHigh(DoubleRegister dst, Register src,
+ Register scratch) {
+#if V8_TARGET_ARCH_PPC64
+ if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
+ mffprd(scratch, dst);
+ rldimi(scratch, src, 32, 0);
+ mtfprd(dst, scratch);
+ return;
+ }
+#endif
+
+ subi(sp, sp, Operand(kDoubleSize));
+ stfd(dst, MemOperand(sp));
+ stw(src, MemOperand(sp, Register::kExponentOffset));
+ nop(GROUP_ENDING_NOP); // LHS/RAW optimization
+ lfd(dst, MemOperand(sp));
+ addi(sp, sp, Operand(kDoubleSize));
+}
+
+
void MacroAssembler::MovDoubleLowToInt(Register dst, DoubleRegister src) {
#if V8_TARGET_ARCH_PPC64
if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
@@ -4253,6 +3692,25 @@
}
+void MacroAssembler::MovIntToFloat(DoubleRegister dst, Register src) {
+ subi(sp, sp, Operand(kFloatSize));
+ stw(src, MemOperand(sp, 0));
+ nop(GROUP_ENDING_NOP); // LHS/RAW optimization
+ lfs(dst, MemOperand(sp, 0));
+ addi(sp, sp, Operand(kFloatSize));
+}
+
+
+void MacroAssembler::MovFloatToInt(Register dst, DoubleRegister src) {
+ subi(sp, sp, Operand(kFloatSize));
+ frsp(src, src);
+ stfs(src, MemOperand(sp, 0));
+ nop(GROUP_ENDING_NOP); // LHS/RAW optimization
+ lwz(dst, MemOperand(sp, 0));
+ addi(sp, sp, Operand(kFloatSize));
+}
+
+
void MacroAssembler::Add(Register dst, Register src, intptr_t value,
Register scratch) {
if (is_int16(value)) {
@@ -4422,9 +3880,10 @@
Register scratch) {
int offset = mem.offset();
- if (!scratch.is(no_reg) && !is_int16(offset)) {
+ if (!is_int16(offset)) {
/* cannot use d-form */
- LoadIntLiteral(scratch, offset);
+ DCHECK(!scratch.is(no_reg));
+ mov(scratch, Operand(offset));
#if V8_TARGET_ARCH_PPC64
ldx(dst, MemOperand(mem.ra(), scratch));
#else
@@ -4454,9 +3913,10 @@
Register scratch) {
int offset = mem.offset();
- if (!scratch.is(no_reg) && !is_int16(offset)) {
+ if (!is_int16(offset)) {
/* cannot use d-form */
- LoadIntLiteral(scratch, offset);
+ DCHECK(!scratch.is(no_reg));
+ mov(scratch, Operand(offset));
#if V8_TARGET_ARCH_PPC64
stdx(src, MemOperand(mem.ra(), scratch));
#else
@@ -4489,15 +3949,10 @@
Register scratch) {
int offset = mem.offset();
- if (!scratch.is(no_reg) && !is_int16(offset)) {
- /* cannot use d-form */
- LoadIntLiteral(scratch, offset);
-#if V8_TARGET_ARCH_PPC64
- // lwax(dst, MemOperand(mem.ra(), scratch));
- DCHECK(0); // lwax not yet implemented
-#else
- lwzx(dst, MemOperand(mem.ra(), scratch));
-#endif
+ if (!is_int16(offset)) {
+ DCHECK(!scratch.is(no_reg));
+ mov(scratch, Operand(offset));
+ lwax(dst, MemOperand(mem.ra(), scratch));
} else {
#if V8_TARGET_ARCH_PPC64
int misaligned = (offset & 3);
@@ -4549,6 +4004,20 @@
}
+void MacroAssembler::LoadHalfWordArith(Register dst, const MemOperand& mem,
+ Register scratch) {
+ int offset = mem.offset();
+
+ if (!is_int16(offset)) {
+ DCHECK(!scratch.is(no_reg));
+ mov(scratch, Operand(offset));
+ lhax(dst, MemOperand(mem.ra(), scratch));
+ } else {
+ lha(dst, mem);
+ }
+}
+
+
// Variable length depending on whether offset fits into immediate field
// MemOperand currently only supports d-form
void MacroAssembler::LoadHalfWord(Register dst, const MemOperand& mem,
@@ -4622,13 +4091,12 @@
} else if (r.IsUInteger8()) {
LoadByte(dst, mem, scratch);
} else if (r.IsInteger16()) {
- LoadHalfWord(dst, mem, scratch);
- extsh(dst, dst);
+ LoadHalfWordArith(dst, mem, scratch);
} else if (r.IsUInteger16()) {
LoadHalfWord(dst, mem, scratch);
#if V8_TARGET_ARCH_PPC64
} else if (r.IsInteger32()) {
- LoadWord(dst, mem, scratch);
+ LoadWordArith(dst, mem, scratch);
#endif
} else {
LoadP(dst, mem, scratch);
@@ -4658,6 +4126,34 @@
}
+void MacroAssembler::LoadDouble(DoubleRegister dst, const MemOperand& mem,
+ Register scratch) {
+ Register base = mem.ra();
+ int offset = mem.offset();
+
+ if (!is_int16(offset)) {
+ mov(scratch, Operand(offset));
+ lfdx(dst, MemOperand(base, scratch));
+ } else {
+ lfd(dst, mem);
+ }
+}
+
+
+void MacroAssembler::StoreDouble(DoubleRegister src, const MemOperand& mem,
+ Register scratch) {
+ Register base = mem.ra();
+ int offset = mem.offset();
+
+ if (!is_int16(offset)) {
+ mov(scratch, Operand(offset));
+ stfdx(src, MemOperand(base, scratch));
+ } else {
+ stfd(src, mem);
+ }
+}
+
+
void MacroAssembler::TestJSArrayForAllocationMemento(Register receiver_reg,
Register scratch_reg,
Label* no_memento_found) {
@@ -4690,8 +4186,11 @@
if (reg5.is_valid()) regs |= reg5.bit();
if (reg6.is_valid()) regs |= reg6.bit();
- for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
- Register candidate = Register::FromAllocationIndex(i);
+ const RegisterConfiguration* config =
+ RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT);
+ for (int i = 0; i < config->num_allocatable_general_registers(); ++i) {
+ int code = config->GetAllocatableGeneralCode(i);
+ Register candidate = Register::from_code(code);
if (regs & candidate.bit()) continue;
return candidate;
}
@@ -4705,32 +4204,46 @@
Register scratch1,
Label* found) {
DCHECK(!scratch1.is(scratch0));
- Factory* factory = isolate()->factory();
Register current = scratch0;
- Label loop_again;
+ Label loop_again, end;
// scratch contained elements pointer.
mr(current, object);
+ LoadP(current, FieldMemOperand(current, HeapObject::kMapOffset));
+ LoadP(current, FieldMemOperand(current, Map::kPrototypeOffset));
+ CompareRoot(current, Heap::kNullValueRootIndex);
+ beq(&end);
// Loop based on the map going up the prototype chain.
bind(&loop_again);
LoadP(current, FieldMemOperand(current, HeapObject::kMapOffset));
+
+ STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE);
+ STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
+ lbz(scratch1, FieldMemOperand(current, Map::kInstanceTypeOffset));
+ cmpi(scratch1, Operand(JS_OBJECT_TYPE));
+ blt(found);
+
lbz(scratch1, FieldMemOperand(current, Map::kBitField2Offset));
DecodeField<Map::ElementsKindBits>(scratch1);
cmpi(scratch1, Operand(DICTIONARY_ELEMENTS));
beq(found);
LoadP(current, FieldMemOperand(current, Map::kPrototypeOffset));
- Cmpi(current, Operand(factory->null_value()), r0);
+ CompareRoot(current, Heap::kNullValueRootIndex);
bne(&loop_again);
+
+ bind(&end);
}
#ifdef DEBUG
bool AreAliased(Register reg1, Register reg2, Register reg3, Register reg4,
- Register reg5, Register reg6, Register reg7, Register reg8) {
+ Register reg5, Register reg6, Register reg7, Register reg8,
+ Register reg9, Register reg10) {
int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() + reg3.is_valid() +
reg4.is_valid() + reg5.is_valid() + reg6.is_valid() +
- reg7.is_valid() + reg8.is_valid();
+ reg7.is_valid() + reg8.is_valid() + reg9.is_valid() +
+ reg10.is_valid();
RegList regs = 0;
if (reg1.is_valid()) regs |= reg1.bit();
@@ -4741,6 +4254,8 @@
if (reg6.is_valid()) regs |= reg6.bit();
if (reg7.is_valid()) regs |= reg7.bit();
if (reg8.is_valid()) regs |= reg8.bit();
+ if (reg9.is_valid()) regs |= reg9.bit();
+ if (reg10.is_valid()) regs |= reg10.bit();
int n_of_non_aliasing_regs = NumRegs(regs);
return n_of_valid_regs != n_of_non_aliasing_regs;
@@ -4748,11 +4263,11 @@
#endif
-CodePatcher::CodePatcher(byte* address, int instructions,
+CodePatcher::CodePatcher(Isolate* isolate, byte* address, int instructions,
FlushICache flush_cache)
: address_(address),
size_(instructions * Assembler::kInstrSize),
- masm_(NULL, address, size_ + Assembler::kGap),
+ masm_(isolate, address, size_ + Assembler::kGap, CodeObjectRequired::kNo),
flush_cache_(flush_cache) {
// 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
@@ -4764,7 +4279,7 @@
CodePatcher::~CodePatcher() {
// Indicate that code has changed.
if (flush_cache_ == FLUSH) {
- CpuFeatures::FlushICache(address_, size_);
+ Assembler::FlushICache(masm_.isolate(), address_, size_);
}
// Check that the code was patched as expected.