Move PropertyAccessCompiler and CallOptimization to their own files

BUG=
R=yangguo@chromium.org

Review URL: https://codereview.chromium.org/480413008

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23320 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
verwaest@chromium.org 2014-08-22 14:36:54 +00:00
parent 082b65c5db
commit 50ea93c614
18 changed files with 527 additions and 370 deletions

View File

@ -714,6 +714,10 @@ source_set("v8_base") {
"src/i18n.h",
"src/icu_util.cc",
"src/icu_util.h",
"src/ic/access-compiler.cc",
"src/ic/access-compiler.h",
"src/ic/call-optimization.cc",
"src/ic/call-optimization.h",
"src/ic/ic-inl.h",
"src/ic/ic.cc",
"src/ic/ic.h",
@ -929,6 +933,7 @@ source_set("v8_base") {
"src/compiler/x64/instruction-codes-x64.h",
"src/compiler/x64/instruction-selector-x64.cc",
"src/compiler/x64/linkage-x64.cc",
"src/ic/x64/access-compiler-x64.cc",
"src/ic/x64/ic-x64.cc",
"src/ic/x64/ic-compiler-x64.cc",
"src/ic/x64/stub-cache-x64.cc",
@ -967,6 +972,7 @@ source_set("v8_base") {
"src/compiler/arm/instruction-codes-arm.h",
"src/compiler/arm/instruction-selector-arm.cc",
"src/compiler/arm/linkage-arm.cc",
"src/ic/arm/access-compiler-arm.cc",
"src/ic/arm/ic-arm.cc",
"src/ic/arm/ic-compiler-arm.cc",
"src/ic/arm/stub-cache-arm.cc",
@ -1016,6 +1022,7 @@ source_set("v8_base") {
"src/compiler/arm64/instruction-codes-arm64.h",
"src/compiler/arm64/instruction-selector-arm64.cc",
"src/compiler/arm64/linkage-arm64.cc",
"src/ic/arm64/access-compiler-arm64.cc",
"src/ic/arm64/ic-arm64.cc",
"src/ic/arm64/ic-compiler-arm64.cc",
"src/ic/arm64/stub-cache-arm64.cc",

View File

@ -34,16 +34,15 @@
#include "src/hydrogen-sce.h"
#include "src/hydrogen-store-elimination.h"
#include "src/hydrogen-uint32-analysis.h"
#include "src/ic/call-optimization.h"
// GetRootConstructor
#include "src/ic/ic-inl.h"
#include "src/lithium-allocator.h"
#include "src/parser.h"
#include "src/runtime.h"
#include "src/scopeinfo.h"
#include "src/scopes.h"
#include "src/typing.h"
// CallOptimization
#include "src/ic/ic-compiler.h"
// GetRootConstructor
#include "src/ic/ic-inl.h"
#if V8_TARGET_ARCH_IA32
#include "src/ia32/lithium-codegen-ia32.h" // NOLINT

55
src/ic/access-compiler.cc Normal file
View File

@ -0,0 +1,55 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/v8.h"
#include "src/ic/access-compiler.h"
namespace v8 {
namespace internal {
Handle<Code> PropertyAccessCompiler::GetCodeWithFlags(Code::Flags flags,
const char* name) {
// Create code object in the heap.
CodeDesc desc;
masm()->GetCode(&desc);
Handle<Code> code = factory()->NewCode(desc, flags, masm()->CodeObject());
if (code->IsCodeStubOrIC()) code->set_stub_key(CodeStub::NoCacheKey());
#ifdef ENABLE_DISASSEMBLER
if (FLAG_print_code_stubs) {
OFStream os(stdout);
code->Disassemble(name, os);
}
#endif
return code;
}
Handle<Code> PropertyAccessCompiler::GetCodeWithFlags(Code::Flags flags,
Handle<Name> name) {
return (FLAG_print_code_stubs && !name.is_null() && name->IsString())
? GetCodeWithFlags(flags,
Handle<String>::cast(name)->ToCString().get())
: GetCodeWithFlags(flags, NULL);
}
void PropertyAccessCompiler::TailCallBuiltin(MacroAssembler* masm,
Builtins::Name name) {
Handle<Code> code(masm->isolate()->builtins()->builtin(name));
GenerateTailCall(masm, code);
}
Register* PropertyAccessCompiler::GetCallingConvention(Code::Kind kind) {
if (kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC) {
return load_calling_convention();
}
DCHECK(kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC);
return store_calling_convention();
}
}
} // namespace v8::internal

83
src/ic/access-compiler.h Normal file
View File

@ -0,0 +1,83 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_IC_ACCESS_COMPILER_H_
#define V8_IC_ACCESS_COMPILER_H_
#include "src/code-stubs.h"
#include "src/macro-assembler.h"
#include "src/objects.h"
namespace v8 {
namespace internal {
class PropertyAccessCompiler BASE_EMBEDDED {
public:
static Builtins::Name MissBuiltin(Code::Kind kind) {
switch (kind) {
case Code::LOAD_IC:
return Builtins::kLoadIC_Miss;
case Code::STORE_IC:
return Builtins::kStoreIC_Miss;
case Code::KEYED_LOAD_IC:
return Builtins::kKeyedLoadIC_Miss;
case Code::KEYED_STORE_IC:
return Builtins::kKeyedStoreIC_Miss;
default:
UNREACHABLE();
}
return Builtins::kLoadIC_Miss;
}
static void TailCallBuiltin(MacroAssembler* masm, Builtins::Name name);
protected:
PropertyAccessCompiler(Isolate* isolate, Code::Kind kind,
CacheHolderFlag cache_holder)
: registers_(GetCallingConvention(kind)),
kind_(kind),
cache_holder_(cache_holder),
isolate_(isolate),
masm_(isolate, NULL, 256) {}
Code::Kind kind() const { return kind_; }
CacheHolderFlag cache_holder() const { return cache_holder_; }
MacroAssembler* masm() { return &masm_; }
Isolate* isolate() const { return isolate_; }
Heap* heap() const { return isolate()->heap(); }
Factory* factory() const { return isolate()->factory(); }
Register receiver() const { return registers_[0]; }
Register name() const { return registers_[1]; }
Register scratch1() const { return registers_[2]; }
Register scratch2() const { return registers_[3]; }
Register scratch3() const { return registers_[4]; }
// Calling convention between indexed store IC and handler.
Register transition_map() const { return scratch1(); }
static Register* GetCallingConvention(Code::Kind);
static Register* load_calling_convention();
static Register* store_calling_convention();
static Register* keyed_store_calling_convention();
Register* registers_;
static void GenerateTailCall(MacroAssembler* masm, Handle<Code> code);
Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name);
Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<Name> name);
private:
Code::Kind kind_;
CacheHolderFlag cache_holder_;
Isolate* isolate_;
MacroAssembler masm_;
};
}
} // namespace v8::internal
#endif // V8_IC_ACCESS_COMPILER_H_

View File

@ -0,0 +1,46 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/v8.h"
#if V8_TARGET_ARCH_ARM
#include "src/ic/access-compiler.h"
namespace v8 {
namespace internal {
#define __ ACCESS_MASM(masm)
void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
Handle<Code> code) {
__ Jump(code, RelocInfo::CODE_TARGET);
}
Register* PropertyAccessCompiler::load_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3, scratch4.
Register receiver = LoadIC::ReceiverRegister();
Register name = LoadIC::NameRegister();
static Register registers[] = {receiver, name, r3, r0, r4, r5};
return registers;
}
Register* PropertyAccessCompiler::store_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3.
Register receiver = StoreIC::ReceiverRegister();
Register name = StoreIC::NameRegister();
DCHECK(r3.is(KeyedStoreIC::MapRegister()));
static Register registers[] = {receiver, name, r3, r4, r5};
return registers;
}
#undef __
}
} // namespace v8::internal
#endif // V8_TARGET_ARCH_IA32

