Refactor fast API call.
Make it use custom call generator infrastructure. Review URL: http://codereview.chromium.org/6686003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7246 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
e26ae48786
commit
6311105e00
@ -2278,6 +2278,60 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* CallStubCompiler::CompileFastApiCall(
|
||||
const CallOptimization& optimization,
|
||||
Object* object,
|
||||
JSObject* holder,
|
||||
JSGlobalPropertyCell* cell,
|
||||
JSFunction* function,
|
||||
String* name) {
|
||||
ASSERT(optimization.is_simple_api_call());
|
||||
// Bail out if object is a global object as we don't want to
|
||||
// repatch it to global receiver.
|
||||
if (object->IsGlobalObject()) return Heap::undefined_value();
|
||||
if (cell != NULL) return Heap::undefined_value();
|
||||
int depth = optimization.GetPrototypeDepthOfExpectedType(
|
||||
JSObject::cast(object), holder);
|
||||
if (depth == kInvalidProtoDepth) return Heap::undefined_value();
|
||||
|
||||
Label miss, miss_before_stack_reserved;
|
||||
|
||||
GenerateNameCheck(name, &miss_before_stack_reserved);
|
||||
|
||||
// Get the receiver from the stack.
|
||||
const int argc = arguments().immediate();
|
||||
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
|
||||
|
||||
// Check that the receiver isn't a smi.
|
||||
__ tst(r1, Operand(kSmiTagMask));
|
||||
__ b(eq, &miss_before_stack_reserved);
|
||||
|
||||
__ IncrementCounter(&Counters::call_const, 1, r0, r3);
|
||||
__ IncrementCounter(&Counters::call_const_fast_api, 1, r0, r3);
|
||||
|
||||
ReserveSpaceForFastApiCall(masm(), r0);
|
||||
|
||||
// Check that the maps haven't changed and find a Holder as a side effect.
|
||||
CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
|
||||
depth, &miss);
|
||||
|
||||
MaybeObject* result = GenerateFastApiDirectCall(masm(), optimization, argc);
|
||||
if (result->IsFailure()) return result;
|
||||
|
||||
__ bind(&miss);
|
||||
FreeSpaceForFastApiCall(masm());
|
||||
|
||||
__ bind(&miss_before_stack_reserved);
|
||||
Object* obj;
|
||||
{ MaybeObject* maybe_obj = GenerateMissBranch();
|
||||
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
|
||||
}
|
||||
|
||||
// Return the generated code.
|
||||
return GetCode(function);
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
JSObject* holder,
|
||||
JSFunction* function,
|
||||
@ -2287,22 +2341,18 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
// -- r2 : name
|
||||
// -- lr : return address
|
||||
// -----------------------------------
|
||||
SharedFunctionInfo* function_info = function->shared();
|
||||
if (function_info->HasBuiltinFunctionId()) {
|
||||
BuiltinFunctionId id = function_info->builtin_function_id();
|
||||
if (HasCustomCallGenerator(function)) {
|
||||
MaybeObject* maybe_result = CompileCustomCall(
|
||||
id, object, holder, NULL, function, name);
|
||||
object, holder, NULL, function, name);
|
||||
Object* result;
|
||||
if (!maybe_result->ToObject(&result)) return maybe_result;
|
||||
// undefined means bail out to regular compiler.
|
||||
if (!result->IsUndefined()) {
|
||||
return result;
|
||||
}
|
||||
if (!result->IsUndefined()) return result;
|
||||
}
|
||||
|
||||
Label miss_in_smi_check;
|
||||
Label miss;
|
||||
|
||||
GenerateNameCheck(name, &miss_in_smi_check);
|
||||
GenerateNameCheck(name, &miss);
|
||||
|
||||
// Get the receiver from the stack
|
||||
const int argc = arguments().immediate();
|
||||
@ -2311,39 +2361,25 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
// Check that the receiver isn't a smi.
|
||||
if (check != NUMBER_CHECK) {
|
||||
__ tst(r1, Operand(kSmiTagMask));
|
||||
__ b(eq, &miss_in_smi_check);
|
||||
__ b(eq, &miss);
|
||||
}
|
||||
|
||||
// Make sure that it's okay not to patch the on stack receiver
|
||||
// unless we're doing a receiver map check.
|
||||
ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
|
||||
|
||||
CallOptimization optimization(function);
|
||||
int depth = kInvalidProtoDepth;
|
||||
Label miss;
|
||||
|
||||
SharedFunctionInfo* function_info = function->shared();
|
||||
switch (check) {
|
||||
case RECEIVER_MAP_CHECK:
|
||||
__ IncrementCounter(&Counters::call_const, 1, r0, r3);
|
||||
|
||||
if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
|
||||
depth = optimization.GetPrototypeDepthOfExpectedType(
|
||||
JSObject::cast(object), holder);
|
||||
}
|
||||
|
||||
if (depth != kInvalidProtoDepth) {
|
||||
__ IncrementCounter(&Counters::call_const_fast_api, 1, r0, r3);
|
||||
ReserveSpaceForFastApiCall(masm(), r0);
|
||||
}
|
||||
|
||||
// Check that the maps haven't changed.
|
||||
CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
|
||||
depth, &miss);
|
||||
&miss);
|
||||
|
||||
// Patch the receiver on the stack with the global proxy if
|
||||
// necessary.
|
||||
if (object->IsGlobalObject()) {
|
||||
ASSERT(depth == kInvalidProtoDepth);
|
||||
__ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
|
||||
__ str(r3, MemOperand(sp, argc * kPointerSize));
|
||||
}
|
||||
@ -2416,20 +2452,10 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
if (depth != kInvalidProtoDepth) {
|
||||
MaybeObject* result = GenerateFastApiDirectCall(masm(), optimization, argc);
|
||||
if (result->IsFailure()) return result;
|
||||
} else {
|
||||
__ InvokeFunction(function, arguments(), JUMP_FUNCTION);
|
||||
}
|
||||
__ InvokeFunction(function, arguments(), JUMP_FUNCTION);
|
||||
|
||||
// Handle call cache miss.
|
||||
__ bind(&miss);
|
||||
if (depth != kInvalidProtoDepth) {
|
||||
FreeSpaceForFastApiCall(masm());
|
||||
}
|
||||
|
||||
__ bind(&miss_in_smi_check);
|
||||
Object* obj;
|
||||
{ MaybeObject* maybe_obj = GenerateMissBranch();
|
||||
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
|
||||
@ -2505,11 +2531,9 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
|
||||
// -- lr : return address
|
||||
// -----------------------------------
|
||||
|
||||
SharedFunctionInfo* function_info = function->shared();
|
||||
if (function_info->HasBuiltinFunctionId()) {
|
||||
BuiltinFunctionId id = function_info->builtin_function_id();
|
||||
if (HasCustomCallGenerator(function)) {
|
||||
MaybeObject* maybe_result = CompileCustomCall(
|
||||
id, object, holder, cell, function, name);
|
||||
object, holder, cell, function, name);
|
||||
Object* result;
|
||||
if (!maybe_result->ToObject(&result)) return maybe_result;
|
||||
// undefined means bail out to regular compiler.
|
||||
|
@ -4224,13 +4224,6 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
|
||||
}
|
||||
|
||||
|
||||
static bool HasCustomCallGenerator(Handle<JSFunction> function) {
|
||||
SharedFunctionInfo* info = function->shared();
|
||||
return info->HasBuiltinFunctionId() &&
|
||||
CallStubCompiler::HasCustomCallGenerator(info->builtin_function_id());
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::VisitCall(Call* expr) {
|
||||
Expression* callee = expr->expression();
|
||||
int argument_count = expr->arguments()->length() + 1; // Plus receiver.
|
||||
@ -4288,13 +4281,11 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasCustomCallGenerator(expr->target()) ||
|
||||
CallOptimization(*expr->target()).is_simple_api_call() ||
|
||||
if (CallStubCompiler::HasCustomCallGenerator(*expr->target()) ||
|
||||
expr->check_type() != RECEIVER_MAP_CHECK) {
|
||||
// When the target has a custom call IC generator, use the IC,
|
||||
// because it is likely to generate better code. Similarly, we
|
||||
// generate better call stubs for some API functions.
|
||||
// Also use the IC when a primitive receiver check is required.
|
||||
// because it is likely to generate better code. Also use the IC
|
||||
// when a primitive receiver check is required.
|
||||
HContext* context = new HContext;
|
||||
AddInstruction(context);
|
||||
call = PreProcessCall(new HCallNamed(context, name, argument_count));
|
||||
|
@ -2127,6 +2127,68 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* CallStubCompiler::CompileFastApiCall(
|
||||
const CallOptimization& optimization,
|
||||
Object* object,
|
||||
JSObject* holder,
|
||||
JSGlobalPropertyCell* cell,
|
||||
JSFunction* function,
|
||||
String* name) {
|
||||
ASSERT(optimization.is_simple_api_call());
|
||||
// Bail out if object is a global object as we don't want to
|
||||
// repatch it to global receiver.
|
||||
if (object->IsGlobalObject()) return Heap::undefined_value();
|
||||
if (cell != NULL) return Heap::undefined_value();
|
||||
int depth = optimization.GetPrototypeDepthOfExpectedType(
|
||||
JSObject::cast(object), holder);
|
||||
if (depth == kInvalidProtoDepth) return Heap::undefined_value();
|
||||
|
||||
Label miss, miss_before_stack_reserved;
|
||||
|
||||
GenerateNameCheck(name, &miss_before_stack_reserved);
|
||||
|
||||
// Get the receiver from the stack.
|
||||
const int argc = arguments().immediate();
|
||||
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
|
||||
|
||||
// Check that the receiver isn't a smi.
|
||||
__ test(edx, Immediate(kSmiTagMask));
|
||||
__ j(zero, &miss_before_stack_reserved, not_taken);
|
||||
|
||||
__ IncrementCounter(&Counters::call_const, 1);
|
||||
__ IncrementCounter(&Counters::call_const_fast_api, 1);
|
||||
|
||||
// Allocate space for v8::Arguments implicit values. Must be initialized
|
||||
// before calling any runtime function.
|
||||
__ sub(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize));
|
||||
|
||||
// Check that the maps haven't changed and find a Holder as a side effect.
|
||||
CheckPrototypes(JSObject::cast(object), edx, holder,
|
||||
ebx, eax, edi, name, depth, &miss);
|
||||
|
||||
// Move the return address on top of the stack.
|
||||
__ mov(eax, Operand(esp, 3 * kPointerSize));
|
||||
__ mov(Operand(esp, 0 * kPointerSize), eax);
|
||||
|
||||
// esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
|
||||
// duplicate of return address and will be overwritten.
|
||||
MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc);
|
||||
if (result->IsFailure()) return result;
|
||||
|
||||
__ bind(&miss);
|
||||
__ add(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize));
|
||||
|
||||
__ bind(&miss_before_stack_reserved);
|
||||
Object* obj;
|
||||
{ MaybeObject* maybe_obj = GenerateMissBranch();
|
||||
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
|
||||
}
|
||||
|
||||
// Return the generated code.
|
||||
return GetCode(function);
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
JSObject* holder,
|
||||
JSFunction* function,
|
||||
@ -2140,20 +2202,18 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
// -- esp[(argc + 1) * 4] : receiver
|
||||
// -----------------------------------
|
||||
|
||||
SharedFunctionInfo* function_info = function->shared();
|
||||
if (function_info->HasBuiltinFunctionId()) {
|
||||
BuiltinFunctionId id = function_info->builtin_function_id();
|
||||
if (HasCustomCallGenerator(function)) {
|
||||
MaybeObject* maybe_result = CompileCustomCall(
|
||||
id, object, holder, NULL, function, name);
|
||||
object, holder, NULL, function, name);
|
||||
Object* result;
|
||||
if (!maybe_result->ToObject(&result)) return maybe_result;
|
||||
// undefined means bail out to regular compiler.
|
||||
if (!result->IsUndefined()) return result;
|
||||
}
|
||||
|
||||
Label miss_in_smi_check;
|
||||
Label miss;
|
||||
|
||||
GenerateNameCheck(name, &miss_in_smi_check);
|
||||
GenerateNameCheck(name, &miss);
|
||||
|
||||
// Get the receiver from the stack.
|
||||
const int argc = arguments().immediate();
|
||||
@ -2162,42 +2222,25 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
// Check that the receiver isn't a smi.
|
||||
if (check != NUMBER_CHECK) {
|
||||
__ test(edx, Immediate(kSmiTagMask));
|
||||
__ j(zero, &miss_in_smi_check, not_taken);
|
||||
__ j(zero, &miss, not_taken);
|
||||
}
|
||||
|
||||
// Make sure that it's okay not to patch the on stack receiver
|
||||
// unless we're doing a receiver map check.
|
||||
ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
|
||||
|
||||
CallOptimization optimization(function);
|
||||
int depth = kInvalidProtoDepth;
|
||||
Label miss;
|
||||
|
||||
SharedFunctionInfo* function_info = function->shared();
|
||||
switch (check) {
|
||||
case RECEIVER_MAP_CHECK:
|
||||
__ IncrementCounter(&Counters::call_const, 1);
|
||||
|
||||
if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
|
||||
depth = optimization.GetPrototypeDepthOfExpectedType(
|
||||
JSObject::cast(object), holder);
|
||||
}
|
||||
|
||||
if (depth != kInvalidProtoDepth) {
|
||||
__ IncrementCounter(&Counters::call_const_fast_api, 1);
|
||||
|
||||
// Allocate space for v8::Arguments implicit values. Must be initialized
|
||||
// before to call any runtime function.
|
||||
__ sub(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize));
|
||||
}
|
||||
|
||||
// Check that the maps haven't changed.
|
||||
CheckPrototypes(JSObject::cast(object), edx, holder,
|
||||
ebx, eax, edi, name, depth, &miss);
|
||||
ebx, eax, edi, name, &miss);
|
||||
|
||||
// Patch the receiver on the stack with the global proxy if
|
||||
// necessary.
|
||||
if (object->IsGlobalObject()) {
|
||||
ASSERT(depth == kInvalidProtoDepth);
|
||||
__ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
|
||||
__ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
|
||||
}
|
||||
@ -2268,25 +2311,10 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
if (depth != kInvalidProtoDepth) {
|
||||
// Move the return address on top of the stack.
|
||||
__ mov(eax, Operand(esp, 3 * kPointerSize));
|
||||
__ mov(Operand(esp, 0 * kPointerSize), eax);
|
||||
|
||||
// esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
|
||||
// duplicate of return address and will be overwritten.
|
||||
MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc);
|
||||
if (result->IsFailure()) return result;
|
||||
} else {
|
||||
__ InvokeFunction(function, arguments(), JUMP_FUNCTION);
|
||||
}
|
||||
__ InvokeFunction(function, arguments(), JUMP_FUNCTION);
|
||||
|
||||
// Handle call cache miss.
|
||||
__ bind(&miss);
|
||||
if (depth != kInvalidProtoDepth) {
|
||||
__ add(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize));
|
||||
}
|
||||
__ bind(&miss_in_smi_check);
|
||||
Object* obj;
|
||||
{ MaybeObject* maybe_obj = GenerateMissBranch();
|
||||
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
|
||||
@ -2378,11 +2406,9 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
|
||||
// -- esp[(argc + 1) * 4] : receiver
|
||||
// -----------------------------------
|
||||
|
||||
SharedFunctionInfo* function_info = function->shared();
|
||||
if (function_info->HasBuiltinFunctionId()) {
|
||||
BuiltinFunctionId id = function_info->builtin_function_id();
|
||||
if (HasCustomCallGenerator(function)) {
|
||||
MaybeObject* maybe_result = CompileCustomCall(
|
||||
id, object, holder, cell, function, name);
|
||||
object, holder, cell, function, name);
|
||||
Object* result;
|
||||
if (!maybe_result->ToObject(&result)) return maybe_result;
|
||||
// undefined means bail out to regular compiler.
|
||||
|
@ -1726,32 +1726,51 @@ CallStubCompiler::CallStubCompiler(int argc,
|
||||
}
|
||||
|
||||
|
||||
bool CallStubCompiler::HasCustomCallGenerator(BuiltinFunctionId id) {
|
||||
bool CallStubCompiler::HasCustomCallGenerator(JSFunction* function) {
|
||||
SharedFunctionInfo* info = function->shared();
|
||||
if (info->HasBuiltinFunctionId()) {
|
||||
BuiltinFunctionId id = info->builtin_function_id();
|
||||
#define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
|
||||
CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
|
||||
CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
|
||||
#undef CALL_GENERATOR_CASE
|
||||
}
|
||||
CallOptimization optimization(function);
|
||||
if (optimization.is_simple_api_call()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* CallStubCompiler::CompileCustomCall(BuiltinFunctionId id,
|
||||
Object* object,
|
||||
MaybeObject* CallStubCompiler::CompileCustomCall(Object* object,
|
||||
JSObject* holder,
|
||||
JSGlobalPropertyCell* cell,
|
||||
JSFunction* function,
|
||||
String* fname) {
|
||||
#define CALL_GENERATOR_CASE(name) \
|
||||
if (id == k##name) { \
|
||||
return CallStubCompiler::Compile##name##Call(object, \
|
||||
holder, \
|
||||
cell, \
|
||||
function, \
|
||||
fname); \
|
||||
}
|
||||
CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
|
||||
ASSERT(HasCustomCallGenerator(function));
|
||||
|
||||
SharedFunctionInfo* info = function->shared();
|
||||
if (info->HasBuiltinFunctionId()) {
|
||||
BuiltinFunctionId id = info->builtin_function_id();
|
||||
#define CALL_GENERATOR_CASE(name) \
|
||||
if (id == k##name) { \
|
||||
return CallStubCompiler::Compile##name##Call(object, \
|
||||
holder, \
|
||||
cell, \
|
||||
function, \
|
||||
fname); \
|
||||
}
|
||||
CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
|
||||
#undef CALL_GENERATOR_CASE
|
||||
ASSERT(!HasCustomCallGenerator(id));
|
||||
return Heap::undefined_value();
|
||||
}
|
||||
CallOptimization optimization(function);
|
||||
ASSERT(optimization.is_simple_api_call());
|
||||
return CompileFastApiCall(optimization,
|
||||
object,
|
||||
holder,
|
||||
cell,
|
||||
function,
|
||||
fname);
|
||||
}
|
||||
|
||||
|
||||
|
@ -680,6 +680,8 @@ class KeyedStoreStubCompiler: public StubCompiler {
|
||||
V(MathAbs)
|
||||
|
||||
|
||||
class CallOptimization;
|
||||
|
||||
class CallStubCompiler: public StubCompiler {
|
||||
public:
|
||||
CallStubCompiler(int argc,
|
||||
@ -706,14 +708,13 @@ class CallStubCompiler: public StubCompiler {
|
||||
JSFunction* function,
|
||||
String* name);
|
||||
|
||||
static bool HasCustomCallGenerator(BuiltinFunctionId id);
|
||||
static bool HasCustomCallGenerator(JSFunction* function);
|
||||
|
||||
private:
|
||||
// Compiles a custom call constant/global IC. For constant calls
|
||||
// cell is NULL. Returns undefined if there is no custom call code
|
||||
// for the given function or it can't be generated.
|
||||
MUST_USE_RESULT MaybeObject* CompileCustomCall(BuiltinFunctionId id,
|
||||
Object* object,
|
||||
MUST_USE_RESULT MaybeObject* CompileCustomCall(Object* object,
|
||||
JSObject* holder,
|
||||
JSGlobalPropertyCell* cell,
|
||||
JSFunction* function,
|
||||
@ -728,6 +729,14 @@ class CallStubCompiler: public StubCompiler {
|
||||
CUSTOM_CALL_IC_GENERATORS(DECLARE_CALL_GENERATOR)
|
||||
#undef DECLARE_CALL_GENERATOR
|
||||
|
||||
MUST_USE_RESULT MaybeObject* CompileFastApiCall(
|
||||
const CallOptimization& optimization,
|
||||
Object* object,
|
||||
JSObject* holder,
|
||||
JSGlobalPropertyCell* cell,
|
||||
JSFunction* function,
|
||||
String* name);
|
||||
|
||||
const ParameterCount arguments_;
|
||||
const InLoopFlag in_loop_;
|
||||
const Code::Kind kind_;
|
||||
|
@ -1982,6 +1982,65 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* CallStubCompiler::CompileFastApiCall(
|
||||
const CallOptimization& optimization,
|
||||
Object* object,
|
||||
JSObject* holder,
|
||||
JSGlobalPropertyCell* cell,
|
||||
JSFunction* function,
|
||||
String* name) {
|
||||
ASSERT(optimization.is_simple_api_call());
|
||||
// Bail out if object is a global object as we don't want to
|
||||
// repatch it to global receiver.
|
||||
if (object->IsGlobalObject()) return Heap::undefined_value();
|
||||
if (cell != NULL) return Heap::undefined_value();
|
||||
int depth = optimization.GetPrototypeDepthOfExpectedType(
|
||||
JSObject::cast(object), holder);
|
||||
if (depth == kInvalidProtoDepth) return Heap::undefined_value();
|
||||
|
||||
Label miss, miss_before_stack_reserved;
|
||||
|
||||
GenerateNameCheck(name, &miss_before_stack_reserved);
|
||||
|
||||
// Get the receiver from the stack.
|
||||
const int argc = arguments().immediate();
|
||||
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
|
||||
|
||||
// Check that the receiver isn't a smi.
|
||||
__ JumpIfSmi(rdx, &miss_before_stack_reserved);
|
||||
|
||||
__ IncrementCounter(&Counters::call_const, 1);
|
||||
__ IncrementCounter(&Counters::call_const_fast_api, 1);
|
||||
|
||||
// Allocate space for v8::Arguments implicit values. Must be initialized
|
||||
// before calling any runtime function.
|
||||
__ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
|
||||
|
||||
// Check that the maps haven't changed and find a Holder as a side effect.
|
||||
CheckPrototypes(JSObject::cast(object), rdx, holder,
|
||||
rbx, rax, rdi, name, depth, &miss);
|
||||
|
||||
// Move the return address on top of the stack.
|
||||
__ movq(rax, Operand(rsp, 3 * kPointerSize));
|
||||
__ movq(Operand(rsp, 0 * kPointerSize), rax);
|
||||
|
||||
MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc);
|
||||
if (result->IsFailure()) return result;
|
||||
|
||||
__ bind(&miss);
|
||||
__ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
|
||||
|
||||
__ bind(&miss_before_stack_reserved);
|
||||
Object* obj;
|
||||
{ MaybeObject* maybe_obj = GenerateMissBranch();
|
||||
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
|
||||
}
|
||||
|
||||
// Return the generated code.
|
||||
return GetCode(function);
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
JSObject* holder,
|
||||
JSFunction* function,
|
||||
@ -1997,20 +2056,18 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
// rsp[(argc + 1) * 8] : argument 0 = receiver
|
||||
// -----------------------------------
|
||||
|
||||
SharedFunctionInfo* function_info = function->shared();
|
||||
if (function_info->HasBuiltinFunctionId()) {
|
||||
BuiltinFunctionId id = function_info->builtin_function_id();
|
||||
if (HasCustomCallGenerator(function)) {
|
||||
MaybeObject* maybe_result = CompileCustomCall(
|
||||
id, object, holder, NULL, function, name);
|
||||
object, holder, NULL, function, name);
|
||||
Object* result;
|
||||
if (!maybe_result->ToObject(&result)) return maybe_result;
|
||||
// undefined means bail out to regular compiler.
|
||||
if (!result->IsUndefined()) return result;
|
||||
}
|
||||
|
||||
Label miss_in_smi_check;
|
||||
Label miss;
|
||||
|
||||
GenerateNameCheck(name, &miss_in_smi_check);
|
||||
GenerateNameCheck(name, &miss);
|
||||
|
||||
// Get the receiver from the stack.
|
||||
const int argc = arguments().immediate();
|
||||
@ -2018,42 +2075,25 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
|
||||
// Check that the receiver isn't a smi.
|
||||
if (check != NUMBER_CHECK) {
|
||||
__ JumpIfSmi(rdx, &miss_in_smi_check);
|
||||
__ JumpIfSmi(rdx, &miss);
|
||||
}
|
||||
|
||||
// Make sure that it's okay not to patch the on stack receiver
|
||||
// unless we're doing a receiver map check.
|
||||
ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
|
||||
|
||||
CallOptimization optimization(function);
|
||||
int depth = kInvalidProtoDepth;
|
||||
Label miss;
|
||||
|
||||
SharedFunctionInfo* function_info = function->shared();
|
||||
switch (check) {
|
||||
case RECEIVER_MAP_CHECK:
|
||||
__ IncrementCounter(&Counters::call_const, 1);
|
||||
|
||||
if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
|
||||
depth = optimization.GetPrototypeDepthOfExpectedType(
|
||||
JSObject::cast(object), holder);
|
||||
}
|
||||
|
||||
if (depth != kInvalidProtoDepth) {
|
||||
__ IncrementCounter(&Counters::call_const_fast_api, 1);
|
||||
|
||||
// Allocate space for v8::Arguments implicit values. Must be initialized
|
||||
// before to call any runtime function.
|
||||
__ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
|
||||
}
|
||||
|
||||
// Check that the maps haven't changed.
|
||||
CheckPrototypes(JSObject::cast(object), rdx, holder,
|
||||
rbx, rax, rdi, name, depth, &miss);
|
||||
rbx, rax, rdi, name, &miss);
|
||||
|
||||
// Patch the receiver on the stack with the global proxy if
|
||||
// necessary.
|
||||
if (object->IsGlobalObject()) {
|
||||
ASSERT(depth == kInvalidProtoDepth);
|
||||
__ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
|
||||
__ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
|
||||
}
|
||||
@ -2123,27 +2163,10 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
if (depth != kInvalidProtoDepth) {
|
||||
// Move the return address on top of the stack.
|
||||
__ movq(rax, Operand(rsp, 3 * kPointerSize));
|
||||
__ movq(Operand(rsp, 0 * kPointerSize), rax);
|
||||
|
||||
// rsp[2 * kPointerSize] is uninitialized, rsp[3 * kPointerSize] contains
|
||||
// duplicate of return address and will be overwritten.
|
||||
MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc);
|
||||
if (result->IsFailure()) return result;
|
||||
} else {
|
||||
__ InvokeFunction(function, arguments(), JUMP_FUNCTION);
|
||||
}
|
||||
__ InvokeFunction(function, arguments(), JUMP_FUNCTION);
|
||||
|
||||
// Handle call cache miss.
|
||||
__ bind(&miss);
|
||||
if (depth != kInvalidProtoDepth) {
|
||||
__ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
|
||||
}
|
||||
|
||||
// Handle call cache miss.
|
||||
__ bind(&miss_in_smi_check);
|
||||
Object* obj;
|
||||
{ MaybeObject* maybe_obj = GenerateMissBranch();
|
||||
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
|
||||
@ -2238,11 +2261,9 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
|
||||
// rsp[(argc + 1) * 8] : argument 0 = receiver
|
||||
// -----------------------------------
|
||||
|
||||
SharedFunctionInfo* function_info = function->shared();
|
||||
if (function_info->HasBuiltinFunctionId()) {
|
||||
BuiltinFunctionId id = function_info->builtin_function_id();
|
||||
if (HasCustomCallGenerator(function)) {
|
||||
MaybeObject* maybe_result = CompileCustomCall(
|
||||
id, object, holder, cell, function, name);
|
||||
object, holder, cell, function, name);
|
||||
Object* result;
|
||||
if (!maybe_result->ToObject(&result)) return maybe_result;
|
||||
// undefined means bail out to regular compiler.
|
||||
@ -2960,7 +2981,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : key
|
||||
// -- rdx : receiver
|
||||
// -- esp[0] : return address
|
||||
// -- rsp[0] : return address
|
||||
// -----------------------------------
|
||||
Label miss;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user