Commit f08b6eca authored by verwaest@chromium.org's avatar verwaest@chromium.org

Split CompileCallConstant into logical parts for Frontend and Backend.

Initial step towards separating IC (map check(s)), handler frontend
(prototype-check) and handler backend (actual handler code).

- Still need to split the map-check (IC) from rest of the prototype
  chain check.
- Still need to turn different parts in own code objects and cache them
  in more optimal places.

Review URL: https://chromiumcodereview.appspot.com/12207016

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13604 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent c26b3c29
...@@ -2437,23 +2437,15 @@ Handle<Code> CallStubCompiler::CompileFastApiCall( ...@@ -2437,23 +2437,15 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
} }
Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object, void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
Handle<JSObject> holder, Handle<JSObject> holder,
Handle<JSFunction> function, Handle<String> name,
Handle<String> name, CheckType check,
CheckType check) { Label* success) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r2 : name // -- r2 : name
// -- lr : return address // -- lr : return address
// ----------------------------------- // -----------------------------------
if (HasCustomCallGenerator(function)) {
Handle<Code> code = CompileCustomCall(object, holder,
Handle<JSGlobalPropertyCell>::null(),
function, name);
// A null handle means bail out to the regular compiler code below.
if (!code.is_null()) return code;
}
Label miss; Label miss;
GenerateNameCheck(name, &miss); GenerateNameCheck(name, &miss);
...@@ -2487,78 +2479,89 @@ Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object, ...@@ -2487,78 +2479,89 @@ Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
break; break;
case STRING_CHECK: case STRING_CHECK:
if (function->IsBuiltin() || !function->shared()->is_classic_mode()) { // Check that the object is a two-byte string or a symbol.
// Check that the object is a two-byte string or a symbol. __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
__ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE); __ b(ge, &miss);
__ b(ge, &miss); // Check that the maps starting from the prototype haven't changed.
// Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(
GenerateDirectLoadGlobalFunctionPrototype( masm(), Context::STRING_FUNCTION_INDEX, r0, &miss);
masm(), Context::STRING_FUNCTION_INDEX, r0, &miss); CheckPrototypes(
CheckPrototypes( Handle<JSObject>(JSObject::cast(object->GetPrototype())),
Handle<JSObject>(JSObject::cast(object->GetPrototype())), r0, holder, r3, r1, r4, name, &miss);
r0, holder, r3, r1, r4, name, &miss);
} else {
// Calling non-strict non-builtins with a value as the receiver
// requires boxing.
__ jmp(&miss);
}
break; break;
case NUMBER_CHECK: case NUMBER_CHECK: {
if (function->IsBuiltin() || !function->shared()->is_classic_mode()) { Label fast;
Label fast; // Check that the object is a smi or a heap number.
// Check that the object is a smi or a heap number. __ JumpIfSmi(r1, &fast);
__ JumpIfSmi(r1, &fast); __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
__ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE); __ b(ne, &miss);
__ b(ne, &miss); __ bind(&fast);
__ bind(&fast); // Check that the maps starting from the prototype haven't changed.
// Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(
GenerateDirectLoadGlobalFunctionPrototype( masm(), Context::NUMBER_FUNCTION_INDEX, r0, &miss);
masm(), Context::NUMBER_FUNCTION_INDEX, r0, &miss); CheckPrototypes(
CheckPrototypes( Handle<JSObject>(JSObject::cast(object->GetPrototype())),
Handle<JSObject>(JSObject::cast(object->GetPrototype())), r0, holder, r3, r1, r4, name, &miss);
r0, holder, r3, r1, r4, name, &miss);
} else {
// Calling non-strict non-builtins with a value as the receiver
// requires boxing.
__ jmp(&miss);
}
break; break;
}
case BOOLEAN_CHECK: case BOOLEAN_CHECK: {
if (function->IsBuiltin() || !function->shared()->is_classic_mode()) { Label fast;
Label fast; // Check that the object is a boolean.
// Check that the object is a boolean. __ LoadRoot(ip, Heap::kTrueValueRootIndex);
__ LoadRoot(ip, Heap::kTrueValueRootIndex); __ cmp(r1, ip);
__ cmp(r1, ip); __ b(eq, &fast);
__ b(eq, &fast); __ LoadRoot(ip, Heap::kFalseValueRootIndex);
__ LoadRoot(ip, Heap::kFalseValueRootIndex); __ cmp(r1, ip);
__ cmp(r1, ip); __ b(ne, &miss);
__ b(ne, &miss); __ bind(&fast);
__ bind(&fast); // Check that the maps starting from the prototype haven't changed.
// Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(
GenerateDirectLoadGlobalFunctionPrototype( masm(), Context::BOOLEAN_FUNCTION_INDEX, r0, &miss);
masm(), Context::BOOLEAN_FUNCTION_INDEX, r0, &miss); CheckPrototypes(
CheckPrototypes( Handle<JSObject>(JSObject::cast(object->GetPrototype())),
Handle<JSObject>(JSObject::cast(object->GetPrototype())), r0, holder, r3, r1, r4, name, &miss);
r0, holder, r3, r1, r4, name, &miss);
} else {
// Calling non-strict non-builtins with a value as the receiver
// requires boxing.
__ jmp(&miss);
}
break; break;
}
} }
__ b(success);
// Handle call cache miss.
__ bind(&miss);
GenerateMissBranch();
}
void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
CallKind call_kind = CallICBase::Contextual::decode(extra_state_) CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
? CALL_AS_FUNCTION ? CALL_AS_FUNCTION
: CALL_AS_METHOD; : CALL_AS_METHOD;
__ InvokeFunction( __ InvokeFunction(
function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind); function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
}
Handle<Code> CallStubCompiler::CompileCallConstant(
Handle<Object> object,
Handle<JSObject> holder,
Handle<String> name,
CheckType check,
Handle<JSFunction> function) {
if (HasCustomCallGenerator(function)) {
Handle<Code> code = CompileCustomCall(object, holder,
Handle<JSGlobalPropertyCell>::null(),
function, name);
// A null handle means bail out to the regular compiler code below.
if (!code.is_null()) return code;
}
Label success;
CompileHandlerFrontend(object, holder, name, check, &success);
__ bind(&success);
CompileHandlerBackend(function);
// Handle call cache miss.
__ bind(&miss);
GenerateMissBranch();
// Return the generated code. // Return the generated code.
return GetCode(function); return GetCode(function);
......
...@@ -2368,11 +2368,11 @@ Handle<Code> CallStubCompiler::CompileFastApiCall( ...@@ -2368,11 +2368,11 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
} }
Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object, void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
Handle<JSObject> holder, Handle<JSObject> holder,
Handle<JSFunction> function, Handle<String> name,
Handle<String> name, CheckType check,
CheckType check) { Label* success) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- ecx : name // -- ecx : name
// -- esp[0] : return address // -- esp[0] : return address
...@@ -2380,15 +2380,6 @@ Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object, ...@@ -2380,15 +2380,6 @@ Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
// -- ... // -- ...
// -- esp[(argc + 1) * 4] : receiver // -- esp[(argc + 1) * 4] : receiver
// ----------------------------------- // -----------------------------------
if (HasCustomCallGenerator(function)) {
Handle<Code> code = CompileCustomCall(object, holder,
Handle<JSGlobalPropertyCell>::null(),
function, name);
// A null handle means bail out to the regular compiler code below.
if (!code.is_null()) return code;
}
Label miss; Label miss;
GenerateNameCheck(name, &miss); GenerateNameCheck(name, &miss);
...@@ -2421,76 +2412,87 @@ Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object, ...@@ -2421,76 +2412,87 @@ Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
break; break;
case STRING_CHECK: case STRING_CHECK:
if (function->IsBuiltin() || !function->shared()->is_classic_mode()) { // Check that the object is a string or a symbol.
// Check that the object is a string or a symbol. __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax);
__ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax); __ j(above_equal, &miss);
__ j(above_equal, &miss); // Check that the maps starting from the prototype haven't changed.
// Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(
GenerateDirectLoadGlobalFunctionPrototype( masm(), Context::STRING_FUNCTION_INDEX, eax, &miss);
masm(), Context::STRING_FUNCTION_INDEX, eax, &miss); CheckPrototypes(
CheckPrototypes( Handle<JSObject>(JSObject::cast(object->GetPrototype())),
Handle<JSObject>(JSObject::cast(object->GetPrototype())), eax, holder, ebx, edx, edi, name, &miss);
eax, holder, ebx, edx, edi, name, &miss);
} else {
// Calling non-strict non-builtins with a value as the receiver
// requires boxing.
__ jmp(&miss);
}
break; break;
case NUMBER_CHECK: case NUMBER_CHECK: {
if (function->IsBuiltin() || !function->shared()->is_classic_mode()) { Label fast;
Label fast; // Check that the object is a smi or a heap number.
// Check that the object is a smi or a heap number. __ JumpIfSmi(edx, &fast);
__ JumpIfSmi(edx, &fast); __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax);
__ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax); __ j(not_equal, &miss);
__ j(not_equal, &miss); __ bind(&fast);
__ bind(&fast); // Check that the maps starting from the prototype haven't changed.
// Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(
GenerateDirectLoadGlobalFunctionPrototype( masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss);
masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss); CheckPrototypes(
CheckPrototypes( Handle<JSObject>(JSObject::cast(object->GetPrototype())),
Handle<JSObject>(JSObject::cast(object->GetPrototype())), eax, holder, ebx, edx, edi, name, &miss);
eax, holder, ebx, edx, edi, name, &miss);
} else {
// Calling non-strict non-builtins with a value as the receiver
// requires boxing.
__ jmp(&miss);
}
break; break;
}
case BOOLEAN_CHECK: case BOOLEAN_CHECK: {
if (function->IsBuiltin() || !function->shared()->is_classic_mode()) { Label fast;
Label fast; // Check that the object is a boolean.
// Check that the object is a boolean. __ cmp(edx, factory()->true_value());
__ cmp(edx, factory()->true_value()); __ j(equal, &fast);
__ j(equal, &fast); __ cmp(edx, factory()->false_value());
__ cmp(edx, factory()->false_value()); __ j(not_equal, &miss);
__ j(not_equal, &miss); __ bind(&fast);
__ bind(&fast); // Check that the maps starting from the prototype haven't changed.
// Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(
GenerateDirectLoadGlobalFunctionPrototype( masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss);
masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss); CheckPrototypes(
CheckPrototypes( Handle<JSObject>(JSObject::cast(object->GetPrototype())),
Handle<JSObject>(JSObject::cast(object->GetPrototype())), eax, holder, ebx, edx, edi, name, &miss);
eax, holder, ebx, edx, edi, name, &miss);
} else {
// Calling non-strict non-builtins with a value as the receiver
// requires boxing.
__ jmp(&miss);
}
break; break;
}
} }
__ jmp(success);
// Handle call cache miss.
__ bind(&miss);
GenerateMissBranch();
}
void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
CallKind call_kind = CallICBase::Contextual::decode(extra_state_) CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
? CALL_AS_FUNCTION ? CALL_AS_FUNCTION
: CALL_AS_METHOD; : CALL_AS_METHOD;
__ InvokeFunction(function, arguments(), JUMP_FUNCTION, __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
NullCallWrapper(), call_kind); NullCallWrapper(), call_kind);
}
// Handle call cache miss.
__ bind(&miss); Handle<Code> CallStubCompiler::CompileCallConstant(
GenerateMissBranch(); Handle<Object> object,
Handle<JSObject> holder,
Handle<String> name,
CheckType check,
Handle<JSFunction> function) {
if (HasCustomCallGenerator(function)) {
Handle<Code> code = CompileCustomCall(object, holder,
Handle<JSGlobalPropertyCell>::null(),
function, name);
// A null handle means bail out to the regular compiler code below.
if (!code.is_null()) return code;
}
Label success;
CompileHandlerFrontend(object, holder, name, check, &success);
__ bind(&success);
CompileHandlerBackend(function);
// Return the generated code. // Return the generated code.
return GetCode(function); return GetCode(function);
......
...@@ -2430,25 +2430,16 @@ Handle<Code> CallStubCompiler::CompileFastApiCall( ...@@ -2430,25 +2430,16 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
} }
Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object, void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
Handle<JSObject> holder, Handle<JSObject> holder,
Handle<JSFunction> function, Handle<String> name,
Handle<String> name, CheckType check,
CheckType check) { Label* success) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a2 : name // -- a2 : name
// -- ra : return address // -- ra : return address
// ----------------------------------- // -----------------------------------
if (HasCustomCallGenerator(function)) {
Handle<Code> code = CompileCustomCall(object, holder,
Handle<JSGlobalPropertyCell>::null(),
function, name);
// A null handle means bail out to the regular compiler code below.
if (!code.is_null()) return code;
}
Label miss; Label miss;
GenerateNameCheck(name, &miss); GenerateNameCheck(name, &miss);
// Get the receiver from the stack. // Get the receiver from the stack.
...@@ -2481,77 +2472,87 @@ Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object, ...@@ -2481,77 +2472,87 @@ Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
break; break;
case STRING_CHECK: case STRING_CHECK:
if (function->IsBuiltin() || !function->shared()->is_classic_mode()) { // Check that the object is a two-byte string or a symbol.
// Check that the object is a two-byte string or a symbol. __ GetObjectType(a1, a3, a3);
__ GetObjectType(a1, a3, a3); __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
__ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE)); // Check that the maps starting from the prototype haven't changed.
// Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(
GenerateDirectLoadGlobalFunctionPrototype( masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
masm(), Context::STRING_FUNCTION_INDEX, a0, &miss); CheckPrototypes(
CheckPrototypes( Handle<JSObject>(JSObject::cast(object->GetPrototype())),
Handle<JSObject>(JSObject::cast(object->GetPrototype())), a0, holder, a3, a1, t0, name, &miss);
a0, holder, a3, a1, t0, name, &miss);
} else {
// Calling non-strict non-builtins with a value as the receiver
// requires boxing.
__ jmp(&miss);
}
break; break;
case NUMBER_CHECK: case NUMBER_CHECK: {
if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
Label fast; Label fast;
// Check that the object is a smi or a heap number. // Check that the object is a smi or a heap number.
__ JumpIfSmi(a1, &fast); __ JumpIfSmi(a1, &fast);
__ GetObjectType(a1, a0, a0); __ GetObjectType(a1, a0, a0);
__ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE)); __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
__ bind(&fast); __ bind(&fast);
// Check that the maps starting from the prototype haven't changed. // Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype( GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss); masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
CheckPrototypes( CheckPrototypes(
Handle<JSObject>(JSObject::cast(object->GetPrototype())), Handle<JSObject>(JSObject::cast(object->GetPrototype())),
a0, holder, a3, a1, t0, name, &miss); a0, holder, a3, a1, t0, name, &miss);
} else {
// Calling non-strict non-builtins with a value as the receiver
// requires boxing.
__ jmp(&miss);
}
break; break;
}
case BOOLEAN_CHECK: case BOOLEAN_CHECK: {
if (function->IsBuiltin() || !function->shared()->is_classic_mode()) { Label fast;
Label fast; // Check that the object is a boolean.
// Check that the object is a boolean. __ LoadRoot(t0, Heap::kTrueValueRootIndex);
__ LoadRoot(t0, Heap::kTrueValueRootIndex); __ Branch(&fast, eq, a1, Operand(t0));
__ Branch(&fast, eq, a1, Operand(t0)); __ LoadRoot(t0, Heap::kFalseValueRootIndex);
__ LoadRoot(t0, Heap::kFalseValueRootIndex); __ Branch(&miss, ne, a1, Operand(t0));
__ Branch(&miss, ne, a1, Operand(t0)); __ bind(&fast);
__ bind(&fast); // Check that the maps starting from the prototype haven't changed.
// Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(
GenerateDirectLoadGlobalFunctionPrototype( masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss); CheckPrototypes(
CheckPrototypes( Handle<JSObject>(JSObject::cast(object->GetPrototype())),
Handle<JSObject>(JSObject::cast(object->GetPrototype())), a0, holder, a3, a1, t0, name, &miss);
a0, holder, a3, a1, t0, name, &miss);
} else {
// Calling non-strict non-builtins with a value as the receiver
// requires boxing.
__ jmp(&miss);
}
break; break;
} }
}
__ jmp(success);
// Handle call cache miss.
__ bind(&miss);
GenerateMissBranch();
}
void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
CallKind call_kind = CallICBase::Contextual::decode(extra_state_) CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
? CALL_AS_FUNCTION ? CALL_AS_FUNCTION
: CALL_AS_METHOD; : CALL_AS_METHOD;
__ InvokeFunction( __ InvokeFunction(
function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind); function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
}
// Handle call cache miss.
__ bind(&miss);
GenerateMissBranch(); Handle<Code> CallStubCompiler::CompileCallConstant(
Handle<Object> object,
Handle<JSObject> holder,
Handle<String> name,
CheckType check,
Handle<JSFunction> function) {
if (HasCustomCallGenerator(function)) {
Handle<Code> code = CompileCustomCall(object, holder,
Handle<JSGlobalPropertyCell>::null(),
function, name);
// A null handle means bail out to the regular compiler code below.
if (!code.is_null()) return code;
}
Label success;
CompileHandlerFrontend(object, holder, name, check, &success);
__ bind(&success);
CompileHandlerBackend(function);
// Return the generated code. // Return the generated code.
return GetCode(function); return GetCode(function);
......
...@@ -578,6 +578,14 @@ Handle<Code> StubCache::ComputeCallConstant(int argc, ...@@ -578,6 +578,14 @@ Handle<Code> StubCache::ComputeCallConstant(int argc,
check = BOOLEAN_CHECK; check = BOOLEAN_CHECK;
} }
if (check != RECEIVER_MAP_CHECK &&
!function->IsBuiltin() &&
function->shared()->is_classic_mode()) {
// Calling non-strict non-builtins with a value as the receiver
// requires boxing.
return Handle<Code>::null();
}
Code::Flags flags = Code::Flags flags =
Code::ComputeMonomorphicFlags(kind, Code::CONSTANT_FUNCTION, extra_state, Code::ComputeMonomorphicFlags(kind, Code::CONSTANT_FUNCTION, extra_state,
cache_holder, argc); cache_holder, argc);
...@@ -587,7 +595,7 @@ Handle<Code> StubCache::ComputeCallConstant(int argc, ...@@ -587,7 +595,7 @@ Handle<Code> StubCache::ComputeCallConstant(int argc,
CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder); CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder);
Handle<Code> code = Handle<Code> code =
compiler.CompileCallConstant(object, holder, function, name, check); compiler.CompileCallConstant(object, holder, name, check, function);
code->set_check_type(check); code->set_check_type(check);
ASSERT_EQ(flags, code->flags()); ASSERT_EQ(flags, code->flags());
PROFILE(isolate_, PROFILE(isolate_,
......
...@@ -817,11 +817,19 @@ class CallStubCompiler: public StubCompiler { ...@@ -817,11 +817,19 @@ class CallStubCompiler: public StubCompiler {
PropertyIndex index, PropertyIndex index,
Handle<String> name); Handle<String> name);
void CompileHandlerFrontend(Handle<Object> object,
Handle<JSObject> holder,
Handle<String> name,
CheckType check,
Label* success);
void CompileHandlerBackend(Handle<JSFunction> function);
Handle<Code> CompileCallConstant(Handle<Object> object, Handle<Code> CompileCallConstant(Handle<Object> object,
Handle<JSObject> holder, Handle<JSObject> holder,
Handle<JSFunction> function,
Handle<String> name, Handle<String> name,
CheckType check); CheckType check,
Handle<JSFunction> function);
Handle<Code> CompileCallInterceptor(Handle<JSObject> object, Handle<Code> CompileCallInterceptor(Handle<JSObject> object,
Handle<JSObject> holder, Handle<JSObject> holder,
......
...@@ -2188,11 +2188,11 @@ Handle<Code> CallStubCompiler::CompileFastApiCall( ...@@ -2188,11 +2188,11 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
} }
Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object, void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
Handle<JSObject> holder, Handle<JSObject> holder,
Handle<JSFunction> function, Handle<String> name,
Handle<String> name, CheckType check,
CheckType check) { Label* success) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// rcx : function name // rcx : function name
// rsp[0] : return address // rsp[0] : return address
...@@ -2202,15 +2202,6 @@ Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object, ...@@ -2202,15 +2202,6 @@ Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
// rsp[argc * 8] : argument 1 // rsp[argc * 8] : argument 1
// rsp[(argc + 1) * 8] : argument 0 = receiver // rsp[(argc + 1) * 8] : argument 0 = receiver
// ----------------------------------- // -----------------------------------
if (HasCustomCallGenerator(function)) {
Handle<Code> code = CompileCustomCall(object, holder,
Handle<JSGlobalPropertyCell>::null(),
function, name);
// A null handle means bail out to the regular compiler code below.
if (!code.is_null()) return code;
}
Label miss; Label miss;
GenerateNameCheck(name, &miss); GenerateNameCheck(name, &miss);
...@@ -2245,76 +2236,86 @@ Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object, ...@@ -2245,76 +2236,86 @@ Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
break; break;
case STRING_CHECK: case STRING_CHECK:
if (function->IsBuiltin() || !function->shared()->is_classic_mode()) { // Check that the object is a two-byte string or a symbol.
// Check that the object is a two-byte string or a symbol. __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax);
__ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax); __ j(above_equal, &miss);
__ j(above_equal, &miss); // Check that the maps starting from the prototype haven't changed.
// Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(
GenerateDirectLoadGlobalFunctionPrototype( masm(), Context::STRING_FUNCTION_INDEX, rax, &miss);
masm(), Context::STRING_FUNCTION_INDEX, rax, &miss); CheckPrototypes(
CheckPrototypes( Handle<JSObject>(JSObject::cast(object->GetPrototype())),
Handle<JSObject>(JSObject::cast(object->GetPrototype())), rax, holder, rbx, rdx, rdi, name, &miss);
rax, holder, rbx, rdx, rdi, name, &miss);
} else {
// Calling non-strict non-builtins with a value as the receiver
// requires boxing.
__ jmp(&miss);
}
break; break;
case NUMBER_CHECK: case NUMBER_CHECK: {
if (function->IsBuiltin() || !function->shared()->is_classic_mode()) { Label fast;
Label fast; // Check that the object is a smi or a heap number.
// Check that the object is a smi or a heap number. __ JumpIfSmi(rdx, &fast);
__ JumpIfSmi(rdx, &fast); __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax);
__ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax); __ j(not_equal, &miss);
__ j(not_equal, &miss); __ bind(&fast);
__ bind(&fast); // Check that the maps starting from the prototype haven't changed.
// Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(
GenerateDirectLoadGlobalFunctionPrototype( masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss);
masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss); CheckPrototypes(
CheckPrototypes( Handle<JSObject>(JSObject::cast(object->GetPrototype())),
Handle<JSObject>(JSObject::cast(object->GetPrototype())), rax, holder, rbx, rdx, rdi, name, &miss);
rax, holder, rbx, rdx, rdi, name, &miss);
} else {
// Calling non-strict non-builtins with a value as the receiver
// requires boxing.
__ jmp(&miss);
}
break; break;
}
case BOOLEAN_CHECK: case BOOLEAN_CHECK: {
if (function->IsBuiltin() || !function->shared()->is_classic_mode()) { Label fast;
Label fast; // Check that the object is a boolean.
// Check that the object is a boolean. __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
__ CompareRoot(rdx, Heap::kTrueValueRootIndex); __ j(equal, &fast);
__ j(equal, &fast); __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
__ CompareRoot(rdx, Heap::kFalseValueRootIndex); __ j(not_equal, &miss);
__ j(not_equal, &miss); __ bind(&fast);
__ bind(&fast); // Check that the maps starting from the prototype haven't changed.
// Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(
GenerateDirectLoadGlobalFunctionPrototype( masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss);
masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss); CheckPrototypes(
CheckPrototypes( Handle<JSObject>(JSObject::cast(object->GetPrototype())),
Handle<JSObject>(JSObject::cast(object->GetPrototype())), rax, holder, rbx, rdx, rdi, name, &miss);
rax, holder, rbx, rdx, rdi, name, &miss);
} else {
// Calling non-strict non-builtins with a value as the receiver
// requires boxing.
__ jmp(&miss);
}
break; break;
}
} }
__ jmp(success);
// Handle call cache miss.
__ bind(&miss);
GenerateMissBranch();
}
void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
CallKind call_kind = CallICBase::Contextual::decode(extra_state_) CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
? CALL_AS_FUNCTION ? CALL_AS_FUNCTION
: CALL_AS_METHOD; : CALL_AS_METHOD;
__ InvokeFunction(function, arguments(), JUMP_FUNCTION, __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
NullCallWrapper(), call_kind); NullCallWrapper(), call_kind);
}
// Handle call cache miss.
__ bind(&miss); Handle<Code> CallStubCompiler::CompileCallConstant(
GenerateMissBranch(); Handle<Object> object,
Handle<JSObject> holder,
Handle<String> name,
CheckType check,
Handle<JSFunction> function) {
if (HasCustomCallGenerator(function)) {
Handle<Code> code = CompileCustomCall(object, holder,
Handle<JSGlobalPropertyCell>::null(),
function, name);
// A null handle means bail out to the regular compiler code below.
if (!code.is_null()) return code;
}
Label success;
CompileHandlerFrontend(object, holder, name, check, &success);
__ bind(&success);
CompileHandlerBackend(function);
// Return the generated code. // Return the generated code.
return GetCode(function); return GetCode(function);
......
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