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) { ...@@ -8206,6 +8206,22 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
// Get the prototype of the function (r4 is result, r2 is scratch). // Get the prototype of the function (r4 is result, r2 is scratch).
__ ldr(r1, MemOperand(sp, 0)); __ 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); __ TryGetFunctionPrototype(r1, r4, r2, &slow);
// Check that the function prototype is a JS object. // Check that the function prototype is a JS object.
...@@ -8215,6 +8231,9 @@ void InstanceofStub::Generate(MacroAssembler* masm) { ...@@ -8215,6 +8231,9 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ cmp(r5, Operand(LAST_JS_OBJECT_TYPE)); __ cmp(r5, Operand(LAST_JS_OBJECT_TYPE));
__ b(gt, &slow); __ b(gt, &slow);
__ StoreRoot(r1, Heap::kInstanceofCacheFunctionRootIndex);
__ StoreRoot(r3, Heap::kInstanceofCacheMapRootIndex);
// Register mapping: r3 is object map and r4 is function prototype. // Register mapping: r3 is object map and r4 is function prototype.
// Get prototype of object into r2. // Get prototype of object into r2.
__ ldr(r2, FieldMemOperand(r3, Map::kPrototypeOffset)); __ ldr(r2, FieldMemOperand(r3, Map::kPrototypeOffset));
...@@ -8232,12 +8251,14 @@ void InstanceofStub::Generate(MacroAssembler* masm) { ...@@ -8232,12 +8251,14 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ bind(&is_instance); __ bind(&is_instance);
__ mov(r0, Operand(Smi::FromInt(0))); __ mov(r0, Operand(Smi::FromInt(0)));
__ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
__ pop(); __ pop();
__ pop(); __ pop();
__ mov(pc, Operand(lr)); // Return. __ mov(pc, Operand(lr)); // Return.
__ bind(&is_not_instance); __ bind(&is_not_instance);
__ mov(r0, Operand(Smi::FromInt(1))); __ mov(r0, Operand(Smi::FromInt(1)));
__ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
__ pop(); __ pop();
__ pop(); __ pop();
__ mov(pc, Operand(lr)); // Return. __ mov(pc, Operand(lr)); // Return.
......
...@@ -232,6 +232,13 @@ void MacroAssembler::LoadRoot(Register destination, ...@@ -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, void MacroAssembler::RecordWriteHelper(Register object,
Register offset, Register offset,
Register scratch) { Register scratch) {
......
...@@ -85,6 +85,10 @@ class MacroAssembler: public Assembler { ...@@ -85,6 +85,10 @@ class MacroAssembler: public Assembler {
void LoadRoot(Register destination, void LoadRoot(Register destination,
Heap::RootListIndex index, Heap::RootListIndex index,
Condition cond = al); 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. // Check if object is in new space.
......
...@@ -674,6 +674,8 @@ void Heap::MarkCompactPrologue(bool is_compacting) { ...@@ -674,6 +674,8 @@ void Heap::MarkCompactPrologue(bool is_compacting) {
Top::MarkCompactPrologue(is_compacting); Top::MarkCompactPrologue(is_compacting);
ThreadManager::MarkCompactPrologue(is_compacting); ThreadManager::MarkCompactPrologue(is_compacting);
CompletelyClearInstanceofCache();
if (is_compacting) FlushNumberStringCache(); if (is_compacting) FlushNumberStringCache();
} }
...@@ -1685,6 +1687,10 @@ bool Heap::CreateInitialObjects() { ...@@ -1685,6 +1687,10 @@ bool Heap::CreateInitialObjects() {
if (obj->IsFailure()) return false; if (obj->IsFailure()) return false;
set_non_monomorphic_cache(NumberDictionary::cast(obj)); 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(); CreateFixedStubs();
if (InitializeNumberStringCache()->IsFailure()) return false; if (InitializeNumberStringCache()->IsFailure()) return false;
......
...@@ -93,6 +93,9 @@ class ZoneScopeInfo; ...@@ -93,6 +93,9 @@ class ZoneScopeInfo;
V(Map, proxy_map, ProxyMap) \ V(Map, proxy_map, ProxyMap) \
V(Object, nan_value, NanValue) \ V(Object, nan_value, NanValue) \
V(Object, minus_zero_value, MinusZeroValue) \ 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(String, empty_string, EmptyString) \
V(DescriptorArray, empty_descriptor_array, EmptyDescriptorArray) \ V(DescriptorArray, empty_descriptor_array, EmptyDescriptorArray) \
V(Map, neander_map, NeanderMap) \ V(Map, neander_map, NeanderMap) \
...@@ -361,6 +364,11 @@ class Heap : public AllStatic { ...@@ -361,6 +364,11 @@ class Heap : public AllStatic {
// Allocates an empty code cache. // Allocates an empty code cache.
static Object* AllocateCodeCache(); 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 // Allocates and fully initializes a String. There are two String
// encodings: ASCII and two byte. One should choose between the three 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 // allocation functions based on the encoding of the string buffer used to
...@@ -1171,6 +1179,13 @@ class Heap : public AllStatic { ...@@ -1171,6 +1179,13 @@ class Heap : public AllStatic {
static void MarkCompactPrologue(bool is_compacting); static void MarkCompactPrologue(bool is_compacting);
static void MarkCompactEpilogue(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 // Helper function used by CopyObject to copy a source object to an
// allocated target object and update the forwarding pointer in the source // allocated target object and update the forwarding pointer in the source
// object. Returns the target object. // object. Returns the target object.
......
...@@ -12126,6 +12126,22 @@ void InstanceofStub::Generate(MacroAssembler* masm) { ...@@ -12126,6 +12126,22 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
// Get the prototype of the function. // Get the prototype of the function.
__ mov(edx, Operand(esp, 1 * kPointerSize)); // 1 ~ return address __ 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); __ TryGetFunctionPrototype(edx, ebx, ecx, &slow);
// Check that the function prototype is a JS object. // Check that the function prototype is a JS object.
...@@ -12138,7 +12154,15 @@ void InstanceofStub::Generate(MacroAssembler* masm) { ...@@ -12138,7 +12154,15 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ cmp(ecx, LAST_JS_OBJECT_TYPE); __ cmp(ecx, LAST_JS_OBJECT_TYPE);
__ j(greater, &slow, not_taken); __ 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)); __ mov(ecx, FieldOperand(eax, Map::kPrototypeOffset));
// Loop through the prototype chain looking for the function prototype. // Loop through the prototype chain looking for the function prototype.
...@@ -12154,10 +12178,14 @@ void InstanceofStub::Generate(MacroAssembler* masm) { ...@@ -12154,10 +12178,14 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ bind(&is_instance); __ bind(&is_instance);
__ Set(eax, Immediate(0)); __ Set(eax, Immediate(0));
__ mov(ecx, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
__ mov(Operand::StaticArray(ecx, times_pointer_size, roots_address), eax);
__ ret(2 * kPointerSize); __ ret(2 * kPointerSize);
__ bind(&is_not_instance); __ bind(&is_not_instance);
__ Set(eax, Immediate(Smi::FromInt(1))); __ Set(eax, Immediate(Smi::FromInt(1)));
__ mov(ecx, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
__ mov(Operand::StaticArray(ecx, times_pointer_size, roots_address), eax);
__ ret(2 * kPointerSize); __ ret(2 * kPointerSize);
// Slow-case: Go through the JavaScript implementation. // Slow-case: Go through the JavaScript implementation.
......
...@@ -4900,6 +4900,7 @@ Object* JSFunction::SetInstancePrototype(Object* value) { ...@@ -4900,6 +4900,7 @@ Object* JSFunction::SetInstancePrototype(Object* value) {
// prototype is put into the initial map where it belongs. // prototype is put into the initial map where it belongs.
set_prototype_or_initial_map(value); set_prototype_or_initial_map(value);
} }
Heap::ClearInstanceofCache();
return value; return value;
} }
...@@ -5601,6 +5602,8 @@ Object* JSObject::SetPrototype(Object* value, ...@@ -5601,6 +5602,8 @@ Object* JSObject::SetPrototype(Object* value,
Map::cast(new_map)->set_prototype(value); Map::cast(new_map)->set_prototype(value);
real_receiver->set_map(Map::cast(new_map)); real_receiver->set_map(Map::cast(new_map));
Heap::ClearInstanceofCache();
return value; return value;
} }
......
...@@ -8792,6 +8792,9 @@ void InstanceofStub::Generate(MacroAssembler* masm) { ...@@ -8792,6 +8792,9 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
// rsp[0] : return address // rsp[0] : return address
// rsp[1] : function pointer // rsp[1] : function pointer
// rsp[2] : value // 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. // Get the object - go slow case if it's a smi.
Label slow; Label slow;
...@@ -8806,6 +8809,18 @@ void InstanceofStub::Generate(MacroAssembler* masm) { ...@@ -8806,6 +8809,18 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
// Get the prototype of the function. // Get the prototype of the function.
__ movq(rdx, Operand(rsp, 1 * kPointerSize)); __ 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); __ TryGetFunctionPrototype(rdx, rbx, &slow);
// Check that the function prototype is a JS object. // Check that the function prototype is a JS object.
...@@ -8815,7 +8830,13 @@ void InstanceofStub::Generate(MacroAssembler* masm) { ...@@ -8815,7 +8830,13 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE); __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE);
__ j(above, &slow); __ 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)); __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset));
// Loop through the prototype chain looking for the function prototype. // Loop through the prototype chain looking for the function prototype.
...@@ -8825,6 +8846,8 @@ void InstanceofStub::Generate(MacroAssembler* masm) { ...@@ -8825,6 +8846,8 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ cmpq(rcx, rbx); __ cmpq(rcx, rbx);
__ j(equal, &is_instance); __ j(equal, &is_instance);
__ cmpq(rcx, kScratchRegister); __ 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); __ j(equal, &is_not_instance);
__ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
__ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset)); __ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset));
...@@ -8832,10 +8855,14 @@ void InstanceofStub::Generate(MacroAssembler* masm) { ...@@ -8832,10 +8855,14 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ bind(&is_instance); __ bind(&is_instance);
__ xorl(rax, rax); __ 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); __ ret(2 * kPointerSize);
__ bind(&is_not_instance); __ 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); __ ret(2 * kPointerSize);
// Slow-case: Go through the JavaScript implementation. // Slow-case: Go through the JavaScript implementation.
......
...@@ -50,6 +50,11 @@ void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index) { ...@@ -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) { void MacroAssembler::PushRoot(Heap::RootListIndex index) {
push(Operand(kRootRegister, index << kPointerSizeLog2)); push(Operand(kRootRegister, index << kPointerSizeLog2));
} }
......
...@@ -62,6 +62,7 @@ class MacroAssembler: public Assembler { ...@@ -62,6 +62,7 @@ class MacroAssembler: public Assembler {
void CompareRoot(Register with, Heap::RootListIndex index); void CompareRoot(Register with, Heap::RootListIndex index);
void CompareRoot(Operand with, Heap::RootListIndex index); void CompareRoot(Operand with, Heap::RootListIndex index);
void PushRoot(Heap::RootListIndex index); void PushRoot(Heap::RootListIndex index);
void StoreRoot(Register source, Heap::RootListIndex index);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// GC Support // 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