View File

@ -6,6 +6,7 @@
#if V8_TARGET_ARCH_ARM
#include "src/ic/call-optimization.h"
#include "src/ic/ic-compiler.h"
namespace v8 {
@ -209,12 +210,6 @@ void PropertyHandlerCompiler::GenerateFastApiCall(
}
void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
Handle<Code> code) {
__ Jump(code, RelocInfo::CODE_TARGET);
}
#undef __
#define __ ACCESS_MASM(masm())
@ -751,25 +746,6 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
}
Register* PropertyAccessCompiler::load_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3, scratch4.
Register receiver = LoadIC::ReceiverRegister();
Register name = LoadIC::NameRegister();
static Register registers[] = {receiver, name, r3, r0, r4, r5};
return registers;
}
Register* PropertyAccessCompiler::store_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3.
Register receiver = StoreIC::ReceiverRegister();
Register name = StoreIC::NameRegister();
DCHECK(r3.is(KeyedStoreIC::MapRegister()));
static Register registers[] = {receiver, name, r3, r4, r5};
return registers;
}
Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); }

View File

@ -0,0 +1,53 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/v8.h"
#if V8_TARGET_ARCH_ARM64
#include "src/ic/access-compiler.h"
namespace v8 {
namespace internal {
#define __ ACCESS_MASM(masm)
void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
Handle<Code> code) {
__ Jump(code, RelocInfo::CODE_TARGET);
}
// TODO(all): The so-called scratch registers are significant in some cases. For
// example, PropertyAccessCompiler::keyed_store_calling_convention()[3] (x3) is
// actually
// used for KeyedStoreCompiler::transition_map(). We should verify which
// registers are actually scratch registers, and which are important. For now,
// we use the same assignments as ARM to remain on the safe side.
Register* PropertyAccessCompiler::load_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3, scratch4.
Register receiver = LoadIC::ReceiverRegister();
Register name = LoadIC::NameRegister();
static Register registers[] = {receiver, name, x3, x0, x4, x5};
return registers;
}
Register* PropertyAccessCompiler::store_calling_convention() {
// receiver, value, scratch1, scratch2, scratch3.
Register receiver = StoreIC::ReceiverRegister();
Register name = StoreIC::NameRegister();
DCHECK(x3.is(KeyedStoreIC::MapRegister()));
static Register registers[] = {receiver, name, x3, x4, x5};
return registers;
}
#undef __
}
} // namespace v8::internal
#endif // V8_TARGET_ARCH_ARM64

