X87: Encapsulate megamorphic load/tail-call in hydrogen

port r23772.

original commit message:

  To aid vector-based load ic work, we need to be able to handle
  the megamorphic load case in hydrogen. A simple approach is to
  wrap the probe activity in a hydrogen instruction.

  The instruction is novel in that it always tail-calls away.

BUG=
R=weiliang.lin@intel.com

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

Patch from Jing Bao <jing.bao@intel.com>.

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23889 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 52eadef7
......@@ -825,24 +825,6 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
}
void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
// The return address is on the stack.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
DCHECK(receiver.is(edx));
DCHECK(name.is(ecx));
// Probe the stub cache.
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
Code::ComputeHandlerFlags(Code::LOAD_IC));
masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, ebx,
eax);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
}
void LoadIC::GenerateNormal(MacroAssembler* masm) {
Register dictionary = eax;
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
......@@ -923,7 +905,7 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
Code::ComputeHandlerFlags(Code::STORE_IC));
masm->isolate()->stub_cache()->GenerateProbe(
masm, flags, StoreDescriptor::ReceiverRegister(),
masm, flags, false, StoreDescriptor::ReceiverRegister(),
StoreDescriptor::NameRegister(), ebx, no_reg);
// Cache miss: Jump to runtime.
......
......@@ -16,8 +16,8 @@ namespace internal {
static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
Code::Flags flags, StubCache::Table table, Register name,
Register receiver,
Code::Flags flags, bool leave_frame,
StubCache::Table table, Register name, Register receiver,
// Number of the cache entry pointer-size scaled.
Register offset, Register extra) {
ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
......@@ -56,6 +56,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
}
#endif
if (leave_frame) __ leave();
// Jump to the first instruction in the code stub.
__ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ jmp(extra);
......@@ -98,6 +100,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
__ pop(offset);
__ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
if (leave_frame) __ leave();
// Jump to the first instruction in the code stub.
__ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ jmp(offset);
......@@ -110,9 +114,9 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
Register receiver, Register name,
Register scratch, Register extra, Register extra2,
Register extra3) {
bool leave_frame, Register receiver,
Register name, Register scratch, Register extra,
Register extra2, Register extra3) {
Label miss;
// Assert that code is valid. The multiplying code relies on the entry size
......@@ -155,7 +159,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
DCHECK(kCacheIndexShift == kPointerSizeLog2);
// Probe the primary table.
ProbeTable(isolate(), masm, flags, kPrimary, name, receiver, offset, extra);
ProbeTable(isolate(), masm, flags, leave_frame, kPrimary, name, receiver,
offset, extra);
// Primary miss: Compute hash for secondary probe.
__ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
......@@ -167,7 +172,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
__ and_(offset, (kSecondaryTableSize - 1) << kCacheIndexShift);
// Probe the secondary table.
ProbeTable(isolate(), masm, flags, kSecondary, name, receiver, offset, extra);
ProbeTable(isolate(), masm, flags, leave_frame, kSecondary, name, receiver,
offset, extra);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.
......
......@@ -11,6 +11,7 @@
#include "src/codegen.h"
#include "src/deoptimizer.h"
#include "src/hydrogen-osr.h"
#include "src/ic/stub-cache.h"
#include "src/x87/lithium-codegen-x87.h"
namespace v8 {
......@@ -3277,11 +3278,9 @@ void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
// Load the result.
__ mov(result,
BuildFastArrayOperand(instr->elements(),
instr->key(),
BuildFastArrayOperand(instr->elements(), instr->key(),
instr->hydrogen()->key()->representation(),
FAST_ELEMENTS,
instr->base_offset()));
FAST_ELEMENTS, instr->base_offset()));
// Check for the hole value.
if (instr->hydrogen()->RequiresHoleCheck()) {
......@@ -3577,6 +3576,32 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
}
void LCodeGen::DoTailCallThroughMegamorphicCache(
LTailCallThroughMegamorphicCache* instr) {
Register receiver = ToRegister(instr->receiver());
Register name = ToRegister(instr->name());
DCHECK(receiver.is(LoadDescriptor::ReceiverRegister()));
DCHECK(name.is(LoadDescriptor::NameRegister()));
Register scratch = ebx;
Register extra = eax;
DCHECK(!scratch.is(receiver) && !scratch.is(name));
DCHECK(!extra.is(receiver) && !extra.is(name));
// Important for the tail-call.
bool must_teardown_frame = NeedsEagerFrame();
// The probe will tail call to a handler if found.
isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
must_teardown_frame, receiver, name,
scratch, extra);
// Tail call to miss if we ended up here.
if (must_teardown_frame) __ leave();
LoadIC::GenerateMiss(masm());
}
void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
DCHECK(ToRegister(instr->result()).is(eax));
......
......@@ -1135,6 +1135,19 @@ LInstruction* LChunkBuilder::DoCallWithDescriptor(
}
LInstruction* LChunkBuilder::DoTailCallThroughMegamorphicCache(
HTailCallThroughMegamorphicCache* instr) {
LOperand* context = UseFixed(instr->context(), esi);
LOperand* receiver_register =
UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
LOperand* name_register =
UseFixed(instr->name(), LoadDescriptor::NameRegister());
// Not marked as call. It can't deoptimize, and it never returns.
return new (zone()) LTailCallThroughMegamorphicCache(
context, receiver_register, name_register);
}
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
LOperand* context = UseFixed(instr->context(), esi);
LOperand* function = UseFixed(instr->function(), edi);
......
This diff is collapsed.
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