Use weak cells in map checks in polymorphic ICs.
BUG=v8:3663 LOG=N Review URL: https://codereview.chromium.org/753993003 Cr-Commit-Position: refs/heads/master@{#25581}
This commit is contained in:
parent
91ec654bf9
commit
45a36948e1
@ -2269,6 +2269,22 @@ void MacroAssembler::DispatchMap(Register obj,
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
|
||||
Register scratch) {
|
||||
mov(scratch, Operand(cell));
|
||||
ldr(scratch, FieldMemOperand(scratch, WeakCell::kValueOffset));
|
||||
cmp(value, scratch);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
|
||||
Label* miss) {
|
||||
mov(value, Operand(cell));
|
||||
ldr(value, FieldMemOperand(value, WeakCell::kValueOffset));
|
||||
JumpIfSmi(value, miss);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::TryGetFunctionPrototype(Register function,
|
||||
Register result,
|
||||
Register scratch,
|
||||
|
@ -927,6 +927,12 @@ class MacroAssembler: public Assembler {
|
||||
Handle<Code> success,
|
||||
SmiCheckType smi_check_type);
|
||||
|
||||
// Compare the given value and the value of weak cell.
|
||||
void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch);
|
||||
|
||||
// Load the value of the weak cell in the value register. Branch to the given
|
||||
// miss label if the weak cell was cleared.
|
||||
void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
|
||||
|
||||
// Compare the object in a register to a value from the root list.
|
||||
// Uses the ip register as scratch.
|
||||
|
@ -5019,7 +5019,6 @@ void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
|
||||
Register scratch2 = x6;
|
||||
DCHECK(instr->IsMarkedAsCall());
|
||||
|
||||
ASM_UNIMPLEMENTED_BREAK("DoDeclareGlobals");
|
||||
// TODO(all): if Mov could handle object in new space then it could be used
|
||||
// here.
|
||||
__ LoadHeapObject(scratch1, instr->hydrogen()->pairs());
|
||||
|
@ -3805,6 +3805,22 @@ void MacroAssembler::DispatchMap(Register obj,
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
|
||||
Register scratch) {
|
||||
Mov(scratch, Operand(cell));
|
||||
Ldr(scratch, FieldMemOperand(scratch, WeakCell::kValueOffset));
|
||||
Cmp(value, scratch);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
|
||||
Label* miss) {
|
||||
Mov(value, Operand(cell));
|
||||
Ldr(value, FieldMemOperand(value, WeakCell::kValueOffset));
|
||||
JumpIfSmi(value, miss);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::TestMapBitfield(Register object, uint64_t mask) {
|
||||
UseScratchRegisterScope temps(this);
|
||||
Register temp = temps.AcquireX();
|
||||
|
@ -1487,6 +1487,13 @@ class MacroAssembler : public Assembler {
|
||||
Handle<Code> success,
|
||||
SmiCheckType smi_check_type);
|
||||
|
||||
// Compare the given value and the value of weak cell.
|
||||
void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch);
|
||||
|
||||
// Load the value of the weak cell in the value register. Branch to the given
|
||||
// miss label if the weak cell was cleared.
|
||||
void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
|
||||
|
||||
// Test the bitfield of the heap object map with mask and set the condition
|
||||
// flags. The object register is preserved.
|
||||
void TestMapBitfield(Register object, uint64_t mask);
|
||||
|
@ -802,6 +802,7 @@ Handle<CodeCache> Factory::NewCodeCache() {
|
||||
Handle<CodeCache>::cast(NewStruct(CODE_CACHE_TYPE));
|
||||
code_cache->set_default_cache(*empty_fixed_array(), SKIP_WRITE_BARRIER);
|
||||
code_cache->set_normal_type_cache(*undefined_value(), SKIP_WRITE_BARRIER);
|
||||
code_cache->set_weak_cell_cache(*undefined_value(), SKIP_WRITE_BARRIER);
|
||||
return code_cache;
|
||||
}
|
||||
|
||||
|
@ -263,9 +263,7 @@ void StaticMarkingVisitor<StaticVisitor>::VisitCodeTarget(Heap* heap,
|
||||
// to be serialized.
|
||||
if (FLAG_cleanup_code_caches_at_gc && target->is_inline_cache_stub() &&
|
||||
!target->is_call_stub() &&
|
||||
(target->ic_state() == MEGAMORPHIC || target->ic_state() == GENERIC ||
|
||||
target->ic_state() == POLYMORPHIC ||
|
||||
(heap->flush_monomorphic_ics() && !target->is_weak_stub()) ||
|
||||
((heap->flush_monomorphic_ics() && !target->is_weak_stub()) ||
|
||||
heap->isolate()->serializer_enabled() ||
|
||||
target->ic_age() != heap->global_ic_age() ||
|
||||
target->is_invalidated_weak_stub())) {
|
||||
|
@ -2580,6 +2580,21 @@ void MacroAssembler::PushHeapObject(Handle<HeapObject> object) {
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
|
||||
Register scratch) {
|
||||
mov(scratch, cell);
|
||||
cmp(value, FieldOperand(scratch, WeakCell::kValueOffset));
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
|
||||
Label* miss) {
|
||||
mov(value, cell);
|
||||
mov(value, FieldOperand(value, WeakCell::kValueOffset));
|
||||
JumpIfSmi(value, miss);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::Ret() {
|
||||
ret(0);
|
||||
}
|
||||
|
@ -299,6 +299,13 @@ class MacroAssembler: public Assembler {
|
||||
}
|
||||
}
|
||||
|
||||
// Compare the given value and the value of weak cell.
|
||||
void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch);
|
||||
|
||||
// Load the value of the weak cell in the value register. Branch to the given
|
||||
// miss label if the weak cell was cleared.
|
||||
void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// JavaScript invokes
|
||||
|
||||
|
@ -72,8 +72,8 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
Handle<Map> map = IC::TypeToMap(*type, isolate());
|
||||
if (!map->is_deprecated()) {
|
||||
number_of_handled_maps++;
|
||||
__ mov(ip, Operand(map));
|
||||
__ cmp(map_reg, ip);
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(map);
|
||||
__ CmpWeakValue(map_reg, cell, scratch2());
|
||||
if (type->Is(HeapType::Number())) {
|
||||
DCHECK(!number_case.is_unused());
|
||||
__ bind(&number_case);
|
||||
@ -100,16 +100,18 @@ Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
|
||||
__ JumpIfSmi(receiver(), &miss);
|
||||
|
||||
int receiver_count = receiver_maps->length();
|
||||
__ ldr(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
|
||||
Register map_reg = scratch1();
|
||||
__ ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
|
||||
for (int i = 0; i < receiver_count; ++i) {
|
||||
__ mov(ip, Operand(receiver_maps->at(i)));
|
||||
__ cmp(scratch1(), ip);
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(receiver_maps->at(i));
|
||||
__ CmpWeakValue(map_reg, cell, scratch2());
|
||||
if (transitioned_maps->at(i).is_null()) {
|
||||
__ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq);
|
||||
} else {
|
||||
Label next_map;
|
||||
__ b(ne, &next_map);
|
||||
__ mov(transition_map(), Operand(transitioned_maps->at(i)));
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(transitioned_maps->at(i));
|
||||
__ LoadWeakValue(transition_map(), cell, &miss);
|
||||
__ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, al);
|
||||
__ bind(&next_map);
|
||||
}
|
||||
|
@ -71,8 +71,9 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
Handle<Map> map = IC::TypeToMap(*type, isolate());
|
||||
if (!map->is_deprecated()) {
|
||||
number_of_handled_maps++;
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(map);
|
||||
__ CmpWeakValue(map_reg, cell, scratch2());
|
||||
Label try_next;
|
||||
__ Cmp(map_reg, Operand(map));
|
||||
__ B(ne, &try_next);
|
||||
if (type->Is(HeapType::Number())) {
|
||||
DCHECK(!number_case.is_unused());
|
||||
@ -104,16 +105,18 @@ Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
|
||||
__ JumpIfSmi(receiver(), &miss);
|
||||
|
||||
int receiver_count = receiver_maps->length();
|
||||
__ Ldr(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
|
||||
Register map_reg = scratch1();
|
||||
__ Ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
|
||||
for (int i = 0; i < receiver_count; i++) {
|
||||
__ Cmp(scratch1(), Operand(receiver_maps->at(i)));
|
||||
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(receiver_maps->at(i));
|
||||
__ CmpWeakValue(map_reg, cell, scratch2());
|
||||
Label skip;
|
||||
__ B(&skip, ne);
|
||||
if (!transitioned_maps->at(i).is_null()) {
|
||||
// This argument is used by the handler stub. For example, see
|
||||
// ElementsTransitionGenerator::GenerateMapChangeElementsTransition.
|
||||
__ Mov(transition_map(), Operand(transitioned_maps->at(i)));
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(transitioned_maps->at(i));
|
||||
__ LoadWeakValue(transition_map(), cell, &miss);
|
||||
}
|
||||
__ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
|
||||
__ Bind(&skip);
|
||||
|
@ -75,7 +75,8 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
Handle<Map> map = IC::TypeToMap(*type, isolate());
|
||||
if (!map->is_deprecated()) {
|
||||
number_of_handled_maps++;
|
||||
__ cmp(map_reg, map);
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(map);
|
||||
__ CmpWeakValue(map_reg, cell, scratch2());
|
||||
if (type->Is(HeapType::Number())) {
|
||||
DCHECK(!number_case.is_unused());
|
||||
__ bind(&number_case);
|
||||
@ -99,16 +100,19 @@ Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
|
||||
MapHandleList* receiver_maps, CodeHandleList* handler_stubs,
|
||||
MapHandleList* transitioned_maps) {
|
||||
Label miss;
|
||||
__ JumpIfSmi(receiver(), &miss, Label::kNear);
|
||||
__ mov(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset));
|
||||
__ JumpIfSmi(receiver(), &miss);
|
||||
Register map_reg = scratch1();
|
||||
__ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
|
||||
for (int i = 0; i < receiver_maps->length(); ++i) {
|
||||
__ cmp(scratch1(), receiver_maps->at(i));
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(receiver_maps->at(i));
|
||||
__ CmpWeakValue(map_reg, cell, scratch2());
|
||||
if (transitioned_maps->at(i).is_null()) {
|
||||
__ j(equal, handler_stubs->at(i));
|
||||
} else {
|
||||
Label next_map;
|
||||
__ j(not_equal, &next_map, Label::kNear);
|
||||
__ mov(transition_map(), Immediate(transitioned_maps->at(i)));
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(transitioned_maps->at(i));
|
||||
__ LoadWeakValue(transition_map(), cell, &miss);
|
||||
__ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
|
||||
__ bind(&next_map);
|
||||
}
|
||||
|
@ -57,7 +57,8 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
number_of_handled_maps++;
|
||||
// Check map and tail call if there's a match.
|
||||
// Separate compare from branch, to provide path for above JumpIfSmi().
|
||||
__ Subu(match, map_reg, Operand(map));
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(map);
|
||||
__ CmpWeakValue(match, map_reg, cell);
|
||||
if (type->Is(HeapType::Number())) {
|
||||
DCHECK(!number_case.is_unused());
|
||||
__ bind(&number_case);
|
||||
@ -85,15 +86,20 @@ Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
|
||||
__ JumpIfSmi(receiver(), &miss);
|
||||
|
||||
int receiver_count = receiver_maps->length();
|
||||
__ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
|
||||
Register map_reg = scratch1();
|
||||
Register match = scratch2();
|
||||
__ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
|
||||
for (int i = 0; i < receiver_count; ++i) {
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(receiver_maps->at(i));
|
||||
__ CmpWeakValue(match, map_reg, cell);
|
||||
if (transitioned_maps->at(i).is_null()) {
|
||||
__ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq, scratch1(),
|
||||
Operand(receiver_maps->at(i)));
|
||||
__ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq, match,
|
||||
Operand(zero_reg));
|
||||
} else {
|
||||
Label next_map;
|
||||
__ Branch(&next_map, ne, scratch1(), Operand(receiver_maps->at(i)));
|
||||
__ li(transition_map(), Operand(transitioned_maps->at(i)));
|
||||
__ Branch(&next_map, ne, match, Operand(zero_reg));
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(transitioned_maps->at(i));
|
||||
__ LoadWeakValue(transition_map(), cell, &miss);
|
||||
__ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
|
||||
__ bind(&next_map);
|
||||
}
|
||||
|
@ -57,7 +57,8 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
number_of_handled_maps++;
|
||||
// Check map and tail call if there's a match.
|
||||
// Separate compare from branch, to provide path for above JumpIfSmi().
|
||||
__ Dsubu(match, map_reg, Operand(map));
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(map);
|
||||
__ CmpWeakValue(match, map_reg, cell);
|
||||
if (type->Is(HeapType::Number())) {
|
||||
DCHECK(!number_case.is_unused());
|
||||
__ bind(&number_case);
|
||||
@ -85,15 +86,20 @@ Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
|
||||
__ JumpIfSmi(receiver(), &miss);
|
||||
|
||||
int receiver_count = receiver_maps->length();
|
||||
__ ld(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
|
||||
Register map_reg = scratch1();
|
||||
Register match = scratch2();
|
||||
__ ld(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
|
||||
for (int i = 0; i < receiver_count; ++i) {
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(receiver_maps->at(i));
|
||||
__ CmpWeakValue(match, map_reg, cell);
|
||||
if (transitioned_maps->at(i).is_null()) {
|
||||
__ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq, scratch1(),
|
||||
Operand(receiver_maps->at(i)));
|
||||
__ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq, match,
|
||||
Operand(zero_reg));
|
||||
} else {
|
||||
Label next_map;
|
||||
__ Branch(&next_map, ne, scratch1(), Operand(receiver_maps->at(i)));
|
||||
__ li(transition_map(), Operand(transitioned_maps->at(i)));
|
||||
__ Branch(&next_map, ne, match, Operand(zero_reg));
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(transitioned_maps->at(i));
|
||||
__ LoadWeakValue(transition_map(), cell, &miss);
|
||||
__ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
|
||||
__ bind(&next_map);
|
||||
}
|
||||
|
@ -42,20 +42,22 @@ Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
|
||||
MapHandleList* receiver_maps, CodeHandleList* handler_stubs,
|
||||
MapHandleList* transitioned_maps) {
|
||||
Label miss;
|
||||
__ JumpIfSmi(receiver(), &miss, Label::kNear);
|
||||
__ JumpIfSmi(receiver(), &miss);
|
||||
|
||||
__ movp(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset));
|
||||
Register map_reg = scratch1();
|
||||
__ movp(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
|
||||
int receiver_count = receiver_maps->length();
|
||||
for (int i = 0; i < receiver_count; ++i) {
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(receiver_maps->at(i));
|
||||
// Check map and tail call if there's a match
|
||||
__ Cmp(scratch1(), receiver_maps->at(i));
|
||||
__ CmpWeakValue(map_reg, cell, scratch2());
|
||||
if (transitioned_maps->at(i).is_null()) {
|
||||
__ j(equal, handler_stubs->at(i), RelocInfo::CODE_TARGET);
|
||||
} else {
|
||||
Label next_map;
|
||||
__ j(not_equal, &next_map, Label::kNear);
|
||||
__ Move(transition_map(), transitioned_maps->at(i),
|
||||
RelocInfo::EMBEDDED_OBJECT);
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(transitioned_maps->at(i));
|
||||
__ LoadWeakValue(transition_map(), cell, &miss);
|
||||
__ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
|
||||
__ bind(&next_map);
|
||||
}
|
||||
@ -109,8 +111,9 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
Handle<Map> map = IC::TypeToMap(*type, isolate());
|
||||
if (!map->is_deprecated()) {
|
||||
number_of_handled_maps++;
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(map);
|
||||
// Check map and tail call if there's a match
|
||||
__ Cmp(map_reg, map);
|
||||
__ CmpWeakValue(map_reg, cell, scratch2());
|
||||
if (type->Is(HeapType::Number())) {
|
||||
DCHECK(!number_case.is_unused());
|
||||
__ bind(&number_case);
|
||||
|
@ -75,7 +75,8 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
Handle<Map> map = IC::TypeToMap(*type, isolate());
|
||||
if (!map->is_deprecated()) {
|
||||
number_of_handled_maps++;
|
||||
__ cmp(map_reg, map);
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(map);
|
||||
__ CmpWeakValue(map_reg, cell, scratch2());
|
||||
if (type->Is(HeapType::Number())) {
|
||||
DCHECK(!number_case.is_unused());
|
||||
__ bind(&number_case);
|
||||
@ -100,15 +101,18 @@ Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
|
||||
MapHandleList* transitioned_maps) {
|
||||
Label miss;
|
||||
__ JumpIfSmi(receiver(), &miss, Label::kNear);
|
||||
__ mov(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset));
|
||||
Register map_reg = scratch1();
|
||||
__ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
|
||||
for (int i = 0; i < receiver_maps->length(); ++i) {
|
||||
__ cmp(scratch1(), receiver_maps->at(i));
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(receiver_maps->at(i));
|
||||
__ CmpWeakValue(map_reg, cell, scratch2());
|
||||
if (transitioned_maps->at(i).is_null()) {
|
||||
__ j(equal, handler_stubs->at(i));
|
||||
} else {
|
||||
Label next_map;
|
||||
__ j(not_equal, &next_map, Label::kNear);
|
||||
__ mov(transition_map(), Immediate(transitioned_maps->at(i)));
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(transitioned_maps->at(i));
|
||||
__ LoadWeakValue(transition_map(), cell, &miss);
|
||||
__ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
|
||||
__ bind(&next_map);
|
||||
}
|
||||
|
@ -4021,6 +4021,22 @@ void MacroAssembler::CheckMap(Register obj,
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::CmpWeakValue(Register match, Register value,
|
||||
Handle<WeakCell> cell) {
|
||||
li(match, Operand(cell));
|
||||
lw(match, FieldMemOperand(match, WeakCell::kValueOffset));
|
||||
Subu(match, value, match);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
|
||||
Label* miss) {
|
||||
li(value, Operand(cell));
|
||||
lw(value, FieldMemOperand(value, WeakCell::kValueOffset));
|
||||
JumpIfNotSmi(value, miss);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::MovFromFloatResult(DoubleRegister dst) {
|
||||
if (IsMipsSoftFloatABI) {
|
||||
if (kArchEndian == kLittle) {
|
||||
|
@ -1091,6 +1091,13 @@ class MacroAssembler: public Assembler {
|
||||
Handle<Code> success,
|
||||
SmiCheckType smi_check_type);
|
||||
|
||||
// Compare the given value and the value of the weak cell. Write the result
|
||||
// to the match register.
|
||||
void CmpWeakValue(Register match, Register value, Handle<WeakCell> cell);
|
||||
|
||||
// Load the value of the weak cell in the value register. Branch to the
|
||||
// given miss label is the weak cell was cleared.
|
||||
void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
|
||||
|
||||
// Load and check the instance type of an object for being a string.
|
||||
// Loads the type into the second argument register.
|
||||
|
@ -3988,6 +3988,22 @@ void MacroAssembler::CheckMap(Register obj,
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::CmpWeakValue(Register match, Register value,
|
||||
Handle<WeakCell> cell) {
|
||||
li(match, Operand(cell));
|
||||
ld(match, FieldMemOperand(match, WeakCell::kValueOffset));
|
||||
Dsubu(match, value, match);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
|
||||
Label* miss) {
|
||||
li(value, Operand(cell));
|
||||
ld(value, FieldMemOperand(value, WeakCell::kValueOffset));
|
||||
JumpIfNotSmi(value, miss);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::MovFromFloatResult(const DoubleRegister dst) {
|
||||
if (IsMipsSoftFloatABI) {
|
||||
Move(dst, v0, v1);
|
||||
|
@ -1121,6 +1121,13 @@ class MacroAssembler: public Assembler {
|
||||
Handle<Code> success,
|
||||
SmiCheckType smi_check_type);
|
||||
|
||||
// Compare the given value and the value of the weak cell. Write the result
|
||||
// to the match register.
|
||||
void CmpWeakValue(Register match, Register value, Handle<WeakCell> cell);
|
||||
|
||||
// Load the value of the weak cell in the value register. Branch to the
|
||||
// given miss label is the weak cell was cleared.
|
||||
void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
|
||||
|
||||
// Load and check the instance type of an object for being a string.
|
||||
// Loads the type into the second argument register.
|
||||
|
@ -5816,6 +5816,7 @@ BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_default_constructor,
|
||||
|
||||
ACCESSORS(CodeCache, default_cache, FixedArray, kDefaultCacheOffset)
|
||||
ACCESSORS(CodeCache, normal_type_cache, Object, kNormalTypeCacheOffset)
|
||||
ACCESSORS(CodeCache, weak_cell_cache, Object, kWeakCellCacheOffset)
|
||||
|
||||
ACCESSORS(PolymorphicCodeCache, cache, Object, kCacheOffset)
|
||||
|
||||
|
@ -847,6 +847,11 @@ void PropertyCell::PropertyCellPrint(std::ostream& os) { // NOLINT
|
||||
|
||||
void WeakCell::WeakCellPrint(std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "WeakCell");
|
||||
if (cleared()) {
|
||||
os << "\n - cleared";
|
||||
} else {
|
||||
os << "\n - value: " << Brief(value());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1577,6 +1577,14 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
|
||||
os << accumulator.ToCString().get();
|
||||
break;
|
||||
}
|
||||
case WEAK_CELL_TYPE: {
|
||||
os << "WeakCell for ";
|
||||
HeapStringAllocator allocator;
|
||||
StringStream accumulator(&allocator);
|
||||
WeakCell::cast(this)->value()->ShortPrint(&accumulator);
|
||||
os << accumulator.ToCString().get();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
os << "<Other heap object (" << map()->instance_type() << ")>";
|
||||
break;
|
||||
@ -3425,6 +3433,21 @@ bool Map::IsMapInArrayPrototypeChain() {
|
||||
}
|
||||
|
||||
|
||||
Handle<WeakCell> Map::WeakCellForMap(Handle<Map> map) {
|
||||
Isolate* isolate = map->GetIsolate();
|
||||
if (map->code_cache()->IsFixedArray()) {
|
||||
return isolate->factory()->NewWeakCell(map);
|
||||
}
|
||||
Handle<CodeCache> code_cache(CodeCache::cast(map->code_cache()), isolate);
|
||||
if (code_cache->weak_cell_cache()->IsWeakCell()) {
|
||||
return Handle<WeakCell>(WeakCell::cast(code_cache->weak_cell_cache()));
|
||||
}
|
||||
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(map);
|
||||
code_cache->set_weak_cell_cache(*weak_cell);
|
||||
return weak_cell;
|
||||
}
|
||||
|
||||
|
||||
static Handle<Map> AddMissingElementsTransitions(Handle<Map> map,
|
||||
ElementsKind to_kind) {
|
||||
DCHECK(IsTransitionElementsKind(map->elements_kind()));
|
||||
@ -10567,6 +10590,7 @@ Object* Code::FindNthObject(int n, Map* match_map) {
|
||||
for (RelocIterator it(this, mask); !it.done(); it.next()) {
|
||||
RelocInfo* info = it.rinfo();
|
||||
Object* object = info->target_object();
|
||||
if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
|
||||
if (object->IsHeapObject()) {
|
||||
if (HeapObject::cast(object)->map() == match_map) {
|
||||
if (--n == 0) return object;
|
||||
@ -10599,6 +10623,7 @@ void Code::FindAndReplace(const FindAndReplacePattern& pattern) {
|
||||
RelocInfo* info = it.rinfo();
|
||||
Object* object = info->target_object();
|
||||
if (object->IsHeapObject()) {
|
||||
DCHECK(!object->IsWeakCell());
|
||||
Map* map = HeapObject::cast(object)->map();
|
||||
if (map == *pattern.find_[current_pattern]) {
|
||||
info->set_target_object(*pattern.replace_[current_pattern]);
|
||||
@ -10617,6 +10642,7 @@ void Code::FindAllMaps(MapHandleList* maps) {
|
||||
for (RelocIterator it(this, mask); !it.done(); it.next()) {
|
||||
RelocInfo* info = it.rinfo();
|
||||
Object* object = info->target_object();
|
||||
if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
|
||||
if (object->IsMap()) maps->Add(handle(Map::cast(object)));
|
||||
}
|
||||
}
|
||||
@ -10625,11 +10651,21 @@ void Code::FindAllMaps(MapHandleList* maps) {
|
||||
Code* Code::FindFirstHandler() {
|
||||
DCHECK(is_inline_cache_stub());
|
||||
DisallowHeapAllocation no_allocation;
|
||||
int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
|
||||
int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
|
||||
RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
|
||||
bool skip_next_handler = false;
|
||||
for (RelocIterator it(this, mask); !it.done(); it.next()) {
|
||||
RelocInfo* info = it.rinfo();
|
||||
Code* code = Code::GetCodeFromTargetAddress(info->target_address());
|
||||
if (code->kind() == Code::HANDLER) return code;
|
||||
if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
|
||||
Object* obj = info->target_object();
|
||||
skip_next_handler |= obj->IsWeakCell() && WeakCell::cast(obj)->cleared();
|
||||
} else {
|
||||
Code* code = Code::GetCodeFromTargetAddress(info->target_address());
|
||||
if (code->kind() == Code::HANDLER) {
|
||||
if (!skip_next_handler) return code;
|
||||
skip_next_handler = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -10638,17 +10674,27 @@ Code* Code::FindFirstHandler() {
|
||||
bool Code::FindHandlers(CodeHandleList* code_list, int length) {
|
||||
DCHECK(is_inline_cache_stub());
|
||||
DisallowHeapAllocation no_allocation;
|
||||
int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
|
||||
int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
|
||||
RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
|
||||
bool skip_next_handler = false;
|
||||
int i = 0;
|
||||
for (RelocIterator it(this, mask); !it.done(); it.next()) {
|
||||
if (i == length) return true;
|
||||
RelocInfo* info = it.rinfo();
|
||||
Code* code = Code::GetCodeFromTargetAddress(info->target_address());
|
||||
// IC stubs with handlers never contain non-handler code objects before
|
||||
// handler targets.
|
||||
if (code->kind() != Code::HANDLER) break;
|
||||
code_list->Add(Handle<Code>(code));
|
||||
i++;
|
||||
if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
|
||||
Object* obj = info->target_object();
|
||||
skip_next_handler |= obj->IsWeakCell() && WeakCell::cast(obj)->cleared();
|
||||
} else {
|
||||
Code* code = Code::GetCodeFromTargetAddress(info->target_address());
|
||||
// IC stubs with handlers never contain non-handler code objects before
|
||||
// handler targets.
|
||||
if (code->kind() != Code::HANDLER) break;
|
||||
if (!skip_next_handler) {
|
||||
code_list->Add(Handle<Code>(code));
|
||||
i++;
|
||||
}
|
||||
skip_next_handler = false;
|
||||
}
|
||||
}
|
||||
return i == length;
|
||||
}
|
||||
@ -10663,6 +10709,7 @@ MaybeHandle<Code> Code::FindHandlerForMap(Map* map) {
|
||||
RelocInfo* info = it.rinfo();
|
||||
if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
|
||||
Object* object = info->target_object();
|
||||
if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
|
||||
if (object == map) return_next = true;
|
||||
} else if (return_next) {
|
||||
Code* code = Code::GetCodeFromTargetAddress(info->target_address());
|
||||
|
@ -6190,6 +6190,8 @@ class Map: public HeapObject {
|
||||
|
||||
bool IsMapInArrayPrototypeChain();
|
||||
|
||||
static Handle<WeakCell> WeakCellForMap(Handle<Map> map);
|
||||
|
||||
// Dispatched behavior.
|
||||
DECLARE_PRINTER(Map)
|
||||
DECLARE_VERIFIER(Map)
|
||||
@ -8025,6 +8027,7 @@ class CodeCache: public Struct {
|
||||
public:
|
||||
DECL_ACCESSORS(default_cache, FixedArray)
|
||||
DECL_ACCESSORS(normal_type_cache, Object)
|
||||
DECL_ACCESSORS(weak_cell_cache, Object)
|
||||
|
||||
// Add the code object to the cache.
|
||||
static void Update(
|
||||
@ -8052,7 +8055,8 @@ class CodeCache: public Struct {
|
||||
static const int kDefaultCacheOffset = HeapObject::kHeaderSize;
|
||||
static const int kNormalTypeCacheOffset =
|
||||
kDefaultCacheOffset + kPointerSize;
|
||||
static const int kSize = kNormalTypeCacheOffset + kPointerSize;
|
||||
static const int kWeakCellCacheOffset = kNormalTypeCacheOffset + kPointerSize;
|
||||
static const int kSize = kWeakCellCacheOffset + kPointerSize;
|
||||
|
||||
private:
|
||||
static void UpdateDefaultCache(
|
||||
|
@ -2852,6 +2852,21 @@ void MacroAssembler::LoadGlobalCell(Register dst, Handle<Cell> cell) {
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
|
||||
Register scratch) {
|
||||
Move(scratch, cell, RelocInfo::EMBEDDED_OBJECT);
|
||||
cmpp(value, FieldOperand(scratch, WeakCell::kValueOffset));
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
|
||||
Label* miss) {
|
||||
Move(value, cell, RelocInfo::EMBEDDED_OBJECT);
|
||||
movp(value, FieldOperand(value, WeakCell::kValueOffset));
|
||||
JumpIfSmi(value, miss);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::Drop(int stack_elements) {
|
||||
if (stack_elements > 0) {
|
||||
addp(rsp, Immediate(stack_elements * kPointerSize));
|
||||
|
@ -847,6 +847,13 @@ class MacroAssembler: public Assembler {
|
||||
// Load a global cell into a register.
|
||||
void LoadGlobalCell(Register dst, Handle<Cell> cell);
|
||||
|
||||
// Compare the given value and the value of weak cell.
|
||||
void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch);
|
||||
|
||||
// Load the value of the weak cell in the value register. Branch to the given
|
||||
// miss label if the weak cell was cleared.
|
||||
void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
|
||||
|
||||
// Emit code to discard a non-negative number of pointer-sized elements
|
||||
// from the stack, clobbering only the rsp register.
|
||||
void Drop(int stack_elements);
|
||||
|
@ -2544,6 +2544,21 @@ void MacroAssembler::PushHeapObject(Handle<HeapObject> object) {
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
|
||||
Register scratch) {
|
||||
mov(scratch, cell);
|
||||
cmp(value, FieldOperand(scratch, WeakCell::kValueOffset));
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
|
||||
Label* miss) {
|
||||
mov(value, cell);
|
||||
mov(value, FieldOperand(value, WeakCell::kValueOffset));
|
||||
JumpIfSmi(value, miss);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::Ret() {
|
||||
ret(0);
|
||||
}
|
||||
|
@ -277,6 +277,9 @@ class MacroAssembler: public Assembler {
|
||||
}
|
||||
}
|
||||
|
||||
void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch);
|
||||
void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// JavaScript invokes
|
||||
|
||||
|
@ -78,6 +78,9 @@
|
||||
'test-debug/RecursiveBreakpoints': [PASS, FLAKY],
|
||||
'test-debug/RecursiveBreakpointsGlobal': [PASS, FLAKY],
|
||||
|
||||
# BUG(3629). Known memory leak.
|
||||
'test-heap/WeakMapInPolymorphicStoreIC': [SKIP],
|
||||
|
||||
##############################################################################
|
||||
# TurboFan compiler failures.
|
||||
|
||||
|
@ -3423,6 +3423,44 @@ TEST(IncrementalMarkingClearsMonomorphicIC) {
|
||||
}
|
||||
|
||||
|
||||
TEST(IncrementalMarkingPreservesPolymorphicIC) {
|
||||
if (i::FLAG_always_opt) return;
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
v8::Local<v8::Value> obj1, obj2;
|
||||
|
||||
{
|
||||
LocalContext env;
|
||||
CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
|
||||
obj1 = env->Global()->Get(v8_str("obj"));
|
||||
}
|
||||
|
||||
{
|
||||
LocalContext env;
|
||||
CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
|
||||
obj2 = env->Global()->Get(v8_str("obj"));
|
||||
}
|
||||
|
||||
// Prepare function f that contains a polymorphic IC for objects
|
||||
// originating from two different native contexts.
|
||||
CcTest::global()->Set(v8_str("obj1"), obj1);
|
||||
CcTest::global()->Set(v8_str("obj2"), obj2);
|
||||
CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
|
||||
Handle<JSFunction> f = v8::Utils::OpenHandle(
|
||||
*v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
|
||||
|
||||
Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
|
||||
CHECK(ic_before->ic_state() == POLYMORPHIC);
|
||||
|
||||
// Fire context dispose notification.
|
||||
SimulateIncrementalMarking(CcTest::heap());
|
||||
CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
|
||||
Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
|
||||
CHECK(ic_after->ic_state() == POLYMORPHIC);
|
||||
}
|
||||
|
||||
|
||||
TEST(IncrementalMarkingClearsPolymorphicIC) {
|
||||
if (i::FLAG_always_opt) return;
|
||||
CcTest::InitializeVM();
|
||||
@ -4380,6 +4418,25 @@ TEST(WeakMapInMonomorphicLoadIC) {
|
||||
}
|
||||
|
||||
|
||||
TEST(WeakMapInPolymorphicLoadIC) {
|
||||
CheckWeakness(
|
||||
"function loadIC(obj) {"
|
||||
" return obj.name;"
|
||||
"}"
|
||||
" (function() {"
|
||||
" var proto = {'name' : 'weak'};"
|
||||
" var obj = Object.create(proto);"
|
||||
" loadIC(obj);"
|
||||
" loadIC(obj);"
|
||||
" loadIC(obj);"
|
||||
" var poly = Object.create(proto);"
|
||||
" poly.x = true;"
|
||||
" loadIC(poly);"
|
||||
" return proto;"
|
||||
" })();");
|
||||
}
|
||||
|
||||
|
||||
TEST(WeakMapInMonomorphicKeyedLoadIC) {
|
||||
// TODO(mvstanton): vector ics need weak support!
|
||||
if (FLAG_vector_ics) return;
|
||||
@ -4397,6 +4454,25 @@ TEST(WeakMapInMonomorphicKeyedLoadIC) {
|
||||
}
|
||||
|
||||
|
||||
TEST(WeakMapInPolymorphicKeyedLoadIC) {
|
||||
CheckWeakness(
|
||||
"function keyedLoadIC(obj, field) {"
|
||||
" return obj[field];"
|
||||
"}"
|
||||
" (function() {"
|
||||
" var proto = {'name' : 'weak'};"
|
||||
" var obj = Object.create(proto);"
|
||||
" keyedLoadIC(obj, 'name');"
|
||||
" keyedLoadIC(obj, 'name');"
|
||||
" keyedLoadIC(obj, 'name');"
|
||||
" var poly = Object.create(proto);"
|
||||
" poly.x = true;"
|
||||
" keyedLoadIC(poly, 'name');"
|
||||
" return proto;"
|
||||
" })();");
|
||||
}
|
||||
|
||||
|
||||
TEST(WeakMapInMonomorphicStoreIC) {
|
||||
CheckWeakness("function storeIC(obj, value) {"
|
||||
" obj.name = value;"
|
||||
@ -4412,6 +4488,25 @@ TEST(WeakMapInMonomorphicStoreIC) {
|
||||
}
|
||||
|
||||
|
||||
TEST(WeakMapInPolymorphicStoreIC) {
|
||||
CheckWeakness(
|
||||
"function storeIC(obj, value) {"
|
||||
" obj.name = value;"
|
||||
"}"
|
||||
" (function() {"
|
||||
" var proto = {'name' : 'weak'};"
|
||||
" var obj = Object.create(proto);"
|
||||
" storeIC(obj, 'x');"
|
||||
" storeIC(obj, 'x');"
|
||||
" storeIC(obj, 'x');"
|
||||
" var poly = Object.create(proto);"
|
||||
" poly.x = true;"
|
||||
" storeIC(poly, 'x');"
|
||||
" return proto;"
|
||||
" })();");
|
||||
}
|
||||
|
||||
|
||||
TEST(WeakMapInMonomorphicKeyedStoreIC) {
|
||||
CheckWeakness("function keyedStoreIC(obj, field, value) {"
|
||||
" obj[field] = value;"
|
||||
@ -4427,6 +4522,25 @@ TEST(WeakMapInMonomorphicKeyedStoreIC) {
|
||||
}
|
||||
|
||||
|
||||
TEST(WeakMapInPolymorphicKeyedStoreIC) {
|
||||
CheckWeakness(
|
||||
"function keyedStoreIC(obj, field, value) {"
|
||||
" obj[field] = value;"
|
||||
"}"
|
||||
" (function() {"
|
||||
" var proto = {'name' : 'weak'};"
|
||||
" var obj = Object.create(proto);"
|
||||
" keyedStoreIC(obj, 'x');"
|
||||
" keyedStoreIC(obj, 'x');"
|
||||
" keyedStoreIC(obj, 'x');"
|
||||
" var poly = Object.create(proto);"
|
||||
" poly.x = true;"
|
||||
" keyedStoreIC(poly, 'x');"
|
||||
" return proto;"
|
||||
" })();");
|
||||
}
|
||||
|
||||
|
||||
TEST(WeakMapInMonomorphicCompareNilIC) {
|
||||
CheckWeakness("function compareNilIC(obj) {"
|
||||
" return obj == null;"
|
||||
|
@ -142,10 +142,16 @@ function test1() {
|
||||
assertTrue(%HaveSameMap(smis, doubles));
|
||||
}
|
||||
|
||||
function clear_ic_state() {
|
||||
%ClearFunctionTypeFeedback(construct_smis);
|
||||
%ClearFunctionTypeFeedback(construct_doubles);
|
||||
%ClearFunctionTypeFeedback(convert_mixed);
|
||||
}
|
||||
|
||||
test1();
|
||||
gc(); // clear IC state
|
||||
clear_ic_state();
|
||||
test1();
|
||||
gc(); // clear IC state
|
||||
clear_ic_state();
|
||||
%OptimizeFunctionOnNextCall(test1);
|
||||
test1();
|
||||
gc(); // clear IC state
|
||||
clear_ic_state();
|
||||
|
Loading…
Reference in New Issue
Block a user