Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(466)

Unified Diff: src/ia32/code-stubs-ia32.cc

Issue 5990005: Optimize instanceof further... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 9 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/hydrogen-instructions.h ('k') | src/ia32/full-codegen-ia32.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/ia32/code-stubs-ia32.cc
===================================================================
--- src/ia32/code-stubs-ia32.cc (revision 6167)
+++ src/ia32/code-stubs-ia32.cc (working copy)
@@ -4973,7 +4973,26 @@
}
+// Generate stub code for instanceof.
+// This code can patch a call site inlined cache of the instance of check,
+// which looks like this.
+//
+// 81 ff XX XX XX XX cmp edi, <the hole, patched to a map>
+// 75 0a jne <some near label>
+// b8 XX XX XX XX mov eax, <the hole, patched to either true or false>
+//
+// If call site patching is requested the stack will have the delta from the
+// return address to the cmp instruction just below the return address. This
+// also means that call site patching can only take place with arguments in
+// registers. TOS looks like this when call site patching is requested
+//
+// esp[0] : return address
+// esp[4] : delta from return address to cmp instruction
+//
void InstanceofStub::Generate(MacroAssembler* masm) {
+ // Call site inlining and patching implies arguments in registers.
+ ASSERT(HasArgsInRegisters() || !HasCallSiteInlineCheck());
+
// Fixed register usage throughout the stub.
Register object = eax; // Object (lhs).
Register map = ebx; // Map of the object.
@@ -4981,9 +5000,22 @@
Register prototype = edi; // Prototype of the function.
Register scratch = ecx;
+ // Constants describing the call site code to patch.
+ static const int kDeltaToCmpImmediate = 2;
+ static const int kDeltaToMov = 8;
+ static const int kDeltaToMovImmediate = 9;
+ static const int8_t kCmpEdiImmediateByte1 = static_cast<int8_t>(0x81);
+ static const int8_t kCmpEdiImmediateByte2 = static_cast<int8_t>(0xff);
+ static const int8_t kMovEaxImmediateByte = static_cast<int8_t>(0xb8);
+
+ ExternalReference roots_address = ExternalReference::roots_address();
+
+ ASSERT_EQ(object.code(), InstanceofStub::left().code());
+ ASSERT_EQ(function.code(), InstanceofStub::right().code());
+
// Get the object and function - they are always both needed.
Label slow, not_js_object;
- if (!args_in_registers()) {
+ if (!HasArgsInRegisters()) {
__ mov(object, Operand(esp, 2 * kPointerSize));
__ mov(function, Operand(esp, 1 * kPointerSize));
}
@@ -4993,22 +5025,26 @@
__ j(zero, &not_js_object, not_taken);
__ IsObjectJSObjectType(object, map, scratch, &not_js_object);
- // Look up the function and the map in the instanceof cache.
- NearLabel miss;
- ExternalReference roots_address = ExternalReference::roots_address();
- __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex));
- __ cmp(function,
- Operand::StaticArray(scratch, times_pointer_size, roots_address));
- __ j(not_equal, &miss);
- __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex));
- __ cmp(map, Operand::StaticArray(scratch, times_pointer_size, roots_address));
- __ j(not_equal, &miss);
- __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
- __ mov(eax, Operand::StaticArray(scratch, times_pointer_size, roots_address));
- __ IncrementCounter(&Counters::instance_of_cache, 1);
- __ ret((args_in_registers() ? 0 : 2) * kPointerSize);
+ // If there is a call site cache don't look in the global cache, but do the
+ // real lookup and update the call site cache.
+ if (!HasCallSiteInlineCheck()) {
+ // Look up the function and the map in the instanceof cache.
+ NearLabel miss;
+ __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex));
+ __ cmp(function,
+ Operand::StaticArray(scratch, times_pointer_size, roots_address));
+ __ j(not_equal, &miss);
+ __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex));
+ __ cmp(map, Operand::StaticArray(
+ scratch, times_pointer_size, roots_address));
+ __ j(not_equal, &miss);
+ __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
+ __ mov(eax, Operand::StaticArray(
+ scratch, times_pointer_size, roots_address));
+ __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
+ __ bind(&miss);
+ }
- __ bind(&miss);
// Get the prototype of the function.
__ TryGetFunctionPrototype(function, prototype, scratch, &slow);
@@ -5017,13 +5053,29 @@
__ j(zero, &slow, not_taken);
__ IsObjectJSObjectType(prototype, scratch, scratch, &slow);
- // Update the golbal instanceof cache with the current map and function. The
- // cached answer will be set when it is known.
+ // Update the global instanceof or call site inlined cache with the current
+ // map and function. The cached answer will be set when it is known below.
+ if (!HasCallSiteInlineCheck()) {
__ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex));
__ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), map);
__ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex));
__ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address),
function);
+ } else {
+ // The constants for the code patching are based on no push instructions
+ // at the call site.
+ ASSERT(HasArgsInRegisters());
+ // Get return address and delta to inlined map check.
+ __ mov(scratch, Operand(esp, 0 * kPointerSize));
+ __ sub(scratch, Operand(esp, 1 * kPointerSize));
+ if (FLAG_debug_code) {
+ __ cmpb(Operand(scratch, 0), kCmpEdiImmediateByte1);
+ __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 1)");
+ __ cmpb(Operand(scratch, 1), kCmpEdiImmediateByte2);
+ __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 2)");
+ }
+ __ mov(Operand(scratch, kDeltaToCmpImmediate), map);
+ }
// Loop through the prototype chain of the object looking for the function
// prototype.
@@ -5039,18 +5091,48 @@
__ jmp(&loop);
__ bind(&is_instance);
- __ IncrementCounter(&Counters::instance_of_stub_true, 1);
- __ Set(eax, Immediate(0));
- __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
- __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), eax);
- __ ret((args_in_registers() ? 0 : 2) * kPointerSize);
+ if (!HasCallSiteInlineCheck()) {
+ __ Set(eax, Immediate(0));
+ __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
+ __ mov(Operand::StaticArray(scratch,
+ times_pointer_size, roots_address), eax);
+ } else {
+ // Get return address and delta to inlined map check.
+ __ mov(eax, Factory::true_value());
+ __ mov(scratch, Operand(esp, 0 * kPointerSize));
+ __ sub(scratch, Operand(esp, 1 * kPointerSize));
+ if (FLAG_debug_code) {
+ __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte);
+ __ Assert(equal, "InstanceofStub unexpected call site cache (mov)");
+ }
+ __ mov(Operand(scratch, kDeltaToMovImmediate), eax);
+ if (!ReturnTrueFalseObject()) {
+ __ Set(eax, Immediate(0));
+ }
+ }
+ __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
__ bind(&is_not_instance);
- __ IncrementCounter(&Counters::instance_of_stub_false, 1);
- __ Set(eax, Immediate(Smi::FromInt(1)));
- __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
- __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), eax);
- __ ret((args_in_registers() ? 0 : 2) * kPointerSize);
+ if (!HasCallSiteInlineCheck()) {
+ __ Set(eax, Immediate(Smi::FromInt(1)));
+ __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
+ __ mov(Operand::StaticArray(
+ scratch, times_pointer_size, roots_address), eax);
+ } else {
+ // Get return address and delta to inlined map check.
+ __ mov(eax, Factory::false_value());
+ __ mov(scratch, Operand(esp, 0 * kPointerSize));
+ __ sub(scratch, Operand(esp, 1 * kPointerSize));
+ if (FLAG_debug_code) {
+ __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte);
+ __ Assert(equal, "InstanceofStub unexpected call site cache (mov)");
+ }
+ __ mov(Operand(scratch, kDeltaToMovImmediate), eax);
+ if (!ReturnTrueFalseObject()) {
+ __ Set(eax, Immediate(Smi::FromInt(1)));
+ }
+ }
+ __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
Label object_not_null, object_not_null_or_smi;
__ bind(&not_js_object);
@@ -5064,39 +5146,72 @@
// Null is not instance of anything.
__ cmp(object, Factory::null_value());
__ j(not_equal, &object_not_null);
- __ IncrementCounter(&Counters::instance_of_stub_false_null, 1);
__ Set(eax, Immediate(Smi::FromInt(1)));
- __ ret((args_in_registers() ? 0 : 2) * kPointerSize);
+ __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
__ bind(&object_not_null);
// Smi values is not instance of anything.
__ test(object, Immediate(kSmiTagMask));
__ j(not_zero, &object_not_null_or_smi, not_taken);
__ Set(eax, Immediate(Smi::FromInt(1)));
- __ ret((args_in_registers() ? 0 : 2) * kPointerSize);
+ __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
__ bind(&object_not_null_or_smi);
// String values is not instance of anything.
Condition is_string = masm->IsObjectStringType(object, scratch, scratch);
__ j(NegateCondition(is_string), &slow);
- __ IncrementCounter(&Counters::instance_of_stub_false_string, 1);
__ Set(eax, Immediate(Smi::FromInt(1)));
- __ ret((args_in_registers() ? 0 : 2) * kPointerSize);
+ __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
// Slow-case: Go through the JavaScript implementation.
__ bind(&slow);
- if (args_in_registers()) {
+ if (HasArgsInRegisters()) {
// Push arguments below return address.
__ pop(scratch);
__ push(object);
__ push(function);
__ push(scratch);
}
- __ IncrementCounter(&Counters::instance_of_slow, 1);
__ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
}
+Register InstanceofStub::left() { return eax; }
+
+
+Register InstanceofStub::right() { return edx; }
+
+
+const char* InstanceofStub::GetName() {
+ if (name_ != NULL) return name_;
+ const int kMaxNameLength = 100;
+ name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength);
+ if (name_ == NULL) return "OOM";
+
+ const char* args = "";
+ if (HasArgsInRegisters()) {
+ args = "_REGS";
+ }
+
+ const char* inline_check = "";
+ if (HasCallSiteInlineCheck()) {
+ inline_check = "_INLINE";
+ }
+
+ const char* return_true_false_object = "";
+ if (ReturnTrueFalseObject()) {
+ return_true_false_object = "_TRUEFALSE";
+ }
+
+ OS::SNPrintF(Vector<char>(name_, kMaxNameLength),
+ "InstanceofStub%s%s%s",
+ args,
+ inline_check,
+ return_true_false_object);
+ return name_;
+}
+
+
int CompareStub::MinorKey() {
// Encode the three parameters in a unique 16 bit value. To avoid duplicate
// stubs the never NaN NaN condition is only taken into account if the
« no previous file with comments | « src/hydrogen-instructions.h ('k') | src/ia32/full-codegen-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698