Merge V8 5.2.361.47 DO NOT MERGE
https://chromium.googlesource.com/v8/v8/+/5.2.361.47
FPIIM-449
Change-Id: Ibec421b85a9b88cb3a432ada642e469fe7e78346
(cherry picked from commit bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8)
diff --git a/src/mips/assembler-mips-inl.h b/src/mips/assembler-mips-inl.h
index 517d4ad..b463c0b 100644
--- a/src/mips/assembler-mips-inl.h
+++ b/src/mips/assembler-mips-inl.h
@@ -102,11 +102,6 @@
return Assembler::target_address_at(pc_, host_);
}
-Address RelocInfo::wasm_memory_reference() {
- DCHECK(IsWasmMemoryReference(rmode_));
- return Assembler::target_address_at(pc_, host_);
-}
-
Address RelocInfo::target_address_address() {
DCHECK(IsCodeTarget(rmode_) ||
IsRuntimeEntry(rmode_) ||
@@ -156,19 +151,6 @@
}
}
-void RelocInfo::update_wasm_memory_reference(
- Address old_base, Address new_base, size_t old_size, size_t new_size,
- ICacheFlushMode icache_flush_mode) {
- DCHECK(IsWasmMemoryReference(rmode_));
- DCHECK(old_base <= wasm_memory_reference() &&
- wasm_memory_reference() < old_base + old_size);
- Address updated_reference = new_base + (wasm_memory_reference() - old_base);
- DCHECK(new_base <= updated_reference &&
- updated_reference < new_base + new_size);
- Assembler::set_target_address_at(isolate_, pc_, host_, updated_reference,
- icache_flush_mode);
-}
-
Address Assembler::target_address_from_return_address(Address pc) {
return pc - kCallTargetAddressOffset;
}
@@ -380,7 +362,7 @@
}
}
-
+template <typename ObjectVisitor>
void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
RelocInfo::Mode mode = rmode();
if (mode == RelocInfo::EMBEDDED_OBJECT) {
diff --git a/src/mips/assembler-mips.cc b/src/mips/assembler-mips.cc
index bfa2328..f95323b 100644
--- a/src/mips/assembler-mips.cc
+++ b/src/mips/assembler-mips.cc
@@ -189,6 +189,42 @@
return false;
}
+Address RelocInfo::wasm_memory_reference() {
+ DCHECK(IsWasmMemoryReference(rmode_));
+ return Assembler::target_address_at(pc_, host_);
+}
+
+uint32_t RelocInfo::wasm_memory_size_reference() {
+ DCHECK(IsWasmMemorySizeReference(rmode_));
+ return reinterpret_cast<uint32_t>(Assembler::target_address_at(pc_, host_));
+}
+
+void RelocInfo::update_wasm_memory_reference(
+ Address old_base, Address new_base, uint32_t old_size, uint32_t new_size,
+ ICacheFlushMode icache_flush_mode) {
+ DCHECK(IsWasmMemoryReference(rmode_) || IsWasmMemorySizeReference(rmode_));
+ if (IsWasmMemoryReference(rmode_)) {
+ Address updated_memory_reference;
+ DCHECK(old_base <= wasm_memory_reference() &&
+ wasm_memory_reference() < old_base + old_size);
+ updated_memory_reference = new_base + (wasm_memory_reference() - old_base);
+ DCHECK(new_base <= updated_memory_reference &&
+ updated_memory_reference < new_base + new_size);
+ Assembler::set_target_address_at(
+ isolate_, pc_, host_, updated_memory_reference, icache_flush_mode);
+ } else if (IsWasmMemorySizeReference(rmode_)) {
+ uint32_t updated_size_reference;
+ DCHECK(wasm_memory_size_reference() <= old_size);
+ updated_size_reference =
+ new_size + (wasm_memory_size_reference() - old_size);
+ DCHECK(updated_size_reference <= new_size);
+ Assembler::set_target_address_at(
+ isolate_, pc_, host_, reinterpret_cast<Address>(updated_size_reference),
+ icache_flush_mode);
+ } else {
+ UNREACHABLE();
+ }
+}
// -----------------------------------------------------------------------------
// Implementation of Operand and MemOperand.
@@ -1829,11 +1865,17 @@
void Assembler::lwl(Register rd, const MemOperand& rs) {
+ DCHECK(is_int16(rs.offset_));
+ DCHECK(IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r1) ||
+ IsMipsArchVariant(kMips32r2));
GenInstrImmediate(LWL, rs.rm(), rd, rs.offset_);
}
void Assembler::lwr(Register rd, const MemOperand& rs) {
+ DCHECK(is_int16(rs.offset_));
+ DCHECK(IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r1) ||
+ IsMipsArchVariant(kMips32r2));
GenInstrImmediate(LWR, rs.rm(), rd, rs.offset_);
}
@@ -1869,11 +1911,17 @@
void Assembler::swl(Register rd, const MemOperand& rs) {
+ DCHECK(is_int16(rs.offset_));
+ DCHECK(IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r1) ||
+ IsMipsArchVariant(kMips32r2));
GenInstrImmediate(SWL, rs.rm(), rd, rs.offset_);
}
void Assembler::swr(Register rd, const MemOperand& rs) {
+ DCHECK(is_int16(rs.offset_));
+ DCHECK(IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r1) ||
+ IsMipsArchVariant(kMips32r2));
GenInstrImmediate(SWR, rs.rm(), rd, rs.offset_);
}
@@ -2009,6 +2057,10 @@
emit(instr);
}
+void Assembler::sync() {
+ Instr sync_instr = SPECIAL | SYNC;
+ emit(sync_instr);
+}
// Move from HI/LO register.
@@ -2955,6 +3007,7 @@
data = reinterpret_cast<uint32_t>(buffer_ + label->pos());
} else {
data = jump_address(label);
+ unbound_labels_count_++;
internal_reference_positions_.insert(label->pos());
}
RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
diff --git a/src/mips/assembler-mips.h b/src/mips/assembler-mips.h
index 886ac6c..c595cc9 100644
--- a/src/mips/assembler-mips.h
+++ b/src/mips/assembler-mips.h
@@ -63,6 +63,8 @@
V(f16) V(f17) V(f18) V(f19) V(f20) V(f21) V(f22) V(f23) \
V(f24) V(f25) V(f26) V(f27) V(f28) V(f29) V(f30) V(f31)
+#define FLOAT_REGISTERS DOUBLE_REGISTERS
+
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
V(f0) V(f2) V(f4) V(f6) V(f8) V(f10) V(f12) V(f14) \
V(f16) V(f18) V(f20) V(f22) V(f24) V(f26)
@@ -154,7 +156,7 @@
Register ToRegister(int num);
// Coprocessor register.
-struct DoubleRegister {
+struct FPURegister {
enum Code {
#define REGISTER_CODE(R) kCode_##R,
DOUBLE_REGISTERS(REGISTER_CODE)
@@ -174,19 +176,19 @@
const char* ToString();
bool IsAllocatable() const;
bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; }
- bool is(DoubleRegister reg) const { return reg_code == reg.reg_code; }
- DoubleRegister low() const {
+ bool is(FPURegister reg) const { return reg_code == reg.reg_code; }
+ FPURegister low() const {
// Find low reg of a Double-reg pair, which is the reg itself.
DCHECK(reg_code % 2 == 0); // Specified Double reg must be even.
- DoubleRegister reg;
+ FPURegister reg;
reg.reg_code = reg_code;
DCHECK(reg.is_valid());
return reg;
}
- DoubleRegister high() const {
+ FPURegister high() const {
// Find high reg of a Doubel-reg pair, which is reg + 1.
DCHECK(reg_code % 2 == 0); // Specified Double reg must be even.
- DoubleRegister reg;
+ FPURegister reg;
reg.reg_code = reg_code + 1;
DCHECK(reg.is_valid());
return reg;
@@ -201,8 +203,8 @@
return 1 << reg_code;
}
- static DoubleRegister from_code(int code) {
- DoubleRegister r = {code};
+ static FPURegister from_code(int code) {
+ FPURegister r = {code};
return r;
}
void setcode(int f) {
@@ -227,8 +229,12 @@
// but it is not in common use. Someday we will want to support this in v8.)
// For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers.
-typedef DoubleRegister FPURegister;
-typedef DoubleRegister FloatRegister;
+typedef FPURegister FloatRegister;
+
+typedef FPURegister DoubleRegister;
+
+// TODO(mips) Define SIMD registers.
+typedef FPURegister Simd128Register;
const DoubleRegister no_freg = {-1};
@@ -304,9 +310,6 @@
const FPUControlRegister no_fpucreg = { kInvalidFPUControlRegister };
const FPUControlRegister FCSR = { kFCSRRegister };
-// TODO(mips) Define SIMD registers.
-typedef DoubleRegister Simd128Register;
-
// -----------------------------------------------------------------------------
// Machine instruction Operands.
@@ -799,6 +802,9 @@
void teq(Register rs, Register rt, uint16_t code);
void tne(Register rs, Register rt, uint16_t code);
+ // Memory barrier instruction.
+ void sync();
+
// Move from HI/LO register.
void mfhi(Register rd);
void mflo(Register rd);
@@ -1039,8 +1045,7 @@
// Record a deoptimization reason that can be used by a log or cpu profiler.
// Use --trace-deopt to enable.
- void RecordDeoptReason(const int reason, int raw_position);
-
+ void RecordDeoptReason(const int reason, int raw_position, int id);
static int RelocateInternalReference(RelocInfo::Mode rmode, byte* pc,
intptr_t pc_delta);
@@ -1158,10 +1163,15 @@
bool IsPrevInstrCompactBranch() { return prev_instr_compact_branch_; }
+ inline int UnboundLabelsCount() { return unbound_labels_count_; }
+
protected:
// Load Scaled Address instruction.
void lsa(Register rd, Register rt, Register rs, uint8_t sa);
+ // Helpers.
+ void LoadRegPlusOffsetToAt(const MemOperand& src);
+
// Relocation for a type-recording IC has the AST id added to it. This
// member variable is a way to pass the information from the call site to
// the relocation info.
@@ -1359,8 +1369,6 @@
void GenInstrJump(Opcode opcode,
uint32_t address);
- // Helpers.
- void LoadRegPlusOffsetToAt(const MemOperand& src);
// Labels.
void print(Label* L);
diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc
index 9693a52..76d0640 100644
--- a/src/mips/builtins-mips.cc
+++ b/src/mips/builtins-mips.cc
@@ -603,16 +603,9 @@
// a0: number of arguments
// a1: constructor function
// a3: new target
- if (is_api_function) {
- __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
- Handle<Code> code =
- masm->isolate()->builtins()->HandleApiCallConstruct();
- __ Call(code, RelocInfo::CODE_TARGET);
- } else {
- ParameterCount actual(a0);
- __ InvokeFunction(a1, a3, actual, CALL_FUNCTION,
- CheckDebugStepCallWrapper());
- }
+ ParameterCount actual(a0);
+ __ InvokeFunction(a1, a3, actual, CALL_FUNCTION,
+ CheckDebugStepCallWrapper());
// Store offset of return address for deoptimizer.
if (create_implicit_receiver && !is_api_function) {
@@ -825,6 +818,139 @@
Generate_JSEntryTrampolineHelper(masm, true);
}
+// static
+void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- v0 : the value to pass to the generator
+ // -- a1 : the JSGeneratorObject to resume
+ // -- a2 : the resume mode (tagged)
+ // -- ra : return address
+ // -----------------------------------
+ __ AssertGeneratorObject(a1);
+
+ // Store input value into generator object.
+ __ sw(v0, FieldMemOperand(a1, JSGeneratorObject::kInputOffset));
+ __ RecordWriteField(a1, JSGeneratorObject::kInputOffset, v0, a3,
+ kRAHasNotBeenSaved, kDontSaveFPRegs);
+
+ // Store resume mode into generator object.
+ __ sw(a2, FieldMemOperand(a1, JSGeneratorObject::kResumeModeOffset));
+
+ // Load suspended function and context.
+ __ lw(cp, FieldMemOperand(a1, JSGeneratorObject::kContextOffset));
+ __ lw(t0, FieldMemOperand(a1, JSGeneratorObject::kFunctionOffset));
+
+ // Flood function if we are stepping.
+ Label skip_flooding;
+ ExternalReference step_in_enabled =
+ ExternalReference::debug_step_in_enabled_address(masm->isolate());
+ __ li(t1, Operand(step_in_enabled));
+ __ lb(t1, MemOperand(t1));
+ __ Branch(&skip_flooding, eq, t1, Operand(zero_reg));
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ __ Push(a1, a2, t0);
+ __ CallRuntime(Runtime::kDebugPrepareStepInIfStepping);
+ __ Pop(a1, a2);
+ __ lw(t0, FieldMemOperand(a1, JSGeneratorObject::kFunctionOffset));
+ }
+ __ bind(&skip_flooding);
+
+ // Push receiver.
+ __ lw(t1, FieldMemOperand(a1, JSGeneratorObject::kReceiverOffset));
+ __ Push(t1);
+
+ // ----------- S t a t e -------------
+ // -- a1 : the JSGeneratorObject to resume
+ // -- a2 : the resume mode (tagged)
+ // -- t0 : generator function
+ // -- cp : generator context
+ // -- ra : return address
+ // -- sp[0] : generator receiver
+ // -----------------------------------
+
+ // Push holes for arguments to generator function. Since the parser forced
+ // context allocation for any variables in generators, the actual argument
+ // values have already been copied into the context and these dummy values
+ // will never be used.
+ __ lw(a3, FieldMemOperand(t0, JSFunction::kSharedFunctionInfoOffset));
+ __ lw(a3,
+ FieldMemOperand(a3, SharedFunctionInfo::kFormalParameterCountOffset));
+ {
+ Label done_loop, loop;
+ __ bind(&loop);
+ __ Subu(a3, a3, Operand(Smi::FromInt(1)));
+ __ Branch(&done_loop, lt, a3, Operand(zero_reg));
+ __ PushRoot(Heap::kTheHoleValueRootIndex);
+ __ Branch(&loop);
+ __ bind(&done_loop);
+ }
+
+ // Dispatch on the kind of generator object.
+ Label old_generator;
+ __ lw(a3, FieldMemOperand(t0, JSFunction::kSharedFunctionInfoOffset));
+ __ lw(a3, FieldMemOperand(a3, SharedFunctionInfo::kFunctionDataOffset));
+ __ GetObjectType(a3, a3, a3);
+ __ Branch(&old_generator, ne, a3, Operand(BYTECODE_ARRAY_TYPE));
+
+ // New-style (ignition/turbofan) generator object.
+ {
+ __ lw(a0, FieldMemOperand(t0, JSFunction::kSharedFunctionInfoOffset));
+ __ lw(a0,
+ FieldMemOperand(a0, SharedFunctionInfo::kFormalParameterCountOffset));
+ __ SmiUntag(a0);
+ // We abuse new.target both to indicate that this is a resume call and to
+ // pass in the generator object. In ordinary calls, new.target is always
+ // undefined because generator functions are non-constructable.
+ __ Move(a3, a1);
+ __ Move(a1, t0);
+ __ lw(a2, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
+ __ Jump(a2);
+ }
+
+ // Old-style (full-codegen) generator object
+ __ bind(&old_generator);
+ {
+ // Enter a new JavaScript frame, and initialize its slots as they were when
+ // the generator was suspended.
+ FrameScope scope(masm, StackFrame::MANUAL);
+ __ Push(ra, fp);
+ __ Move(fp, sp);
+ __ Push(cp, t0);
+
+ // Restore the operand stack.
+ __ lw(a0, FieldMemOperand(a1, JSGeneratorObject::kOperandStackOffset));
+ __ lw(a3, FieldMemOperand(a0, FixedArray::kLengthOffset));
+ __ Addu(a0, a0, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+ __ Lsa(a3, a0, a3, kPointerSizeLog2 - 1);
+ {
+ Label done_loop, loop;
+ __ bind(&loop);
+ __ Branch(&done_loop, eq, a0, Operand(a3));
+ __ lw(t1, MemOperand(a0));
+ __ Push(t1);
+ __ Branch(USE_DELAY_SLOT, &loop);
+ __ addiu(a0, a0, kPointerSize); // In delay slot.
+ __ bind(&done_loop);
+ }
+
+ // Reset operand stack so we don't leak.
+ __ LoadRoot(t1, Heap::kEmptyFixedArrayRootIndex);
+ __ sw(t1, FieldMemOperand(a1, JSGeneratorObject::kOperandStackOffset));
+
+ // Resume the generator function at the continuation.
+ __ lw(a3, FieldMemOperand(t0, JSFunction::kSharedFunctionInfoOffset));
+ __ lw(a3, FieldMemOperand(a3, SharedFunctionInfo::kCodeOffset));
+ __ Addu(a3, a3, Operand(Code::kHeaderSize - kHeapObjectTag));
+ __ lw(a2, FieldMemOperand(a1, JSGeneratorObject::kContinuationOffset));
+ __ SmiUntag(a2);
+ __ Addu(a3, a3, Operand(a2));
+ __ li(a2, Operand(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)));
+ __ sw(a2, FieldMemOperand(a1, JSGeneratorObject::kContinuationOffset));
+ __ Move(v0, a1); // Continuation expects generator object in v0.
+ __ Jump(a3);
+ }
+}
// Generate code for entering a JS function with the interpreter.
// On entry to the function the receiver and arguments have been pushed on the
@@ -842,14 +968,16 @@
// The function builds an interpreter frame. See InterpreterFrameConstants in
// frames.h for its layout.
void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
+ ProfileEntryHookStub::MaybeCallEntryHook(masm);
+
// Open a frame scope to indicate that there is a frame on the stack. The
// MANUAL indicates that the scope shouldn't actually generate code to set up
// the frame (that is done below).
FrameScope frame_scope(masm, StackFrame::MANUAL);
__ PushStandardFrame(a1);
- // Get the bytecode array from the function object and load the pointer to the
- // first entry into kInterpreterBytecodeRegister.
+ // Get the bytecode array from the function object (or from the DebugInfo if
+ // it is present) and load it into kInterpreterBytecodeArrayRegister.
__ lw(a0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
Label load_debug_bytecode_array, bytecode_array_loaded;
Register debug_info = kInterpreterBytecodeArrayRegister;
@@ -861,8 +989,11 @@
FieldMemOperand(a0, SharedFunctionInfo::kFunctionDataOffset));
__ bind(&bytecode_array_loaded);
+ // Check function data field is actually a BytecodeArray object.
+ Label bytecode_array_not_present;
+ __ JumpIfRoot(kInterpreterBytecodeArrayRegister,
+ Heap::kUndefinedValueRootIndex, &bytecode_array_not_present);
if (FLAG_debug_code) {
- // Check function data field is actually a BytecodeArray object.
__ SmiTst(kInterpreterBytecodeArrayRegister, t0);
__ Assert(ne, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry, t0,
Operand(zero_reg));
@@ -871,8 +1002,13 @@
Operand(BYTECODE_ARRAY_TYPE));
}
- // Push new.target, bytecode array and zero for bytecode array offset.
- __ Push(a3, kInterpreterBytecodeArrayRegister, zero_reg);
+ // Load initial bytecode offset.
+ __ li(kInterpreterBytecodeOffsetRegister,
+ Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
+
+ // Push new.target, bytecode array and Smi tagged bytecode array offset.
+ __ SmiTag(t0, kInterpreterBytecodeOffsetRegister);
+ __ Push(a3, kInterpreterBytecodeArrayRegister, t0);
// Allocate the local and temporary register file on the stack.
{
@@ -902,17 +1038,8 @@
__ Branch(&loop_header, ge, t0, Operand(zero_reg));
}
- // TODO(rmcilroy): List of things not currently dealt with here but done in
- // fullcodegen's prologue:
- // - Call ProfileEntryHookStub when isolate has a function_entry_hook.
- // - Code aging of the BytecodeArray object.
-
- // Load bytecode offset and dispatch table into registers.
+ // Load accumulator and dispatch table into registers.
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
- __ Addu(kInterpreterRegisterFileRegister, fp,
- Operand(InterpreterFrameConstants::kRegisterFilePointerFromFp));
- __ li(kInterpreterBytecodeOffsetRegister,
- Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
__ li(kInterpreterDispatchTableRegister,
Operand(ExternalReference::interpreter_dispatch_table_address(
masm->isolate())));
@@ -923,42 +1050,41 @@
__ lbu(a0, MemOperand(a0));
__ Lsa(at, kInterpreterDispatchTableRegister, a0, kPointerSizeLog2);
__ lw(at, MemOperand(at));
- // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
- // and header removal.
- __ Addu(at, at, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Call(at);
+ masm->isolate()->heap()->SetInterpreterEntryReturnPCOffset(masm->pc_offset());
- // Even though the first bytecode handler was called, we will never return.
- __ Abort(kUnexpectedReturnFromBytecodeHandler);
+ // The return value is in v0.
+
+ // Get the arguments + reciever count.
+ __ lw(t0, MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp));
+ __ lw(t0, FieldMemOperand(t0, BytecodeArray::kParameterSizeOffset));
+
+ // Leave the frame (also dropping the register file).
+ __ LeaveFrame(StackFrame::JAVA_SCRIPT);
+
+ // Drop receiver + arguments and return.
+ __ Addu(sp, sp, t0);
+ __ Jump(ra);
// Load debug copy of the bytecode array.
__ bind(&load_debug_bytecode_array);
__ lw(kInterpreterBytecodeArrayRegister,
FieldMemOperand(debug_info, DebugInfo::kAbstractCodeIndex));
__ Branch(&bytecode_array_loaded);
-}
-
-void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
- // TODO(rmcilroy): List of things not currently dealt with here but done in
- // fullcodegen's EmitReturnSequence.
- // - Supporting FLAG_trace for Runtime::TraceExit.
- // - Support profiler (specifically decrementing profiling_counter
- // appropriately and calling out to HandleInterrupts if necessary).
-
- // The return value is in accumulator, which is already in v0.
-
- // Leave the frame (also dropping the register file).
+ // If the bytecode array is no longer present, then the underlying function
+ // has been switched to a different kind of code and we heal the closure by
+ // switching the code entry field over to the new code object as well.
+ __ bind(&bytecode_array_not_present);
__ LeaveFrame(StackFrame::JAVA_SCRIPT);
-
- // Drop receiver + arguments and return.
- __ lw(at, FieldMemOperand(kInterpreterBytecodeArrayRegister,
- BytecodeArray::kParameterSizeOffset));
- __ Addu(sp, sp, at);
- __ Jump(ra);
+ __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
+ __ lw(t0, FieldMemOperand(t0, SharedFunctionInfo::kCodeOffset));
+ __ Addu(t0, t0, Operand(Code::kHeaderSize - kHeapObjectTag));
+ __ sw(t0, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
+ __ RecordWriteCodeEntryField(a1, t0, t1);
+ __ Jump(t0);
}
-
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
@@ -991,7 +1117,6 @@
RelocInfo::CODE_TARGET);
}
-
// static
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
// ----------- S t a t e -------------
@@ -1022,25 +1147,24 @@
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
+void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
+ // Set the return address to the correct point in the interpreter entry
+ // trampoline.
+ Smi* interpreter_entry_return_pc_offset(
+ masm->isolate()->heap()->interpreter_entry_return_pc_offset());
+ DCHECK_NE(interpreter_entry_return_pc_offset, Smi::FromInt(0));
+ __ li(t0, Operand(masm->isolate()->builtins()->InterpreterEntryTrampoline()));
+ __ Addu(ra, t0, Operand(interpreter_entry_return_pc_offset->value() +
+ Code::kHeaderSize - kHeapObjectTag));
-static void Generate_EnterBytecodeDispatch(MacroAssembler* masm) {
- // Initialize register file register and dispatch table register.
- __ Addu(kInterpreterRegisterFileRegister, fp,
- Operand(InterpreterFrameConstants::kRegisterFilePointerFromFp));
+ // Initialize the dispatch table register.
__ li(kInterpreterDispatchTableRegister,
Operand(ExternalReference::interpreter_dispatch_table_address(
masm->isolate())));
- // Get the context from the frame.
- __ lw(kContextRegister,
- MemOperand(kInterpreterRegisterFileRegister,
- InterpreterFrameConstants::kContextFromRegisterPointer));
-
// Get the bytecode array pointer from the frame.
- __ lw(
- kInterpreterBytecodeArrayRegister,
- MemOperand(kInterpreterRegisterFileRegister,
- InterpreterFrameConstants::kBytecodeArrayFromRegisterPointer));
+ __ lw(kInterpreterBytecodeArrayRegister,
+ MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp));
if (FLAG_debug_code) {
// Check function data field is actually a BytecodeArray object.
@@ -1054,9 +1178,7 @@
// Get the target bytecode offset from the frame.
__ lw(kInterpreterBytecodeOffsetRegister,
- MemOperand(
- kInterpreterRegisterFileRegister,
- InterpreterFrameConstants::kBytecodeOffsetFromRegisterPointer));
+ MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp));
__ SmiUntag(kInterpreterBytecodeOffsetRegister);
// Dispatch to the target bytecode.
@@ -1065,63 +1187,164 @@
__ lbu(a1, MemOperand(a1));
__ Lsa(a1, kInterpreterDispatchTableRegister, a1, kPointerSizeLog2);
__ lw(a1, MemOperand(a1));
- __ Addu(a1, a1, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(a1);
}
-
-static void Generate_InterpreterNotifyDeoptimizedHelper(
- MacroAssembler* masm, Deoptimizer::BailoutType type) {
- // Enter an internal frame.
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Pass the deoptimization type to the runtime system.
- __ li(a1, Operand(Smi::FromInt(static_cast<int>(type))));
- __ push(a1);
- __ CallRuntime(Runtime::kNotifyDeoptimized);
- // Tear down internal frame.
- }
-
- // Drop state (we don't use these for interpreter deopts) and and pop the
- // accumulator value into the accumulator register.
- __ Drop(1);
- __ Pop(kInterpreterAccumulatorRegister);
-
- // Enter the bytecode dispatch.
- Generate_EnterBytecodeDispatch(masm);
-}
-
-
-void Builtins::Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm) {
- Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
-}
-
-
-void Builtins::Generate_InterpreterNotifySoftDeoptimized(MacroAssembler* masm) {
- Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
-}
-
-
-void Builtins::Generate_InterpreterNotifyLazyDeoptimized(MacroAssembler* masm) {
- Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
-}
-
-void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
- // Set the address of the interpreter entry trampoline as a return address.
- // This simulates the initial call to bytecode handlers in interpreter entry
- // trampoline. The return will never actually be taken, but our stack walker
- // uses this address to determine whether a frame is interpreted.
- __ li(ra, Operand(masm->isolate()->builtins()->InterpreterEntryTrampoline()));
-
- Generate_EnterBytecodeDispatch(masm);
-}
-
-
void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- a0 : argument count (preserved for callee)
+ // -- a3 : new target (preserved for callee)
+ // -- a1 : target function (preserved for callee)
+ // -----------------------------------
+ // First lookup code, maybe we don't need to compile!
+ Label gotta_call_runtime, gotta_call_runtime_no_stack;
+ Label maybe_call_runtime;
+ Label try_shared;
+ Label loop_top, loop_bottom;
+
+ Register argument_count = a0;
+ Register closure = a1;
+ Register new_target = a3;
+ __ push(argument_count);
+ __ push(new_target);
+ __ push(closure);
+
+ Register map = a0;
+ Register index = a2;
+ __ lw(map, FieldMemOperand(closure, JSFunction::kSharedFunctionInfoOffset));
+ __ lw(map, FieldMemOperand(map, SharedFunctionInfo::kOptimizedCodeMapOffset));
+ __ lw(index, FieldMemOperand(map, FixedArray::kLengthOffset));
+ __ Branch(&gotta_call_runtime, lt, index, Operand(Smi::FromInt(2)));
+
+ // Find literals.
+ // a3 : native context
+ // a2 : length / index
+ // a0 : optimized code map
+ // stack[0] : new target
+ // stack[4] : closure
+ Register native_context = a3;
+ __ lw(native_context, NativeContextMemOperand());
+
+ __ bind(&loop_top);
+ Register temp = a1;
+ Register array_pointer = t1;
+
+ // Does the native context match?
+ __ sll(at, index, kPointerSizeLog2 - kSmiTagSize);
+ __ Addu(array_pointer, map, Operand(at));
+ __ lw(temp, FieldMemOperand(array_pointer,
+ SharedFunctionInfo::kOffsetToPreviousContext));
+ __ lw(temp, FieldMemOperand(temp, WeakCell::kValueOffset));
+ __ Branch(&loop_bottom, ne, temp, Operand(native_context));
+ // OSR id set to none?
+ __ lw(temp, FieldMemOperand(array_pointer,
+ SharedFunctionInfo::kOffsetToPreviousOsrAstId));
+ const int bailout_id = BailoutId::None().ToInt();
+ __ Branch(&loop_bottom, ne, temp, Operand(Smi::FromInt(bailout_id)));
+ // Literals available?
+ __ lw(temp, FieldMemOperand(array_pointer,
+ SharedFunctionInfo::kOffsetToPreviousLiterals));
+ __ lw(temp, FieldMemOperand(temp, WeakCell::kValueOffset));
+ __ JumpIfSmi(temp, &gotta_call_runtime);
+
+ // Save the literals in the closure.
+ __ lw(t0, MemOperand(sp, 0));
+ __ sw(temp, FieldMemOperand(t0, JSFunction::kLiteralsOffset));
+ __ push(index);
+ __ RecordWriteField(t0, JSFunction::kLiteralsOffset, temp, index,
+ kRAHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ __ pop(index);
+
+ // Code available?
+ Register entry = t0;
+ __ lw(entry,
+ FieldMemOperand(array_pointer,
+ SharedFunctionInfo::kOffsetToPreviousCachedCode));
+ __ lw(entry, FieldMemOperand(entry, WeakCell::kValueOffset));
+ __ JumpIfSmi(entry, &maybe_call_runtime);
+
+ // Found literals and code. Get them into the closure and return.
+ __ pop(closure);
+ // Store code entry in the closure.
+ __ Addu(entry, entry, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+ Label install_optimized_code_and_tailcall;
+ __ bind(&install_optimized_code_and_tailcall);
+ __ sw(entry, FieldMemOperand(closure, JSFunction::kCodeEntryOffset));
+ __ RecordWriteCodeEntryField(closure, entry, t1);
+
+ // Link the closure into the optimized function list.
+ // t0 : code entry
+ // a3 : native context
+ // a1 : closure
+ __ lw(t1,
+ ContextMemOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST));
+ __ sw(t1, FieldMemOperand(closure, JSFunction::kNextFunctionLinkOffset));
+ __ RecordWriteField(closure, JSFunction::kNextFunctionLinkOffset, t1, a0,
+ kRAHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
+ OMIT_SMI_CHECK);
+ const int function_list_offset =
+ Context::SlotOffset(Context::OPTIMIZED_FUNCTIONS_LIST);
+ __ sw(closure,
+ ContextMemOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST));
+ // Save closure before the write barrier.
+ __ mov(t1, closure);
+ __ RecordWriteContextSlot(native_context, function_list_offset, closure, a0,
+ kRAHasNotBeenSaved, kDontSaveFPRegs);
+ __ mov(closure, t1);
+ __ pop(new_target);
+ __ pop(argument_count);
+ __ Jump(entry);
+
+ __ bind(&loop_bottom);
+ __ Subu(index, index,
+ Operand(Smi::FromInt(SharedFunctionInfo::kEntryLength)));
+ __ Branch(&loop_top, gt, index, Operand(Smi::FromInt(1)));
+
+ // We found neither literals nor code.
+ __ jmp(&gotta_call_runtime);
+
+ __ bind(&maybe_call_runtime);
+ __ pop(closure);
+
+ // Last possibility. Check the context free optimized code map entry.
+ __ lw(entry, FieldMemOperand(map, FixedArray::kHeaderSize +
+ SharedFunctionInfo::kSharedCodeIndex));
+ __ lw(entry, FieldMemOperand(entry, WeakCell::kValueOffset));
+ __ JumpIfSmi(entry, &try_shared);
+
+ // Store code entry in the closure.
+ __ Addu(entry, entry, Operand(Code::kHeaderSize - kHeapObjectTag));
+ __ jmp(&install_optimized_code_and_tailcall);
+
+ __ bind(&try_shared);
+ __ pop(new_target);
+ __ pop(argument_count);
+ // Is the full code valid?
+ __ lw(entry, FieldMemOperand(closure, JSFunction::kSharedFunctionInfoOffset));
+ __ lw(entry, FieldMemOperand(entry, SharedFunctionInfo::kCodeOffset));
+ __ lw(t1, FieldMemOperand(entry, Code::kFlagsOffset));
+ __ And(t1, t1, Operand(Code::KindField::kMask));
+ __ srl(t1, t1, Code::KindField::kShift);
+ __ Branch(&gotta_call_runtime_no_stack, eq, t1, Operand(Code::BUILTIN));
+ // Yes, install the full code.
+ __ Addu(entry, entry, Operand(Code::kHeaderSize - kHeapObjectTag));
+ __ sw(entry, FieldMemOperand(closure, JSFunction::kCodeEntryOffset));
+ __ RecordWriteCodeEntryField(closure, entry, t1);
+ __ Jump(entry);
+
+ __ bind(&gotta_call_runtime);
+ __ pop(closure);
+ __ pop(new_target);
+ __ pop(argument_count);
+ __ bind(&gotta_call_runtime_no_stack);
GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
}
+void Builtins::Generate_CompileBaseline(MacroAssembler* masm) {
+ GenerateTailCallToReturnedCode(masm, Runtime::kCompileBaseline);
+}
void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm,
@@ -1264,15 +1487,17 @@
__ SmiUntag(t2);
// Switch on the state.
Label with_tos_register, unknown_state;
- __ Branch(&with_tos_register,
- ne, t2, Operand(FullCodeGenerator::NO_REGISTERS));
+ __ Branch(&with_tos_register, ne, t2,
+ Operand(static_cast<int>(Deoptimizer::BailoutState::NO_REGISTERS)));
__ Ret(USE_DELAY_SLOT);
// Safe to fill delay slot Addu will emit one instruction.
__ Addu(sp, sp, Operand(1 * kPointerSize)); // Remove state.
__ bind(&with_tos_register);
+ DCHECK_EQ(kInterpreterAccumulatorRegister.code(), v0.code());
__ lw(v0, MemOperand(sp, 1 * kPointerSize));
- __ Branch(&unknown_state, ne, t2, Operand(FullCodeGenerator::TOS_REG));
+ __ Branch(&unknown_state, ne, t2,
+ Operand(static_cast<int>(Deoptimizer::BailoutState::TOS_REGISTER)));
__ Ret(USE_DELAY_SLOT);
// Safe to fill delay slot Addu will emit one instruction.
@@ -1478,28 +1703,6 @@
}
// static
-void Builtins::Generate_FunctionHasInstance(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- a0 : argc
- // -- sp[0] : first argument (left-hand side)
- // -- sp[4] : receiver (right-hand side)
- // -----------------------------------
-
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
- __ lw(InstanceOfDescriptor::LeftRegister(),
- MemOperand(fp, 2 * kPointerSize)); // Load left-hand side.
- __ lw(InstanceOfDescriptor::RightRegister(),
- MemOperand(fp, 3 * kPointerSize)); // Load right-hand side.
- InstanceOfStub stub(masm->isolate(), true);
- __ CallStub(&stub);
- }
-
- // Pop the argument and the receiver.
- __ DropAndRet(2);
-}
-
-// static
void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : argc
@@ -2469,6 +2672,30 @@
RelocInfo::CODE_TARGET);
}
+// static
+void Builtins::Generate_AllocateInNewSpace(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- a0 : requested object size (untagged)
+ // -- ra : return address
+ // -----------------------------------
+ __ SmiTag(a0);
+ __ Push(a0);
+ __ Move(cp, Smi::FromInt(0));
+ __ TailCallRuntime(Runtime::kAllocateInNewSpace);
+}
+
+// static
+void Builtins::Generate_AllocateInOldSpace(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- a0 : requested object size (untagged)
+ // -- ra : return address
+ // -----------------------------------
+ __ SmiTag(a0);
+ __ Move(a1, Smi::FromInt(AllocateTargetSpace::encode(OLD_SPACE)));
+ __ Push(a0, a1);
+ __ Move(cp, Smi::FromInt(0));
+ __ TailCallRuntime(Runtime::kAllocateInTargetSpace);
+}
void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// State setup as expected by MacroAssembler::InvokePrologue.
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index fd286fb..4084964 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -54,12 +54,6 @@
}
-void ArrayNoArgumentConstructorStub::InitializeDescriptor(
- CodeStubDescriptor* descriptor) {
- InitializeArrayConstructorDescriptor(isolate(), descriptor, 0);
-}
-
-
void ArraySingleArgumentConstructorStub::InitializeDescriptor(
CodeStubDescriptor* descriptor) {
InitializeArrayConstructorDescriptor(isolate(), descriptor, 1);
@@ -72,11 +66,6 @@
}
-void InternalArrayNoArgumentConstructorStub::InitializeDescriptor(
- CodeStubDescriptor* descriptor) {
- InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, 0);
-}
-
void FastArrayPushStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
Address deopt_handler = Runtime::FunctionForId(Runtime::kArrayPush)->entry;
descriptor->Initialize(a0, deopt_handler, -1, JS_FUNCTION_STUB_MODE);
@@ -1465,128 +1454,6 @@
}
-void InstanceOfStub::Generate(MacroAssembler* masm) {
- Register const object = a1; // Object (lhs).
- Register const function = a0; // Function (rhs).
- Register const object_map = a2; // Map of {object}.
- Register const function_map = a3; // Map of {function}.
- Register const function_prototype = t0; // Prototype of {function}.
- Register const scratch = t1;
-
- DCHECK(object.is(InstanceOfDescriptor::LeftRegister()));
- DCHECK(function.is(InstanceOfDescriptor::RightRegister()));
-
- // Check if {object} is a smi.
- Label object_is_smi;
- __ JumpIfSmi(object, &object_is_smi);
-
- // Lookup the {function} and the {object} map in the global instanceof cache.
- // Note: This is safe because we clear the global instanceof cache whenever
- // we change the prototype of any object.
- Label fast_case, slow_case;
- __ lw(object_map, FieldMemOperand(object, HeapObject::kMapOffset));
- __ LoadRoot(at, Heap::kInstanceofCacheFunctionRootIndex);
- __ Branch(&fast_case, ne, function, Operand(at));
- __ LoadRoot(at, Heap::kInstanceofCacheMapRootIndex);
- __ Branch(&fast_case, ne, object_map, Operand(at));
- __ Ret(USE_DELAY_SLOT);
- __ LoadRoot(v0, Heap::kInstanceofCacheAnswerRootIndex); // In delay slot.
-
- // If {object} is a smi we can safely return false if {function} is a JS
- // function, otherwise we have to miss to the runtime and throw an exception.
- __ bind(&object_is_smi);
- __ JumpIfSmi(function, &slow_case);
- __ GetObjectType(function, function_map, scratch);
- __ Branch(&slow_case, ne, scratch, Operand(JS_FUNCTION_TYPE));
- __ Ret(USE_DELAY_SLOT);
- __ LoadRoot(v0, Heap::kFalseValueRootIndex); // In delay slot.
-
- // Fast-case: The {function} must be a valid JSFunction.
- __ bind(&fast_case);
- __ JumpIfSmi(function, &slow_case);
- __ GetObjectType(function, function_map, scratch);
- __ Branch(&slow_case, ne, scratch, Operand(JS_FUNCTION_TYPE));
-
- // Go to the runtime if the function is not a constructor.
- __ lbu(scratch, FieldMemOperand(function_map, Map::kBitFieldOffset));
- __ And(at, scratch, Operand(1 << Map::kIsConstructor));
- __ Branch(&slow_case, eq, at, Operand(zero_reg));
-
- // Ensure that {function} has an instance prototype.
- __ And(at, scratch, Operand(1 << Map::kHasNonInstancePrototype));
- __ Branch(&slow_case, ne, at, Operand(zero_reg));
-
- // Get the "prototype" (or initial map) of the {function}.
- __ lw(function_prototype,
- FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
- __ AssertNotSmi(function_prototype);
-
- // Resolve the prototype if the {function} has an initial map. Afterwards the
- // {function_prototype} will be either the JSReceiver prototype object or the
- // hole value, which means that no instances of the {function} were created so
- // far and hence we should return false.
- Label function_prototype_valid;
- __ GetObjectType(function_prototype, scratch, scratch);
- __ Branch(&function_prototype_valid, ne, scratch, Operand(MAP_TYPE));
- __ lw(function_prototype,
- FieldMemOperand(function_prototype, Map::kPrototypeOffset));
- __ bind(&function_prototype_valid);
- __ AssertNotSmi(function_prototype);
-
- // Update the global instanceof cache with the current {object} map and
- // {function}. The cached answer will be set when it is known below.
- __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex);
- __ StoreRoot(object_map, Heap::kInstanceofCacheMapRootIndex);
-
- // Loop through the prototype chain looking for the {function} prototype.
- // Assume true, and change to false if not found.
- Register const object_instance_type = function_map;
- Register const map_bit_field = function_map;
- Register const null = scratch;
- Register const result = v0;
-
- Label done, loop, fast_runtime_fallback;
- __ LoadRoot(result, Heap::kTrueValueRootIndex);
- __ LoadRoot(null, Heap::kNullValueRootIndex);
- __ bind(&loop);
-
- // Check if the object needs to be access checked.
- __ lbu(map_bit_field, FieldMemOperand(object_map, Map::kBitFieldOffset));
- __ And(map_bit_field, map_bit_field, Operand(1 << Map::kIsAccessCheckNeeded));
- __ Branch(&fast_runtime_fallback, ne, map_bit_field, Operand(zero_reg));
- // Check if the current object is a Proxy.
- __ lbu(object_instance_type,
- FieldMemOperand(object_map, Map::kInstanceTypeOffset));
- __ Branch(&fast_runtime_fallback, eq, object_instance_type,
- Operand(JS_PROXY_TYPE));
-
- __ lw(object, FieldMemOperand(object_map, Map::kPrototypeOffset));
- __ Branch(&done, eq, object, Operand(function_prototype));
- __ Branch(USE_DELAY_SLOT, &loop, ne, object, Operand(null));
- __ lw(object_map,
- FieldMemOperand(object, HeapObject::kMapOffset)); // In delay slot.
- __ LoadRoot(result, Heap::kFalseValueRootIndex);
- __ bind(&done);
- __ Ret(USE_DELAY_SLOT);
- __ StoreRoot(result,
- Heap::kInstanceofCacheAnswerRootIndex); // In delay slot.
-
- // Found Proxy or access check needed: Call the runtime
- __ bind(&fast_runtime_fallback);
- __ Push(object, function_prototype);
- // Invalidate the instanceof cache.
- DCHECK(Smi::FromInt(0) == 0);
- __ StoreRoot(zero_reg, Heap::kInstanceofCacheFunctionRootIndex);
- __ TailCallRuntime(Runtime::kHasInPrototypeChain);
-
- // Slow-case: Call the %InstanceOf runtime function.
- __ bind(&slow_case);
- __ Push(object, function);
- __ TailCallRuntime(is_es6_instanceof() ? Runtime::kOrdinaryHasInstance
- : Runtime::kInstanceOf);
-}
-
-
void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
Label miss;
Register receiver = LoadDescriptor::ReceiverRegister();
@@ -4037,8 +3904,8 @@
__ bind(¬_array);
__ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
__ Branch(&miss, ne, at, Operand(feedback));
- Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::LOAD_IC));
+ Code::Flags code_flags =
+ Code::RemoveHolderFromFlags(Code::ComputeHandlerFlags(Code::LOAD_IC));
masm->isolate()->stub_cache()->GenerateProbe(masm, Code::LOAD_IC, code_flags,
receiver, name, feedback,
receiver_map, scratch1, t5);
@@ -4179,8 +4046,8 @@
__ bind(¬_array);
__ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
__ Branch(&miss, ne, feedback, Operand(at));
- Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::STORE_IC));
+ Code::Flags code_flags =
+ Code::RemoveHolderFromFlags(Code::ComputeHandlerFlags(Code::STORE_IC));
masm->isolate()->stub_cache()->GenerateProbe(
masm, Code::STORE_IC, code_flags, receiver, key, feedback, receiver_map,
scratch1, scratch2);
@@ -4748,15 +4615,15 @@
__ bind(&done_allocate);
// Initialize the JSObject fields.
- __ sw(a2, MemOperand(v0, JSObject::kMapOffset));
+ __ sw(a2, FieldMemOperand(v0, JSObject::kMapOffset));
__ LoadRoot(a3, Heap::kEmptyFixedArrayRootIndex);
- __ sw(a3, MemOperand(v0, JSObject::kPropertiesOffset));
- __ sw(a3, MemOperand(v0, JSObject::kElementsOffset));
+ __ sw(a3, FieldMemOperand(v0, JSObject::kPropertiesOffset));
+ __ sw(a3, FieldMemOperand(v0, JSObject::kElementsOffset));
STATIC_ASSERT(JSObject::kHeaderSize == 3 * kPointerSize);
- __ Addu(a1, v0, Operand(JSObject::kHeaderSize));
+ __ Addu(a1, v0, Operand(JSObject::kHeaderSize - kHeapObjectTag));
// ----------- S t a t e -------------
- // -- v0 : result (untagged)
+ // -- v0 : result (tagged)
// -- a1 : result fields (untagged)
// -- t1 : result end (untagged)
// -- a2 : initial map
@@ -4774,11 +4641,7 @@
{
// Initialize all in-object fields with undefined.
__ InitializeFieldsWithFiller(a1, t1, a0);
-
- // Add the object tag to make the JSObject real.
- STATIC_ASSERT(kHeapObjectTag == 1);
- __ Ret(USE_DELAY_SLOT);
- __ Addu(v0, v0, Operand(kHeapObjectTag)); // In delay slot.
+ __ Ret();
}
__ bind(&slack_tracking);
{
@@ -4801,9 +4664,7 @@
Label finalize;
STATIC_ASSERT(Map::kSlackTrackingCounterEnd == 1);
__ And(a3, a3, Operand(Map::ConstructionCounter::kMask));
- __ Branch(USE_DELAY_SLOT, &finalize, eq, a3, Operand(zero_reg));
- STATIC_ASSERT(kHeapObjectTag == 1);
- __ Addu(v0, v0, Operand(kHeapObjectTag)); // In delay slot.
+ __ Branch(&finalize, eq, a3, Operand(zero_reg));
__ Ret();
// Finalize the instance size.
@@ -4828,10 +4689,10 @@
__ CallRuntime(Runtime::kAllocateInNewSpace);
__ Pop(a2);
}
- STATIC_ASSERT(kHeapObjectTag == 1);
- __ Subu(v0, v0, Operand(kHeapObjectTag));
__ lbu(t1, FieldMemOperand(a2, Map::kInstanceSizeOffset));
__ Lsa(t1, v0, t1, kPointerSizeLog2);
+ STATIC_ASSERT(kHeapObjectTag == 1);
+ __ Subu(t1, t1, Operand(kHeapObjectTag));
__ jmp(&done_allocate);
// Fall back to %NewObject.
@@ -4850,19 +4711,19 @@
// -----------------------------------
__ AssertFunction(a1);
- // For Ignition we need to skip all possible handler/stub frames until
- // we reach the JavaScript frame for the function (similar to what the
- // runtime fallback implementation does). So make a2 point to that
- // JavaScript frame.
- {
- Label loop, loop_entry;
- __ Branch(USE_DELAY_SLOT, &loop_entry);
- __ mov(a2, fp); // In delay slot.
- __ bind(&loop);
+ // Make a2 point to the JavaScript frame.
+ __ mov(a2, fp);
+ if (skip_stub_frame()) {
+ // For Ignition we need to skip the handler/stub frame to reach the
+ // JavaScript frame for the function.
__ lw(a2, MemOperand(a2, StandardFrameConstants::kCallerFPOffset));
- __ bind(&loop_entry);
+ }
+ if (FLAG_debug_code) {
+ Label ok;
__ lw(a3, MemOperand(a2, StandardFrameConstants::kFunctionOffset));
- __ Branch(&loop, ne, a1, Operand(a3));
+ __ Branch(&ok, eq, a1, Operand(a3));
+ __ Abort(kInvalidFrameForFastNewRestArgumentsStub);
+ __ bind(&ok);
}
// Check if we have rest parameters (only possible if we have an
@@ -4893,7 +4754,7 @@
// Allocate an empty rest parameter array.
Label allocate, done_allocate;
- __ Allocate(JSArray::kSize, v0, a0, a1, &allocate, TAG_OBJECT);
+ __ Allocate(JSArray::kSize, v0, a0, a1, &allocate, NO_ALLOCATION_FLAGS);
__ bind(&done_allocate);
// Setup the rest parameter array in v0.
@@ -4935,7 +4796,7 @@
Label allocate, done_allocate;
__ li(a1, Operand(JSArray::kSize + FixedArray::kHeaderSize));
__ Lsa(a1, a1, a0, kPointerSizeLog2 - 1);
- __ Allocate(a1, v0, a3, t0, &allocate, TAG_OBJECT);
+ __ Allocate(a1, v0, a3, t0, &allocate, NO_ALLOCATION_FLAGS);
__ bind(&done_allocate);
// Setup the elements array in v0.
@@ -4991,23 +4852,39 @@
// -----------------------------------
__ AssertFunction(a1);
+ // Make t0 point to the JavaScript frame.
+ __ mov(t0, fp);
+ if (skip_stub_frame()) {
+ // For Ignition we need to skip the handler/stub frame to reach the
+ // JavaScript frame for the function.
+ __ lw(t0, MemOperand(t0, StandardFrameConstants::kCallerFPOffset));
+ }
+ if (FLAG_debug_code) {
+ Label ok;
+ __ lw(a3, MemOperand(t0, StandardFrameConstants::kFunctionOffset));
+ __ Branch(&ok, eq, a1, Operand(a3));
+ __ Abort(kInvalidFrameForFastNewRestArgumentsStub);
+ __ bind(&ok);
+ }
+
// TODO(bmeurer): Cleanup to match the FastNewStrictArgumentsStub.
__ lw(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
__ lw(a2,
FieldMemOperand(a2, SharedFunctionInfo::kFormalParameterCountOffset));
- __ Lsa(a3, fp, a2, kPointerSizeLog2 - 1);
+ __ Lsa(a3, t0, a2, kPointerSizeLog2 - 1);
__ Addu(a3, a3, Operand(StandardFrameConstants::kCallerSPOffset));
// a1 : function
// a2 : number of parameters (tagged)
// a3 : parameters pointer
+ // t0 : Javascript frame pointer
// Registers used over whole function:
// t1 : arguments count (tagged)
// t2 : mapped parameter count (tagged)
// Check if the calling frame is an arguments adaptor frame.
Label adaptor_frame, try_allocate, runtime;
- __ lw(t0, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+ __ lw(t0, MemOperand(t0, StandardFrameConstants::kCallerFPOffset));
__ lw(a0, MemOperand(t0, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Branch(&adaptor_frame, eq, a0,
Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
@@ -5053,7 +4930,7 @@
__ Addu(t5, t5, Operand(JSSloppyArgumentsObject::kSize));
// Do the allocation of all three objects in one go.
- __ Allocate(t5, v0, t5, t0, &runtime, TAG_OBJECT);
+ __ Allocate(t5, v0, t5, t0, &runtime, NO_ALLOCATION_FLAGS);
// v0 = address of new object(s) (tagged)
// a2 = argument count (smi-tagged)
@@ -5205,19 +5082,19 @@
// -----------------------------------
__ AssertFunction(a1);
- // For Ignition we need to skip all possible handler/stub frames until
- // we reach the JavaScript frame for the function (similar to what the
- // runtime fallback implementation does). So make a2 point to that
- // JavaScript frame.
- {
- Label loop, loop_entry;
- __ Branch(USE_DELAY_SLOT, &loop_entry);
- __ mov(a2, fp); // In delay slot.
- __ bind(&loop);
+ // Make a2 point to the JavaScript frame.
+ __ mov(a2, fp);
+ if (skip_stub_frame()) {
+ // For Ignition we need to skip the handler/stub frame to reach the
+ // JavaScript frame for the function.
__ lw(a2, MemOperand(a2, StandardFrameConstants::kCallerFPOffset));
- __ bind(&loop_entry);
+ }
+ if (FLAG_debug_code) {
+ Label ok;
__ lw(a3, MemOperand(a2, StandardFrameConstants::kFunctionOffset));
- __ Branch(&loop, ne, a1, Operand(a3));
+ __ Branch(&ok, eq, a1, Operand(a3));
+ __ Abort(kInvalidFrameForFastNewRestArgumentsStub);
+ __ bind(&ok);
}
// Check if we have an arguments adaptor frame below the function frame.
@@ -5255,7 +5132,7 @@
Label allocate, done_allocate;
__ li(a1, Operand(JSStrictArgumentsObject::kSize + FixedArray::kHeaderSize));
__ Lsa(a1, a1, a0, kPointerSizeLog2 - 1);
- __ Allocate(a1, v0, a3, t0, &allocate, TAG_OBJECT);
+ __ Allocate(a1, v0, a3, t0, &allocate, NO_ALLOCATION_FLAGS);
__ bind(&done_allocate);
// Setup the elements array in v0.
@@ -5608,7 +5485,11 @@
STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
STATIC_ASSERT(FCA::kIsolateIndex == 1);
STATIC_ASSERT(FCA::kHolderIndex == 0);
- STATIC_ASSERT(FCA::kArgsLength == 7);
+ STATIC_ASSERT(FCA::kNewTargetIndex == 7);
+ STATIC_ASSERT(FCA::kArgsLength == 8);
+
+ // new target
+ __ PushRoot(Heap::kUndefinedValueRootIndex);
// Save context, callee and call data.
__ Push(context, callee, call_data);
@@ -5632,7 +5513,7 @@
// Allocate the v8::Arguments structure in the arguments' space since
// it's not controlled by GC.
- const int kApiStackSpace = 4;
+ const int kApiStackSpace = 3;
FrameScope frame_scope(masm, StackFrame::MANUAL);
__ EnterExitFrame(false, kApiStackSpace);
@@ -5649,8 +5530,6 @@
// FunctionCallbackInfo::length_ = argc
__ li(at, Operand(argc()));
__ sw(at, MemOperand(a0, 2 * kPointerSize));
- // FunctionCallbackInfo::is_construct_call_ = 0
- __ sw(zero_reg, MemOperand(a0, 3 * kPointerSize));
ExternalReference thunk_ref =
ExternalReference::invoke_function_callback(masm->isolate());
@@ -5667,8 +5546,9 @@
}
MemOperand return_value_operand(fp, return_value_offset * kPointerSize);
int stack_space = 0;
- int32_t stack_space_offset = 4 * kPointerSize;
+ int32_t stack_space_offset = 3 * kPointerSize;
stack_space = argc() + FCA::kArgsLength + 1;
+ // TODO(adamk): Why are we clobbering this immediately?
stack_space_offset = kInvalidStackOffset;
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, stack_space,
stack_space_offset, return_value_operand,
@@ -5677,15 +5557,44 @@
void CallApiGetterStub::Generate(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- sp[0] : name
- // -- sp[4 .. (4 + kArgsLength*4)] : v8::PropertyCallbackInfo::args_
- // -- ...
- // -- a2 : api_function_address
- // -----------------------------------
+ // Build v8::PropertyCallbackInfo::args_ array on the stack and push property
+ // name below the exit frame to make GC aware of them.
+ STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
+ STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
+ STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
+ STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
+ STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
+ STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
+ STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
+ STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
- Register api_function_address = ApiGetterDescriptor::function_address();
- DCHECK(api_function_address.is(a2));
+ Register receiver = ApiGetterDescriptor::ReceiverRegister();
+ Register holder = ApiGetterDescriptor::HolderRegister();
+ Register callback = ApiGetterDescriptor::CallbackRegister();
+ Register scratch = t0;
+ DCHECK(!AreAliased(receiver, holder, callback, scratch));
+
+ Register api_function_address = a2;
+
+ // Here and below +1 is for name() pushed after the args_ array.
+ typedef PropertyCallbackArguments PCA;
+ __ Subu(sp, sp, (PCA::kArgsLength + 1) * kPointerSize);
+ __ sw(receiver, MemOperand(sp, (PCA::kThisIndex + 1) * kPointerSize));
+ __ lw(scratch, FieldMemOperand(callback, AccessorInfo::kDataOffset));
+ __ sw(scratch, MemOperand(sp, (PCA::kDataIndex + 1) * kPointerSize));
+ __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
+ __ sw(scratch, MemOperand(sp, (PCA::kReturnValueOffset + 1) * kPointerSize));
+ __ sw(scratch, MemOperand(sp, (PCA::kReturnValueDefaultValueIndex + 1) *
+ kPointerSize));
+ __ li(scratch, Operand(ExternalReference::isolate_address(isolate())));
+ __ sw(scratch, MemOperand(sp, (PCA::kIsolateIndex + 1) * kPointerSize));
+ __ sw(holder, MemOperand(sp, (PCA::kHolderIndex + 1) * kPointerSize));
+ // should_throw_on_error -> false
+ DCHECK(Smi::FromInt(0) == nullptr);
+ __ sw(zero_reg,
+ MemOperand(sp, (PCA::kShouldThrowOnErrorIndex + 1) * kPointerSize));
+ __ lw(scratch, FieldMemOperand(callback, AccessorInfo::kNameOffset));
+ __ sw(scratch, MemOperand(sp, 0 * kPointerSize));
// v8::PropertyCallbackInfo::args_ array and name handle.
const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
@@ -5706,6 +5615,10 @@
ExternalReference thunk_ref =
ExternalReference::invoke_accessor_getter_callback(isolate());
+ __ lw(scratch, FieldMemOperand(callback, AccessorInfo::kJsGetterOffset));
+ __ lw(api_function_address,
+ FieldMemOperand(scratch, Foreign::kForeignAddressOffset));
+
// +3 is to skip prolog, return address and name handle.
MemOperand return_value_operand(
fp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize);
@@ -5714,7 +5627,6 @@
return_value_operand, NULL);
}
-
#undef __
} // namespace internal
diff --git a/src/mips/codegen-mips.cc b/src/mips/codegen-mips.cc
index 1c6c169..63bbda3 100644
--- a/src/mips/codegen-mips.cc
+++ b/src/mips/codegen-mips.cc
@@ -733,13 +733,13 @@
__ sll(scratch, length, 2);
__ Addu(scratch, scratch, FixedDoubleArray::kHeaderSize);
__ Allocate(scratch, array, t3, scratch2, &gc_required, DOUBLE_ALIGNMENT);
- // array: destination FixedDoubleArray, not tagged as heap object
+ // array: destination FixedDoubleArray, tagged as heap object
// Set destination FixedDoubleArray's length and map.
__ LoadRoot(scratch2, Heap::kFixedDoubleArrayMapRootIndex);
- __ sw(length, MemOperand(array, FixedDoubleArray::kLengthOffset));
+ __ sw(length, FieldMemOperand(array, FixedDoubleArray::kLengthOffset));
// Update receiver's map.
- __ sw(scratch2, MemOperand(array, HeapObject::kMapOffset));
+ __ sw(scratch2, FieldMemOperand(array, HeapObject::kMapOffset));
__ sw(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ RecordWriteField(receiver,
@@ -751,7 +751,7 @@
OMIT_REMEMBERED_SET,
OMIT_SMI_CHECK);
// Replace receiver's backing store with newly created FixedDoubleArray.
- __ Addu(scratch1, array, Operand(kHeapObjectTag));
+ __ Addu(scratch1, array, Operand(kHeapObjectTag - kHeapObjectTag));
__ sw(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset));
__ RecordWriteField(receiver,
JSObject::kElementsOffset,
@@ -766,7 +766,8 @@
// Prepare for conversion loop.
__ Addu(scratch1, elements,
Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ Addu(scratch3, array, Operand(FixedDoubleArray::kHeaderSize));
+ __ Addu(scratch3, array,
+ Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
__ Lsa(array_end, scratch3, length, 2);
// Repurpose registers no longer in use.
@@ -886,8 +887,8 @@
// array: destination FixedArray, not tagged as heap object
// Set destination FixedDoubleArray's length and map.
__ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
- __ sw(length, MemOperand(array, FixedDoubleArray::kLengthOffset));
- __ sw(scratch, MemOperand(array, HeapObject::kMapOffset));
+ __ sw(length, FieldMemOperand(array, FixedDoubleArray::kLengthOffset));
+ __ sw(scratch, FieldMemOperand(array, HeapObject::kMapOffset));
// Prepare for conversion loop.
Register src_elements = elements;
@@ -897,7 +898,8 @@
__ Addu(src_elements, src_elements, Operand(
FixedDoubleArray::kHeaderSize - kHeapObjectTag
+ Register::kExponentOffset));
- __ Addu(dst_elements, array, Operand(FixedArray::kHeaderSize));
+ __ Addu(dst_elements, array,
+ Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ Lsa(dst_end, dst_elements, dst_end, 1);
// Allocating heap numbers in the loop below can fail and cause a jump to
@@ -912,8 +914,8 @@
__ bind(&initialization_loop_entry);
__ Branch(&initialization_loop, lt, dst_elements, Operand(dst_end));
- __ Addu(dst_elements, array, Operand(FixedArray::kHeaderSize));
- __ Addu(array, array, Operand(kHeapObjectTag));
+ __ Addu(dst_elements, array,
+ Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
// Using offsetted addresses.
// dst_elements: begin of destination FixedArray element fields, not tagged
diff --git a/src/mips/constants-mips.h b/src/mips/constants-mips.h
index 4914251..f50a849 100644
--- a/src/mips/constants-mips.h
+++ b/src/mips/constants-mips.h
@@ -108,6 +108,19 @@
(CpuFeatures::IsSupported(static_cast<CpuFeature>(check)))
#endif
+#if defined(V8_TARGET_LITTLE_ENDIAN)
+const uint32_t kMipsLwrOffset = 0;
+const uint32_t kMipsLwlOffset = 3;
+const uint32_t kMipsSwrOffset = 0;
+const uint32_t kMipsSwlOffset = 3;
+#elif defined(V8_TARGET_BIG_ENDIAN)
+const uint32_t kMipsLwrOffset = 3;
+const uint32_t kMipsLwlOffset = 0;
+const uint32_t kMipsSwrOffset = 3;
+const uint32_t kMipsSwlOffset = 0;
+#else
+#error Unknown endianness
+#endif
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
@@ -409,6 +422,7 @@
MOVZ = ((1U << 3) + 2),
MOVN = ((1U << 3) + 3),
BREAK = ((1U << 3) + 5),
+ SYNC = ((1U << 3) + 7),
MFHI = ((2U << 3) + 0),
CLZ_R6 = ((2U << 3) + 0),
@@ -620,7 +634,6 @@
NULLSF = 0U
};
-
// ----- Emulated conditions.
// On MIPS we use this enum to abstract from conditional branch instructions.
// The 'U' prefix is used to specify unsigned comparisons.
@@ -928,8 +941,7 @@
FunctionFieldToBitNumber(TEQ) | FunctionFieldToBitNumber(TNE) |
FunctionFieldToBitNumber(MOVZ) | FunctionFieldToBitNumber(MOVN) |
FunctionFieldToBitNumber(MOVCI) | FunctionFieldToBitNumber(SELEQZ_S) |
- FunctionFieldToBitNumber(SELNEZ_S);
-
+ FunctionFieldToBitNumber(SELNEZ_S) | FunctionFieldToBitNumber(SYNC);
// Get the encoding type of the instruction.
inline Type InstructionType(TypeChecks checks = NORMAL) const;
diff --git a/src/mips/disasm-mips.cc b/src/mips/disasm-mips.cc
index 7e0a480..e1890ee 100644
--- a/src/mips/disasm-mips.cc
+++ b/src/mips/disasm-mips.cc
@@ -1191,6 +1191,9 @@
case TNE:
Format(instr, "tne 'rs, 'rt, code: 'code");
break;
+ case SYNC:
+ Format(instr, "sync");
+ break;
case MOVZ:
Format(instr, "movz 'rd, 'rs, 'rt");
break;
diff --git a/src/mips/interface-descriptors-mips.cc b/src/mips/interface-descriptors-mips.cc
index 06e3b77..30a7a74 100644
--- a/src/mips/interface-descriptors-mips.cc
+++ b/src/mips/interface-descriptors-mips.cc
@@ -46,16 +46,11 @@
const Register StoreGlobalViaContextDescriptor::ValueRegister() { return a0; }
-const Register InstanceOfDescriptor::LeftRegister() { return a1; }
-const Register InstanceOfDescriptor::RightRegister() { return a0; }
-
-
const Register StringCompareDescriptor::LeftRegister() { return a1; }
const Register StringCompareDescriptor::RightRegister() { return a0; }
-
-const Register ApiGetterDescriptor::function_address() { return a2; }
-
+const Register ApiGetterDescriptor::HolderRegister() { return a0; }
+const Register ApiGetterDescriptor::CallbackRegister() { return a3; }
const Register MathPowTaggedDescriptor::exponent() { return a2; }
@@ -68,6 +63,8 @@
const Register GrowArrayElementsDescriptor::ObjectRegister() { return a0; }
const Register GrowArrayElementsDescriptor::KeyRegister() { return a3; }
+const Register HasPropertyDescriptor::ObjectRegister() { return a0; }
+const Register HasPropertyDescriptor::KeyRegister() { return a3; }
void FastNewClosureDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
@@ -247,13 +244,16 @@
SIMD128_TYPES(SIMD128_ALLOC_DESC)
#undef SIMD128_ALLOC_DESC
-void AllocateInNewSpaceDescriptor::InitializePlatformSpecific(
+void ArrayNoArgumentConstructorDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
- Register registers[] = {a0};
- data->InitializePlatformSpecific(arraysize(registers), registers);
+ // register state
+ // a0 -- number of arguments
+ // a1 -- function
+ // a2 -- allocation site with elements kind
+ Register registers[] = {a1, a2, a0};
+ data->InitializePlatformSpecific(arraysize(registers), registers, NULL);
}
-
void ArrayConstructorConstantArgCountDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// register state
@@ -317,6 +317,11 @@
data->InitializePlatformSpecific(arraysize(registers), registers, NULL);
}
+void CountOpDescriptor::InitializePlatformSpecific(
+ CallInterfaceDescriptorData* data) {
+ Register registers[] = {a1};
+ data->InitializePlatformSpecific(arraysize(registers), registers);
+}
void StringAddDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
@@ -377,9 +382,8 @@
void InterpreterDispatchDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
- kInterpreterAccumulatorRegister, kInterpreterRegisterFileRegister,
- kInterpreterBytecodeOffsetRegister, kInterpreterBytecodeArrayRegister,
- kInterpreterDispatchTableRegister};
+ kInterpreterAccumulatorRegister, kInterpreterBytecodeOffsetRegister,
+ kInterpreterBytecodeArrayRegister, kInterpreterDispatchTableRegister};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
@@ -414,6 +418,16 @@
data->InitializePlatformSpecific(arraysize(registers), registers);
}
+void ResumeGeneratorDescriptor::InitializePlatformSpecific(
+ CallInterfaceDescriptorData* data) {
+ Register registers[] = {
+ v0, // the value to pass to the generator
+ a1, // the JSGeneratorObject to resume
+ a2 // the resume mode (tagged)
+ };
+ data->InitializePlatformSpecific(arraysize(registers), registers);
+}
+
} // namespace internal
} // namespace v8
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index 7cbbd3a..3dbfd6b 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -1192,14 +1192,199 @@
// ------------Pseudo-instructions-------------
void MacroAssembler::Ulw(Register rd, const MemOperand& rs) {
- lwr(rd, rs);
- lwl(rd, MemOperand(rs.rm(), rs.offset() + 3));
+ DCHECK(!rd.is(at));
+ DCHECK(!rs.rm().is(at));
+ if (IsMipsArchVariant(kMips32r6)) {
+ lw(rd, rs);
+ } else {
+ DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) ||
+ IsMipsArchVariant(kLoongson));
+ if (is_int16(rs.offset() + kMipsLwrOffset) &&
+ is_int16(rs.offset() + kMipsLwlOffset)) {
+ if (!rd.is(rs.rm())) {
+ lwr(rd, MemOperand(rs.rm(), rs.offset() + kMipsLwrOffset));
+ lwl(rd, MemOperand(rs.rm(), rs.offset() + kMipsLwlOffset));
+ } else {
+ lwr(at, MemOperand(rs.rm(), rs.offset() + kMipsLwrOffset));
+ lwl(at, MemOperand(rs.rm(), rs.offset() + kMipsLwlOffset));
+ mov(rd, at);
+ }
+ } else { // Offset > 16 bits, use multiple instructions to load.
+ LoadRegPlusOffsetToAt(rs);
+ lwr(rd, MemOperand(at, kMipsLwrOffset));
+ lwl(rd, MemOperand(at, kMipsLwlOffset));
+ }
+ }
}
void MacroAssembler::Usw(Register rd, const MemOperand& rs) {
- swr(rd, rs);
- swl(rd, MemOperand(rs.rm(), rs.offset() + 3));
+ DCHECK(!rd.is(at));
+ DCHECK(!rs.rm().is(at));
+ if (IsMipsArchVariant(kMips32r6)) {
+ sw(rd, rs);
+ } else {
+ DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) ||
+ IsMipsArchVariant(kLoongson));
+ if (is_int16(rs.offset() + kMipsSwrOffset) &&
+ is_int16(rs.offset() + kMipsSwlOffset)) {
+ swr(rd, MemOperand(rs.rm(), rs.offset() + kMipsSwrOffset));
+ swl(rd, MemOperand(rs.rm(), rs.offset() + kMipsSwlOffset));
+ } else {
+ LoadRegPlusOffsetToAt(rs);
+ swr(rd, MemOperand(at, kMipsSwrOffset));
+ swl(rd, MemOperand(at, kMipsSwlOffset));
+ }
+ }
+}
+
+void MacroAssembler::Ulh(Register rd, const MemOperand& rs) {
+ DCHECK(!rd.is(at));
+ DCHECK(!rs.rm().is(at));
+ if (IsMipsArchVariant(kMips32r6)) {
+ lh(rd, rs);
+ } else {
+ DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) ||
+ IsMipsArchVariant(kLoongson));
+ if (is_int16(rs.offset()) && is_int16(rs.offset() + 1)) {
+#if defined(V8_TARGET_LITTLE_ENDIAN)
+ lbu(at, rs);
+ lb(rd, MemOperand(rs.rm(), rs.offset() + 1));
+#elif defined(V8_TARGET_BIG_ENDIAN)
+ lbu(at, MemOperand(rs.rm(), rs.offset() + 1));
+ lb(rd, rs);
+#endif
+ } else { // Offset > 16 bits, use multiple instructions to load.
+ LoadRegPlusOffsetToAt(rs);
+#if defined(V8_TARGET_LITTLE_ENDIAN)
+ lb(rd, MemOperand(at, 1));
+ lbu(at, MemOperand(at, 0));
+#elif defined(V8_TARGET_BIG_ENDIAN)
+ lb(rd, MemOperand(at, 0));
+ lbu(at, MemOperand(at, 1));
+#endif
+ }
+ sll(rd, rd, 8);
+ or_(rd, rd, at);
+ }
+}
+
+void MacroAssembler::Ulhu(Register rd, const MemOperand& rs) {
+ DCHECK(!rd.is(at));
+ DCHECK(!rs.rm().is(at));
+ if (IsMipsArchVariant(kMips32r6)) {
+ lhu(rd, rs);
+ } else {
+ DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) ||
+ IsMipsArchVariant(kLoongson));
+ if (is_int16(rs.offset()) && is_int16(rs.offset() + 1)) {
+#if defined(V8_TARGET_LITTLE_ENDIAN)
+ lbu(at, rs);
+ lbu(rd, MemOperand(rs.rm(), rs.offset() + 1));
+#elif defined(V8_TARGET_BIG_ENDIAN)
+ lbu(at, MemOperand(rs.rm(), rs.offset() + 1));
+ lbu(rd, rs);
+#endif
+ } else { // Offset > 16 bits, use multiple instructions to load.
+ LoadRegPlusOffsetToAt(rs);
+#if defined(V8_TARGET_LITTLE_ENDIAN)
+ lbu(rd, MemOperand(at, 1));
+ lbu(at, MemOperand(at, 0));
+#elif defined(V8_TARGET_BIG_ENDIAN)
+ lbu(rd, MemOperand(at, 0));
+ lbu(at, MemOperand(at, 1));
+#endif
+ }
+ sll(rd, rd, 8);
+ or_(rd, rd, at);
+ }
+}
+
+void MacroAssembler::Ush(Register rd, const MemOperand& rs, Register scratch) {
+ DCHECK(!rd.is(at));
+ DCHECK(!rs.rm().is(at));
+ DCHECK(!rs.rm().is(scratch));
+ DCHECK(!scratch.is(at));
+ if (IsMipsArchVariant(kMips32r6)) {
+ sh(rd, rs);
+ } else {
+ DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) ||
+ IsMipsArchVariant(kLoongson));
+ MemOperand source = rs;
+ // If offset > 16 bits, load address to at with offset 0.
+ if (!is_int16(rs.offset()) || !is_int16(rs.offset() + 1)) {
+ LoadRegPlusOffsetToAt(rs);
+ source = MemOperand(at, 0);
+ }
+
+ if (!scratch.is(rd)) {
+ mov(scratch, rd);
+ }
+
+#if defined(V8_TARGET_LITTLE_ENDIAN)
+ sb(scratch, source);
+ srl(scratch, scratch, 8);
+ sb(scratch, MemOperand(source.rm(), source.offset() + 1));
+#elif defined(V8_TARGET_BIG_ENDIAN)
+ sb(scratch, MemOperand(source.rm(), source.offset() + 1));
+ srl(scratch, scratch, 8);
+ sb(scratch, source);
+#endif
+ }
+}
+
+void MacroAssembler::Ulwc1(FPURegister fd, const MemOperand& rs,
+ Register scratch) {
+ if (IsMipsArchVariant(kMips32r6)) {
+ lwc1(fd, rs);
+ } else {
+ DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) ||
+ IsMipsArchVariant(kLoongson));
+ Ulw(scratch, rs);
+ mtc1(scratch, fd);
+ }
+}
+
+void MacroAssembler::Uswc1(FPURegister fd, const MemOperand& rs,
+ Register scratch) {
+ if (IsMipsArchVariant(kMips32r6)) {
+ swc1(fd, rs);
+ } else {
+ DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) ||
+ IsMipsArchVariant(kLoongson));
+ mfc1(scratch, fd);
+ Usw(scratch, rs);
+ }
+}
+
+void MacroAssembler::Uldc1(FPURegister fd, const MemOperand& rs,
+ Register scratch) {
+ DCHECK(!scratch.is(at));
+ if (IsMipsArchVariant(kMips32r6)) {
+ ldc1(fd, rs);
+ } else {
+ DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) ||
+ IsMipsArchVariant(kLoongson));
+ Ulw(scratch, MemOperand(rs.rm(), rs.offset() + Register::kMantissaOffset));
+ mtc1(scratch, fd);
+ Ulw(scratch, MemOperand(rs.rm(), rs.offset() + Register::kExponentOffset));
+ Mthc1(scratch, fd);
+ }
+}
+
+void MacroAssembler::Usdc1(FPURegister fd, const MemOperand& rs,
+ Register scratch) {
+ DCHECK(!scratch.is(at));
+ if (IsMipsArchVariant(kMips32r6)) {
+ sdc1(fd, rs);
+ } else {
+ DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1) ||
+ IsMipsArchVariant(kLoongson));
+ mfc1(scratch, fd);
+ Usw(scratch, MemOperand(rs.rm(), rs.offset() + Register::kMantissaOffset));
+ Mfhc1(scratch, fd);
+ Usw(scratch, MemOperand(rs.rm(), rs.offset() + Register::kExponentOffset));
+ }
}
@@ -1354,6 +1539,252 @@
addiu(sp, sp, stack_offset);
}
+void MacroAssembler::AddPair(Register dst_low, Register dst_high,
+ Register left_low, Register left_high,
+ Register right_low, Register right_high) {
+ Label no_overflow;
+ Register kScratchReg = s3;
+ Register kScratchReg2 = s4;
+ // Add lower word
+ Addu(dst_low, left_low, right_low);
+ Addu(dst_high, left_high, right_high);
+ // Check for lower word unsigned overflow
+ Sltu(kScratchReg, dst_low, left_low);
+ Sltu(kScratchReg2, dst_low, right_low);
+ Or(kScratchReg, kScratchReg2, kScratchReg);
+ Branch(&no_overflow, eq, kScratchReg, Operand(zero_reg));
+ // Increment higher word if there was overflow
+ Addu(dst_high, dst_high, 0x1);
+ bind(&no_overflow);
+}
+
+void MacroAssembler::SubPair(Register dst_low, Register dst_high,
+ Register left_low, Register left_high,
+ Register right_low, Register right_high) {
+ Label no_overflow;
+ Register kScratchReg = s3;
+ // Subtract lower word
+ Subu(dst_low, left_low, right_low);
+ Subu(dst_high, left_high, right_high);
+ // Check for lower word unsigned underflow
+ Sltu(kScratchReg, left_low, right_low);
+ Branch(&no_overflow, eq, kScratchReg, Operand(zero_reg));
+ // Decrement higher word if there was underflow
+ Subu(dst_high, dst_high, 0x1);
+ bind(&no_overflow);
+}
+
+void MacroAssembler::ShlPair(Register dst_low, Register dst_high,
+ Register src_low, Register src_high,
+ Register shift) {
+ Label less_than_32;
+ Label zero_shift;
+ Label word_shift;
+ Label done;
+ Register kScratchReg = s3;
+ And(shift, shift, 0x3F);
+ li(kScratchReg, 0x20);
+ Branch(&less_than_32, lt, shift, Operand(kScratchReg));
+
+ Branch(&word_shift, eq, shift, Operand(kScratchReg));
+ // Shift more than 32
+ Subu(kScratchReg, shift, kScratchReg);
+ mov(dst_low, zero_reg);
+ sllv(dst_high, src_low, kScratchReg);
+ Branch(&done);
+ // Word shift
+ bind(&word_shift);
+ mov(dst_low, zero_reg);
+ mov(dst_high, src_low);
+ Branch(&done);
+
+ bind(&less_than_32);
+ // Check if zero shift
+ Branch(&zero_shift, eq, shift, Operand(zero_reg));
+ // Shift less than 32
+ Subu(kScratchReg, kScratchReg, shift);
+ sllv(dst_high, src_high, shift);
+ sllv(dst_low, src_low, shift);
+ srlv(kScratchReg, src_low, kScratchReg);
+ Or(dst_high, dst_high, kScratchReg);
+ Branch(&done);
+ // Zero shift
+ bind(&zero_shift);
+ mov(dst_low, src_low);
+ mov(dst_high, src_high);
+ bind(&done);
+}
+
+void MacroAssembler::ShlPair(Register dst_low, Register dst_high,
+ Register src_low, Register src_high,
+ uint32_t shift) {
+ Register kScratchReg = s3;
+ shift = shift & 0x3F;
+ if (shift < 32) {
+ if (shift == 0) {
+ mov(dst_low, src_low);
+ mov(dst_high, src_high);
+ } else {
+ sll(dst_high, src_high, shift);
+ sll(dst_low, src_low, shift);
+ shift = 32 - shift;
+ srl(kScratchReg, src_low, shift);
+ Or(dst_high, dst_high, kScratchReg);
+ }
+ } else {
+ if (shift == 32) {
+ mov(dst_low, zero_reg);
+ mov(dst_high, src_low);
+ } else {
+ shift = shift - 32;
+ mov(dst_low, zero_reg);
+ sll(dst_high, src_low, shift);
+ }
+ }
+}
+
+void MacroAssembler::ShrPair(Register dst_low, Register dst_high,
+ Register src_low, Register src_high,
+ Register shift) {
+ Label less_than_32;
+ Label zero_shift;
+ Label word_shift;
+ Label done;
+ Register kScratchReg = s3;
+ And(shift, shift, 0x3F);
+ li(kScratchReg, 0x20);
+ Branch(&less_than_32, lt, shift, Operand(kScratchReg));
+
+ Branch(&word_shift, eq, shift, Operand(kScratchReg));
+ // Shift more than 32
+ Subu(kScratchReg, shift, kScratchReg);
+ mov(dst_high, zero_reg);
+ srlv(dst_low, src_high, kScratchReg);
+ Branch(&done);
+ // Word shift
+ bind(&word_shift);
+ mov(dst_high, zero_reg);
+ mov(dst_low, src_high);
+ Branch(&done);
+
+ bind(&less_than_32);
+ // Check if zero shift
+ Branch(&zero_shift, eq, shift, Operand(zero_reg));
+ // Shift less than 32
+ Subu(kScratchReg, kScratchReg, shift);
+ srlv(dst_high, src_high, shift);
+ srlv(dst_low, src_low, shift);
+ sllv(kScratchReg, src_high, kScratchReg);
+ Or(dst_low, dst_low, kScratchReg);
+ Branch(&done);
+ // Zero shift
+ bind(&zero_shift);
+ mov(dst_low, src_low);
+ mov(dst_high, src_high);
+ bind(&done);
+}
+
+void MacroAssembler::ShrPair(Register dst_low, Register dst_high,
+ Register src_low, Register src_high,
+ uint32_t shift) {
+ Register kScratchReg = s3;
+ shift = shift & 0x3F;
+ if (shift < 32) {
+ if (shift == 0) {
+ mov(dst_low, src_low);
+ mov(dst_high, src_high);
+ } else {
+ srl(dst_high, src_high, shift);
+ srl(dst_low, src_low, shift);
+ shift = 32 - shift;
+ sll(kScratchReg, src_high, shift);
+ Or(dst_low, dst_low, kScratchReg);
+ }
+ } else {
+ if (shift == 32) {
+ mov(dst_high, zero_reg);
+ mov(dst_low, src_high);
+ } else {
+ shift = shift - 32;
+ mov(dst_high, zero_reg);
+ srl(dst_low, src_high, shift);
+ }
+ }
+}
+
+void MacroAssembler::SarPair(Register dst_low, Register dst_high,
+ Register src_low, Register src_high,
+ Register shift) {
+ Label less_than_32;
+ Label zero_shift;
+ Label word_shift;
+ Label done;
+ Register kScratchReg = s3;
+ Register kScratchReg2 = s4;
+ And(shift, shift, 0x3F);
+ li(kScratchReg, 0x20);
+ Branch(&less_than_32, lt, shift, Operand(kScratchReg));
+
+ Branch(&word_shift, eq, shift, Operand(kScratchReg));
+
+ // Shift more than 32
+ li(kScratchReg2, 0x1F);
+ Subu(kScratchReg, shift, kScratchReg);
+ srav(dst_high, src_high, kScratchReg2);
+ srav(dst_low, src_high, kScratchReg);
+ Branch(&done);
+ // Word shift
+ bind(&word_shift);
+ li(kScratchReg2, 0x1F);
+ srav(dst_high, src_high, kScratchReg2);
+ mov(dst_low, src_high);
+ Branch(&done);
+
+ bind(&less_than_32);
+ // Check if zero shift
+ Branch(&zero_shift, eq, shift, Operand(zero_reg));
+
+ // Shift less than 32
+ Subu(kScratchReg, kScratchReg, shift);
+ srav(dst_high, src_high, shift);
+ srlv(dst_low, src_low, shift);
+ sllv(kScratchReg, src_high, kScratchReg);
+ Or(dst_low, dst_low, kScratchReg);
+ Branch(&done);
+ // Zero shift
+ bind(&zero_shift);
+ mov(dst_low, src_low);
+ mov(dst_high, src_high);
+ bind(&done);
+}
+
+void MacroAssembler::SarPair(Register dst_low, Register dst_high,
+ Register src_low, Register src_high,
+ uint32_t shift) {
+ Register kScratchReg = s3;
+ shift = shift & 0x3F;
+ if (shift < 32) {
+ if (shift == 0) {
+ mov(dst_low, src_low);
+ mov(dst_high, src_high);
+ } else {
+ sra(dst_high, src_high, shift);
+ srl(dst_low, src_low, shift);
+ shift = 32 - shift;
+ sll(kScratchReg, src_high, shift);
+ Or(dst_low, dst_low, kScratchReg);
+ }
+ } else {
+ if (shift == 32) {
+ sra(dst_high, src_high, 31);
+ mov(dst_low, src_high);
+ } else {
+ shift = shift - 32;
+ sra(dst_high, src_high, 31);
+ sra(dst_low, src_high, shift);
+ }
+ }
+}
void MacroAssembler::Ext(Register rt,
Register rs,
@@ -3654,6 +4085,7 @@
Label* gc_required,
AllocationFlags flags) {
DCHECK(object_size <= Page::kMaxRegularHeapObjectSize);
+ DCHECK((flags & ALLOCATION_FOLDED) == 0);
if (!FLAG_inline_new) {
if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
@@ -3726,18 +4158,21 @@
// to calculate the new top.
Addu(result_end, result, Operand(object_size));
Branch(gc_required, Ugreater, result_end, Operand(alloc_limit));
- sw(result_end, MemOperand(top_address));
- // Tag object if requested.
- if ((flags & TAG_OBJECT) != 0) {
- Addu(result, result, Operand(kHeapObjectTag));
+ if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) {
+ // The top pointer is not updated for allocation folding dominators.
+ sw(result_end, MemOperand(top_address));
}
+
+ // Tag object.
+ Addu(result, result, Operand(kHeapObjectTag));
}
void MacroAssembler::Allocate(Register object_size, Register result,
Register result_end, Register scratch,
Label* gc_required, AllocationFlags flags) {
+ DCHECK((flags & ALLOCATION_FOLDED) == 0);
if (!FLAG_inline_new) {
if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
@@ -3810,6 +4245,7 @@
} else {
Addu(result_end, result, Operand(object_size));
}
+
Branch(gc_required, Ugreater, result_end, Operand(alloc_limit));
// Update allocation top. result temporarily holds the new top.
@@ -3817,14 +4253,104 @@
And(alloc_limit, result_end, Operand(kObjectAlignmentMask));
Check(eq, kUnalignedAllocationInNewSpace, alloc_limit, Operand(zero_reg));
}
- sw(result_end, MemOperand(top_address));
- // Tag object if requested.
- if ((flags & TAG_OBJECT) != 0) {
- Addu(result, result, Operand(kHeapObjectTag));
+ if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) {
+ // The top pointer is not updated for allocation folding dominators.
+ sw(result_end, MemOperand(top_address));
}
+
+ // Tag object.
+ Addu(result, result, Operand(kHeapObjectTag));
}
+void MacroAssembler::FastAllocate(int object_size, Register result,
+ Register scratch1, Register scratch2,
+ AllocationFlags flags) {
+ DCHECK(object_size <= Page::kMaxRegularHeapObjectSize);
+ DCHECK(!AreAliased(result, scratch1, scratch2, t9, at));
+
+ // Make object size into bytes.
+ if ((flags & SIZE_IN_WORDS) != 0) {
+ object_size *= kPointerSize;
+ }
+ DCHECK_EQ(0, object_size & kObjectAlignmentMask);
+
+ ExternalReference allocation_top =
+ AllocationUtils::GetAllocationTopReference(isolate(), flags);
+
+ // Set up allocation top address and allocation limit registers.
+ Register top_address = scratch1;
+ // This code stores a temporary value in t9.
+ Register result_end = scratch2;
+ li(top_address, Operand(allocation_top));
+ lw(result, MemOperand(top_address));
+
+ 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(kPointerAlignment * 2 == kDoubleAlignment);
+ And(result_end, result, Operand(kDoubleAlignmentMask));
+ Label aligned;
+ Branch(&aligned, eq, result_end, Operand(zero_reg));
+ li(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
+ sw(result_end, MemOperand(result));
+ Addu(result, result, Operand(kDoubleSize / 2));
+ bind(&aligned);
+ }
+
+ Addu(result_end, result, Operand(object_size));
+
+ // The top pointer is not updated for allocation folding dominators.
+ sw(result_end, MemOperand(top_address));
+
+ Addu(result, result, Operand(kHeapObjectTag));
+}
+
+void MacroAssembler::FastAllocate(Register object_size, Register result,
+ Register result_end, Register scratch,
+ AllocationFlags flags) {
+ // |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, t9, at));
+ DCHECK(!AreAliased(result_end, result, scratch, t9, at));
+ DCHECK((flags & DOUBLE_ALIGNMENT) == 0 || !object_size.is(result_end));
+
+ ExternalReference allocation_top =
+ AllocationUtils::GetAllocationTopReference(isolate(), flags);
+
+ // Set up allocation top address and allocation limit registers.
+ Register top_address = scratch;
+ // This code stores a temporary value in t9.
+ li(top_address, Operand(allocation_top));
+ lw(result, MemOperand(top_address));
+
+ 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(kPointerAlignment * 2 == kDoubleAlignment);
+ And(result_end, result, Operand(kDoubleAlignmentMask));
+ Label aligned;
+ Branch(&aligned, eq, result_end, Operand(zero_reg));
+ li(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
+ sw(result_end, MemOperand(result));
+ Addu(result, result, Operand(kDoubleSize / 2));
+ bind(&aligned);
+ }
+
+ // 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.
+ if ((flags & SIZE_IN_WORDS) != 0) {
+ Lsa(result_end, result, object_size, kPointerSizeLog2);
+ } else {
+ Addu(result_end, result, Operand(object_size));
+ }
+
+ // The top pointer is not updated for allocation folding dominators.
+ sw(result_end, MemOperand(top_address));
+
+ Addu(result, result, Operand(kHeapObjectTag));
+}
void MacroAssembler::AllocateTwoByteString(Register result,
Register length,
@@ -3841,12 +4367,8 @@
And(scratch1, scratch1, Operand(~kObjectAlignmentMask));
// Allocate two-byte string in new space.
- Allocate(scratch1,
- result,
- scratch2,
- scratch3,
- gc_required,
- TAG_OBJECT);
+ Allocate(scratch1, result, scratch2, scratch3, gc_required,
+ NO_ALLOCATION_FLAGS);
// Set the map, length and hash field.
InitializeNewString(result,
@@ -3869,12 +4391,8 @@
And(scratch1, scratch1, Operand(~kObjectAlignmentMask));
// Allocate one-byte string in new space.
- Allocate(scratch1,
- result,
- scratch2,
- scratch3,
- gc_required,
- TAG_OBJECT);
+ Allocate(scratch1, result, scratch2, scratch3, gc_required,
+ NO_ALLOCATION_FLAGS);
// Set the map, length and hash field.
InitializeNewString(result, length, Heap::kOneByteStringMapRootIndex,
@@ -3888,7 +4406,7 @@
Register scratch2,
Label* gc_required) {
Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
- TAG_OBJECT);
+ NO_ALLOCATION_FLAGS);
InitializeNewString(result,
length,
Heap::kConsStringMapRootIndex,
@@ -3901,12 +4419,8 @@
Register scratch1,
Register scratch2,
Label* gc_required) {
- Allocate(ConsString::kSize,
- result,
- scratch1,
- scratch2,
- gc_required,
- TAG_OBJECT);
+ Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
+ NO_ALLOCATION_FLAGS);
InitializeNewString(result, length, Heap::kConsOneByteStringMapRootIndex,
scratch1, scratch2);
@@ -3919,7 +4433,7 @@
Register scratch2,
Label* gc_required) {
Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
- TAG_OBJECT);
+ NO_ALLOCATION_FLAGS);
InitializeNewString(result,
length,
@@ -3935,7 +4449,7 @@
Register scratch2,
Label* gc_required) {
Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
- TAG_OBJECT);
+ NO_ALLOCATION_FLAGS);
InitializeNewString(result, length, Heap::kSlicedOneByteStringMapRootIndex,
scratch1, scratch2);
@@ -3961,12 +4475,11 @@
Register scratch2,
Register heap_number_map,
Label* need_gc,
- TaggingMode tagging_mode,
MutableMode mode) {
// Allocate an object in the heap for the heap number and tag it as a heap
// object.
Allocate(HeapNumber::kSize, result, scratch1, scratch2, need_gc,
- tagging_mode == TAG_RESULT ? TAG_OBJECT : NO_ALLOCATION_FLAGS);
+ NO_ALLOCATION_FLAGS);
Heap::RootListIndex map_index = mode == MUTABLE
? Heap::kMutableHeapNumberMapRootIndex
@@ -3974,11 +4487,7 @@
AssertIsRoot(heap_number_map, map_index);
// Store heap number map in the allocated object.
- if (tagging_mode == TAG_RESULT) {
- sw(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset));
- } else {
- sw(heap_number_map, MemOperand(result, HeapObject::kMapOffset));
- }
+ sw(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset));
}
@@ -4002,7 +4511,8 @@
DCHECK(!result.is(value));
// Allocate JSValue in new space.
- Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required, TAG_OBJECT);
+ Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required,
+ NO_ALLOCATION_FLAGS);
// Initialize the JSValue.
LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2);
@@ -5615,6 +6125,16 @@
}
}
+void MacroAssembler::AssertGeneratorObject(Register object) {
+ if (emit_debug_code()) {
+ STATIC_ASSERT(kSmiTag == 0);
+ SmiTst(object, t8);
+ Check(ne, kOperandIsASmiAndNotAGeneratorObject, t8, Operand(zero_reg));
+ GetObjectType(object, t8, t8);
+ Check(eq, kOperandIsNotAGeneratorObject, t8,
+ Operand(JS_GENERATOR_OBJECT_TYPE));
+ }
+}
void MacroAssembler::AssertReceiver(Register object) {
if (emit_debug_code()) {
@@ -6089,7 +6609,7 @@
Label* no_memento_found) {
Label map_check;
Label top_check;
- ExternalReference new_space_allocation_top =
+ ExternalReference new_space_allocation_top_adr =
ExternalReference::new_space_allocation_top_address(isolate());
const int kMementoMapOffset = JSArray::kSize - kHeapObjectTag;
const int kMementoEndOffset = kMementoMapOffset + AllocationMemento::kSize;
@@ -6099,7 +6619,9 @@
// If the object is in new space, we need to check whether it is on the same
// page as the current top.
Addu(scratch_reg, receiver_reg, Operand(kMementoEndOffset));
- Xor(scratch_reg, scratch_reg, Operand(new_space_allocation_top));
+ li(at, Operand(new_space_allocation_top_adr));
+ lw(at, MemOperand(at));
+ Xor(scratch_reg, scratch_reg, Operand(at));
And(scratch_reg, scratch_reg, Operand(~Page::kPageAlignmentMask));
Branch(&top_check, eq, scratch_reg, Operand(zero_reg));
// The object is on a different page than allocation top. Bail out if the
@@ -6115,7 +6637,7 @@
// we are below top.
bind(&top_check);
Addu(scratch_reg, receiver_reg, Operand(kMementoEndOffset));
- li(at, Operand(new_space_allocation_top));
+ li(at, Operand(new_space_allocation_top_adr));
lw(at, MemOperand(at));
Branch(no_memento_found, gt, scratch_reg, Operand(at));
// Memento map check.
diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
index 2f02865..2417025 100644
--- a/src/mips/macro-assembler-mips.h
+++ b/src/mips/macro-assembler-mips.h
@@ -18,8 +18,8 @@
const Register kReturnRegister2 = {Register::kCode_a0};
const Register kJSFunctionRegister = {Register::kCode_a1};
const Register kContextRegister = {Register::kCpRegister};
+const Register kAllocateSizeRegister = {Register::kCode_a0};
const Register kInterpreterAccumulatorRegister = {Register::kCode_v0};
-const Register kInterpreterRegisterFileRegister = {Register::kCode_t3};
const Register kInterpreterBytecodeOffsetRegister = {Register::kCode_t4};
const Register kInterpreterBytecodeArrayRegister = {Register::kCode_t5};
const Register kInterpreterDispatchTableRegister = {Register::kCode_t6};
@@ -555,6 +555,15 @@
void Allocate(Register object_size, Register result, Register result_new,
Register scratch, Label* gc_required, AllocationFlags flags);
+ // FastAllocate is right now only used for folded allocations. It just
+ // increments the top pointer without checking against limit. This can only
+ // be done if it was proved earlier that the allocation will succeed.
+ void FastAllocate(int object_size, Register result, Register scratch1,
+ Register scratch2, AllocationFlags flags);
+
+ void FastAllocate(Register object_size, Register result, Register result_new,
+ Register scratch, AllocationFlags flags);
+
void AllocateTwoByteString(Register result,
Register length,
Register scratch1,
@@ -589,7 +598,6 @@
Register scratch2,
Register heap_number_map,
Label* gc_required,
- TaggingMode tagging_mode = TAG_RESULT,
MutableMode mode = IMMUTABLE);
void AllocateHeapNumberWithValue(Register result,
FPURegister value,
@@ -681,9 +689,19 @@
void mov(Register rd, Register rt) { or_(rd, rt, zero_reg); }
+ void Ulh(Register rd, const MemOperand& rs);
+ void Ulhu(Register rd, const MemOperand& rs);
+ void Ush(Register rd, const MemOperand& rs, Register scratch);
+
void Ulw(Register rd, const MemOperand& rs);
void Usw(Register rd, const MemOperand& rs);
+ void Ulwc1(FPURegister fd, const MemOperand& rs, Register scratch);
+ void Uswc1(FPURegister fd, const MemOperand& rs, Register scratch);
+
+ void Uldc1(FPURegister fd, const MemOperand& rs, Register scratch);
+ void Usdc1(FPURegister fd, const MemOperand& rs, Register scratch);
+
// Load int32 in the rd register.
void li(Register rd, Operand j, LiFlags mode = OPTIMIZE_SIZE);
inline void li(Register rd, int32_t j, LiFlags mode = OPTIMIZE_SIZE) {
@@ -809,6 +827,31 @@
void Ins(Register rt, Register rs, uint16_t pos, uint16_t size);
void Ext(Register rt, Register rs, uint16_t pos, uint16_t size);
+ // Int64Lowering instructions
+ void AddPair(Register dst_low, Register dst_high, Register left_low,
+ Register left_high, Register right_low, Register right_high);
+
+ void SubPair(Register dst_low, Register dst_high, Register left_low,
+ Register left_high, Register right_low, Register right_high);
+
+ void ShlPair(Register dst_low, Register dst_high, Register src_low,
+ Register src_high, Register shift);
+
+ void ShlPair(Register dst_low, Register dst_high, Register src_low,
+ Register src_high, uint32_t shift);
+
+ void ShrPair(Register dst_low, Register dst_high, Register src_low,
+ Register src_high, Register shift);
+
+ void ShrPair(Register dst_low, Register dst_high, Register src_low,
+ Register src_high, uint32_t shift);
+
+ void SarPair(Register dst_low, Register dst_high, Register src_low,
+ Register src_high, Register shift);
+
+ void SarPair(Register dst_low, Register dst_high, Register src_low,
+ Register src_high, uint32_t shift);
+
// ---------------------------------------------------------------------------
// FPU macros. These do not handle special cases like NaN or +- inf.
@@ -1546,6 +1589,10 @@
// enabled via --debug-code.
void AssertBoundFunction(Register object);
+ // Abort execution if argument is not a JSGeneratorObject,
+ // enabled via --debug-code.
+ void AssertGeneratorObject(Register object);
+
// Abort execution if argument is not a JSReceiver, enabled via --debug-code.
void AssertReceiver(Register object);
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
index e37b6e1..f8dc515 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips/simulator-mips.cc
@@ -586,7 +586,7 @@
}
while (cur < end) {
- PrintF(" 0x%08x: 0x%08x %10d",
+ PrintF(" 0x%08" PRIxPTR ": 0x%08x %10d",
reinterpret_cast<intptr_t>(cur), *cur, *cur);
HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
int value = *cur;
@@ -649,8 +649,8 @@
while (cur < end) {
dasm.InstructionDecode(buffer, cur);
- PrintF(" 0x%08x %s\n",
- reinterpret_cast<intptr_t>(cur), buffer.start());
+ PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur),
+ buffer.start());
cur += Instruction::kInstrSize;
}
} else if (strcmp(cmd, "gdb") == 0) {
@@ -771,8 +771,8 @@
while (cur < end) {
dasm.InstructionDecode(buffer, cur);
- PrintF(" 0x%08x %s\n",
- reinterpret_cast<intptr_t>(cur), buffer.start());
+ PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur),
+ buffer.start());
cur += Instruction::kInstrSize;
}
} else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
@@ -1786,12 +1786,12 @@
int Simulator::ReadW(int32_t addr, Instruction* instr) {
if (addr >=0 && addr < 0x400) {
// This has to be a NULL-dereference, drop into debugger.
- PrintF("Memory read from bad address: 0x%08x, pc=0x%08x\n",
- addr, reinterpret_cast<intptr_t>(instr));
+ PrintF("Memory read from bad address: 0x%08x, pc=0x%08" PRIxPTR "\n", addr,
+ reinterpret_cast<intptr_t>(instr));
MipsDebugger dbg(this);
dbg.Debug();
}
- if ((addr & kPointerAlignmentMask) == 0) {
+ if ((addr & kPointerAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
TraceMemRd(addr, static_cast<int32_t>(*ptr));
return *ptr;
@@ -1808,12 +1808,12 @@
void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
if (addr >= 0 && addr < 0x400) {
// This has to be a NULL-dereference, drop into debugger.
- PrintF("Memory write to bad address: 0x%08x, pc=0x%08x\n",
- addr, reinterpret_cast<intptr_t>(instr));
+ PrintF("Memory write to bad address: 0x%08x, pc=0x%08" PRIxPTR "\n", addr,
+ reinterpret_cast<intptr_t>(instr));
MipsDebugger dbg(this);
dbg.Debug();
}
- if ((addr & kPointerAlignmentMask) == 0) {
+ if ((addr & kPointerAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
TraceMemWr(addr, value, WORD);
*ptr = value;
@@ -1828,7 +1828,7 @@
double Simulator::ReadD(int32_t addr, Instruction* instr) {
- if ((addr & kDoubleAlignmentMask) == 0) {
+ if ((addr & kDoubleAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
double* ptr = reinterpret_cast<double*>(addr);
return *ptr;
}
@@ -1841,7 +1841,7 @@
void Simulator::WriteD(int32_t addr, double value, Instruction* instr) {
- if ((addr & kDoubleAlignmentMask) == 0) {
+ if ((addr & kDoubleAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
double* ptr = reinterpret_cast<double*>(addr);
*ptr = value;
return;
@@ -1854,7 +1854,7 @@
uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
- if ((addr & 1) == 0) {
+ if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
TraceMemRd(addr, static_cast<int32_t>(*ptr));
return *ptr;
@@ -1868,7 +1868,7 @@
int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
- if ((addr & 1) == 0) {
+ if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
int16_t* ptr = reinterpret_cast<int16_t*>(addr);
TraceMemRd(addr, static_cast<int32_t>(*ptr));
return *ptr;
@@ -1882,7 +1882,7 @@
void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
- if ((addr & 1) == 0) {
+ if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
TraceMemWr(addr, value, HALF);
*ptr = value;
@@ -1896,7 +1896,7 @@
void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
- if ((addr & 1) == 0) {
+ if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
int16_t* ptr = reinterpret_cast<int16_t*>(addr);
TraceMemWr(addr, value, HALF);
*ptr = value;
@@ -1953,7 +1953,7 @@
// Unsupported instructions use Format to print an error and stop execution.
void Simulator::Format(Instruction* instr, const char* format) {
- PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n",
+ PrintF("Simulator found unsupported instruction:\n 0x%08" PRIxPTR ": %s\n",
reinterpret_cast<intptr_t>(instr), format);
UNIMPLEMENTED_MIPS();
}
@@ -3731,6 +3731,9 @@
case TNE:
do_interrupt = rs() != rt();
break;
+ case SYNC:
+ // TODO(palfia): Ignore sync instruction for now.
+ break;
// Conditional moves.
case MOVN:
if (rt()) {
@@ -4413,8 +4416,9 @@
UNSUPPORTED();
}
if (::v8::internal::FLAG_trace_sim) {
- PrintF(" 0x%08x %-44s %s\n", reinterpret_cast<intptr_t>(instr),
- buffer.start(), trace_buf_.start());
+ PrintF(" 0x%08" PRIxPTR " %-44s %s\n",
+ reinterpret_cast<intptr_t>(instr), buffer.start(),
+ trace_buf_.start());
}
if (!pc_modified_) {
set_register(pc, reinterpret_cast<int32_t>(instr) +