}
+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,
// -- 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();
// 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));
}
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;
// -- 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.
}
-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.
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));
}
+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,
// -- 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();
// 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);
}
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;
// -- 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.
}
-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);
}
V(MathAbs)
+class CallOptimization;
+
class CallStubCompiler: public StubCompiler {
public:
CallStubCompiler(int argc,
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,
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_;
}
+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,
// 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();
// 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);
}
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;
// 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.
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
- // -- esp[0] : return address
+ // -- rsp[0] : return address
// -----------------------------------
Label miss;