Commit d18b73c2 authored by erik.corry@gmail.com's avatar erik.corry@gmail.com

Add a single-element global positive and negative cache to

the implementation of instanceof.
Review URL: http://codereview.chromium.org/1765012

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4599 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 1f13b58b
......@@ -8206,6 +8206,22 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
// Get the prototype of the function (r4 is result, r2 is scratch).
__ ldr(r1, MemOperand(sp, 0));
// r1 is function, r3 is map.
// Look up the function and the map in the instanceof cache.
Label miss;
__ LoadRoot(ip, Heap::kInstanceofCacheFunctionRootIndex);
__ cmp(r1, ip);
__ b(ne, &miss);
__ LoadRoot(ip, Heap::kInstanceofCacheMapRootIndex);
__ cmp(r3, ip);
__ b(ne, &miss);
__ LoadRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
__ pop();
__ pop();
__ mov(pc, Operand(lr));
__ bind(&miss);
__ TryGetFunctionPrototype(r1, r4, r2, &slow);
// Check that the function prototype is a JS object.
......@@ -8215,6 +8231,9 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ cmp(r5, Operand(LAST_JS_OBJECT_TYPE));
__ b(gt, &slow);
__ StoreRoot(r1, Heap::kInstanceofCacheFunctionRootIndex);
__ StoreRoot(r3, Heap::kInstanceofCacheMapRootIndex);
// Register mapping: r3 is object map and r4 is function prototype.
// Get prototype of object into r2.
__ ldr(r2, FieldMemOperand(r3, Map::kPrototypeOffset));
......@@ -8232,12 +8251,14 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ bind(&is_instance);
__ mov(r0, Operand(Smi::FromInt(0)));
__ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
__ pop();
__ pop();
__ mov(pc, Operand(lr)); // Return.
__ bind(&is_not_instance);
__ mov(r0, Operand(Smi::FromInt(1)));
__ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
__ pop();
__ pop();
__ mov(pc, Operand(lr)); // Return.
......
......@@ -232,6 +232,13 @@ void MacroAssembler::LoadRoot(Register destination,
}
void MacroAssembler::StoreRoot(Register source,
Heap::RootListIndex index,
Condition cond) {
str(source, MemOperand(roots, index << kPointerSizeLog2), cond);
}
void MacroAssembler::RecordWriteHelper(Register object,
Register offset,
Register scratch) {
......
......@@ -85,6 +85,10 @@ class MacroAssembler: public Assembler {
void LoadRoot(Register destination,
Heap::RootListIndex index,
Condition cond = al);
// Store an object to the root table.
void StoreRoot(Register source,
Heap::RootListIndex index,
Condition cond = al);
// Check if object is in new space.
......
......@@ -674,6 +674,8 @@ void Heap::MarkCompactPrologue(bool is_compacting) {
Top::MarkCompactPrologue(is_compacting);
ThreadManager::MarkCompactPrologue(is_compacting);
CompletelyClearInstanceofCache();
if (is_compacting) FlushNumberStringCache();
}
......@@ -1685,6 +1687,10 @@ bool Heap::CreateInitialObjects() {
if (obj->IsFailure()) return false;
set_non_monomorphic_cache(NumberDictionary::cast(obj));
set_instanceof_cache_function(Smi::FromInt(0));
set_instanceof_cache_map(Smi::FromInt(0));
set_instanceof_cache_answer(Smi::FromInt(0));
CreateFixedStubs();
if (InitializeNumberStringCache()->IsFailure()) return false;
......
......@@ -93,6 +93,9 @@ class ZoneScopeInfo;
V(Map, proxy_map, ProxyMap) \
V(Object, nan_value, NanValue) \
V(Object, minus_zero_value, MinusZeroValue) \
V(Object, instanceof_cache_function, InstanceofCacheFunction) \
V(Object, instanceof_cache_map, InstanceofCacheMap) \
V(Object, instanceof_cache_answer, InstanceofCacheAnswer) \
V(String, empty_string, EmptyString) \
V(DescriptorArray, empty_descriptor_array, EmptyDescriptorArray) \
V(Map, neander_map, NeanderMap) \
......@@ -361,6 +364,11 @@ class Heap : public AllStatic {
// Allocates an empty code cache.
static Object* AllocateCodeCache();
// Clear the Instanceof cache (used when a prototype changes).
static void ClearInstanceofCache() {
set_instanceof_cache_function(the_hole_value());
}
// Allocates and fully initializes a String. There are two String
// encodings: ASCII and two byte. One should choose between the three string
// allocation functions based on the encoding of the string buffer used to
......@@ -1171,6 +1179,13 @@ class Heap : public AllStatic {
static void MarkCompactPrologue(bool is_compacting);
static void MarkCompactEpilogue(bool is_compacting);
// Completely clear the Instanceof cache (to stop it keeping objects alive
// around a GC).
static void CompletelyClearInstanceofCache() {
set_instanceof_cache_map(the_hole_value());
set_instanceof_cache_function(the_hole_value());
}
// Helper function used by CopyObject to copy a source object to an
// allocated target object and update the forwarding pointer in the source
// object. Returns the target object.
......
......@@ -12126,6 +12126,22 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
// Get the prototype of the function.
__ mov(edx, Operand(esp, 1 * kPointerSize)); // 1 ~ return address
// edx is function, eax is map.
// Look up the function and the map in the instanceof cache.
Label miss;
ExternalReference roots_address = ExternalReference::roots_address();
__ mov(ecx, Immediate(Heap::kInstanceofCacheFunctionRootIndex));
__ cmp(edx, Operand::StaticArray(ecx, times_pointer_size, roots_address));
__ j(not_equal, &miss);
__ mov(ecx, Immediate(Heap::kInstanceofCacheMapRootIndex));
__ cmp(eax, Operand::StaticArray(ecx, times_pointer_size, roots_address));
__ j(not_equal, &miss);
__ mov(ecx, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
__ mov(eax, Operand::StaticArray(ecx, times_pointer_size, roots_address));
__ ret(2 * kPointerSize);
__ bind(&miss);
__ TryGetFunctionPrototype(edx, ebx, ecx, &slow);
// Check that the function prototype is a JS object.
......@@ -12138,7 +12154,15 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ cmp(ecx, LAST_JS_OBJECT_TYPE);
__ j(greater, &slow, not_taken);
// Register mapping: eax is object map and ebx is function prototype.
// Register mapping:
// eax is object map.
// edx is function.
// ebx is function prototype.
__ mov(ecx, Immediate(Heap::kInstanceofCacheMapRootIndex));
__ mov(Operand::StaticArray(ecx, times_pointer_size, roots_address), eax);
__ mov(ecx, Immediate(Heap::kInstanceofCacheFunctionRootIndex));
__ mov(Operand::StaticArray(ecx, times_pointer_size, roots_address), edx);
__ mov(ecx, FieldOperand(eax, Map::kPrototypeOffset));
// Loop through the prototype chain looking for the function prototype.
......@@ -12154,10 +12178,14 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ bind(&is_instance);
__ Set(eax, Immediate(0));
__ mov(ecx, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
__ mov(Operand::StaticArray(ecx, times_pointer_size, roots_address), eax);
__ ret(2 * kPointerSize);
__ bind(&is_not_instance);
__ Set(eax, Immediate(Smi::FromInt(1)));
__ mov(ecx, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
__ mov(Operand::StaticArray(ecx, times_pointer_size, roots_address), eax);
__ ret(2 * kPointerSize);
// Slow-case: Go through the JavaScript implementation.
......
......@@ -4900,6 +4900,7 @@ Object* JSFunction::SetInstancePrototype(Object* value) {
// prototype is put into the initial map where it belongs.
set_prototype_or_initial_map(value);
}
Heap::ClearInstanceofCache();
return value;
}
......@@ -5601,6 +5602,8 @@ Object* JSObject::SetPrototype(Object* value,
Map::cast(new_map)->set_prototype(value);
real_receiver->set_map(Map::cast(new_map));
Heap::ClearInstanceofCache();
return value;
}
......
......@@ -8792,6 +8792,9 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
// rsp[0] : return address
// rsp[1] : function pointer
// rsp[2] : value
// Returns a bitwise zero to indicate that the value
// is and instance of the function and anything else to
// indicate that the value is not an instance.
// Get the object - go slow case if it's a smi.
Label slow;
......@@ -8806,6 +8809,18 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
// Get the prototype of the function.
__ movq(rdx, Operand(rsp, 1 * kPointerSize));
// rdx is function, rax is map.
// Look up the function and the map in the instanceof cache.
Label miss;
__ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex);
__ j(not_equal, &miss);
__ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex);
__ j(not_equal, &miss);
__ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex);
__ ret(2 * kPointerSize);
__ bind(&miss);
__ TryGetFunctionPrototype(rdx, rbx, &slow);
// Check that the function prototype is a JS object.
......@@ -8815,7 +8830,13 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE);
__ j(above, &slow);
// Register mapping: rax is object map and rbx is function prototype.
// Register mapping:
// rax is object map.
// rdx is function.
// rbx is function prototype.
__ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex);
__ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex);
__ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset));
// Loop through the prototype chain looking for the function prototype.
......@@ -8825,6 +8846,8 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ cmpq(rcx, rbx);
__ j(equal, &is_instance);
__ cmpq(rcx, kScratchRegister);
// The code at is_not_instance assumes that kScratchRegister contains a
// non-zero GCable value (the null object in this case).
__ j(equal, &is_not_instance);
__ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
__ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset));
......@@ -8832,10 +8855,14 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ bind(&is_instance);
__ xorl(rax, rax);
// Store bitwise zero in the cache. This is a Smi in GC terms.
ASSERT_EQ(0, kSmiTag);
__ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex);
__ ret(2 * kPointerSize);
__ bind(&is_not_instance);
__ movl(rax, Immediate(1));
// We have to store a non-zero value in the cache.
__ StoreRoot(kScratchRegister, Heap::kInstanceofCacheAnswerRootIndex);
__ ret(2 * kPointerSize);
// Slow-case: Go through the JavaScript implementation.
......
......@@ -50,6 +50,11 @@ void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index) {
}
void MacroAssembler::StoreRoot(Register source, Heap::RootListIndex index) {
movq(Operand(kRootRegister, index << kPointerSizeLog2), source);
}
void MacroAssembler::PushRoot(Heap::RootListIndex index) {
push(Operand(kRootRegister, index << kPointerSizeLog2));
}
......
......@@ -62,6 +62,7 @@ class MacroAssembler: public Assembler {
void CompareRoot(Register with, Heap::RootListIndex index);
void CompareRoot(Operand with, Heap::RootListIndex index);
void PushRoot(Heap::RootListIndex index);
void StoreRoot(Register source, Heap::RootListIndex index);
// ---------------------------------------------------------------------------
// GC Support
......
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