X64: Implement InstanceofStub. Prohibit zero-size code objects.
authorwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 2 Jul 2009 07:09:49 +0000 (07:09 +0000)
committerwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 2 Jul 2009 07:09:49 +0000 (07:09 +0000)
Review URL: http://codereview.chromium.org/151142

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2330 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/x64/assembler-x64.cc
src/x64/codegen-x64.cc
src/x64/macro-assembler-x64.cc
src/x64/macro-assembler-x64.h

index ced7577..c3b2538 100644 (file)
@@ -273,6 +273,7 @@ void Assembler::GetCode(CodeDesc* desc) {
   desc->buffer = buffer_;
   desc->buffer_size = buffer_size_;
   desc->instr_size = pc_offset();
+  ASSERT(desc->instr_size > 0);  // Zero-size code objects upset the system.
   desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
   desc->origin = this;
 
index 4df63da..9ac05b0 100644 (file)
@@ -5771,6 +5771,62 @@ void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
 
 
 void InstanceofStub::Generate(MacroAssembler* masm) {
+  // Implements "value instanceof function" operator.
+  // Expected input state:
+  //   rsp[0] : return address
+  //   rsp[1] : function pointer
+  //   rsp[2] : value
+
+  // Get the object - go slow case if it's a smi.
+  Label slow;
+  __ movq(rax, Operand(rsp, 2 * kPointerSize));
+  __ testl(rax, Immediate(kSmiTagMask));
+  __ j(zero, &slow);
+
+  // Check that the left hand is a JS object. Leave its map in rax.
+  __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rax);
+  __ j(below, &slow);
+  __ CmpInstanceType(rax, LAST_JS_OBJECT_TYPE);
+  __ j(above, &slow);
+
+  // Get the prototype of the function.
+  __ movq(rdx, Operand(rsp, 1 * kPointerSize));
+  __ TryGetFunctionPrototype(rdx, rbx, &slow);
+
+  // Check that the function prototype is a JS object.
+  __ testl(rbx, Immediate(kSmiTagMask));
+  __ j(zero, &slow);
+  __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, kScratchRegister);
+  __ j(below, &slow);
+  __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE);
+  __ j(above, &slow);
+
+  // Register mapping: rax is object map and rbx is function prototype.
+  __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset));
+
+  // Loop through the prototype chain looking for the function prototype.
+  Label loop, is_instance, is_not_instance;
+  __ Move(kScratchRegister, Factory::null_value());
+  __ bind(&loop);
+  __ cmpq(rcx, rbx);
+  __ j(equal, &is_instance);
+  __ cmpq(rcx, kScratchRegister);
+  __ j(equal, &is_not_instance);
+  __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
+  __ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset));
+  __ jmp(&loop);
+
+  __ bind(&is_instance);
+  __ xor_(rax, rax);
+  __ ret(2 * kPointerSize);
+
+  __ bind(&is_not_instance);
+  __ movq(rax, Immediate(Smi::FromInt(1)));
+  __ ret(2 * kPointerSize);
+
+  // Slow-case: Go through the JavaScript implementation.
+  __ bind(&slow);
+  __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
 }
 
 
index 780fcdb..62b818a 100644 (file)
@@ -399,6 +399,51 @@ void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
 }
 
 
+void MacroAssembler::TryGetFunctionPrototype(Register function,
+                                             Register result,
+                                             Label* miss) {
+  // Check that the receiver isn't a smi.
+  testl(function, Immediate(kSmiTagMask));
+  j(zero, miss);
+
+  // Check that the function really is a function.
+  CmpObjectType(function, JS_FUNCTION_TYPE, result);
+  j(not_equal, miss);
+
+  // Make sure that the function has an instance prototype.
+  Label non_instance;
+  testb(FieldOperand(result, Map::kBitFieldOffset),
+        Immediate(1 << Map::kHasNonInstancePrototype));
+  j(not_zero, &non_instance);
+
+  // Get the prototype or initial map from the function.
+  movq(result,
+       FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
+
+  // If the prototype or initial map is the hole, don't return it and
+  // simply miss the cache instead. This will allow us to allocate a
+  // prototype object on-demand in the runtime system.
+  Cmp(result, Factory::the_hole_value());
+  j(equal, miss);
+
+  // If the function does not have an initial map, we're done.
+  Label done;
+  CmpObjectType(result, MAP_TYPE, kScratchRegister);
+  j(not_equal, &done);
+
+  // Get the prototype from the initial map.
+  movq(result, FieldOperand(result, Map::kPrototypeOffset));
+  jmp(&done);
+
+  // Non-instance prototype: Fetch prototype from constructor field
+  // in initial map.
+  bind(&non_instance);
+  movq(result, FieldOperand(result, Map::kConstructorOffset));
+
+  // All done.
+  bind(&done);
+}
+
 
 void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
   if (FLAG_native_code_counters && counter->Enabled()) {
index c298a25..f13a7ad 100644 (file)
@@ -176,6 +176,7 @@ class MacroAssembler: public Assembler {
 
   // Compare object type for heap object.
   // Incoming register is heap_object and outgoing register is map.
+  // They may be the same register, and may be kScratchRegister.
   void CmpObjectType(Register heap_object, InstanceType type, Register map);
 
   // Compare instance type for map.
@@ -237,11 +238,10 @@ class MacroAssembler: public Assembler {
   // Try to get function prototype of a function and puts the value in
   // the result register. Checks that the function really is a
   // function and jumps to the miss label if the fast checks fail. The
-  // function register will be untouched; the other registers may be
+  // function register will be untouched; the other register may be
   // clobbered.
   void TryGetFunctionPrototype(Register function,
                                Register result,
-                               Register scratch,
                                Label* miss);
 
   // Generates code for reporting that an illegal operation has
@@ -384,12 +384,12 @@ extern void LogGeneratedCodeCoverage(const char* file_line);
 #define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
 #define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
 #define ACCESS_MASM(masm) {                                               \
-    byte* x64_coverage_function =                                        \
+    byte* x64_coverage_function =                                         \
         reinterpret_cast<byte*>(FUNCTION_ADDR(LogGeneratedCodeCoverage)); \
     masm->pushfd();                                                       \
     masm->pushad();                                                       \
     masm->push(Immediate(reinterpret_cast<int>(&__FILE_LINE__)));         \
-    masm->call(x64_coverage_function, RelocInfo::RUNTIME_ENTRY);         \
+    masm->call(x64_coverage_function, RelocInfo::RUNTIME_ENTRY);          \
     masm->pop(rax);                                                       \
     masm->popad();                                                        \
     masm->popfd();                                                        \