Port inlining of type checks in call ICs for API functions to x64 and arm (issue 602, r3825).

Review URL: http://codereview.chromium.org/1650011


git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4540 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6f099e4c
......@@ -722,6 +722,7 @@ void MacroAssembler::PopTryHandler() {
Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
JSObject* holder, Register holder_reg,
Register scratch,
int save_at_depth,
Label* miss) {
// Make sure there's no overlap between scratch and the other
// registers.
......@@ -729,7 +730,11 @@ Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
// Keep track of the current object in register reg.
Register reg = object_reg;
int depth = 1;
int depth = 0;
if (save_at_depth == depth) {
str(reg, MemOperand(sp));
}
// Check the maps in the prototype chain.
// Traverse the prototype chain from the object and do map checks.
......@@ -769,6 +774,10 @@ Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
mov(reg, Operand(Handle<JSObject>(prototype)));
}
if (save_at_depth == depth) {
str(reg, MemOperand(sp));
}
// Go to the next object in the prototype chain.
object = prototype;
}
......@@ -779,7 +788,7 @@ Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
b(ne, miss);
// Log the check depth.
LOG(IntEvent("check-maps-depth", depth));
LOG(IntEvent("check-maps-depth", depth + 1));
// Perform security check for access to the global object and return
// the holder register.
......
......@@ -243,9 +243,14 @@ class MacroAssembler: public Assembler {
// clobbered if it the same as the holder register. The function
// returns a register containing the holder - either object_reg or
// holder_reg.
// The function can optionally (when save_at_depth !=
// kInvalidProtoDepth) save the object at the given depth by moving
// it to [sp].
Register CheckMaps(JSObject* object, Register object_reg,
JSObject* holder, Register holder_reg,
Register scratch, Label* miss);
Register scratch,
int save_at_depth,
Label* miss);
// Generate code for checking access rights - used for security checks
// on access to global objects across environments. The holder register
......
This diff is collapsed.
......@@ -477,107 +477,6 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
};
// Holds information about possible function call optimizations.
class CallOptimization BASE_EMBEDDED {
public:
explicit CallOptimization(LookupResult* lookup) {
if (!lookup->IsProperty() || !lookup->IsCacheable() ||
lookup->type() != CONSTANT_FUNCTION) {
Initialize(NULL);
} else {
// We only optimize constant function calls.
Initialize(lookup->GetConstantFunction());
}
}
explicit CallOptimization(JSFunction* function) {
Initialize(function);
}
bool is_constant_call() const {
return constant_function_ != NULL;
}
JSFunction* constant_function() const {
ASSERT(constant_function_ != NULL);
return constant_function_;
}
bool is_simple_api_call() const {
return is_simple_api_call_;
}
FunctionTemplateInfo* expected_receiver_type() const {
ASSERT(is_simple_api_call_);
return expected_receiver_type_;
}
CallHandlerInfo* api_call_info() const {
ASSERT(is_simple_api_call_);
return api_call_info_;
}
// Returns the depth of the object having the expected type in the
// prototype chain between the two arguments.
int GetPrototypeDepthOfExpectedType(JSObject* object,
JSObject* holder) const {
ASSERT(is_simple_api_call_);
if (expected_receiver_type_ == NULL) return 0;
int depth = 0;
while (object != holder) {
if (object->IsInstanceOf(expected_receiver_type_)) return depth;
object = JSObject::cast(object->GetPrototype());
++depth;
}
if (holder->IsInstanceOf(expected_receiver_type_)) return depth;
return kInvalidProtoDepth;
}
private:
void Initialize(JSFunction* function) {
constant_function_ = NULL;
is_simple_api_call_ = false;
expected_receiver_type_ = NULL;
api_call_info_ = NULL;
if (function == NULL || !function->is_compiled()) return;
constant_function_ = function;
AnalyzePossibleApiFunction(function);
}
// Determines whether the given function can be called using the
// fast api call builtin.
void AnalyzePossibleApiFunction(JSFunction* function) {
SharedFunctionInfo* sfi = function->shared();
if (!sfi->IsApiFunction()) return;
FunctionTemplateInfo* info = sfi->get_api_func_data();
// Require a C++ callback.
if (info->call_code()->IsUndefined()) return;
api_call_info_ = 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()) {
SignatureInfo* signature = SignatureInfo::cast(info->signature());
if (!signature->args()->IsUndefined()) return;
if (!signature->receiver()->IsUndefined()) {
expected_receiver_type_ =
FunctionTemplateInfo::cast(signature->receiver());
}
}
is_simple_api_call_ = true;
}
JSFunction* constant_function_;
bool is_simple_api_call_;
FunctionTemplateInfo* expected_receiver_type_;
CallHandlerInfo* api_call_info_;
};
// Reserves space for the extra arguments to FastHandleApiCall in the
// caller's frame.
//
......
......@@ -1164,4 +1164,71 @@ Object* ConstructStubCompiler::GetCode() {
}
CallOptimization::CallOptimization(LookupResult* lookup) {
if (!lookup->IsProperty() || !lookup->IsCacheable() ||
lookup->type() != CONSTANT_FUNCTION) {
Initialize(NULL);
} else {
// We only optimize constant function calls.
Initialize(lookup->GetConstantFunction());
}
}
CallOptimization::CallOptimization(JSFunction* function) {
Initialize(function);
}
int CallOptimization::GetPrototypeDepthOfExpectedType(JSObject* object,
JSObject* holder) const {
ASSERT(is_simple_api_call_);
if (expected_receiver_type_ == NULL) return 0;
int depth = 0;
while (object != holder) {
if (object->IsInstanceOf(expected_receiver_type_)) return depth;
object = JSObject::cast(object->GetPrototype());
++depth;
}
if (holder->IsInstanceOf(expected_receiver_type_)) return depth;
return kInvalidProtoDepth;
}
void CallOptimization::Initialize(JSFunction* function) {
constant_function_ = NULL;
is_simple_api_call_ = false;
expected_receiver_type_ = NULL;
api_call_info_ = NULL;
if (function == NULL || !function->is_compiled()) return;
constant_function_ = function;
AnalyzePossibleApiFunction(function);
}
void CallOptimization::AnalyzePossibleApiFunction(JSFunction* function) {
SharedFunctionInfo* sfi = function->shared();
if (!sfi->IsApiFunction()) return;
FunctionTemplateInfo* info = sfi->get_api_func_data();
// Require a C++ callback.
if (info->call_code()->IsUndefined()) return;
api_call_info_ = 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()) {
SignatureInfo* signature = SignatureInfo::cast(info->signature());
if (!signature->args()->IsUndefined()) return;
if (!signature->receiver()->IsUndefined()) {
expected_receiver_type_ =
FunctionTemplateInfo::cast(signature->receiver());
}
}
is_simple_api_call_ = true;
}
} } // namespace v8::internal
......@@ -615,6 +615,55 @@ class ConstructStubCompiler: public StubCompiler {
};
// Holds information about possible function call optimizations.
class CallOptimization BASE_EMBEDDED {
public:
explicit CallOptimization(LookupResult* lookup);
explicit CallOptimization(JSFunction* function);
bool is_constant_call() const {
return constant_function_ != NULL;
}
JSFunction* constant_function() const {
ASSERT(constant_function_ != NULL);
return constant_function_;
}
bool is_simple_api_call() const {
return is_simple_api_call_;
}
FunctionTemplateInfo* expected_receiver_type() const {
ASSERT(is_simple_api_call_);
return expected_receiver_type_;
}
CallHandlerInfo* api_call_info() const {
ASSERT(is_simple_api_call_);
return api_call_info_;
}
// Returns the depth of the object having the expected type in the
// prototype chain between the two arguments.
int GetPrototypeDepthOfExpectedType(JSObject* object,
JSObject* holder) const;
private:
void Initialize(JSFunction* function);
// Determines whether the given function can be called using the
// fast api call builtin.
void AnalyzePossibleApiFunction(JSFunction* function);
JSFunction* constant_function_;
bool is_simple_api_call_;
FunctionTemplateInfo* expected_receiver_type_;
CallHandlerInfo* api_call_info_;
};
typedef Object* (*CustomCallGenerator)(CallStubCompiler* compiler,
Object* object,
JSObject* holder,
......
......@@ -2172,6 +2172,7 @@ Register MacroAssembler::CheckMaps(JSObject* object,
JSObject* holder,
Register holder_reg,
Register scratch,
int save_at_depth,
Label* miss) {
// Make sure there's no overlap between scratch and the other
// registers.
......@@ -2181,7 +2182,11 @@ Register MacroAssembler::CheckMaps(JSObject* object,
// iteration, reg is an alias for object_reg, on later iterations,
// it is an alias for holder_reg.
Register reg = object_reg;
int depth = 1;
int depth = 0;
if (save_at_depth == depth) {
movq(Operand(rsp, kPointerSize), reg);
}
// Check the maps in the prototype chain.
// Traverse the prototype chain from the object and do map checks.
......@@ -2231,6 +2236,10 @@ Register MacroAssembler::CheckMaps(JSObject* object,
Move(reg, Handle<JSObject>(prototype));
}
if (save_at_depth == depth) {
movq(Operand(rsp, kPointerSize), reg);
}
// Go to the next object in the prototype chain.
object = prototype;
}
......@@ -2240,7 +2249,7 @@ Register MacroAssembler::CheckMaps(JSObject* object,
j(not_equal, miss);
// Log the check depth.
LOG(IntEvent("check-maps-depth", depth));
LOG(IntEvent("check-maps-depth", depth + 1));
// Perform security check for access to the global object and return
// the holder register.
......
......@@ -529,9 +529,14 @@ class MacroAssembler: public Assembler {
// clobbered if it the same as the holder register. The function
// returns a register containing the holder - either object_reg or
// holder_reg.
// The function can optionally (when save_at_depth !=
// kInvalidProtoDepth) save the object at the given depth by moving
// it to [rsp + kPointerSize].
Register CheckMaps(JSObject* object, Register object_reg,
JSObject* holder, Register holder_reg,
Register scratch, Label* miss);
Register scratch,
int save_at_depth,
Label* miss);
// Generate code for checking access rights - used for security checks
// on access to global objects across environments. The holder register
......
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