View File

@ -6,6 +6,7 @@
#if V8_TARGET_ARCH_ARM64
#include "src/ic/call-optimization.h"
#include "src/ic/ic-compiler.h"
namespace v8 {
@ -205,12 +206,6 @@ void PropertyHandlerCompiler::GenerateFastApiCall(
}
void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
Handle<Code> code) {
__ Jump(code, RelocInfo::CODE_TARGET);
}
#undef __
#define __ ACCESS_MASM(masm())
@ -763,32 +758,6 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
}
// TODO(all): The so-called scratch registers are significant in some cases. For
// example, PropertyAccessCompiler::keyed_store_calling_convention()[3] (x3) is
// actually
// used for KeyedStoreCompiler::transition_map(). We should verify which
// registers are actually scratch registers, and which are important. For now,
// we use the same assignments as ARM to remain on the safe side.
Register* PropertyAccessCompiler::load_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3, scratch4.
Register receiver = LoadIC::ReceiverRegister();
Register name = LoadIC::NameRegister();
static Register registers[] = {receiver, name, x3, x0, x4, x5};
return registers;
}
Register* PropertyAccessCompiler::store_calling_convention() {
// receiver, value, scratch1, scratch2, scratch3.
Register receiver = StoreIC::ReceiverRegister();
Register name = StoreIC::NameRegister();
DCHECK(x3.is(KeyedStoreIC::MapRegister()));
static Register registers[] = {receiver, name, x3, x4, x5};
return registers;
}
Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); }

113
src/ic/call-optimization.cc Normal file
View File

@ -0,0 +1,113 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/v8.h"
#include "src/ic/call-optimization.h"
namespace v8 {
namespace internal {
CallOptimization::CallOptimization(Handle<JSFunction> function) {
Initialize(function);
}
Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
Handle<Map> object_map, HolderLookup* holder_lookup) const {
DCHECK(is_simple_api_call());
if (!object_map->IsJSObjectMap()) {
*holder_lookup = kHolderNotFound;
return Handle<JSObject>::null();
}
if (expected_receiver_type_.is_null() ||
expected_receiver_type_->IsTemplateFor(*object_map)) {
*holder_lookup = kHolderIsReceiver;
return Handle<JSObject>::null();
}
while (true) {
if (!object_map->prototype()->IsJSObject()) break;
Handle<JSObject> prototype(JSObject::cast(object_map->prototype()));
if (!prototype->map()->is_hidden_prototype()) break;
object_map = handle(prototype->map());
if (expected_receiver_type_->IsTemplateFor(*object_map)) {
*holder_lookup = kHolderFound;
return prototype;
}
}
*holder_lookup = kHolderNotFound;
return Handle<JSObject>::null();
}
bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
Handle<JSObject> holder) const {
DCHECK(is_simple_api_call());
if (!receiver->IsJSObject()) return false;
Handle<Map> map(JSObject::cast(*receiver)->map());
HolderLookup holder_lookup;
Handle<JSObject> api_holder = LookupHolderOfExpectedType(map, &holder_lookup);
switch (holder_lookup) {
case kHolderNotFound:
return false;
case kHolderIsReceiver:
return true;
case kHolderFound:
if (api_holder.is_identical_to(holder)) return true;
// Check if holder is in prototype chain of api_holder.
{
JSObject* object = *api_holder;
while (true) {
Object* prototype = object->map()->prototype();
if (!prototype->IsJSObject()) return false;
if (prototype == *holder) return true;
object = JSObject::cast(prototype);
}
}
break;
}
UNREACHABLE();
return false;
}
void CallOptimization::Initialize(Handle<JSFunction> function) {
constant_function_ = Handle<JSFunction>::null();
is_simple_api_call_ = false;
expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
api_call_info_ = Handle<CallHandlerInfo>::null();
if (function.is_null() || !function->is_compiled()) return;
constant_function_ = function;
AnalyzePossibleApiFunction(function);
}
void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
if (!function->shared()->IsApiFunction()) return;
Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data());
// Require a C++ callback.
if (info->call_code()->IsUndefined()) return;
api_call_info_ =
Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code()));
// Accept signatures that either have no restrictions at all or
// only have restrictions on the receiver.
if (!info->signature()->IsUndefined()) {
Handle<SignatureInfo> signature =
Handle<SignatureInfo>(SignatureInfo::cast(info->signature()));
if (!signature->args()->IsUndefined()) return;
if (!signature->receiver()->IsUndefined()) {
expected_receiver_type_ = Handle<FunctionTemplateInfo>(
FunctionTemplateInfo::cast(signature->receiver()));
}
}
is_simple_api_call_ = true;
}
}
} // namespace v8::internal

View File

@ -0,0 +1,62 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_IC_CALL_OPTIMIZATION_H_
#define V8_IC_CALL_OPTIMIZATION_H_
#include "src/code-stubs.h"
#include "src/ic/access-compiler.h"
#include "src/macro-assembler.h"
#include "src/objects.h"
namespace v8 {
namespace internal {
// Holds information about possible function call optimizations.
class CallOptimization BASE_EMBEDDED {
public:
explicit CallOptimization(Handle<JSFunction> function);
bool is_constant_call() const { return !constant_function_.is_null(); }
Handle<JSFunction> constant_function() const {
DCHECK(is_constant_call());
return constant_function_;
}
bool is_simple_api_call() const { return is_simple_api_call_; }
Handle<FunctionTemplateInfo> expected_receiver_type() const {
DCHECK(is_simple_api_call());
return expected_receiver_type_;
}
Handle<CallHandlerInfo> api_call_info() const {
DCHECK(is_simple_api_call());
return api_call_info_;
}
enum HolderLookup { kHolderNotFound, kHolderIsReceiver, kHolderFound };
Handle<JSObject> LookupHolderOfExpectedType(
Handle<Map> receiver_map, HolderLookup* holder_lookup) const;
// Check if the api holder is between the receiver and the holder.
bool IsCompatibleReceiver(Handle<Object> receiver,
Handle<JSObject> holder) const;
private:
void Initialize(Handle<JSFunction> function);
// Determines whether the given function can be called using the
// fast api call builtin.
void AnalyzePossibleApiFunction(Handle<JSFunction> function);
Handle<JSFunction> constant_function_;
bool is_simple_api_call_;
Handle<FunctionTemplateInfo> expected_receiver_type_;
Handle<CallHandlerInfo> api_call_info_;
};
}
} // namespace v8::internal
#endif // V8_IC_CALL_OPTIMIZATION_H_

