Upgrade V8 to version 4.9.385.28
https://chromium.googlesource.com/v8/v8/+/4.9.385.28
FPIIM-449
Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 0aa886b..57fa3f5 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -4,29 +4,29 @@
#include <limits.h> // For LONG_MIN, LONG_MAX.
-#include "src/v8.h"
-
#if V8_TARGET_ARCH_ARM
#include "src/base/bits.h"
#include "src/base/division-by-constant.h"
#include "src/bootstrapper.h"
#include "src/codegen.h"
-#include "src/cpu-profiler.h"
-#include "src/debug.h"
-#include "src/isolate-inl.h"
+#include "src/debug/debug.h"
+#include "src/register-configuration.h"
#include "src/runtime/runtime.h"
+#include "src/arm/macro-assembler-arm.h"
+
namespace v8 {
namespace internal {
-MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size)
+MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size,
+ CodeObjectRequired create_code_object)
: Assembler(arg_isolate, buffer, size),
generating_stub_(false),
has_frame_(false) {
- if (isolate() != NULL) {
- code_object_ = Handle<Object>(isolate()->heap()->undefined_value(),
- isolate());
+ if (create_code_object == CodeObjectRequired::kYes) {
+ code_object_ =
+ Handle<Object>::New(isolate()->heap()->undefined_value(), isolate());
}
}
@@ -428,7 +428,7 @@
!predictable_code_size()) {
// The CPU supports fast immediate values, and this root will never
// change. We will load it as a relocatable immediate value.
- Handle<Object> root(&isolate()->heap()->roots_array_start()[index]);
+ Handle<Object> root = isolate()->heap()->root_handle(index);
mov(destination, Operand(root), LeaveCC, cond);
return;
}
@@ -439,6 +439,7 @@
void MacroAssembler::StoreRoot(Register source,
Heap::RootListIndex index,
Condition cond) {
+ DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
str(source, MemOperand(kRootRegister, index << kPointerSizeLog2), cond);
}
@@ -691,28 +692,28 @@
void MacroAssembler::PushFixedFrame(Register marker_reg) {
DCHECK(!marker_reg.is_valid() || marker_reg.code() < cp.code());
- stm(db_w, sp, (marker_reg.is_valid() ? marker_reg.bit() : 0) |
- cp.bit() |
- (FLAG_enable_ool_constant_pool ? pp.bit() : 0) |
- fp.bit() |
- lr.bit());
+ stm(db_w, sp, (marker_reg.is_valid() ? marker_reg.bit() : 0) | cp.bit() |
+ (FLAG_enable_embedded_constant_pool ? pp.bit() : 0) |
+ fp.bit() | lr.bit());
}
void MacroAssembler::PopFixedFrame(Register marker_reg) {
DCHECK(!marker_reg.is_valid() || marker_reg.code() < cp.code());
- ldm(ia_w, sp, (marker_reg.is_valid() ? marker_reg.bit() : 0) |
- cp.bit() |
- (FLAG_enable_ool_constant_pool ? pp.bit() : 0) |
- fp.bit() |
- lr.bit());
+ ldm(ia_w, sp, (marker_reg.is_valid() ? marker_reg.bit() : 0) | cp.bit() |
+ (FLAG_enable_embedded_constant_pool ? pp.bit() : 0) |
+ fp.bit() | lr.bit());
}
// Push and pop all registers that can hold pointers.
void MacroAssembler::PushSafepointRegisters() {
- // Safepoints expect a block of contiguous register values starting with r0:
- DCHECK(((1 << kNumSafepointSavedRegisters) - 1) == kSafepointSavedRegisters);
+ // Safepoints expect a block of contiguous register values starting with r0.
+ // except when FLAG_enable_embedded_constant_pool, which omits pp.
+ DCHECK(kSafepointSavedRegisters ==
+ (FLAG_enable_embedded_constant_pool
+ ? ((1 << (kNumSafepointSavedRegisters + 1)) - 1) & ~pp.bit()
+ : (1 << kNumSafepointSavedRegisters) - 1));
// Safepoints expect a block of kNumSafepointRegisters values on the
// stack, so adjust the stack for unsaved registers.
const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
@@ -742,6 +743,10 @@
int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
// The registers are pushed starting with the highest encoding,
// which means that lowest encodings are closest to the stack pointer.
+ if (FLAG_enable_embedded_constant_pool && reg_code > pp.code()) {
+ // RegList omits pp.
+ reg_code -= 1;
+ }
DCHECK(reg_code >= 0 && reg_code < kNumSafepointRegisters);
return reg_code;
}
@@ -756,7 +761,9 @@
// Number of d-regs not known at snapshot time.
DCHECK(!serializer_enabled());
// General purpose registers are pushed last on the stack.
- int doubles_size = DwVfpRegister::NumAllocatableRegisters() * kDoubleSize;
+ const RegisterConfiguration* config =
+ RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT);
+ int doubles_size = config->num_allocatable_double_registers() * kDoubleSize;
int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
return MemOperand(sp, doubles_size + register_offset);
}
@@ -860,6 +867,21 @@
}
+void MacroAssembler::VFPCompareAndSetFlags(const SwVfpRegister src1,
+ const SwVfpRegister src2,
+ const Condition cond) {
+ // Compare and move FPSCR flags to the normal condition flags.
+ VFPCompareAndLoadFlags(src1, src2, pc, cond);
+}
+
+void MacroAssembler::VFPCompareAndSetFlags(const SwVfpRegister src1,
+ const float src2,
+ const Condition cond) {
+ // Compare and move FPSCR flags to the normal condition flags.
+ VFPCompareAndLoadFlags(src1, src2, pc, cond);
+}
+
+
void MacroAssembler::VFPCompareAndSetFlags(const DwVfpRegister src1,
const DwVfpRegister src2,
const Condition cond) {
@@ -875,6 +897,25 @@
}
+void MacroAssembler::VFPCompareAndLoadFlags(const SwVfpRegister src1,
+ const SwVfpRegister src2,
+ const Register fpscr_flags,
+ const Condition cond) {
+ // Compare and load FPSCR.
+ vcmp(src1, src2, cond);
+ vmrs(fpscr_flags, cond);
+}
+
+void MacroAssembler::VFPCompareAndLoadFlags(const SwVfpRegister src1,
+ const float src2,
+ const Register fpscr_flags,
+ const Condition cond) {
+ // Compare and load FPSCR.
+ vcmp(src1, src2, cond);
+ vmrs(fpscr_flags, cond);
+}
+
+
void MacroAssembler::VFPCompareAndLoadFlags(const DwVfpRegister src1,
const DwVfpRegister src2,
const Register fpscr_flags,
@@ -893,6 +934,7 @@
vmrs(fpscr_flags, cond);
}
+
void MacroAssembler::Vmov(const DwVfpRegister dst,
const double imm,
const Register scratch) {
@@ -950,13 +992,20 @@
}
+void MacroAssembler::LoadConstantPoolPointerRegisterFromCodeTargetAddress(
+ Register code_target_address) {
+ DCHECK(FLAG_enable_embedded_constant_pool);
+ ldr(pp, MemOperand(code_target_address,
+ Code::kConstantPoolOffset - Code::kHeaderSize));
+ add(pp, pp, code_target_address);
+}
+
+
void MacroAssembler::LoadConstantPoolPointerRegister() {
- if (FLAG_enable_ool_constant_pool) {
- int constant_pool_offset = Code::kConstantPoolOffset - Code::kHeaderSize -
- pc_offset() - Instruction::kPCReadOffset;
- DCHECK(ImmediateFitsAddrMode2Instruction(constant_pool_offset));
- ldr(pp, MemOperand(pc, constant_pool_offset));
- }
+ DCHECK(FLAG_enable_embedded_constant_pool);
+ int entry_offset = pc_offset() + Instruction::kPCReadOffset;
+ sub(ip, pc, Operand(entry_offset));
+ LoadConstantPoolPointerRegisterFromCodeTargetAddress(ip);
}
@@ -965,9 +1014,9 @@
Push(Smi::FromInt(StackFrame::STUB));
// Adjust FP to point to saved FP.
add(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
- if (FLAG_enable_ool_constant_pool) {
+ if (FLAG_enable_embedded_constant_pool) {
LoadConstantPoolPointerRegister();
- set_ool_constant_pool_available(true);
+ set_constant_pool_available(true);
}
}
@@ -990,18 +1039,26 @@
add(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
}
}
- if (FLAG_enable_ool_constant_pool) {
+ if (FLAG_enable_embedded_constant_pool) {
LoadConstantPoolPointerRegister();
- set_ool_constant_pool_available(true);
+ set_constant_pool_available(true);
}
}
+void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) {
+ ldr(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+ ldr(vector, FieldMemOperand(vector, JSFunction::kSharedFunctionInfoOffset));
+ ldr(vector,
+ FieldMemOperand(vector, SharedFunctionInfo::kFeedbackVectorOffset));
+}
+
+
void MacroAssembler::EnterFrame(StackFrame::Type type,
bool load_constant_pool_pointer_reg) {
// r0-r3: preserved
PushFixedFrame();
- if (FLAG_enable_ool_constant_pool && load_constant_pool_pointer_reg) {
+ if (FLAG_enable_embedded_constant_pool && load_constant_pool_pointer_reg) {
LoadConstantPoolPointerRegister();
}
mov(ip, Operand(Smi::FromInt(type)));
@@ -1021,9 +1078,9 @@
// Drop the execution stack down to the frame pointer and restore
// the caller frame pointer, return address and constant pool pointer
- // (if FLAG_enable_ool_constant_pool).
+ // (if FLAG_enable_embedded_constant_pool).
int frame_ends;
- if (FLAG_enable_ool_constant_pool) {
+ if (FLAG_enable_embedded_constant_pool) {
add(sp, fp, Operand(StandardFrameConstants::kConstantPoolOffset));
frame_ends = pc_offset();
ldm(ia_w, sp, pp.bit() | fp.bit() | lr.bit());
@@ -1049,7 +1106,7 @@
mov(ip, Operand::Zero());
str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset));
}
- if (FLAG_enable_ool_constant_pool) {
+ if (FLAG_enable_embedded_constant_pool) {
str(pp, MemOperand(fp, ExitFrameConstants::kConstantPoolOffset));
}
mov(ip, Operand(CodeObject()));
@@ -1068,7 +1125,7 @@
// fp - ExitFrameConstants::kFrameSize -
// DwVfpRegister::kMaxNumRegisters * kDoubleSize,
// since the sp slot, code slot and constant pool slot (if
- // FLAG_enable_ool_constant_pool) were pushed after the fp.
+ // FLAG_enable_embedded_constant_pool) were pushed after the fp.
}
// Reserve place for the return address and stack space and align the frame
@@ -1118,9 +1175,9 @@
}
-void MacroAssembler::LeaveExitFrame(bool save_doubles,
- Register argument_count,
- bool restore_context) {
+void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
+ bool restore_context,
+ bool argument_count_is_length) {
ConstantPoolUnavailableScope constant_pool_unavailable(this);
// Optionally restore all double registers.
@@ -1148,13 +1205,17 @@
#endif
// Tear down the exit frame, pop the arguments, and return.
- if (FLAG_enable_ool_constant_pool) {
+ if (FLAG_enable_embedded_constant_pool) {
ldr(pp, MemOperand(fp, ExitFrameConstants::kConstantPoolOffset));
}
mov(sp, Operand(fp));
ldm(ia_w, sp, fp.bit() | lr.bit());
if (argument_count.is_valid()) {
- add(sp, sp, Operand(argument_count, LSL, kPointerSizeLog2));
+ if (argument_count_is_length) {
+ add(sp, sp, argument_count);
+ } else {
+ add(sp, sp, Operand(argument_count, LSL, kPointerSizeLog2));
+ }
}
}
@@ -1176,8 +1237,6 @@
void MacroAssembler::InvokePrologue(const ParameterCount& expected,
const ParameterCount& actual,
- Handle<Code> code_constant,
- Register code_reg,
Label* done,
bool* definitely_mismatches,
InvokeFlag flag,
@@ -1197,14 +1256,13 @@
// passed in registers.
DCHECK(actual.is_immediate() || actual.reg().is(r0));
DCHECK(expected.is_immediate() || expected.reg().is(r2));
- DCHECK((!code_constant.is_null() && code_reg.is(no_reg)) || code_reg.is(r3));
if (expected.is_immediate()) {
DCHECK(actual.is_immediate());
+ mov(r0, Operand(actual.immediate()));
if (expected.immediate() == actual.immediate()) {
definitely_matches = true;
} else {
- mov(r0, Operand(actual.immediate()));
const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
if (expected.immediate() == sentinel) {
// Don't worry about adapting arguments for builtins that
@@ -1219,9 +1277,9 @@
}
} else {
if (actual.is_immediate()) {
+ mov(r0, Operand(actual.immediate()));
cmp(expected.reg(), Operand(actual.immediate()));
b(eq, ®ular_invoke);
- mov(r0, Operand(actual.immediate()));
} else {
cmp(expected.reg(), Operand(actual.reg()));
b(eq, ®ular_invoke);
@@ -1229,11 +1287,6 @@
}
if (!definitely_matches) {
- if (!code_constant.is_null()) {
- mov(r3, Operand(code_constant));
- add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag));
- }
-
Handle<Code> adaptor =
isolate()->builtins()->ArgumentsAdaptorTrampoline();
if (flag == CALL_FUNCTION) {
@@ -1251,20 +1304,79 @@
}
-void MacroAssembler::InvokeCode(Register code,
- const ParameterCount& expected,
- const ParameterCount& actual,
- InvokeFlag flag,
- const CallWrapper& call_wrapper) {
+void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target,
+ const ParameterCount& expected,
+ const ParameterCount& actual) {
+ Label skip_flooding;
+ ExternalReference step_in_enabled =
+ ExternalReference::debug_step_in_enabled_address(isolate());
+ mov(r4, Operand(step_in_enabled));
+ ldrb(r4, MemOperand(r4));
+ cmp(r4, Operand(0));
+ b(eq, &skip_flooding);
+ {
+ FrameScope frame(this,
+ has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
+ if (expected.is_reg()) {
+ SmiTag(expected.reg());
+ Push(expected.reg());
+ }
+ if (actual.is_reg()) {
+ SmiTag(actual.reg());
+ Push(actual.reg());
+ }
+ if (new_target.is_valid()) {
+ Push(new_target);
+ }
+ Push(fun);
+ Push(fun);
+ CallRuntime(Runtime::kDebugPrepareStepInIfStepping, 1);
+ Pop(fun);
+ if (new_target.is_valid()) {
+ Pop(new_target);
+ }
+ if (actual.is_reg()) {
+ Pop(actual.reg());
+ SmiUntag(actual.reg());
+ }
+ if (expected.is_reg()) {
+ Pop(expected.reg());
+ SmiUntag(expected.reg());
+ }
+ }
+ bind(&skip_flooding);
+}
+
+
+void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
+ const ParameterCount& expected,
+ const ParameterCount& actual,
+ InvokeFlag flag,
+ const CallWrapper& call_wrapper) {
// You can't call a function without a valid frame.
DCHECK(flag == JUMP_FUNCTION || has_frame());
+ DCHECK(function.is(r1));
+ DCHECK_IMPLIES(new_target.is_valid(), new_target.is(r3));
+
+ if (call_wrapper.NeedsDebugStepCheck()) {
+ FloodFunctionIfStepping(function, new_target, expected, actual);
+ }
+
+ // Clear the new.target register if not given.
+ if (!new_target.is_valid()) {
+ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
+ }
Label done;
bool definitely_mismatches = false;
- InvokePrologue(expected, actual, Handle<Code>::null(), code,
- &done, &definitely_mismatches, flag,
+ InvokePrologue(expected, actual, &done, &definitely_mismatches, flag,
call_wrapper);
if (!definitely_mismatches) {
+ // We call indirectly through the code field in the function to
+ // allow recompilation to take effect without changing any of the
+ // call sites.
+ Register code = r4;
+ ldr(code, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
if (flag == CALL_FUNCTION) {
call_wrapper.BeforeCall(CallSize(code));
Call(code);
@@ -1282,6 +1394,7 @@
void MacroAssembler::InvokeFunction(Register fun,
+ Register new_target,
const ParameterCount& actual,
InvokeFlag flag,
const CallWrapper& call_wrapper) {
@@ -1292,19 +1405,17 @@
DCHECK(fun.is(r1));
Register expected_reg = r2;
- Register code_reg = r3;
+ Register temp_reg = r4;
- ldr(code_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
+ ldr(temp_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
ldr(expected_reg,
- FieldMemOperand(code_reg,
+ FieldMemOperand(temp_reg,
SharedFunctionInfo::kFormalParameterCountOffset));
SmiUntag(expected_reg);
- ldr(code_reg,
- FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
ParameterCount expected(expected_reg);
- InvokeCode(code_reg, expected, actual, flag, call_wrapper);
+ InvokeFunctionCode(fun, new_target, expected, actual, flag, call_wrapper);
}
@@ -1322,11 +1433,7 @@
// Get the function and setup the context.
ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
- // We call indirectly through the code field in the function to
- // allow recompilation to take effect without changing any of the
- // call sites.
- ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
- InvokeCode(r3, expected, actual, flag, call_wrapper);
+ InvokeFunctionCode(r1, no_reg, expected, actual, flag, call_wrapper);
}
@@ -1340,26 +1447,6 @@
}
-void MacroAssembler::IsObjectJSObjectType(Register heap_object,
- Register map,
- Register scratch,
- Label* fail) {
- ldr(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
- IsInstanceJSObjectType(map, scratch, fail);
-}
-
-
-void MacroAssembler::IsInstanceJSObjectType(Register map,
- Register scratch,
- Label* fail) {
- ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
- cmp(scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
- b(lt, fail);
- cmp(scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
- b(gt, fail);
-}
-
-
void MacroAssembler::IsObjectJSStringType(Register object,
Register scratch,
Label* fail) {
@@ -1384,51 +1471,30 @@
void MacroAssembler::DebugBreak() {
mov(r0, Operand::Zero());
- mov(r1, Operand(ExternalReference(Runtime::kDebugBreak, isolate())));
+ mov(r1,
+ Operand(ExternalReference(Runtime::kHandleDebuggerStatement, isolate())));
CEntryStub ces(isolate(), 1);
DCHECK(AllowThisStubCall(&ces));
- Call(ces.GetCode(), RelocInfo::DEBUG_BREAK);
+ Call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT);
}
-void MacroAssembler::PushTryHandler(StackHandler::Kind kind,
- int handler_index) {
+void MacroAssembler::PushStackHandler() {
// Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
-
- // For the JSEntry handler, we must preserve r0-r4, r5-r6 are available.
- // We will build up the handler from the bottom by pushing on the stack.
- // Set up the code object (r5) and the state (r6) for pushing.
- unsigned state =
- StackHandler::IndexField::encode(handler_index) |
- StackHandler::KindField::encode(kind);
- mov(r5, Operand(CodeObject()));
- mov(r6, Operand(state));
-
- // Push the frame pointer, context, state, and code object.
- if (kind == StackHandler::JS_ENTRY) {
- mov(cp, Operand(Smi::FromInt(0))); // Indicates no context.
- mov(ip, Operand::Zero()); // NULL frame pointer.
- stm(db_w, sp, r5.bit() | r6.bit() | cp.bit() | ip.bit());
- } else {
- stm(db_w, sp, r5.bit() | r6.bit() | cp.bit() | fp.bit());
- }
// Link the current handler as the next handler.
mov(r6, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
ldr(r5, MemOperand(r6));
push(r5);
+
// Set this new handler as the current one.
str(sp, MemOperand(r6));
}
-void MacroAssembler::PopTryHandler() {
+void MacroAssembler::PopStackHandler() {
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(r1);
mov(ip, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
@@ -1437,98 +1503,6 @@
}
-void MacroAssembler::JumpToHandlerEntry() {
- // Compute the handler entry address and jump to it. The handler table is
- // a fixed array of (smi-tagged) code offsets.
- // r0 = exception, r1 = code object, r2 = state.
-
- ConstantPoolUnavailableScope constant_pool_unavailable(this);
- if (FLAG_enable_ool_constant_pool) {
- ldr(pp, FieldMemOperand(r1, Code::kConstantPoolOffset)); // Constant pool.
- }
- ldr(r3, FieldMemOperand(r1, Code::kHandlerTableOffset)); // Handler table.
- add(r3, r3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- mov(r2, Operand(r2, LSR, StackHandler::kKindWidth)); // Handler index.
- ldr(r2, MemOperand(r3, r2, LSL, kPointerSizeLog2)); // Smi-tagged offset.
- add(r1, r1, Operand(Code::kHeaderSize - kHeapObjectTag)); // Code start.
- add(pc, r1, Operand::SmiUntag(r2)); // Jump
-}
-
-
-void MacroAssembler::Throw(Register value) {
- // Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
- STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
-
- // The exception is expected in r0.
- if (!value.is(r0)) {
- mov(r0, value);
- }
- // Drop the stack pointer to the top of the top handler.
- mov(r3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
- ldr(sp, MemOperand(r3));
- // Restore the next handler.
- pop(r2);
- str(r2, MemOperand(r3));
-
- // Get the code object (r1) and state (r2). Restore the context and frame
- // pointer.
- ldm(ia_w, sp, r1.bit() | r2.bit() | cp.bit() | fp.bit());
-
- // If the handler is a JS frame, restore the context to the frame.
- // (kind == ENTRY) == (fp == 0) == (cp == 0), so we could test either fp
- // or cp.
- tst(cp, cp);
- str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
-
- JumpToHandlerEntry();
-}
-
-
-void MacroAssembler::ThrowUncatchable(Register value) {
- // Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
-
- // The exception is expected in r0.
- if (!value.is(r0)) {
- mov(r0, value);
- }
- // Drop the stack pointer to the top of the top stack handler.
- mov(r3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
- ldr(sp, MemOperand(r3));
-
- // Unwind the handlers until the ENTRY handler is found.
- Label fetch_next, check_kind;
- jmp(&check_kind);
- bind(&fetch_next);
- ldr(sp, MemOperand(sp, StackHandlerConstants::kNextOffset));
-
- bind(&check_kind);
- STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
- ldr(r2, MemOperand(sp, StackHandlerConstants::kStateOffset));
- tst(r2, Operand(StackHandler::KindField::kMask));
- b(ne, &fetch_next);
-
- // Set the top handler address to next handler past the top ENTRY handler.
- pop(r2);
- str(r2, MemOperand(r3));
- // Get the code object (r1) and state (r2). Clear the context and frame
- // pointer (0 was saved in the handler).
- ldm(ia_w, sp, r1.bit() | r2.bit() | cp.bit() | fp.bit());
-
- JumpToHandlerEntry();
-}
-
-
void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
Register scratch,
Label* miss) {
@@ -1547,10 +1521,7 @@
#endif
// Load the native context of the current context.
- int offset =
- Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
- ldr(scratch, FieldMemOperand(scratch, offset));
- ldr(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset));
+ ldr(scratch, ContextMemOperand(scratch, Context::NATIVE_CONTEXT_INDEX));
// Check the context is a native context.
if (emit_debug_code()) {
@@ -1634,6 +1605,7 @@
add(t0, t0, scratch);
// hash = hash ^ (hash >> 16);
eor(t0, t0, Operand(t0, LSR, 16));
+ bic(t0, t0, Operand(0xc0000000u));
}
@@ -1704,7 +1676,7 @@
const int kDetailsOffset =
SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
ldr(t1, FieldMemOperand(t2, kDetailsOffset));
- DCHECK_EQ(FIELD, 0);
+ DCHECK_EQ(DATA, 0);
tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
b(ne, miss);
@@ -1733,11 +1705,7 @@
return;
}
- DCHECK(!result.is(scratch1));
- DCHECK(!result.is(scratch2));
- DCHECK(!scratch1.is(scratch2));
- DCHECK(!scratch1.is(ip));
- DCHECK(!scratch2.is(ip));
+ DCHECK(!AreAliased(result, scratch1, scratch2, ip));
// Make object size into bytes.
if ((flags & SIZE_IN_WORDS) != 0) {
@@ -1754,49 +1722,46 @@
ExternalReference allocation_limit =
AllocationUtils::GetAllocationLimitReference(isolate(), flags);
- intptr_t top =
- reinterpret_cast<intptr_t>(allocation_top.address());
- intptr_t limit =
- reinterpret_cast<intptr_t>(allocation_limit.address());
+ intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address());
+ intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
DCHECK((limit - top) == kPointerSize);
DCHECK(result.code() < ip.code());
// Set up allocation top address register.
- Register topaddr = scratch1;
- mov(topaddr, Operand(allocation_top));
-
+ Register top_address = scratch1;
// This code stores a temporary value in ip. This is OK, as the code below
// does not need ip for implicit literal generation.
+ Register alloc_limit = ip;
+ Register result_end = scratch2;
+ mov(top_address, Operand(allocation_top));
+
if ((flags & RESULT_CONTAINS_TOP) == 0) {
- // Load allocation top into result and allocation limit into ip.
- ldm(ia, topaddr, result.bit() | ip.bit());
+ // Load allocation top into result and allocation limit into alloc_limit.
+ ldm(ia, top_address, result.bit() | alloc_limit.bit());
} else {
if (emit_debug_code()) {
- // Assert that result actually contains top on entry. ip is used
- // immediately below so this use of ip does not cause difference with
- // respect to register content between debug and release mode.
- ldr(ip, MemOperand(topaddr));
- cmp(result, ip);
+ // Assert that result actually contains top on entry.
+ ldr(alloc_limit, MemOperand(top_address));
+ cmp(result, alloc_limit);
Check(eq, kUnexpectedAllocationTop);
}
- // Load allocation limit into ip. Result already contains allocation top.
- ldr(ip, MemOperand(topaddr, limit - top));
+ // Load allocation limit. Result already contains allocation top.
+ ldr(alloc_limit, MemOperand(top_address, limit - top));
}
if ((flags & DOUBLE_ALIGNMENT) != 0) {
// Align the next allocation. Storing the filler map without checking top is
// safe in new-space because the limit of the heap is aligned there.
- DCHECK((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
- and_(scratch2, result, Operand(kDoubleAlignmentMask), SetCC);
+ and_(result_end, result, Operand(kDoubleAlignmentMask), SetCC);
Label aligned;
b(eq, &aligned);
- if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
- cmp(result, Operand(ip));
+ if ((flags & PRETENURE) != 0) {
+ cmp(result, Operand(alloc_limit));
b(hs, gc_required);
}
- mov(scratch2, Operand(isolate()->factory()->one_pointer_filler_map()));
- str(scratch2, MemOperand(result, kDoubleSize / 2, PostIndex));
+ mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
+ str(result_end, MemOperand(result, kDoubleSize / 2, PostIndex));
bind(&aligned);
}
@@ -1816,15 +1781,15 @@
shift += 8;
Operand bits_operand(bits);
DCHECK(bits_operand.instructions_required(this) == 1);
- add(scratch2, source, bits_operand, SetCC, cond);
- source = scratch2;
+ add(result_end, source, bits_operand, SetCC, cond);
+ source = result_end;
cond = cc;
}
}
b(cs, gc_required);
- cmp(scratch2, Operand(ip));
+ cmp(result_end, Operand(alloc_limit));
b(hi, gc_required);
- str(scratch2, MemOperand(topaddr));
+ str(result_end, MemOperand(top_address));
// Tag object if requested.
if ((flags & TAG_OBJECT) != 0) {
@@ -1833,32 +1798,25 @@
}
-void MacroAssembler::Allocate(Register object_size,
- Register result,
- Register scratch1,
- Register scratch2,
- Label* gc_required,
- AllocationFlags flags) {
+void MacroAssembler::Allocate(Register object_size, Register result,
+ Register result_end, Register scratch,
+ Label* gc_required, AllocationFlags flags) {
if (!FLAG_inline_new) {
if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
mov(result, Operand(0x7091));
- mov(scratch1, Operand(0x7191));
- mov(scratch2, Operand(0x7291));
+ mov(scratch, Operand(0x7191));
+ mov(result_end, Operand(0x7291));
}
jmp(gc_required);
return;
}
- // Assert that the register arguments are different and that none of
- // them are ip. ip is used explicitly in the code generated below.
- DCHECK(!result.is(scratch1));
- DCHECK(!result.is(scratch2));
- DCHECK(!scratch1.is(scratch2));
- DCHECK(!object_size.is(ip));
- DCHECK(!result.is(ip));
- DCHECK(!scratch1.is(ip));
- DCHECK(!scratch2.is(ip));
+ // |object_size| and |result_end| may overlap if the DOUBLE_ALIGNMENT flag
+ // is not specified. Other registers must not overlap.
+ DCHECK(!AreAliased(object_size, result, scratch, ip));
+ DCHECK(!AreAliased(result_end, result, scratch, ip));
+ DCHECK((flags & DOUBLE_ALIGNMENT) == 0 || !object_size.is(result_end));
// Check relative positions of allocation top and limit addresses.
// The values must be adjacent in memory to allow the use of LDM.
@@ -1868,49 +1826,45 @@
AllocationUtils::GetAllocationTopReference(isolate(), flags);
ExternalReference allocation_limit =
AllocationUtils::GetAllocationLimitReference(isolate(), flags);
- intptr_t top =
- reinterpret_cast<intptr_t>(allocation_top.address());
- intptr_t limit =
- reinterpret_cast<intptr_t>(allocation_limit.address());
+ intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address());
+ intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
DCHECK((limit - top) == kPointerSize);
DCHECK(result.code() < ip.code());
- // Set up allocation top address.
- Register topaddr = scratch1;
- mov(topaddr, Operand(allocation_top));
-
+ // Set up allocation top address and allocation limit registers.
+ Register top_address = scratch;
// This code stores a temporary value in ip. This is OK, as the code below
// does not need ip for implicit literal generation.
+ Register alloc_limit = ip;
+ mov(top_address, Operand(allocation_top));
+
if ((flags & RESULT_CONTAINS_TOP) == 0) {
- // Load allocation top into result and allocation limit into ip.
- ldm(ia, topaddr, result.bit() | ip.bit());
+ // Load allocation top into result and allocation limit into alloc_limit.
+ ldm(ia, top_address, result.bit() | alloc_limit.bit());
} else {
if (emit_debug_code()) {
- // Assert that result actually contains top on entry. ip is used
- // immediately below so this use of ip does not cause difference with
- // respect to register content between debug and release mode.
- ldr(ip, MemOperand(topaddr));
- cmp(result, ip);
+ // Assert that result actually contains top on entry.
+ ldr(alloc_limit, MemOperand(top_address));
+ cmp(result, alloc_limit);
Check(eq, kUnexpectedAllocationTop);
}
- // Load allocation limit into ip. Result already contains allocation top.
- ldr(ip, MemOperand(topaddr, limit - top));
+ // Load allocation limit. Result already contains allocation top.
+ ldr(alloc_limit, MemOperand(top_address, limit - top));
}
if ((flags & DOUBLE_ALIGNMENT) != 0) {
// Align the next allocation. Storing the filler map without checking top is
// safe in new-space because the limit of the heap is aligned there.
- DCHECK((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
- and_(scratch2, result, Operand(kDoubleAlignmentMask), SetCC);
+ and_(result_end, result, Operand(kDoubleAlignmentMask), SetCC);
Label aligned;
b(eq, &aligned);
- if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
- cmp(result, Operand(ip));
+ if ((flags & PRETENURE) != 0) {
+ cmp(result, Operand(alloc_limit));
b(hs, gc_required);
}
- mov(scratch2, Operand(isolate()->factory()->one_pointer_filler_map()));
- str(scratch2, MemOperand(result, kDoubleSize / 2, PostIndex));
+ mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
+ str(result_end, MemOperand(result, kDoubleSize / 2, PostIndex));
bind(&aligned);
}
@@ -1918,20 +1872,20 @@
// 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) {
- add(scratch2, result, Operand(object_size, LSL, kPointerSizeLog2), SetCC);
+ add(result_end, result, Operand(object_size, LSL, kPointerSizeLog2), SetCC);
} else {
- add(scratch2, result, Operand(object_size), SetCC);
+ add(result_end, result, Operand(object_size), SetCC);
}
b(cs, gc_required);
- cmp(scratch2, Operand(ip));
+ cmp(result_end, Operand(alloc_limit));
b(hi, gc_required);
// Update allocation top. result temporarily holds the new top.
if (emit_debug_code()) {
- tst(scratch2, Operand(kObjectAlignmentMask));
+ tst(result_end, Operand(kObjectAlignmentMask));
Check(eq, kUnalignedAllocationInNewSpace);
}
- str(scratch2, MemOperand(topaddr));
+ str(result_end, MemOperand(top_address));
// Tag object if requested.
if ((flags & TAG_OBJECT) != 0) {
@@ -1940,26 +1894,6 @@
}
-void MacroAssembler::UndoAllocationInNewSpace(Register object,
- Register scratch) {
- ExternalReference new_space_allocation_top =
- ExternalReference::new_space_allocation_top_address(isolate());
-
- // Make sure the object has no tag before resetting top.
- and_(object, object, Operand(~kHeapObjectTagMask));
-#ifdef DEBUG
- // Check that the object un-allocated is below the current top.
- mov(scratch, Operand(new_space_allocation_top));
- ldr(scratch, MemOperand(scratch));
- cmp(object, scratch);
- Check(lt, kUndoAllocationOfNonAllocatedMemory);
-#endif
- // Write the address of the object to un-allocate as the current top.
- mov(scratch, Operand(new_space_allocation_top));
- str(object, MemOperand(scratch));
-}
-
-
void MacroAssembler::AllocateTwoByteString(Register result,
Register length,
Register scratch1,
@@ -2089,21 +2023,6 @@
}
-void MacroAssembler::CheckObjectTypeRange(Register object,
- Register map,
- InstanceType min_type,
- InstanceType max_type,
- Label* false_label) {
- STATIC_ASSERT(Map::kInstanceTypeOffset < 4096);
- STATIC_ASSERT(LAST_TYPE < 256);
- ldr(map, FieldMemOperand(object, HeapObject::kMapOffset));
- ldrb(ip, FieldMemOperand(map, Map::kInstanceTypeOffset));
- sub(ip, ip, Operand(min_type));
- cmp(ip, Operand(max_type - min_type));
- b(hi, false_label);
-}
-
-
void MacroAssembler::CompareInstanceType(Register map,
Register type_reg,
InstanceType type) {
@@ -2172,6 +2091,7 @@
LowDwVfpRegister double_scratch,
Label* fail,
int elements_offset) {
+ DCHECK(!AreAliased(value_reg, key_reg, elements_reg, scratch1));
Label smi_value, store;
// Handle smi values specially.
@@ -2275,42 +2195,35 @@
}
-void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
- Label* miss) {
+void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) {
mov(value, Operand(cell));
ldr(value, FieldMemOperand(value, WeakCell::kValueOffset));
+}
+
+
+void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
+ Label* miss) {
+ GetWeakValue(value, cell);
JumpIfSmi(value, miss);
}
-void MacroAssembler::TryGetFunctionPrototype(Register function,
- Register result,
- Register scratch,
- Label* miss,
- bool miss_on_bound_function) {
- Label non_instance;
- if (miss_on_bound_function) {
- // Check that the receiver isn't a smi.
- JumpIfSmi(function, miss);
+void MacroAssembler::GetMapConstructor(Register result, Register map,
+ Register temp, Register temp2) {
+ Label done, loop;
+ ldr(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset));
+ bind(&loop);
+ JumpIfSmi(result, &done);
+ CompareObjectType(result, temp, temp2, MAP_TYPE);
+ b(ne, &done);
+ ldr(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset));
+ b(&loop);
+ bind(&done);
+}
- // Check that the function really is a function. Load map into result reg.
- CompareObjectType(function, result, scratch, JS_FUNCTION_TYPE);
- b(ne, miss);
- ldr(scratch,
- FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
- ldr(scratch,
- FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset));
- tst(scratch,
- Operand(Smi::FromInt(1 << SharedFunctionInfo::kBoundFunction)));
- b(ne, miss);
-
- // Make sure that the function has an instance prototype.
- ldrb(scratch, FieldMemOperand(result, Map::kBitFieldOffset));
- tst(scratch, Operand(1 << Map::kHasNonInstancePrototype));
- b(ne, &non_instance);
- }
-
+void MacroAssembler::TryGetFunctionPrototype(Register function, Register result,
+ Register scratch, Label* miss) {
// Get the prototype or initial map from the function.
ldr(result,
FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
@@ -2330,15 +2243,6 @@
// Get the prototype from the initial map.
ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
- if (miss_on_bound_function) {
- jmp(&done);
-
- // Non-instance prototype: Fetch prototype from constructor field
- // in initial map.
- bind(&non_instance);
- ldr(result, FieldMemOperand(result, Map::kConstructorOffset));
- }
-
// All done.
bind(&done);
}
@@ -2357,139 +2261,6 @@
}
-static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
- return ref0.address() - ref1.address();
-}
-
-
-void MacroAssembler::CallApiFunctionAndReturn(
- Register function_address,
- ExternalReference thunk_ref,
- int stack_space,
- MemOperand return_value_operand,
- MemOperand* context_restore_operand) {
- ExternalReference next_address =
- ExternalReference::handle_scope_next_address(isolate());
- const int kNextOffset = 0;
- const int kLimitOffset = AddressOffset(
- ExternalReference::handle_scope_limit_address(isolate()),
- next_address);
- const int kLevelOffset = AddressOffset(
- ExternalReference::handle_scope_level_address(isolate()),
- next_address);
-
- DCHECK(function_address.is(r1) || function_address.is(r2));
-
- Label profiler_disabled;
- Label end_profiler_check;
- mov(r9, Operand(ExternalReference::is_profiling_address(isolate())));
- ldrb(r9, MemOperand(r9, 0));
- cmp(r9, Operand(0));
- b(eq, &profiler_disabled);
-
- // Additional parameter is the address of the actual callback.
- mov(r3, Operand(thunk_ref));
- jmp(&end_profiler_check);
-
- bind(&profiler_disabled);
- Move(r3, function_address);
- bind(&end_profiler_check);
-
- // Allocate HandleScope in callee-save registers.
- mov(r9, Operand(next_address));
- ldr(r4, MemOperand(r9, kNextOffset));
- ldr(r5, MemOperand(r9, kLimitOffset));
- ldr(r6, MemOperand(r9, kLevelOffset));
- add(r6, r6, Operand(1));
- str(r6, MemOperand(r9, kLevelOffset));
-
- if (FLAG_log_timer_events) {
- FrameScope frame(this, StackFrame::MANUAL);
- PushSafepointRegisters();
- PrepareCallCFunction(1, r0);
- mov(r0, Operand(ExternalReference::isolate_address(isolate())));
- CallCFunction(ExternalReference::log_enter_external_function(isolate()), 1);
- PopSafepointRegisters();
- }
-
- // Native call returns to the DirectCEntry stub which redirects to the
- // return address pushed on stack (could have moved after GC).
- // DirectCEntry stub itself is generated early and never moves.
- DirectCEntryStub stub(isolate());
- stub.GenerateCall(this, r3);
-
- if (FLAG_log_timer_events) {
- FrameScope frame(this, StackFrame::MANUAL);
- PushSafepointRegisters();
- PrepareCallCFunction(1, r0);
- mov(r0, Operand(ExternalReference::isolate_address(isolate())));
- CallCFunction(ExternalReference::log_leave_external_function(isolate()), 1);
- PopSafepointRegisters();
- }
-
- Label promote_scheduled_exception;
- Label exception_handled;
- Label delete_allocated_handles;
- Label leave_exit_frame;
- Label return_value_loaded;
-
- // load value from ReturnValue
- ldr(r0, return_value_operand);
- bind(&return_value_loaded);
- // No more valid handles (the result handle was the last one). Restore
- // previous handle scope.
- str(r4, MemOperand(r9, kNextOffset));
- if (emit_debug_code()) {
- ldr(r1, MemOperand(r9, kLevelOffset));
- cmp(r1, r6);
- Check(eq, kUnexpectedLevelAfterReturnFromApiCall);
- }
- sub(r6, r6, Operand(1));
- str(r6, MemOperand(r9, kLevelOffset));
- ldr(ip, MemOperand(r9, kLimitOffset));
- cmp(r5, ip);
- b(ne, &delete_allocated_handles);
-
- // Check if the function scheduled an exception.
- bind(&leave_exit_frame);
- LoadRoot(r4, Heap::kTheHoleValueRootIndex);
- mov(ip, Operand(ExternalReference::scheduled_exception_address(isolate())));
- ldr(r5, MemOperand(ip));
- cmp(r4, r5);
- b(ne, &promote_scheduled_exception);
- bind(&exception_handled);
-
- bool restore_context = context_restore_operand != NULL;
- if (restore_context) {
- ldr(cp, *context_restore_operand);
- }
- // LeaveExitFrame expects unwind space to be in a register.
- mov(r4, Operand(stack_space));
- LeaveExitFrame(false, r4, !restore_context);
- mov(pc, lr);
-
- bind(&promote_scheduled_exception);
- {
- FrameScope frame(this, StackFrame::INTERNAL);
- CallExternalReference(
- ExternalReference(Runtime::kPromoteScheduledException, isolate()),
- 0);
- }
- jmp(&exception_handled);
-
- // HandleScope limit has changed. Delete allocated extensions.
- bind(&delete_allocated_handles);
- str(r5, MemOperand(r9, kLimitOffset));
- mov(r4, r0);
- PrepareCallCFunction(1, r5);
- mov(r0, Operand(ExternalReference::isolate_address(isolate())));
- CallCFunction(
- ExternalReference::delete_handle_scope_extensions(isolate()), 1);
- mov(r0, r4);
- jmp(&leave_exit_frame);
-}
-
-
bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
return has_frame_ || !stub->SometimesSetsUpAFrame();
}
@@ -2710,24 +2481,17 @@
}
-void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
- int num_arguments,
- int result_size) {
- // TODO(1236192): Most runtime routines don't need the number of
- // arguments passed in because it is constant. At some point we
- // should remove this need and make the runtime routine entry code
- // smarter.
- mov(r0, Operand(num_arguments));
- JumpToExternalReference(ext);
-}
-
-
-void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
- int num_arguments,
- int result_size) {
- TailCallExternalReference(ExternalReference(fid, isolate()),
- num_arguments,
- result_size);
+void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
+ const Runtime::Function* function = Runtime::FunctionForId(fid);
+ DCHECK_EQ(1, function->result_size);
+ if (function->nargs >= 0) {
+ // TODO(1236192): Most runtime routines don't need the number of
+ // arguments passed in because it is constant. At some point we
+ // should remove this need and make the runtime routine entry code
+ // smarter.
+ mov(r0, Operand(function->nargs));
+ }
+ JumpToExternalReference(ExternalReference(fid, isolate()));
}
@@ -2742,41 +2506,15 @@
}
-void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
- InvokeFlag flag,
+void MacroAssembler::InvokeBuiltin(int native_context_index, InvokeFlag flag,
const CallWrapper& call_wrapper) {
// You can't call a builtin without a valid frame.
DCHECK(flag == JUMP_FUNCTION || has_frame());
- GetBuiltinEntry(r2, id);
- if (flag == CALL_FUNCTION) {
- call_wrapper.BeforeCall(CallSize(r2));
- Call(r2);
- call_wrapper.AfterCall();
- } else {
- DCHECK(flag == JUMP_FUNCTION);
- Jump(r2);
- }
-}
-
-
-void MacroAssembler::GetBuiltinFunction(Register target,
- Builtins::JavaScript id) {
- // Load the builtins object into target register.
- ldr(target,
- MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
- ldr(target, FieldMemOperand(target, GlobalObject::kBuiltinsOffset));
- // Load the JavaScript builtin function from the builtins object.
- ldr(target, FieldMemOperand(target,
- JSBuiltinsObject::OffsetOfFunctionWithId(id)));
-}
-
-
-void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
- DCHECK(!target.is(r1));
- GetBuiltinFunction(r1, id);
- // Load the code entry point from the builtins object.
- ldr(target, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
+ // Fake a parameter count to avoid emitting code to do the check.
+ ParameterCount expected(0);
+ LoadNativeContextSlot(native_context_index, r1);
+ InvokeFunctionCode(r1, no_reg, expected, expected, flag, call_wrapper);
}
@@ -2916,37 +2654,24 @@
Register map_in_out,
Register scratch,
Label* no_map_match) {
- // Load the global or builtins object from the current context.
- ldr(scratch,
- MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
- ldr(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset));
+ DCHECK(IsFastElementsKind(expected_kind));
+ DCHECK(IsFastElementsKind(transitioned_kind));
// Check that the function's map is the same as the expected cached map.
- ldr(scratch,
- MemOperand(scratch,
- Context::SlotOffset(Context::JS_ARRAY_MAPS_INDEX)));
- size_t offset = expected_kind * kPointerSize +
- FixedArrayBase::kHeaderSize;
- ldr(ip, FieldMemOperand(scratch, offset));
+ ldr(scratch, NativeContextMemOperand());
+ ldr(ip, ContextMemOperand(scratch, Context::ArrayMapIndex(expected_kind)));
cmp(map_in_out, ip);
b(ne, no_map_match);
// Use the transitioned cached map.
- offset = transitioned_kind * kPointerSize +
- FixedArrayBase::kHeaderSize;
- ldr(map_in_out, FieldMemOperand(scratch, offset));
+ ldr(map_in_out,
+ ContextMemOperand(scratch, Context::ArrayMapIndex(transitioned_kind)));
}
-void MacroAssembler::LoadGlobalFunction(int index, Register function) {
- // Load the global or builtins object from the current context.
- ldr(function,
- MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
- // Load the native context from the global or builtins object.
- ldr(function, FieldMemOperand(function,
- GlobalObject::kNativeContextOffset));
- // Load the function from the native context.
- ldr(function, MemOperand(function, Context::SlotOffset(index)));
+void MacroAssembler::LoadNativeContextSlot(int index, Register dst) {
+ ldr(dst, NativeContextMemOperand());
+ ldr(dst, ContextMemOperand(dst, index));
}
@@ -3071,6 +2796,32 @@
}
+void MacroAssembler::AssertFunction(Register object) {
+ if (emit_debug_code()) {
+ STATIC_ASSERT(kSmiTag == 0);
+ tst(object, Operand(kSmiTagMask));
+ Check(ne, kOperandIsASmiAndNotAFunction);
+ push(object);
+ CompareObjectType(object, object, object, JS_FUNCTION_TYPE);
+ pop(object);
+ Check(eq, kOperandIsNotAFunction);
+ }
+}
+
+
+void MacroAssembler::AssertBoundFunction(Register object) {
+ if (emit_debug_code()) {
+ STATIC_ASSERT(kSmiTag == 0);
+ tst(object, Operand(kSmiTagMask));
+ Check(ne, kOperandIsASmiAndNotABoundFunction);
+ push(object);
+ CompareObjectType(object, object, object, JS_BOUND_FUNCTION_TYPE);
+ pop(object);
+ Check(eq, kOperandIsNotABoundFunction);
+ }
+}
+
+
void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
Register scratch) {
if (emit_debug_code()) {
@@ -3105,88 +2856,6 @@
}
-void MacroAssembler::LookupNumberStringCache(Register object,
- Register result,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- Label* not_found) {
- // Use of registers. Register result is used as a temporary.
- Register number_string_cache = result;
- Register mask = scratch3;
-
- // Load the number string cache.
- LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex);
-
- // Make the hash mask from the length of the number string cache. It
- // contains two elements (number and string) for each cache entry.
- ldr(mask, FieldMemOperand(number_string_cache, FixedArray::kLengthOffset));
- // Divide length by two (length is a smi).
- mov(mask, Operand(mask, ASR, kSmiTagSize + 1));
- sub(mask, mask, Operand(1)); // Make mask.
-
- // Calculate the entry in the number string cache. The hash value in the
- // number string cache for smis is just the smi value, and the hash for
- // doubles is the xor of the upper and lower words. See
- // Heap::GetNumberStringCache.
- Label is_smi;
- Label load_result_from_cache;
- JumpIfSmi(object, &is_smi);
- CheckMap(object,
- scratch1,
- Heap::kHeapNumberMapRootIndex,
- not_found,
- DONT_DO_SMI_CHECK);
-
- STATIC_ASSERT(8 == kDoubleSize);
- add(scratch1,
- object,
- Operand(HeapNumber::kValueOffset - kHeapObjectTag));
- ldm(ia, scratch1, scratch1.bit() | scratch2.bit());
- eor(scratch1, scratch1, Operand(scratch2));
- and_(scratch1, scratch1, Operand(mask));
-
- // Calculate address of entry in string cache: each entry consists
- // of two pointer sized fields.
- add(scratch1,
- number_string_cache,
- Operand(scratch1, LSL, kPointerSizeLog2 + 1));
-
- Register probe = mask;
- ldr(probe, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
- JumpIfSmi(probe, not_found);
- sub(scratch2, object, Operand(kHeapObjectTag));
- vldr(d0, scratch2, HeapNumber::kValueOffset);
- sub(probe, probe, Operand(kHeapObjectTag));
- vldr(d1, probe, HeapNumber::kValueOffset);
- VFPCompareAndSetFlags(d0, d1);
- b(ne, not_found); // The cache did not contain this value.
- b(&load_result_from_cache);
-
- bind(&is_smi);
- Register scratch = scratch1;
- and_(scratch, mask, Operand(object, ASR, 1));
- // Calculate address of entry in string cache: each entry consists
- // of two pointer sized fields.
- add(scratch,
- number_string_cache,
- Operand(scratch, LSL, kPointerSizeLog2 + 1));
-
- // Check if the entry is the smi we are looking for.
- ldr(probe, FieldMemOperand(scratch, FixedArray::kHeaderSize));
- cmp(object, probe);
- b(ne, not_found);
-
- // Get the result from the cache.
- bind(&load_result_from_cache);
- ldr(result, FieldMemOperand(scratch, FixedArray::kHeaderSize + kPointerSize));
- IncrementCounter(isolate()->counters()->number_to_string_native(),
- 1,
- scratch1,
- scratch2);
-}
-
-
void MacroAssembler::JumpIfNonSmisNotBothSequentialOneByteStrings(
Register first, Register second, Register scratch1, Register scratch2,
Label* failure) {
@@ -3267,27 +2936,25 @@
}
-// Copies a fixed number of fields of heap objects from src to dst.
-void MacroAssembler::CopyFields(Register dst,
- Register src,
- LowDwVfpRegister double_scratch,
- int field_count) {
- int double_count = field_count / (DwVfpRegister::kSizeInBytes / kPointerSize);
- for (int i = 0; i < double_count; i++) {
- vldr(double_scratch, FieldMemOperand(src, i * DwVfpRegister::kSizeInBytes));
- vstr(double_scratch, FieldMemOperand(dst, i * DwVfpRegister::kSizeInBytes));
- }
+void MacroAssembler::AllocateJSValue(Register result, Register constructor,
+ Register value, Register scratch1,
+ Register scratch2, Label* gc_required) {
+ DCHECK(!result.is(constructor));
+ DCHECK(!result.is(scratch1));
+ DCHECK(!result.is(scratch2));
+ DCHECK(!result.is(value));
- STATIC_ASSERT(SwVfpRegister::kSizeInBytes == kPointerSize);
- STATIC_ASSERT(2 * SwVfpRegister::kSizeInBytes == DwVfpRegister::kSizeInBytes);
+ // Allocate JSValue in new space.
+ Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required, TAG_OBJECT);
- int remain = field_count % (DwVfpRegister::kSizeInBytes / kPointerSize);
- if (remain != 0) {
- vldr(double_scratch.low(),
- FieldMemOperand(src, (field_count - 1) * kPointerSize));
- vstr(double_scratch.low(),
- FieldMemOperand(dst, (field_count - 1) * kPointerSize));
- }
+ // Initialize the JSValue.
+ LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2);
+ str(scratch1, FieldMemOperand(result, HeapObject::kMapOffset));
+ LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
+ str(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset));
+ str(scratch1, FieldMemOperand(result, JSObject::kElementsOffset));
+ str(value, FieldMemOperand(result, JSValue::kValueOffset));
+ STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
}
@@ -3344,16 +3011,16 @@
}
-void MacroAssembler::InitializeFieldsWithFiller(Register start_offset,
- Register end_offset,
+void MacroAssembler::InitializeFieldsWithFiller(Register current_address,
+ Register end_address,
Register filler) {
Label loop, entry;
b(&entry);
bind(&loop);
- str(filler, MemOperand(start_offset, kPointerSize, PostIndex));
+ str(filler, MemOperand(current_address, kPointerSize, PostIndex));
bind(&entry);
- cmp(start_offset, end_offset);
- b(lt, &loop);
+ cmp(current_address, end_address);
+ b(lo, &loop);
}
@@ -3581,76 +3248,7 @@
if (ActivationFrameAlignment() > kPointerSize) {
ldr(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
} else {
- add(sp, sp, Operand(stack_passed_arguments * sizeof(kPointerSize)));
- }
-}
-
-
-void MacroAssembler::GetRelocatedValueLocation(Register ldr_location,
- Register result,
- Register scratch) {
- Label small_constant_pool_load, load_result;
- ldr(result, MemOperand(ldr_location));
-
- if (FLAG_enable_ool_constant_pool) {
- // Check if this is an extended constant pool load.
- and_(scratch, result, Operand(GetConsantPoolLoadMask()));
- teq(scratch, Operand(GetConsantPoolLoadPattern()));
- b(eq, &small_constant_pool_load);
- if (emit_debug_code()) {
- // Check that the instruction sequence is:
- // movw reg, #offset_low
- // movt reg, #offset_high
- // ldr reg, [pp, reg]
- Instr patterns[] = {GetMovWPattern(), GetMovTPattern(),
- GetLdrPpRegOffsetPattern()};
- for (int i = 0; i < 3; i++) {
- ldr(result, MemOperand(ldr_location, i * kInstrSize));
- and_(result, result, Operand(patterns[i]));
- cmp(result, Operand(patterns[i]));
- Check(eq, kTheInstructionToPatchShouldBeALoadFromConstantPool);
- }
- // Result was clobbered. Restore it.
- ldr(result, MemOperand(ldr_location));
- }
-
- // Get the offset into the constant pool. First extract movw immediate into
- // result.
- and_(scratch, result, Operand(0xfff));
- mov(ip, Operand(result, LSR, 4));
- and_(ip, ip, Operand(0xf000));
- orr(result, scratch, Operand(ip));
- // Then extract movt immediate and or into result.
- ldr(scratch, MemOperand(ldr_location, kInstrSize));
- and_(ip, scratch, Operand(0xf0000));
- orr(result, result, Operand(ip, LSL, 12));
- and_(scratch, scratch, Operand(0xfff));
- orr(result, result, Operand(scratch, LSL, 16));
-
- b(&load_result);
- }
-
- bind(&small_constant_pool_load);
- if (emit_debug_code()) {
- // Check that the instruction is a ldr reg, [<pc or pp> + offset] .
- and_(result, result, Operand(GetConsantPoolLoadPattern()));
- cmp(result, Operand(GetConsantPoolLoadPattern()));
- Check(eq, kTheInstructionToPatchShouldBeALoadFromConstantPool);
- // Result was clobbered. Restore it.
- ldr(result, MemOperand(ldr_location));
- }
-
- // Get the offset into the constant pool.
- const uint32_t kLdrOffsetMask = (1 << 12) - 1;
- and_(result, result, Operand(kLdrOffsetMask));
-
- bind(&load_result);
- // Get the address of the constant.
- if (FLAG_enable_ool_constant_pool) {
- add(result, pp, Operand(result));
- } else {
- add(result, ldr_location, Operand(result));
- add(result, result, Operand(Instruction::kPCReadOffset));
+ add(sp, sp, Operand(stack_passed_arguments * kPointerSize));
}
}
@@ -3672,8 +3270,8 @@
Register scratch0,
Register scratch1,
Label* on_black) {
- HasColor(object, scratch0, scratch1, on_black, 1, 0); // kBlackBitPattern.
- DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0);
+ HasColor(object, scratch0, scratch1, on_black, 1, 1); // kBlackBitPattern.
+ DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
}
@@ -3706,27 +3304,6 @@
}
-// Detect some, but not all, common pointer-free objects. This is used by the
-// incremental write barrier which doesn't care about oddballs (they are always
-// marked black immediately so this code is not hit).
-void MacroAssembler::JumpIfDataObject(Register value,
- Register scratch,
- Label* not_data_object) {
- Label is_data_object;
- ldr(scratch, FieldMemOperand(value, HeapObject::kMapOffset));
- CompareRoot(scratch, Heap::kHeapNumberMapRootIndex);
- b(eq, &is_data_object);
- DCHECK(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1);
- DCHECK(kNotStringTag == 0x80 && kIsNotStringMask == 0x80);
- // If it's a string and it's not a cons string then it's an object containing
- // no GC pointers.
- ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
- tst(scratch, Operand(kIsIndirectStringMask | kIsNotStringMask));
- b(ne, not_data_object);
- bind(&is_data_object);
-}
-
-
void MacroAssembler::GetMarkBits(Register addr_reg,
Register bitmap_reg,
Register mask_reg) {
@@ -3741,96 +3318,23 @@
}
-void MacroAssembler::EnsureNotWhite(
- Register value,
- Register bitmap_scratch,
- Register mask_scratch,
- Register load_scratch,
- Label* value_is_white_and_not_data) {
+void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch,
+ Register mask_scratch, Register load_scratch,
+ Label* value_is_white) {
DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ip));
GetMarkBits(value, bitmap_scratch, mask_scratch);
// If the value is black or grey we don't need to do anything.
DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
- DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0);
- DCHECK(strcmp(Marking::kGreyBitPattern, "11") == 0);
+ DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
+ DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0);
DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
- Label done;
-
// Since both black and grey have a 1 in the first position and white does
// not have a 1 there we only need to check one bit.
ldr(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
tst(mask_scratch, load_scratch);
- b(ne, &done);
-
- if (emit_debug_code()) {
- // Check for impossible bit pattern.
- Label ok;
- // LSL may overflow, making the check conservative.
- tst(load_scratch, Operand(mask_scratch, LSL, 1));
- b(eq, &ok);
- stop("Impossible marking bit pattern");
- bind(&ok);
- }
-
- // Value is white. We check whether it is data that doesn't need scanning.
- // Currently only checks for HeapNumber and non-cons strings.
- Register map = load_scratch; // Holds map while checking type.
- Register length = load_scratch; // Holds length of object after testing type.
- Label is_data_object;
-
- // Check for heap-number
- ldr(map, FieldMemOperand(value, HeapObject::kMapOffset));
- CompareRoot(map, Heap::kHeapNumberMapRootIndex);
- mov(length, Operand(HeapNumber::kSize), LeaveCC, eq);
- b(eq, &is_data_object);
-
- // Check for strings.
- DCHECK(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1);
- DCHECK(kNotStringTag == 0x80 && kIsNotStringMask == 0x80);
- // If it's a string and it's not a cons string then it's an object containing
- // no GC pointers.
- Register instance_type = load_scratch;
- ldrb(instance_type, FieldMemOperand(map, Map::kInstanceTypeOffset));
- tst(instance_type, Operand(kIsIndirectStringMask | kIsNotStringMask));
- b(ne, value_is_white_and_not_data);
- // It's a non-indirect (non-cons and non-slice) string.
- // If it's external, the length is just ExternalString::kSize.
- // Otherwise it's String::kHeaderSize + string->length() * (1 or 2).
- // External strings are the only ones with the kExternalStringTag bit
- // set.
- DCHECK_EQ(0, kSeqStringTag & kExternalStringTag);
- DCHECK_EQ(0, kConsStringTag & kExternalStringTag);
- tst(instance_type, Operand(kExternalStringTag));
- mov(length, Operand(ExternalString::kSize), LeaveCC, ne);
- b(ne, &is_data_object);
-
- // Sequential string, either Latin1 or UC16.
- // For Latin1 (char-size of 1) we shift the smi tag away to get the length.
- // For UC16 (char-size of 2) we just leave the smi tag in place, thereby
- // getting the length multiplied by 2.
- DCHECK(kOneByteStringTag == 4 && kStringEncodingMask == 4);
- DCHECK(kSmiTag == 0 && kSmiTagSize == 1);
- ldr(ip, FieldMemOperand(value, String::kLengthOffset));
- tst(instance_type, Operand(kStringEncodingMask));
- mov(ip, Operand(ip, LSR, 1), LeaveCC, ne);
- add(length, ip, Operand(SeqString::kHeaderSize + kObjectAlignmentMask));
- and_(length, length, Operand(~kObjectAlignmentMask));
-
- bind(&is_data_object);
- // Value is a data object, and it is white. Mark it black. Since we know
- // that the object is white we can make it black by flipping one bit.
- ldr(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
- orr(ip, ip, Operand(mask_scratch));
- str(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
-
- and_(bitmap_scratch, bitmap_scratch, Operand(~Page::kPageAlignmentMask));
- ldr(ip, MemOperand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
- add(ip, ip, Operand(length));
- str(ip, MemOperand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
-
- bind(&done);
+ b(eq, value_is_white);
}
@@ -3879,6 +3383,19 @@
}
+void MacroAssembler::LoadAccessor(Register dst, Register holder,
+ int accessor_index,
+ AccessorComponent accessor) {
+ ldr(dst, FieldMemOperand(holder, HeapObject::kMapOffset));
+ LoadInstanceDescriptors(dst, dst);
+ ldr(dst,
+ FieldMemOperand(dst, DescriptorArray::GetValueOffset(accessor_index)));
+ int offset = accessor == ACCESSOR_GETTER ? AccessorPair::kGetterOffset
+ : AccessorPair::kSetterOffset;
+ ldr(dst, FieldMemOperand(dst, offset));
+}
+
+
void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) {
Register empty_fixed_array_value = r6;
LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
@@ -3959,8 +3476,11 @@
if (reg5.is_valid()) regs |= reg5.bit();
if (reg6.is_valid()) regs |= reg6.bit();
- for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
- Register candidate = Register::FromAllocationIndex(i);
+ const RegisterConfiguration* config =
+ RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT);
+ for (int i = 0; i < config->num_allocatable_general_registers(); ++i) {
+ int code = config->GetAllocatableGeneralCode(i);
+ Register candidate = Register::from_code(code);
if (regs & candidate.bit()) continue;
return candidate;
}
@@ -3975,23 +3495,35 @@
Register scratch1,
Label* found) {
DCHECK(!scratch1.is(scratch0));
- Factory* factory = isolate()->factory();
Register current = scratch0;
- Label loop_again;
+ Label loop_again, end;
// scratch contained elements pointer.
mov(current, object);
+ ldr(current, FieldMemOperand(current, HeapObject::kMapOffset));
+ ldr(current, FieldMemOperand(current, Map::kPrototypeOffset));
+ CompareRoot(current, Heap::kNullValueRootIndex);
+ b(eq, &end);
// Loop based on the map going up the prototype chain.
bind(&loop_again);
ldr(current, FieldMemOperand(current, HeapObject::kMapOffset));
+
+ STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE);
+ STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
+ ldrb(scratch1, FieldMemOperand(current, Map::kInstanceTypeOffset));
+ cmp(scratch1, Operand(JS_OBJECT_TYPE));
+ b(lo, found);
+
ldr(scratch1, FieldMemOperand(current, Map::kBitField2Offset));
DecodeField<Map::ElementsKindBits>(scratch1);
cmp(scratch1, Operand(DICTIONARY_ELEMENTS));
b(eq, found);
ldr(current, FieldMemOperand(current, Map::kPrototypeOffset));
- cmp(current, Operand(factory->null_value()));
+ CompareRoot(current, Heap::kNullValueRootIndex);
b(ne, &loop_again);
+
+ bind(&end);
}
@@ -4024,12 +3556,11 @@
#endif
-CodePatcher::CodePatcher(byte* address,
- int instructions,
+CodePatcher::CodePatcher(Isolate* isolate, byte* address, int instructions,
FlushICache flush_cache)
: address_(address),
size_(instructions * Assembler::kInstrSize),
- masm_(NULL, address, size_ + Assembler::kGap),
+ masm_(isolate, address, size_ + Assembler::kGap, CodeObjectRequired::kNo),
flush_cache_(flush_cache) {
// Create a new macro assembler pointing to the address of the code to patch.
// The size is adjusted with kGap on order for the assembler to generate size
@@ -4041,7 +3572,7 @@
CodePatcher::~CodePatcher() {
// Indicate that code has changed.
if (flush_cache_ == FLUSH) {
- CpuFeatures::FlushICache(address_, size_);
+ Assembler::FlushICache(masm_.isolate(), address_, size_);
}
// Check that the code was patched as expected.