From 2ddf3301da10d35975f461e1255cd865d74db998 Mon Sep 17 00:00:00 2001 From: "whesse@chromium.org" Date: Thu, 2 Jul 2009 07:09:49 +0000 Subject: [PATCH] X64: Implement InstanceofStub. Prohibit zero-size code objects. 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 | 1 + src/x64/codegen-x64.cc | 56 ++++++++++++++++++++++++++++++++++++++++++ src/x64/macro-assembler-x64.cc | 45 +++++++++++++++++++++++++++++++++ src/x64/macro-assembler-x64.h | 8 +++--- 4 files changed, 106 insertions(+), 4 deletions(-) diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc index ced7577..c3b2538 100644 --- a/src/x64/assembler-x64.cc +++ b/src/x64/assembler-x64.cc @@ -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; diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc index 4df63da..9ac05b0 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -5771,6 +5771,62 @@ void CodeGenerator::CallWithArguments(ZoneList* 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); } diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index 780fcdb..62b818a 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -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()) { diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h index c298a25..f13a7ad 100644 --- a/src/x64/macro-assembler-x64.h +++ b/src/x64/macro-assembler-x64.h @@ -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(FUNCTION_ADDR(LogGeneratedCodeCoverage)); \ masm->pushfd(); \ masm->pushad(); \ masm->push(Immediate(reinterpret_cast(&__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(); \ -- 2.7.4