View File

@ -0,0 +1,44 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/v8.h"
#if V8_TARGET_ARCH_IA32
#include "src/ic/access-compiler.h"
namespace v8 {
namespace internal {
#define __ ACCESS_MASM(masm)
void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
Handle<Code> code) {
__ jmp(code, RelocInfo::CODE_TARGET);
}
Register* PropertyAccessCompiler::load_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3, scratch4.
Register receiver = LoadIC::ReceiverRegister();
Register name = LoadIC::NameRegister();
static Register registers[] = {receiver, name, ebx, eax, edi, no_reg};
return registers;
}
Register* PropertyAccessCompiler::store_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3.
Register receiver = StoreIC::ReceiverRegister();
Register name = StoreIC::NameRegister();
DCHECK(ebx.is(KeyedStoreIC::MapRegister()));
static Register registers[] = {receiver, name, ebx, edi, no_reg};
return registers;
}
#undef __
}
} // namespace v8::internal
#endif // V8_TARGET_ARCH_IA32

View File

@ -6,6 +6,7 @@
#if V8_TARGET_ARCH_IA32
#include "src/ic/call-optimization.h"
#include "src/ic/ic-compiler.h"
namespace v8 {
@ -206,12 +207,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
}
void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
Handle<Code> code) {
__ jmp(code, RelocInfo::CODE_TARGET);
}
#undef __
#define __ ACCESS_MASM(masm())
@ -778,25 +773,6 @@ Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
}
Register* PropertyAccessCompiler::load_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3, scratch4.
Register receiver = LoadIC::ReceiverRegister();
Register name = LoadIC::NameRegister();
static Register registers[] = {receiver, name, ebx, eax, edi, no_reg};
return registers;
}
Register* PropertyAccessCompiler::store_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3.
Register receiver = StoreIC::ReceiverRegister();
Register name = StoreIC::NameRegister();
DCHECK(ebx.is(KeyedStoreIC::MapRegister()));
static Register registers[] = {receiver, name, ebx, edi, no_reg};
return registers;
}
Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); }

View File

