Commit 5d2de78a authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Load immortal heap objects from the heap roots.

It's cheaper to materialize heap constants by loading from the roots
array instead of embedding the constant into the instruction stream, at
least on x64, arm and arm64.

Drive-by-fix: Also cleanup the materialize constant from frame
optimization.

R=dcarney@chromium.org

Review URL: https://codereview.chromium.org/1088913002

Cr-Commit-Position: refs/heads/master@{#27818}
parent 2ebb794b
......@@ -1018,17 +1018,12 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
break;
case Constant::kHeapObject: {
Handle<HeapObject> src_object = src.ToHeapObject();
if (info()->IsOptimizing() &&
src_object.is_identical_to(info()->context())) {
// Loading the context from the frame is way cheaper than
// materializing the actual context heap object address.
__ ldr(dst, MemOperand(fp, StandardFrameConstants::kContextOffset));
} else if (info()->IsOptimizing() &&
src_object.is_identical_to(info()->closure())) {
// Loading the JSFunction from the frame is way cheaper than
// materializing the actual JSFunction heap object address.
__ ldr(dst,
MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
Heap::RootListIndex index;
int offset;
if (IsMaterializableFromFrame(src_object, &offset)) {
__ ldr(dst, MemOperand(fp, offset));
} else if (IsMaterializableFromRoot(src_object, &index)) {
__ LoadRoot(dst, index);
} else {
__ Move(dst, src_object);
}
......
......@@ -1128,17 +1128,12 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
: scope.AcquireX();
if (src.type() == Constant::kHeapObject) {
Handle<HeapObject> src_object = src.ToHeapObject();
if (info()->IsOptimizing() &&
src_object.is_identical_to(info()->context())) {
// Loading the context from the frame is way cheaper than
// materializing the actual context heap object address.
__ Ldr(dst, MemOperand(fp, StandardFrameConstants::kContextOffset));
} else if (info()->IsOptimizing() &&
src_object.is_identical_to(info()->closure())) {
// Loading the JSFunction from the frame is way cheaper than
// materializing the actual JSFunction heap object address.
__ Ldr(dst,
MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
Heap::RootListIndex index;
int offset;
if (IsMaterializableFromFrame(src_object, &offset)) {
__ Ldr(dst, MemOperand(fp, offset));
} else if (IsMaterializableFromRoot(src_object, &index)) {
__ LoadRoot(dst, index);
} else {
__ LoadObject(dst, src_object);
}
......
......@@ -184,6 +184,36 @@ void CodeGenerator::RecordSafepoint(ReferenceMap* references,
}
bool CodeGenerator::IsMaterializableFromFrame(Handle<HeapObject> object,
int* offset_return) {
if (linkage()->GetIncomingDescriptor()->IsJSFunctionCall()) {
if (object.is_identical_to(info()->context())) {
*offset_return = StandardFrameConstants::kContextOffset;
return true;
} else if (object.is_identical_to(info()->closure())) {
*offset_return = JavaScriptFrameConstants::kFunctionOffset;
return true;
}
}
return false;
}
bool CodeGenerator::IsMaterializableFromRoot(
Handle<HeapObject> object, Heap::RootListIndex* index_return) {
if (linkage()->GetIncomingDescriptor()->IsJSFunctionCall()) {
#define IMMORTAL_IMMOVABLE_ROOT(Name) \
if (*object == isolate()->heap()->root(Heap::k##Name##RootIndex)) { \
*index_return = Heap::k##Name##RootIndex; \
return true; \
}
IMMORTAL_IMMOVABLE_ROOT_LIST(IMMORTAL_IMMOVABLE_ROOT)
#undef IMMORTAL_IMMOVABLE_ROOT
}
return false;
}
void CodeGenerator::AssembleInstruction(Instruction* instr) {
AssembleGaps(instr);
AssembleSourcePosition(instr);
......
......@@ -58,6 +58,15 @@ class CodeGenerator FINAL : public GapResolver::Assembler {
void RecordSafepoint(ReferenceMap* references, Safepoint::Kind kind,
int arguments, Safepoint::DeoptMode deopt_mode);
// Check if a heap object can be materialized by loading from the frame, which
// is usually way cheaper than materializing the actual heap object constant.
bool IsMaterializableFromFrame(Handle<HeapObject> object, int* offset_return);
// Check if a heap object can be materialized by loading from a heap root,
// which is cheaper on some platforms than materializing the actual heap
// object constant.
bool IsMaterializableFromRoot(Handle<HeapObject> object,
Heap::RootListIndex* index_return);
// Assemble code for the specified instruction.
void AssembleInstruction(Instruction* instr);
void AssembleSourcePosition(Instruction* instr);
......
......@@ -1309,29 +1309,15 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
Constant src_constant = g.ToConstant(source);
if (src_constant.type() == Constant::kHeapObject) {
Handle<HeapObject> src = src_constant.ToHeapObject();
if (info()->IsOptimizing() && src.is_identical_to(info()->context())) {
// Loading the context from the frame is way cheaper than materializing
// the actual context heap object address.
int offset;
if (IsMaterializableFromFrame(src, &offset)) {
if (destination->IsRegister()) {
Register dst = g.ToRegister(destination);
__ mov(dst, Operand(ebp, StandardFrameConstants::kContextOffset));
__ mov(dst, Operand(ebp, offset));
} else {
DCHECK(destination->IsStackSlot());
Operand dst = g.ToOperand(destination);
__ push(Operand(ebp, StandardFrameConstants::kContextOffset));
__ pop(dst);
}
} else if (info()->IsOptimizing() &&
src.is_identical_to(info()->closure())) {
// Loading the JSFunction from the frame is way cheaper than
// materializing the actual JSFunction heap object address.
if (destination->IsRegister()) {
Register dst = g.ToRegister(destination);
__ mov(dst, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
} else {
DCHECK(destination->IsStackSlot());
Operand dst = g.ToOperand(destination);
__ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ push(Operand(ebp, offset));
__ pop(dst);
}
} else if (destination->IsRegister()) {
......
......@@ -1531,17 +1531,12 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
break;
case Constant::kHeapObject: {
Handle<HeapObject> src_object = src.ToHeapObject();
if (info()->IsOptimizing() &&
src_object.is_identical_to(info()->context())) {
// Loading the context from the frame is way cheaper than
// materializing the actual context heap object address.
__ movp(dst, Operand(rbp, StandardFrameConstants::kContextOffset));
} else if (info()->IsOptimizing() &&
src_object.is_identical_to(info()->closure())) {
// Loading the JSFunction from the frame is way cheaper than
// materializing the actual JSFunction heap object address.
__ movp(dst,
Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
Heap::RootListIndex index;
int offset;
if (IsMaterializableFromFrame(src_object, &offset)) {
__ movp(dst, Operand(rbp, offset));
} else if (IsMaterializableFromRoot(src_object, &index)) {
__ LoadRoot(dst, index);
} else {
__ Move(dst, src_object);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment