Commit d1d56d98 authored by vitalyr@chromium.org's avatar vitalyr@chromium.org

ia32: Fuse map and type checks in call ICs for API functions.

This uses the fact that if a map stayed the same then the object
still passes the type check. A new builtin is added to handle the
API call in this case.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3825 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent ad83e411
...@@ -737,7 +737,11 @@ Register StubCompiler::CheckPrototypes(JSObject* object, ...@@ -737,7 +737,11 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
Register holder_reg, Register holder_reg,
Register scratch, Register scratch,
String* name, String* name,
int save_at_depth,
Label* miss) { Label* miss) {
// TODO(602): support object saving.
ASSERT(save_at_depth == kInvalidProtoDepth);
// Check that the maps haven't changed. // Check that the maps haven't changed.
Register result = Register result =
masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss); masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss);
......
...@@ -474,6 +474,76 @@ BUILTIN(HandleApiCallConstruct) { ...@@ -474,6 +474,76 @@ BUILTIN(HandleApiCallConstruct) {
} }
#ifdef DEBUG
static void VerifyTypeCheck(Handle<JSObject> object,
Handle<JSFunction> function) {
FunctionTemplateInfo* info =
FunctionTemplateInfo::cast(function->shared()->function_data());
if (info->signature()->IsUndefined()) return;
SignatureInfo* signature = SignatureInfo::cast(info->signature());
Object* receiver_type = signature->receiver();
if (receiver_type->IsUndefined()) return;
FunctionTemplateInfo* type = FunctionTemplateInfo::cast(receiver_type);
ASSERT(object->IsInstanceOf(type));
}
#endif
BUILTIN(FastHandleApiCall) {
ASSERT(!CalledAsConstructor());
const bool is_construct = false;
// We expect four more arguments: function, callback, call data, and holder.
const int args_length = args.length() - 4;
ASSERT(args_length >= 0);
Handle<JSFunction> function = args.at<JSFunction>(args_length);
Object* callback_obj = args[args_length + 1];
Handle<Object> data_handle = args.at<Object>(args_length + 2);
Handle<JSObject> checked_holder = args.at<JSObject>(args_length + 3);
#ifdef DEBUG
VerifyTypeCheck(checked_holder, function);
#endif
v8::Local<v8::Object> holder = v8::Utils::ToLocal(checked_holder);
v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
v8::InvocationCallback callback =
v8::ToCData<v8::InvocationCallback>(callback_obj);
v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
data,
holder,
callee,
is_construct,
reinterpret_cast<void**>(&args[0] - 1),
args_length - 1);
HandleScope scope;
Object* result;
v8::Handle<v8::Value> value;
{
// Leaving JavaScript.
VMState state(EXTERNAL);
#ifdef ENABLE_LOGGING_AND_PROFILING
state.set_external_callback(v8::ToCData<Address>(callback_obj));
#endif
value = callback(new_args);
}
if (value.IsEmpty()) {
result = Heap::undefined_value();
} else {
result = *reinterpret_cast<Object**>(*value);
}
RETURN_IF_SCHEDULED_EXCEPTION();
return result;
}
// Helper function to handle calls to non-function objects created through the // Helper function to handle calls to non-function objects created through the
// API. The object can be called as either a constructor (using new) or just as // API. The object can be called as either a constructor (using new) or just as
// a function (without new). // a function (without new).
......
...@@ -50,6 +50,7 @@ enum BuiltinExtraArguments { ...@@ -50,6 +50,7 @@ enum BuiltinExtraArguments {
V(ArrayPop, NO_EXTRA_ARGUMENTS) \ V(ArrayPop, NO_EXTRA_ARGUMENTS) \
\ \
V(HandleApiCall, NEEDS_CALLED_FUNCTION) \ V(HandleApiCall, NEEDS_CALLED_FUNCTION) \
V(FastHandleApiCall, NO_EXTRA_ARGUMENTS) \
V(HandleApiCallConstruct, NEEDS_CALLED_FUNCTION) \ V(HandleApiCallConstruct, NEEDS_CALLED_FUNCTION) \
V(HandleApiCallAsFunction, NO_EXTRA_ARGUMENTS) \ V(HandleApiCallAsFunction, NO_EXTRA_ARGUMENTS) \
V(HandleApiCallAsConstructor, NO_EXTRA_ARGUMENTS) V(HandleApiCallAsConstructor, NO_EXTRA_ARGUMENTS)
......
...@@ -554,6 +554,7 @@ void MacroAssembler::PopTryHandler() { ...@@ -554,6 +554,7 @@ void MacroAssembler::PopTryHandler() {
Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg, Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
JSObject* holder, Register holder_reg, JSObject* holder, Register holder_reg,
Register scratch, Register scratch,
int save_at_depth,
Label* miss) { Label* miss) {
// Make sure there's no overlap between scratch and the other // Make sure there's no overlap between scratch and the other
// registers. // registers.
...@@ -561,7 +562,11 @@ Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg, ...@@ -561,7 +562,11 @@ Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
// Keep track of the current object in register reg. // Keep track of the current object in register reg.
Register reg = object_reg; Register reg = object_reg;
int depth = 1; int depth = 0;
if (save_at_depth == depth) {
mov(Operand(esp, kPointerSize), object_reg);
}
// Check the maps in the prototype chain. // Check the maps in the prototype chain.
// Traverse the prototype chain from the object and do map checks. // Traverse the prototype chain from the object and do map checks.
...@@ -593,7 +598,6 @@ Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg, ...@@ -593,7 +598,6 @@ Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
// to it in the code. Load it from the map. // to it in the code. Load it from the map.
reg = holder_reg; // from now the object is in holder_reg reg = holder_reg; // from now the object is in holder_reg
mov(reg, FieldOperand(scratch, Map::kPrototypeOffset)); mov(reg, FieldOperand(scratch, Map::kPrototypeOffset));
} else { } else {
// Check the map of the current object. // Check the map of the current object.
cmp(FieldOperand(reg, HeapObject::kMapOffset), cmp(FieldOperand(reg, HeapObject::kMapOffset),
...@@ -611,6 +615,10 @@ Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg, ...@@ -611,6 +615,10 @@ Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
mov(reg, Handle<JSObject>(prototype)); mov(reg, Handle<JSObject>(prototype));
} }
if (save_at_depth == depth) {
mov(Operand(esp, kPointerSize), reg);
}
// Go to the next object in the prototype chain. // Go to the next object in the prototype chain.
object = prototype; object = prototype;
} }
...@@ -621,7 +629,7 @@ Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg, ...@@ -621,7 +629,7 @@ Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
j(not_equal, miss, not_taken); j(not_equal, miss, not_taken);
// Log the check depth. // 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 // Perform security check for access to the global object and return
// the holder register. // the holder register.
......
...@@ -194,9 +194,14 @@ class MacroAssembler: public Assembler { ...@@ -194,9 +194,14 @@ class MacroAssembler: public Assembler {
// clobbered if it the same as the holder register. The function // clobbered if it the same as the holder register. The function
// returns a register containing the holder - either object_reg or // returns a register containing the holder - either object_reg or
// holder_reg. // holder_reg.
// The function can optionally (when save_at_depth !=
// kInvalidProtoDepth) save the object at the given depth by moving
// it to [esp + kPointerSize].
Register CheckMaps(JSObject* object, Register object_reg, Register CheckMaps(JSObject* object, Register object_reg,
JSObject* holder, Register holder_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 // Generate code for checking access rights - used for security checks
// on access to global objects across environments. The holder register // on access to global objects across environments. The holder register
......
This diff is collapsed.
...@@ -61,6 +61,8 @@ enum AllocationFlags { ...@@ -61,6 +61,8 @@ enum AllocationFlags {
RESULT_CONTAINS_TOP = 1 << 1 RESULT_CONTAINS_TOP = 1 << 1
}; };
// Invalid depth in prototype chain.
const int kInvalidProtoDepth = -1;
#if V8_TARGET_ARCH_IA32 #if V8_TARGET_ARCH_IA32
#include "assembler.h" #include "assembler.h"
......
...@@ -381,12 +381,25 @@ class StubCompiler BASE_EMBEDDED { ...@@ -381,12 +381,25 @@ class StubCompiler BASE_EMBEDDED {
// Check the integrity of the prototype chain to make sure that the // Check the integrity of the prototype chain to make sure that the
// current IC is still valid. // current IC is still valid.
Register CheckPrototypes(JSObject* object,
Register object_reg,
JSObject* holder,
Register holder_reg,
Register scratch,
String* name,
Label* miss) {
return CheckPrototypes(object, object_reg, holder, holder_reg, scratch,
name, kInvalidProtoDepth, miss);
}
Register CheckPrototypes(JSObject* object, Register CheckPrototypes(JSObject* object,
Register object_reg, Register object_reg,
JSObject* holder, JSObject* holder,
Register holder_reg, Register holder_reg,
Register scratch, Register scratch,
String* name, String* name,
int save_at_depth,
Label* miss); Label* miss);
protected: protected:
......
...@@ -949,10 +949,15 @@ Handle<Context> Top::GetCallingGlobalContext() { ...@@ -949,10 +949,15 @@ Handle<Context> Top::GetCallingGlobalContext() {
} }
bool Top::CanHaveSpecialFunctions(JSObject* object) {
return object->IsJSArray();
}
Object* Top::LookupSpecialFunction(JSObject* receiver, Object* Top::LookupSpecialFunction(JSObject* receiver,
JSObject* prototype, JSObject* prototype,
JSFunction* function) { JSFunction* function) {
if (receiver->IsJSArray()) { if (CanHaveSpecialFunctions(receiver)) {
FixedArray* table = context()->global_context()->special_function_table(); FixedArray* table = context()->global_context()->special_function_table();
for (int index = 0; index < table->length(); index +=3) { for (int index = 0; index < table->length(); index +=3) {
if ((prototype == table->get(index)) && if ((prototype == table->get(index)) &&
......
...@@ -342,6 +342,7 @@ class Top { ...@@ -342,6 +342,7 @@ class Top {
return Handle<JSBuiltinsObject>(thread_local_.context_->builtins()); return Handle<JSBuiltinsObject>(thread_local_.context_->builtins());
} }
static bool CanHaveSpecialFunctions(JSObject* object);
static Object* LookupSpecialFunction(JSObject* receiver, static Object* LookupSpecialFunction(JSObject* receiver,
JSObject* prototype, JSObject* prototype,
JSFunction* value); JSFunction* value);
......
...@@ -140,6 +140,10 @@ namespace internal { ...@@ -140,6 +140,10 @@ namespace internal {
SC(keyed_store_inline_miss, V8.KeyedStoreInlineMiss) \ SC(keyed_store_inline_miss, V8.KeyedStoreInlineMiss) \
SC(named_store_global_inline, V8.NamedStoreGlobalInline) \ SC(named_store_global_inline, V8.NamedStoreGlobalInline) \
SC(named_store_global_inline_miss, V8.NamedStoreGlobalInlineMiss) \ SC(named_store_global_inline_miss, V8.NamedStoreGlobalInlineMiss) \
SC(call_const, V8.CallConst) \
SC(call_const_fast_api, V8.CallConstFastApi) \
SC(call_const_interceptor, V8.CallConstInterceptor) \
SC(call_const_interceptor_fast_api, V8.CallConstInterceptorFastApi) \
SC(call_global_inline, V8.CallGlobalInline) \ SC(call_global_inline, V8.CallGlobalInline) \
SC(call_global_inline_miss, V8.CallGlobalInlineMiss) \ SC(call_global_inline_miss, V8.CallGlobalInlineMiss) \
SC(constructed_objects, V8.ConstructedObjects) \ SC(constructed_objects, V8.ConstructedObjects) \
......
...@@ -1669,7 +1669,11 @@ Register StubCompiler::CheckPrototypes(JSObject* object, ...@@ -1669,7 +1669,11 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
Register holder_reg, Register holder_reg,
Register scratch, Register scratch,
String* name, String* name,
int save_at_depth,
Label* miss) { Label* miss) {
// TODO(602): support object saving.
ASSERT(save_at_depth == kInvalidProtoDepth);
// Check that the maps haven't changed. // Check that the maps haven't changed.
Register result = Register result =
__ CheckMaps(object, object_reg, holder, holder_reg, scratch, miss); __ CheckMaps(object, object_reg, holder, holder_reg, scratch, miss);
......
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