@ -4,6 +4,7 @@
#include "src/v8.h"
#include "src/ic/call-optimization.h"
#include "src/ic/ic-inl.h"
#include "src/ic/ic-compiler.h"
@ -178,9 +179,6 @@ Handle<Code> PropertyICCompiler::ComputeKeyedStoreMonomorphic(
}
#define CALL_LOGGER_TAG(kind, type) (Logger::KEYED_##type)
Code* PropertyICCompiler::FindPreMonomorphic(Isolate* isolate, Code::Kind kind,
ExtraICState state) {
Code::Flags flags = Code::ComputeFlags(kind, PREMONOMORPHIC, state);
@ -402,35 +400,6 @@ Handle<Code> PropertyICCompiler::CompileStoreMegamorphic(Code::Flags flags) {
}
#undef CALL_LOGGER_TAG
Handle<Code> PropertyAccessCompiler::GetCodeWithFlags(Code::Flags flags,
const char* name) {
// Create code object in the heap.
CodeDesc desc;
masm()->GetCode(&desc);
Handle<Code> code = factory()->NewCode(desc, flags, masm()->CodeObject());
if (code->IsCodeStubOrIC()) code->set_stub_key(CodeStub::NoCacheKey());
#ifdef ENABLE_DISASSEMBLER
if (FLAG_print_code_stubs) {
OFStream os(stdout);
code->Disassemble(name, os);
}
#endif
return code;
}
Handle<Code> PropertyAccessCompiler::GetCodeWithFlags(Code::Flags flags,
Handle<Name> name) {
return (FLAG_print_code_stubs && !name.is_null() && name->IsString())
? GetCodeWithFlags(flags,
Handle<String>::cast(name)->ToCString().get())
: GetCodeWithFlags(flags, NULL);
}
#define __ ACCESS_MASM(masm())
@ -755,22 +724,6 @@ Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphic(
#undef __
void PropertyAccessCompiler::TailCallBuiltin(MacroAssembler* masm,
Builtins::Name name) {
Handle<Code> code(masm->isolate()->builtins()->builtin(name));
GenerateTailCall(masm, code);
}
Register* PropertyAccessCompiler::GetCallingConvention(Code::Kind kind) {
if (kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC) {
return load_calling_convention();
}
DCHECK(kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC);
return store_calling_convention();
}
Handle<Code> PropertyICCompiler::GetCode(Code::Kind kind, Code::StubType type,
Handle<Name> name,
InlineCacheState state) {
@ -880,104 +833,5 @@ void ElementHandlerCompiler::GenerateStoreDictionaryElement(
}
CallOptimization::CallOptimization(Handle<JSFunction> function) {
Initialize(function);
}
Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
Handle<Map> object_map, HolderLookup* holder_lookup) const {
DCHECK(is_simple_api_call());
if (!object_map->IsJSObjectMap()) {
*holder_lookup = kHolderNotFound;
return Handle<JSObject>::null();
}
if (expected_receiver_type_.is_null() ||
expected_receiver_type_->IsTemplateFor(*object_map)) {
*holder_lookup = kHolderIsReceiver;
return Handle<JSObject>::null();
}
while (true) {
if (!object_map->prototype()->IsJSObject()) break;
Handle<JSObject> prototype(JSObject::cast(object_map->prototype()));
if (!prototype->map()->is_hidden_prototype()) break;
object_map = handle(prototype->map());
if (expected_receiver_type_->IsTemplateFor(*object_map)) {
*holder_lookup = kHolderFound;
return prototype;
}
}
*holder_lookup = kHolderNotFound;
return Handle<JSObject>::null();
}
bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
Handle<JSObject> holder) const {
DCHECK(is_simple_api_call());
if (!receiver->IsJSObject()) return false;
Handle<Map> map(JSObject::cast(*receiver)->map());
HolderLookup holder_lookup;
Handle<JSObject> api_holder = LookupHolderOfExpectedType(map, &holder_lookup);
switch (holder_lookup) {
case kHolderNotFound:
return false;
case kHolderIsReceiver:
return true;
case kHolderFound:
if (api_holder.is_identical_to(holder)) return true;
// Check if holder is in prototype chain of api_holder.
{
JSObject* object = *api_holder;
while (true) {
Object* prototype = object->map()->prototype();
if (!prototype->IsJSObject()) return false;
if (prototype == *holder) return true;
object = JSObject::cast(prototype);
}
}
break;
}
UNREACHABLE();
return false;
}
void CallOptimization::Initialize(Handle<JSFunction> function) {
constant_function_ = Handle<JSFunction>::null();
is_simple_api_call_ = false;
expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
api_call_info_ = Handle<CallHandlerInfo>::null();
if (function.is_null() || !function->is_compiled()) return;
constant_function_ = function;
AnalyzePossibleApiFunction(function);
}
void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
if (!function->shared()->IsApiFunction()) return;
Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data());
// Require a C++ callback.
if (info->call_code()->IsUndefined()) return;
api_call_info_ =
Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code()));
// Accept signatures that either have no restrictions at all or
// only have restrictions on the receiver.
if (!info->signature()->IsUndefined()) {
Handle<SignatureInfo> signature =
Handle<SignatureInfo>(SignatureInfo::cast(info->signature()));
if (!signature->args()->IsUndefined()) return;
if (!signature->receiver()->IsUndefined()) {
expected_receiver_type_ = Handle<FunctionTemplateInfo>(
FunctionTemplateInfo::cast(signature->receiver()));
}
}
is_simple_api_call_ = true;
}
}
} // namespace v8::internal

View File

@ -6,6 +6,7 @@
#define V8_IC_IC_COMPILER_H_
#include "src/code-stubs.h"
#include "src/ic/access-compiler.h"
#include "src/macro-assembler.h"
#include "src/objects.h"
@ -14,80 +15,12 @@ namespace internal {
class CallOptimization;
class SmallMapList;
class StubCache;
enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER };
enum IcCheckType { ELEMENT, PROPERTY };
class PropertyAccessCompiler BASE_EMBEDDED {
public:
static Builtins::Name MissBuiltin(Code::Kind kind) {
switch (kind) {
case Code::LOAD_IC:
return Builtins::kLoadIC_Miss;
case Code::STORE_IC:
return Builtins::kStoreIC_Miss;
case Code::KEYED_LOAD_IC:
return Builtins::kKeyedLoadIC_Miss;
case Code::KEYED_STORE_IC:
return Builtins::kKeyedStoreIC_Miss;
default:
UNREACHABLE();
}
return Builtins::kLoadIC_Miss;
}
static void TailCallBuiltin(MacroAssembler* masm, Builtins::Name name);
protected:
PropertyAccessCompiler(Isolate* isolate, Code::Kind kind,
CacheHolderFlag cache_holder)
: registers_(GetCallingConvention(kind)),
kind_(kind),
cache_holder_(cache_holder),
isolate_(isolate),
masm_(isolate, NULL, 256) {}
Code::Kind kind() const { return kind_; }
CacheHolderFlag cache_holder() const { return cache_holder_; }
MacroAssembler* masm() { return &masm_; }
Isolate* isolate() const { return isolate_; }
Heap* heap() const { return isolate()->heap(); }
Factory* factory() const { return isolate()->factory(); }
Register receiver() const { return registers_[0]; }
Register name() const { return registers_[1]; }
Register scratch1() const { return registers_[2]; }
Register scratch2() const { return registers_[3]; }
Register scratch3() const { return registers_[4]; }
// Calling convention between indexed store IC and handler.
Register transition_map() const { return scratch1(); }
static Register* GetCallingConvention(Code::Kind);
static Register* load_calling_convention();
static Register* store_calling_convention();
static Register* keyed_store_calling_convention();
Register* registers_;
static void GenerateTailCall(MacroAssembler* masm, Handle<Code> code);
Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name);
Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<Name> name);
private:
Code::Kind kind_;
CacheHolderFlag cache_holder_;
Isolate* isolate_;
MacroAssembler masm_;
};
class PropertyICCompiler : public PropertyAccessCompiler {
public:
// Finds the Code object stored in the Heap::non_monomorphic_cache().
@ -451,50 +384,6 @@ class ElementHandlerCompiler : public PropertyHandlerCompiler {
};
// Holds information about possible function call optimizations.
class CallOptimization BASE_EMBEDDED {
public:
explicit CallOptimization(Handle<JSFunction> function);
bool is_constant_call() const { return !constant_function_.is_null(); }
Handle<JSFunction> constant_function() const {
DCHECK(is_constant_call());
return constant_function_;
}
bool is_simple_api_call() const { return is_simple_api_call_; }
Handle<FunctionTemplateInfo> expected_receiver_type() const {
DCHECK(is_simple_api_call());
return expected_receiver_type_;
}
Handle<CallHandlerInfo> api_call_info() const {
DCHECK(is_simple_api_call());
return api_call_info_;
}
enum HolderLookup { kHolderNotFound, kHolderIsReceiver, kHolderFound };
Handle<JSObject> LookupHolderOfExpectedType(
Handle<Map> receiver_map, HolderLookup* holder_lookup) const;
// Check if the api holder is between the receiver and the holder.
bool IsCompatibleReceiver(Handle<Object> receiver,
Handle<JSObject> holder) const;
private:
void Initialize(Handle<JSFunction> function);
// Determines whether the given function can be called using the
// fast api call builtin.
void AnalyzePossibleApiFunction(Handle<JSFunction> function);
Handle<JSFunction> constant_function_;
bool is_simple_api_call_;
Handle<FunctionTemplateInfo> expected_receiver_type_;
Handle<CallHandlerInfo> api_call_info_;
};
}
} // namespace v8::internal

View File

@ -10,6 +10,7 @@
#include "src/codegen.h"
#include "src/conversions.h"
#include "src/execution.h"
#include "src/ic/call-optimization.h"
#include "src/ic/ic-inl.h"
#include "src/ic/ic-compiler.h"
#include "src/ic/stub-cache.h"

View File

@ -0,0 +1,46 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/v8.h"
#if V8_TARGET_ARCH_X64
#include "src/ic/access-compiler.h"
namespace v8 {
namespace internal {
#define __ ACCESS_MASM(masm)
void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
Handle<Code> code) {
__ jmp(code, RelocInfo::CODE_TARGET);
}
Register* PropertyAccessCompiler::load_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3, scratch4.
Register receiver = LoadIC::ReceiverRegister();
Register name = LoadIC::NameRegister();
static Register registers[] = {receiver, name, rax, rbx, rdi, r8};
return registers;
}
Register* PropertyAccessCompiler::store_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3.
Register receiver = KeyedStoreIC::ReceiverRegister();
Register name = KeyedStoreIC::NameRegister();
DCHECK(rbx.is(KeyedStoreIC::MapRegister()));
static Register registers[] = {receiver, name, rbx, rdi, r8};
return registers;
}
#undef __
}
} // namespace v8::internal
#endif // V8_TARGET_ARCH_X64

View File

@ -6,6 +6,7 @@
#if V8_TARGET_ARCH_X64
#include "src/ic/call-optimization.h"
#include "src/ic/ic-compiler.h"
namespace v8 {
@ -198,12 +199,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
}
void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
Handle<Code> code) {
__ jmp(code, RelocInfo::CODE_TARGET);
}
#undef __
#define __ ACCESS_MASM((masm()))
@ -768,25 +763,6 @@ Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
}
Register* PropertyAccessCompiler::load_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3, scratch4.
Register receiver = LoadIC::ReceiverRegister();
Register name = LoadIC::NameRegister();
static Register registers[] = {receiver, name, rax, rbx, rdi, r8};
return registers;
}
Register* PropertyAccessCompiler::store_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3.
Register receiver = KeyedStoreIC::ReceiverRegister();
Register name = KeyedStoreIC::NameRegister();
DCHECK(rbx.is(KeyedStoreIC::MapRegister()));
static Register registers[] = {receiver, name, rbx, rdi, r8};
return registers;
}
Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); }

View File

@ -599,6 +599,10 @@
'../../src/i18n.h',
'../../src/icu_util.cc',
'../../src/icu_util.h',
'../../src/ic/access-compiler.cc',
'../../src/ic/access-compiler.h',
'../../src/ic/call-optimization.cc',
'../../src/ic/call-optimization.h',
'../../src/ic/ic-inl.h',
'../../src/ic/ic.cc',
'../../src/ic/ic.h',
@ -789,6 +793,7 @@
'../../src/compiler/arm/instruction-codes-arm.h',
'../../src/compiler/arm/instruction-selector-arm.cc',
'../../src/compiler/arm/linkage-arm.cc',
'../../src/ic/arm/access-compiler-arm.cc',
'../../src/ic/arm/ic-arm.cc',
'../../src/ic/arm/ic-compiler-arm.cc',
'../../src/ic/arm/stub-cache-arm.cc',
@ -842,6 +847,7 @@
'../../src/compiler/arm64/instruction-codes-arm64.h',
'../../src/compiler/arm64/instruction-selector-arm64.cc',
'../../src/compiler/arm64/linkage-arm64.cc',
'../../src/ic/arm64/access-compiler-arm64.cc',
'../../src/ic/arm64/ic-arm64.cc',
'../../src/ic/arm64/ic-compiler-arm64.cc',
'../../src/ic/arm64/stub-cache-arm64.cc',
@ -878,6 +884,7 @@
'../../src/compiler/ia32/instruction-codes-ia32.h',
'../../src/compiler/ia32/instruction-selector-ia32.cc',
'../../src/compiler/ia32/linkage-ia32.cc',
'../../src/ic/ia32/access-compiler-ia32.cc',
'../../src/ic/ia32/ic-ia32.cc',
'../../src/ic/ia32/ic-compiler-ia32.cc',
'../../src/ic/ia32/stub-cache-ia32.cc',
@ -1013,6 +1020,7 @@
'../../src/compiler/x64/instruction-codes-x64.h',
'../../src/compiler/x64/instruction-selector-x64.cc',
'../../src/compiler/x64/linkage-x64.cc',
'../../src/ic/x64/access-compiler-x64.cc',
'../../src/ic/x64/ic-x64.cc',
'../../src/ic/x64/ic-compiler-x64.cc',
'../../src/ic/x64/stub-cache-x64.cc',