}
+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,
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.
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());
}
+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();
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);
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;
}
}
+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);
}
}
}
+ // 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
}
+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));
+ JumpIfSmi(value, miss);
+}
+
+
void MacroAssembler::MovFromFloatResult(DoubleRegister dst) {
if (IsMipsSoftFloatABI) {
if (kArchEndian == kLittle) {
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.
}
+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));
+ JumpIfSmi(value, miss);
+}
+
+
void MacroAssembler::MovFromFloatResult(const DoubleRegister dst) {
if (IsMipsSoftFloatABI) {
Move(dst, v0, v1);
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.
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)
void WeakCell::WeakCellPrint(std::ostream& os) { // NOLINT
HeapObject::PrintHeader(os, "WeakCell");
+ if (cleared()) {
+ os << "\n - cleared";
+ } else {
+ os << "\n - value: " << Brief(value());
+ }
}
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;
}
+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()));
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;
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]);
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)));
}
}
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;
}
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;
}
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());
bool IsMapInArrayPrototypeChain();
+ static Handle<WeakCell> WeakCellForMap(Handle<Map> map);
+
// Dispatched behavior.
DECLARE_PRINTER(Map)
DECLARE_VERIFIER(Map)
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(
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(
}
+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));
// 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);
}
+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);
}
}
}
+ void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch);
+ void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
+
// ---------------------------------------------------------------------------
// JavaScript invokes
'test-debug/RecursiveBreakpoints': [PASS, FLAKY],
'test-debug/RecursiveBreakpointsGlobal': [PASS, FLAKY],
+ # BUG(3629). Known memory leak.
+ 'test-heap/WeakMapInPolymorphicStoreIC': [SKIP],
+ # BUG(3663).
+ 'test-heap/WeakMapInPolymorphicLoadIC': [SKIP],
+ 'test-heap/WeakMapInPolymorphicKeyedLoadIC': [SKIP],
+ 'test-heap/WeakMapInPolymorphicKeyedStoreIC': [SKIP],
+ 'test-heap/IncrementalMarkingPreservesPolymorphicIC': [SKIP],
+
##############################################################################
# TurboFan compiler failures.
}
+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();
}
+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;
}
+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;"
}
+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;"
}
+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;"
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();