Commit 624b13a8 authored by vitalyr@chromium.org's avatar vitalyr@chromium.org

Custom call IC for String.fromCharCode.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5433 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent d1a674f7
...@@ -1220,6 +1220,62 @@ void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) { ...@@ -1220,6 +1220,62 @@ void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
} }
void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
JSObject* holder,
String* name,
Label* miss) {
ASSERT(holder->IsGlobalObject());
// Get the number of arguments.
const int argc = arguments().immediate();
// Get the receiver from the stack.
__ ldr(r0, MemOperand(sp, argc * kPointerSize));
// If the object is the holder then we know that it's a global
// object which can only happen for contextual calls. In this case,
// the receiver cannot be a smi.
if (object != holder) {
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, miss);
}
// Check that the maps haven't changed.
CheckPrototypes(object, r0, holder, r3, r1, r4, name, miss);
}
void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
JSFunction* function,
Label* miss) {
// Get the value from the cell.
__ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
__ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
// Check that the cell contains the same function.
if (Heap::InNewSpace(function)) {
// We can't embed a pointer to a function in new space so we have
// to verify that the shared function info is unchanged. This has
// the nice side effect that multiple closures based on the same
// function can all use this call IC. Before we load through the
// function, we have to verify that it still is a function.
__ tst(r1, Operand(kSmiTagMask));
__ b(eq, miss);
__ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
__ b(ne, miss);
// Check the shared function info. Make sure it hasn't changed.
__ Move(r3, Handle<SharedFunctionInfo>(function->shared()));
__ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
__ cmp(r4, r3);
__ b(ne, miss);
} else {
__ cmp(r1, Operand(Handle<JSFunction>(function)));
__ b(ne, miss);
}
}
Object* CallStubCompiler::GenerateMissBranch() { Object* CallStubCompiler::GenerateMissBranch() {
Object* obj = StubCache::ComputeCallMiss(arguments().immediate(), kind_); Object* obj = StubCache::ComputeCallMiss(arguments().immediate(), kind_);
if (obj->IsFailure()) return obj; if (obj->IsFailure()) return obj;
...@@ -1266,21 +1322,18 @@ Object* CallStubCompiler::CompileCallField(JSObject* object, ...@@ -1266,21 +1322,18 @@ Object* CallStubCompiler::CompileCallField(JSObject* object,
Object* CallStubCompiler::CompileArrayPushCall(Object* object, Object* CallStubCompiler::CompileArrayPushCall(Object* object,
JSObject* holder, JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function, JSFunction* function,
String* name, String* name) {
CheckType check) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r2 : name // -- r2 : name
// -- lr : return address // -- lr : return address
// ----------------------------------- // -----------------------------------
// If object is not an array, bail out to regular call.
if (!object->IsJSArray()) {
return Heap::undefined_value();
}
// TODO(639): faster implementation. // TODO(639): faster implementation.
ASSERT(check == RECEIVER_MAP_CHECK);
// If object is not an array, bail out to regular call.
if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
Label miss; Label miss;
...@@ -1313,21 +1366,18 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object, ...@@ -1313,21 +1366,18 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
Object* CallStubCompiler::CompileArrayPopCall(Object* object, Object* CallStubCompiler::CompileArrayPopCall(Object* object,
JSObject* holder, JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function, JSFunction* function,
String* name, String* name) {
CheckType check) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r2 : name // -- r2 : name
// -- lr : return address // -- lr : return address
// ----------------------------------- // -----------------------------------
// If object is not an array, bail out to regular call.
if (!object->IsJSArray()) {
return Heap::undefined_value();
}
// TODO(642): faster implementation. // TODO(642): faster implementation.
ASSERT(check == RECEIVER_MAP_CHECK);
// If object is not an array, bail out to regular call.
if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
Label miss; Label miss;
...@@ -1358,11 +1408,12 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object, ...@@ -1358,11 +1408,12 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object,
} }
Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object, Object* CallStubCompiler::CompileStringCharCodeAtCall(
Object* object,
JSObject* holder, JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function, JSFunction* function,
String* name, String* name) {
CheckType check) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r2 : function name // -- r2 : function name
// -- lr : return address // -- lr : return address
...@@ -1372,7 +1423,7 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object, ...@@ -1372,7 +1423,7 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object,
// ----------------------------------- // -----------------------------------
// If object is not a string, bail out to regular call. // If object is not a string, bail out to regular call.
if (!object->IsString()) return Heap::undefined_value(); if (!object->IsString() || cell != NULL) return Heap::undefined_value();
const int argc = arguments().immediate(); const int argc = arguments().immediate();
...@@ -1430,9 +1481,9 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object, ...@@ -1430,9 +1481,9 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object,
Object* CallStubCompiler::CompileStringCharAtCall(Object* object, Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
JSObject* holder, JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function, JSFunction* function,
String* name, String* name) {
CheckType check) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r2 : function name // -- r2 : function name
// -- lr : return address // -- lr : return address
...@@ -1442,7 +1493,7 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object, ...@@ -1442,7 +1493,7 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
// ----------------------------------- // -----------------------------------
// If object is not a string, bail out to regular call. // If object is not a string, bail out to regular call.
if (!object->IsString()) return Heap::undefined_value(); if (!object->IsString() || cell != NULL) return Heap::undefined_value();
const int argc = arguments().immediate(); const int argc = arguments().immediate();
...@@ -1501,6 +1552,80 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object, ...@@ -1501,6 +1552,80 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
} }
Object* CallStubCompiler::CompileStringFromCharCodeCall(
Object* object,
JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
// ----------- S t a t e -------------
// -- r2 : function name
// -- lr : return address
// -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
// -- ...
// -- sp[argc * 4] : receiver
// -----------------------------------
const int argc = arguments().immediate();
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
Label miss;
GenerateNameCheck(name, &miss);
if (cell == NULL) {
__ ldr(r1, MemOperand(sp, 1 * kPointerSize));
STATIC_ASSERT(kSmiTag == 0);
__ tst(r1, Operand(kSmiTagMask));
__ b(eq, &miss);
CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
&miss);
} else {
ASSERT(cell->value() == function);
GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
GenerateLoadFunctionFromCell(cell, function, &miss);
}
// Load the char code argument.
Register code = r1;
__ ldr(code, MemOperand(sp, 0 * kPointerSize));
// Check the code is a smi.
Label slow;
STATIC_ASSERT(kSmiTag == 0);
__ tst(code, Operand(kSmiTagMask));
__ b(ne, &slow);
// Convert the smi code to uint16.
__ and_(code, code, Operand(Smi::FromInt(0xffff)));
StringCharFromCodeGenerator char_from_code_generator(code, r0);
char_from_code_generator.GenerateFast(masm());
__ Drop(argc + 1);
__ Ret();
ICRuntimeCallHelper call_helper;
char_from_code_generator.GenerateSlow(masm(), call_helper);
// Tail call the full function. We do not have to patch the receiver
// because the function makes no use of it.
__ bind(&slow);
__ InvokeFunction(function, arguments(), JUMP_FUNCTION);
__ bind(&miss);
// r2: function name.
Object* obj = GenerateMissBranch();
if (obj->IsFailure()) return obj;
// Return the generated code.
return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
}
Object* CallStubCompiler::CompileCallConstant(Object* object, Object* CallStubCompiler::CompileCallConstant(Object* object,
JSObject* holder, JSObject* holder,
JSFunction* function, JSFunction* function,
...@@ -1513,8 +1638,8 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, ...@@ -1513,8 +1638,8 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
SharedFunctionInfo* function_info = function->shared(); SharedFunctionInfo* function_info = function->shared();
if (function_info->HasCustomCallGenerator()) { if (function_info->HasCustomCallGenerator()) {
const int id = function_info->custom_call_generator_id(); const int id = function_info->custom_call_generator_id();
Object* result = Object* result = CompileCustomCall(
CompileCustomCall(id, object, holder, function, name, check); id, object, holder, NULL, function, name);
// undefined means bail out to regular compiler. // undefined means bail out to regular compiler.
if (!result->IsUndefined()) { if (!result->IsUndefined()) {
return result; return result;
...@@ -1714,6 +1839,16 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, ...@@ -1714,6 +1839,16 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
// -- r2 : name // -- r2 : name
// -- lr : return address // -- lr : return address
// ----------------------------------- // -----------------------------------
SharedFunctionInfo* function_info = function->shared();
if (function_info->HasCustomCallGenerator()) {
const int id = function_info->custom_call_generator_id();
Object* result = CompileCustomCall(
id, object, holder, cell, function, name);
// undefined means bail out to regular compiler.
if (!result->IsUndefined()) return result;
}
Label miss; Label miss;
GenerateNameCheck(name, &miss); GenerateNameCheck(name, &miss);
...@@ -1721,45 +1856,9 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, ...@@ -1721,45 +1856,9 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
// Get the number of arguments. // Get the number of arguments.
const int argc = arguments().immediate(); const int argc = arguments().immediate();
// Get the receiver from the stack. GenerateGlobalReceiverCheck(object, holder, name, &miss);
__ ldr(r0, MemOperand(sp, argc * kPointerSize));
// If the object is the holder then we know that it's a global
// object which can only happen for contextual calls. In this case,
// the receiver cannot be a smi.
if (object != holder) {
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &miss);
}
// Check that the maps haven't changed.
CheckPrototypes(object, r0, holder, r3, r1, r4, name, &miss);
// Get the value from the cell.
__ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
__ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
// Check that the cell contains the same function. GenerateLoadFunctionFromCell(cell, function, &miss);
if (Heap::InNewSpace(function)) {
// We can't embed a pointer to a function in new space so we have
// to verify that the shared function info is unchanged. This has
// the nice side effect that multiple closures based on the same
// function can all use this call IC. Before we load through the
// function, we have to verify that it still is a function.
__ tst(r1, Operand(kSmiTagMask));
__ b(eq, &miss);
__ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
__ b(ne, &miss);
// Check the shared function info. Make sure it hasn't changed.
__ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared())));
__ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
__ cmp(r4, r3);
__ b(ne, &miss);
} else {
__ cmp(r1, Operand(Handle<JSFunction>(function)));
__ b(ne, &miss);
}
// Patch the receiver on the stack with the global proxy if // Patch the receiver on the stack with the global proxy if
// necessary. // necessary.
......
...@@ -1344,23 +1344,33 @@ bool Genesis::InstallNatives() { ...@@ -1344,23 +1344,33 @@ bool Genesis::InstallNatives() {
} }
static void InstallCustomCallGenerator(Handle<JSFunction> holder_function, static void InstallCustomCallGenerator(
Handle<JSFunction> holder_function,
CallStubCompiler::CustomGeneratorOwner owner_flag,
const char* function_name, const char* function_name,
int id) { int id) {
Handle<JSObject> proto(JSObject::cast(holder_function->instance_prototype())); Handle<JSObject> owner;
if (owner_flag == CallStubCompiler::FUNCTION) {
owner = Handle<JSObject>::cast(holder_function);
} else {
ASSERT(owner_flag == CallStubCompiler::INSTANCE_PROTOTYPE);
owner = Handle<JSObject>(
JSObject::cast(holder_function->instance_prototype()));
}
Handle<String> name = Factory::LookupAsciiSymbol(function_name); Handle<String> name = Factory::LookupAsciiSymbol(function_name);
Handle<JSFunction> function(JSFunction::cast(proto->GetProperty(*name))); Handle<JSFunction> function(JSFunction::cast(owner->GetProperty(*name)));
function->shared()->set_function_data(Smi::FromInt(id)); function->shared()->set_function_data(Smi::FromInt(id));
} }
void Genesis::InstallCustomCallGenerators() { void Genesis::InstallCustomCallGenerators() {
HandleScope scope; HandleScope scope;
#define INSTALL_CALL_GENERATOR(holder_fun, fun_name, name) \ #define INSTALL_CALL_GENERATOR(holder_fun, owner_flag, fun_name, name) \
{ \ { \
Handle<JSFunction> holder(global_context()->holder_fun##_function()); \ Handle<JSFunction> holder(global_context()->holder_fun##_function()); \
const int id = CallStubCompiler::k##name##CallGenerator; \ const int id = CallStubCompiler::k##name##CallGenerator; \
InstallCustomCallGenerator(holder, #fun_name, id); \ InstallCustomCallGenerator(holder, CallStubCompiler::owner_flag, \
#fun_name, id); \
} }
CUSTOM_CALL_IC_GENERATORS(INSTALL_CALL_GENERATOR) CUSTOM_CALL_IC_GENERATORS(INSTALL_CALL_GENERATOR)
#undef INSTALL_CALL_GENERATOR #undef INSTALL_CALL_GENERATOR
......
...@@ -860,9 +860,14 @@ void Assembler::add(const Operand& dst, const Immediate& x) { ...@@ -860,9 +860,14 @@ void Assembler::add(const Operand& dst, const Immediate& x) {
void Assembler::and_(Register dst, int32_t imm32) { void Assembler::and_(Register dst, int32_t imm32) {
and_(dst, Immediate(imm32));
}
void Assembler::and_(Register dst, const Immediate& x) {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
last_pc_ = pc_; last_pc_ = pc_;
emit_arith(4, Operand(dst), Immediate(imm32)); emit_arith(4, Operand(dst), x);
} }
......
...@@ -577,6 +577,7 @@ class Assembler : public Malloced { ...@@ -577,6 +577,7 @@ class Assembler : public Malloced {
void add(const Operand& dst, const Immediate& x); void add(const Operand& dst, const Immediate& x);
void and_(Register dst, int32_t imm32); void and_(Register dst, int32_t imm32);
void and_(Register dst, const Immediate& x);
void and_(Register dst, const Operand& src); void and_(Register dst, const Operand& src);
void and_(const Operand& src, Register dst); void and_(const Operand& src, Register dst);
void and_(const Operand& dst, const Immediate& x); void and_(const Operand& dst, const Immediate& x);
......
...@@ -1255,6 +1255,61 @@ void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) { ...@@ -1255,6 +1255,61 @@ void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
} }
void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
JSObject* holder,
String* name,
Label* miss) {
ASSERT(holder->IsGlobalObject());
// Get the number of arguments.
const int argc = arguments().immediate();
// Get the receiver from the stack.
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
// If the object is the holder then we know that it's a global
// object which can only happen for contextual calls. In this case,
// the receiver cannot be a smi.
if (object != holder) {
__ test(edx, Immediate(kSmiTagMask));
__ j(zero, miss, not_taken);
}
// Check that the maps haven't changed.
CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss);
}
void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
JSFunction* function,
Label* miss) {
// Get the value from the cell.
__ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell)));
__ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset));
// Check that the cell contains the same function.
if (Heap::InNewSpace(function)) {
// We can't embed a pointer to a function in new space so we have
// to verify that the shared function info is unchanged. This has
// the nice side effect that multiple closures based on the same
// function can all use this call IC. Before we load through the
// function, we have to verify that it still is a function.
__ test(edi, Immediate(kSmiTagMask));
__ j(zero, miss, not_taken);
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
__ j(not_equal, miss, not_taken);
// Check the shared function info. Make sure it hasn't changed.
__ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset),
Immediate(Handle<SharedFunctionInfo>(function->shared())));
__ j(not_equal, miss, not_taken);
} else {
__ cmp(Operand(edi), Immediate(Handle<JSFunction>(function)));
__ j(not_equal, miss, not_taken);
}
}
Object* CallStubCompiler::GenerateMissBranch() { Object* CallStubCompiler::GenerateMissBranch() {
Object* obj = StubCache::ComputeCallMiss(arguments().immediate(), kind_); Object* obj = StubCache::ComputeCallMiss(arguments().immediate(), kind_);
if (obj->IsFailure()) return obj; if (obj->IsFailure()) return obj;
...@@ -1320,9 +1375,9 @@ Object* CallStubCompiler::CompileCallField(JSObject* object, ...@@ -1320,9 +1375,9 @@ Object* CallStubCompiler::CompileCallField(JSObject* object,
Object* CallStubCompiler::CompileArrayPushCall(Object* object, Object* CallStubCompiler::CompileArrayPushCall(Object* object,
JSObject* holder, JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function, JSFunction* function,
String* name, String* name) {
CheckType check) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- ecx : name // -- ecx : name
// -- esp[0] : return address // -- esp[0] : return address
...@@ -1330,12 +1385,9 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object, ...@@ -1330,12 +1385,9 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
// -- ... // -- ...
// -- esp[(argc + 1) * 4] : receiver // -- esp[(argc + 1) * 4] : receiver
// ----------------------------------- // -----------------------------------
ASSERT(check == RECEIVER_MAP_CHECK);
// If object is not an array, bail out to regular call. // If object is not an array, bail out to regular call.
if (!object->IsJSArray()) { if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
return Heap::undefined_value();
}
Label miss; Label miss;
...@@ -1469,9 +1521,9 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object, ...@@ -1469,9 +1521,9 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
Object* CallStubCompiler::CompileArrayPopCall(Object* object, Object* CallStubCompiler::CompileArrayPopCall(Object* object,
JSObject* holder, JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function, JSFunction* function,
String* name, String* name) {
CheckType check) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- ecx : name // -- ecx : name
// -- esp[0] : return address // -- esp[0] : return address
...@@ -1479,12 +1531,9 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object, ...@@ -1479,12 +1531,9 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object,
// -- ... // -- ...
// -- esp[(argc + 1) * 4] : receiver // -- esp[(argc + 1) * 4] : receiver
// ----------------------------------- // -----------------------------------
ASSERT(check == RECEIVER_MAP_CHECK);
// If object is not an array, bail out to regular call. // If object is not an array, bail out to regular call.
if (!object->IsJSArray()) { if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
return Heap::undefined_value();
}
Label miss, return_undefined, call_builtin; Label miss, return_undefined, call_builtin;
...@@ -1551,11 +1600,12 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object, ...@@ -1551,11 +1600,12 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object,
} }
Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object, Object* CallStubCompiler::CompileStringCharCodeAtCall(
Object* object,
JSObject* holder, JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function, JSFunction* function,
String* name, String* name) {
CheckType check) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- ecx : function name // -- ecx : function name
// -- esp[0] : return address // -- esp[0] : return address
...@@ -1565,7 +1615,7 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object, ...@@ -1565,7 +1615,7 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object,
// ----------------------------------- // -----------------------------------
// If object is not a string, bail out to regular call. // If object is not a string, bail out to regular call.
if (!object->IsString()) return Heap::undefined_value(); if (!object->IsString() || cell != NULL) return Heap::undefined_value();
const int argc = arguments().immediate(); const int argc = arguments().immediate();
...@@ -1621,9 +1671,9 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object, ...@@ -1621,9 +1671,9 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object,
Object* CallStubCompiler::CompileStringCharAtCall(Object* object, Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
JSObject* holder, JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function, JSFunction* function,
String* name, String* name) {
CheckType check) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- ecx : function name // -- ecx : function name
// -- esp[0] : return address // -- esp[0] : return address
...@@ -1633,7 +1683,7 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object, ...@@ -1633,7 +1683,7 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
// ----------------------------------- // -----------------------------------
// If object is not a string, bail out to regular call. // If object is not a string, bail out to regular call.
if (!object->IsString()) return Heap::undefined_value(); if (!object->IsString() || cell != NULL) return Heap::undefined_value();
const int argc = arguments().immediate(); const int argc = arguments().immediate();
...@@ -1690,6 +1740,79 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object, ...@@ -1690,6 +1740,79 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
} }
Object* CallStubCompiler::CompileStringFromCharCodeCall(
Object* object,
JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
// ----------- S t a t e -------------
// -- ecx : function name
// -- esp[0] : return address
// -- esp[(argc - n) * 4] : arg[n] (zero-based)
// -- ...
// -- esp[(argc + 1) * 4] : receiver
// -----------------------------------
const int argc = arguments().immediate();
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
Label miss;
GenerateNameCheck(name, &miss);
if (cell == NULL) {
__ mov(edx, Operand(esp, 2 * kPointerSize));
STATIC_ASSERT(kSmiTag == 0);
__ test(edx, Immediate(kSmiTagMask));
__ j(zero, &miss);
CheckPrototypes(JSObject::cast(object), edx, holder, ebx, eax, edi, name,
&miss);
} else {
ASSERT(cell->value() == function);
GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
GenerateLoadFunctionFromCell(cell, function, &miss);
}
// Load the char code argument.
Register code = ebx;
__ mov(code, Operand(esp, 1 * kPointerSize));
// Check the code is a smi.
Label slow;
STATIC_ASSERT(kSmiTag == 0);
__ test(code, Immediate(kSmiTagMask));
__ j(not_zero, &slow);
// Convert the smi code to uint16.
__ and_(code, Immediate(Smi::FromInt(0xffff)));
StringCharFromCodeGenerator char_from_code_generator(code, eax);
char_from_code_generator.GenerateFast(masm());
__ ret(2 * kPointerSize);
ICRuntimeCallHelper call_helper;
char_from_code_generator.GenerateSlow(masm(), call_helper);
// Tail call the full function. We do not have to patch the receiver
// because the function makes no use of it.
__ bind(&slow);
__ InvokeFunction(function, arguments(), JUMP_FUNCTION);
__ bind(&miss);
// ecx: function name.
Object* obj = GenerateMissBranch();
if (obj->IsFailure()) return obj;
// Return the generated code.
return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
}
Object* CallStubCompiler::CompileCallConstant(Object* object, Object* CallStubCompiler::CompileCallConstant(Object* object,
JSObject* holder, JSObject* holder,
JSFunction* function, JSFunction* function,
...@@ -1706,12 +1829,10 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, ...@@ -1706,12 +1829,10 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
SharedFunctionInfo* function_info = function->shared(); SharedFunctionInfo* function_info = function->shared();
if (function_info->HasCustomCallGenerator()) { if (function_info->HasCustomCallGenerator()) {
const int id = function_info->custom_call_generator_id(); const int id = function_info->custom_call_generator_id();
Object* result = Object* result = CompileCustomCall(
CompileCustomCall(id, object, holder, function, name, check); id, object, holder, NULL, function, name);
// undefined means bail out to regular compiler. // undefined means bail out to regular compiler.
if (!result->IsUndefined()) { if (!result->IsUndefined()) return result;
return result;
}
} }
Label miss_in_smi_check; Label miss_in_smi_check;
...@@ -1922,6 +2043,16 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, ...@@ -1922,6 +2043,16 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
// -- ... // -- ...
// -- esp[(argc + 1) * 4] : receiver // -- esp[(argc + 1) * 4] : receiver
// ----------------------------------- // -----------------------------------
SharedFunctionInfo* function_info = function->shared();
if (function_info->HasCustomCallGenerator()) {
const int id = function_info->custom_call_generator_id();
Object* result = CompileCustomCall(
id, object, holder, cell, function, name);
// undefined means bail out to regular compiler.
if (!result->IsUndefined()) return result;
}
Label miss; Label miss;
GenerateNameCheck(name, &miss); GenerateNameCheck(name, &miss);
...@@ -1929,44 +2060,9 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, ...@@ -1929,44 +2060,9 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
// Get the number of arguments. // Get the number of arguments.
const int argc = arguments().immediate(); const int argc = arguments().immediate();
// Get the receiver from the stack. GenerateGlobalReceiverCheck(object, holder, name, &miss);
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
// If the object is the holder then we know that it's a global
// object which can only happen for contextual calls. In this case,
// the receiver cannot be a smi.
if (object != holder) {
__ test(edx, Immediate(kSmiTagMask));
__ j(zero, &miss, not_taken);
}
// Check that the maps haven't changed.
CheckPrototypes(object, edx, holder, ebx, eax, edi, name, &miss);
// Get the value from the cell.
__ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell)));
__ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset));
// Check that the cell contains the same function. GenerateLoadFunctionFromCell(cell, function, &miss);
if (Heap::InNewSpace(function)) {
// We can't embed a pointer to a function in new space so we have
// to verify that the shared function info is unchanged. This has
// the nice side effect that multiple closures based on the same
// function can all use this call IC. Before we load through the
// function, we have to verify that it still is a function.
__ test(edi, Immediate(kSmiTagMask));
__ j(zero, &miss, not_taken);
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
__ j(not_equal, &miss, not_taken);
// Check the shared function info. Make sure it hasn't changed.
__ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset),
Immediate(Handle<SharedFunctionInfo>(function->shared())));
__ j(not_equal, &miss, not_taken);
} else {
__ cmp(Operand(edi), Immediate(Handle<JSFunction>(function)));
__ j(not_equal, &miss, not_taken);
}
// Patch the receiver on the stack with the global proxy. // Patch the receiver on the stack with the global proxy.
if (object->IsGlobalObject()) { if (object->IsGlobalObject()) {
......
...@@ -1222,18 +1222,18 @@ CallStubCompiler::CallStubCompiler(int argc, ...@@ -1222,18 +1222,18 @@ CallStubCompiler::CallStubCompiler(int argc,
Object* CallStubCompiler::CompileCustomCall(int generator_id, Object* CallStubCompiler::CompileCustomCall(int generator_id,
Object* object, Object* object,
JSObject* holder, JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function, JSFunction* function,
String* fname, String* fname) {
CheckType check) {
ASSERT(generator_id >= 0 && generator_id < kNumCallGenerators); ASSERT(generator_id >= 0 && generator_id < kNumCallGenerators);
switch (generator_id) { switch (generator_id) {
#define CALL_GENERATOR_CASE(ignored1, ignored2, name) \ #define CALL_GENERATOR_CASE(ignored1, ignored2, ignored3, name) \
case k##name##CallGenerator: \ case k##name##CallGenerator: \
return CallStubCompiler::Compile##name##Call(object, \ return CallStubCompiler::Compile##name##Call(object, \
holder, \ holder, \
cell, \
function, \ function, \
fname, \ fname);
check);
CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE) CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
#undef CALL_GENERATOR_CASE #undef CALL_GENERATOR_CASE
} }
......
...@@ -612,21 +612,29 @@ class KeyedStoreStubCompiler: public StubCompiler { ...@@ -612,21 +612,29 @@ class KeyedStoreStubCompiler: public StubCompiler {
// Installation of custom call generators for the selected builtins is // Installation of custom call generators for the selected builtins is
// handled by the bootstrapper. // handled by the bootstrapper.
// //
// Each entry has a name of a global function (lowercased), a name of // Each entry has a name of a global function (lowercased), a flag
// a builtin function on its instance prototype (the one the generator // controlling whether the generator is set on the function itself or
// is set for), and a name of a generator itself (used to build ids // on its instance prototype, a name of a builtin function on the
// and generator function names). // function or its instance prototype (the one the generator is set
// for), and a name of a generator itself (used to build ids and
// generator function names).
#define CUSTOM_CALL_IC_GENERATORS(V) \ #define CUSTOM_CALL_IC_GENERATORS(V) \
V(array, push, ArrayPush) \ V(array, INSTANCE_PROTOTYPE, push, ArrayPush) \
V(array, pop, ArrayPop) \ V(array, INSTANCE_PROTOTYPE, pop, ArrayPop) \
V(string, charCodeAt, StringCharCodeAt) \ V(string, INSTANCE_PROTOTYPE, charCodeAt, StringCharCodeAt) \
V(string, charAt, StringCharAt) V(string, INSTANCE_PROTOTYPE, charAt, StringCharAt) \
V(string, FUNCTION, fromCharCode, StringFromCharCode)
class CallStubCompiler: public StubCompiler { class CallStubCompiler: public StubCompiler {
public: public:
enum CustomGeneratorOwner {
FUNCTION,
INSTANCE_PROTOTYPE
};
enum { enum {
#define DECLARE_CALL_GENERATOR_ID(ignored1, ignored2, name) \ #define DECLARE_CALL_GENERATOR_ID(ignored1, ignore2, ignored3, name) \
k##name##CallGenerator, k##name##CallGenerator,
CUSTOM_CALL_IC_GENERATORS(DECLARE_CALL_GENERATOR_ID) CUSTOM_CALL_IC_GENERATORS(DECLARE_CALL_GENERATOR_ID)
#undef DECLARE_CALL_GENERATOR_ID #undef DECLARE_CALL_GENERATOR_ID
...@@ -656,20 +664,21 @@ class CallStubCompiler: public StubCompiler { ...@@ -656,20 +664,21 @@ class CallStubCompiler: public StubCompiler {
JSFunction* function, JSFunction* function,
String* name); String* name);
// Compiles a custom call constant IC using the generator with given id. // Compiles a custom call constant/global IC using the generator
// with given id. For constant calls cell is NULL.
Object* CompileCustomCall(int generator_id, Object* CompileCustomCall(int generator_id,
Object* object, Object* object,
JSObject* holder, JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function, JSFunction* function,
String* name, String* name);
CheckType check);
#define DECLARE_CALL_GENERATOR(ignored1, ignored2, name) \ #define DECLARE_CALL_GENERATOR(ignored1, ignored2, ignored3, name) \
Object* Compile##name##Call(Object* object, \ Object* Compile##name##Call(Object* object, \
JSObject* holder, \ JSObject* holder, \
JSGlobalPropertyCell* cell, \
JSFunction* function, \ JSFunction* function, \
String* fname, \ String* fname);
CheckType check);
CUSTOM_CALL_IC_GENERATORS(DECLARE_CALL_GENERATOR) CUSTOM_CALL_IC_GENERATORS(DECLARE_CALL_GENERATOR)
#undef DECLARE_CALL_GENERATOR #undef DECLARE_CALL_GENERATOR
...@@ -689,6 +698,17 @@ class CallStubCompiler: public StubCompiler { ...@@ -689,6 +698,17 @@ class CallStubCompiler: public StubCompiler {
void GenerateNameCheck(String* name, Label* miss); void GenerateNameCheck(String* name, Label* miss);
void GenerateGlobalReceiverCheck(JSObject* object,
JSObject* holder,
String* name,
Label* miss);
// Generates code to load the function from the cell checking that
// it still contains the same function.
void GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
JSFunction* function,
Label* miss);
// Generates a jump to CallIC miss stub. Returns Failure if the jump cannot // Generates a jump to CallIC miss stub. Returns Failure if the jump cannot
// be generated. // be generated.
Object* GenerateMissBranch(); Object* GenerateMissBranch();
......
...@@ -821,6 +821,59 @@ void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) { ...@@ -821,6 +821,59 @@ void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
} }
void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
JSObject* holder,
String* name,
Label* miss) {
ASSERT(holder->IsGlobalObject());
// Get the number of arguments.
const int argc = arguments().immediate();
// Get the receiver from the stack.
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
// If the object is the holder then we know that it's a global
// object which can only happen for contextual calls. In this case,
// the receiver cannot be a smi.
if (object != holder) {
__ JumpIfSmi(rdx, miss);
}
// Check that the maps haven't changed.
CheckPrototypes(object, rdx, holder, rbx, rax, rdi, name, miss);
}
void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
JSFunction* function,
Label* miss) {
// Get the value from the cell.
__ Move(rdi, Handle<JSGlobalPropertyCell>(cell));
__ movq(rdi, FieldOperand(rdi, JSGlobalPropertyCell::kValueOffset));
// Check that the cell contains the same function.
if (Heap::InNewSpace(function)) {
// We can't embed a pointer to a function in new space so we have
// to verify that the shared function info is unchanged. This has
// the nice side effect that multiple closures based on the same
// function can all use this call IC. Before we load through the
// function, we have to verify that it still is a function.
__ JumpIfSmi(rdi, miss);
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax);
__ j(not_equal, miss);
// Check the shared function info. Make sure it hasn't changed.
__ Move(rax, Handle<SharedFunctionInfo>(function->shared()));
__ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax);
__ j(not_equal, miss);
} else {
__ Cmp(rdi, Handle<JSFunction>(function));
__ j(not_equal, miss);
}
}
Object* CallStubCompiler::GenerateMissBranch() { Object* CallStubCompiler::GenerateMissBranch() {
Object* obj = StubCache::ComputeCallMiss(arguments().immediate(), kind_); Object* obj = StubCache::ComputeCallMiss(arguments().immediate(), kind_);
if (obj->IsFailure()) return obj; if (obj->IsFailure()) return obj;
...@@ -847,12 +900,10 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, ...@@ -847,12 +900,10 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
SharedFunctionInfo* function_info = function->shared(); SharedFunctionInfo* function_info = function->shared();
if (function_info->HasCustomCallGenerator()) { if (function_info->HasCustomCallGenerator()) {
const int id = function_info->custom_call_generator_id(); const int id = function_info->custom_call_generator_id();
Object* result = Object* result = CompileCustomCall(
CompileCustomCall(id, object, holder, function, name, check); id, object, holder, NULL, function, name);
// undefined means bail out to regular compiler. // undefined means bail out to regular compiler.
if (!result->IsUndefined()) { if (!result->IsUndefined()) return result;
return result;
}
} }
Label miss_in_smi_check; Label miss_in_smi_check;
...@@ -1043,9 +1094,9 @@ Object* CallStubCompiler::CompileCallField(JSObject* object, ...@@ -1043,9 +1094,9 @@ Object* CallStubCompiler::CompileCallField(JSObject* object,
Object* CallStubCompiler::CompileArrayPushCall(Object* object, Object* CallStubCompiler::CompileArrayPushCall(Object* object,
JSObject* holder, JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function, JSFunction* function,
String* name, String* name) {
CheckType check) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- rcx : name // -- rcx : name
// -- rsp[0] : return address // -- rsp[0] : return address
...@@ -1053,12 +1104,9 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object, ...@@ -1053,12 +1104,9 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
// -- ... // -- ...
// -- rsp[(argc + 1) * 8] : receiver // -- rsp[(argc + 1) * 8] : receiver
// ----------------------------------- // -----------------------------------
ASSERT(check == RECEIVER_MAP_CHECK);
// If object is not an array, bail out to regular call. // If object is not an array, bail out to regular call.
if (!object->IsJSArray()) { if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
return Heap::undefined_value();
}
Label miss; Label miss;
...@@ -1204,9 +1252,9 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object, ...@@ -1204,9 +1252,9 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
Object* CallStubCompiler::CompileArrayPopCall(Object* object, Object* CallStubCompiler::CompileArrayPopCall(Object* object,
JSObject* holder, JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function, JSFunction* function,
String* name, String* name) {
CheckType check) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- rcx : name // -- rcx : name
// -- rsp[0] : return address // -- rsp[0] : return address
...@@ -1214,12 +1262,9 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object, ...@@ -1214,12 +1262,9 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object,
// -- ... // -- ...
// -- rsp[(argc + 1) * 8] : receiver // -- rsp[(argc + 1) * 8] : receiver
// ----------------------------------- // -----------------------------------
ASSERT(check == RECEIVER_MAP_CHECK);
// If object is not an array, bail out to regular call. // If object is not an array, bail out to regular call.
if (!object->IsJSArray()) { if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
return Heap::undefined_value();
}
Label miss, return_undefined, call_builtin; Label miss, return_undefined, call_builtin;
...@@ -1289,9 +1334,9 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object, ...@@ -1289,9 +1334,9 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object,
Object* CallStubCompiler::CompileStringCharAtCall(Object* object, Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
JSObject* holder, JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function, JSFunction* function,
String* name, String* name) {
CheckType check) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- rcx : function name // -- rcx : function name
// -- rsp[0] : return address // -- rsp[0] : return address
...@@ -1301,7 +1346,7 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object, ...@@ -1301,7 +1346,7 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
// ----------------------------------- // -----------------------------------
// If object is not a string, bail out to regular call. // If object is not a string, bail out to regular call.
if (!object->IsString()) return Heap::undefined_value(); if (!object->IsString() || cell != NULL) return Heap::undefined_value();
const int argc = arguments().immediate(); const int argc = arguments().immediate();
...@@ -1358,11 +1403,12 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object, ...@@ -1358,11 +1403,12 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
} }
Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object, Object* CallStubCompiler::CompileStringCharCodeAtCall(
Object* object,
JSObject* holder, JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function, JSFunction* function,
String* name, String* name) {
CheckType check) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- rcx : function name // -- rcx : function name
// -- rsp[0] : return address // -- rsp[0] : return address
...@@ -1372,7 +1418,7 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object, ...@@ -1372,7 +1418,7 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object,
// ----------------------------------- // -----------------------------------
// If object is not a string, bail out to regular call. // If object is not a string, bail out to regular call.
if (!object->IsString()) return Heap::undefined_value(); if (!object->IsString() || cell != NULL) return Heap::undefined_value();
const int argc = arguments().immediate(); const int argc = arguments().immediate();
...@@ -1426,6 +1472,75 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object, ...@@ -1426,6 +1472,75 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object,
} }
Object* CallStubCompiler::CompileStringFromCharCodeCall(
Object* object,
JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
// ----------- S t a t e -------------
// -- rcx : function name
// -- rsp[0] : return address
// -- rsp[(argc - n) * 8] : arg[n] (zero-based)
// -- ...
// -- rsp[(argc + 1) * 8] : receiver
// -----------------------------------
const int argc = arguments().immediate();
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
Label miss;
GenerateNameCheck(name, &miss);
if (cell == NULL) {
__ movq(rdx, Operand(rsp, 2 * kPointerSize));
__ JumpIfSmi(rdx, &miss);
CheckPrototypes(JSObject::cast(object), rdx, holder, rbx, rax, rdi, name,
&miss);
} else {
ASSERT(cell->value() == function);
GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
GenerateLoadFunctionFromCell(cell, function, &miss);
}
// Load the char code argument.
Register code = rbx;
__ movq(code, Operand(rsp, 1 * kPointerSize));
// Check the code is a smi.
Label slow;
__ JumpIfNotSmi(code, &slow);
// Convert the smi code to uint16.
__ SmiAndConstant(code, code, Smi::FromInt(0xffff));
StringCharFromCodeGenerator char_from_code_generator(code, rax);
char_from_code_generator.GenerateFast(masm());
__ ret(2 * kPointerSize);
ICRuntimeCallHelper call_helper;
char_from_code_generator.GenerateSlow(masm(), call_helper);
// Tail call the full function. We do not have to patch the receiver
// because the function makes no use of it.
__ bind(&slow);
__ InvokeFunction(function, arguments(), JUMP_FUNCTION);
__ bind(&miss);
// rcx: function name.
Object* obj = GenerateMissBranch();
if (obj->IsFailure()) return obj;
// Return the generated code.
return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
}
Object* CallStubCompiler::CompileCallInterceptor(JSObject* object, Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
JSObject* holder, JSObject* holder,
String* name) { String* name) {
...@@ -1498,7 +1613,6 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, ...@@ -1498,7 +1613,6 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
JSFunction* function, JSFunction* function,
String* name) { String* name) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -----------------------------------
// rcx : function name // rcx : function name
// rsp[0] : return address // rsp[0] : return address
// rsp[8] : argument argc // rsp[8] : argument argc
...@@ -1506,6 +1620,17 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, ...@@ -1506,6 +1620,17 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* 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
// -----------------------------------
SharedFunctionInfo* function_info = function->shared();
if (function_info->HasCustomCallGenerator()) {
const int id = function_info->custom_call_generator_id();
Object* result = CompileCustomCall(
id, object, holder, cell, function, name);
// undefined means bail out to regular compiler.
if (!result->IsUndefined()) return result;
}
Label miss; Label miss;
GenerateNameCheck(name, &miss); GenerateNameCheck(name, &miss);
...@@ -1513,42 +1638,9 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, ...@@ -1513,42 +1638,9 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
// Get the number of arguments. // Get the number of arguments.
const int argc = arguments().immediate(); const int argc = arguments().immediate();
// Get the receiver from the stack. GenerateGlobalReceiverCheck(object, holder, name, &miss);
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
// If the object is the holder then we know that it's a global
// object which can only happen for contextual calls. In this case,
// the receiver cannot be a smi.
if (object != holder) {
__ JumpIfSmi(rdx, &miss);
}
// Check that the maps haven't changed.
CheckPrototypes(object, rdx, holder, rbx, rax, rdi, name, &miss);
// Get the value from the cell.
__ Move(rdi, Handle<JSGlobalPropertyCell>(cell));
__ movq(rdi, FieldOperand(rdi, JSGlobalPropertyCell::kValueOffset));
// Check that the cell contains the same function.
if (Heap::InNewSpace(function)) {
// We can't embed a pointer to a function in new space so we have
// to verify that the shared function info is unchanged. This has
// the nice side effect that multiple closures based on the same
// function can all use this call IC. Before we load through the
// function, we have to verify that it still is a function.
__ JumpIfSmi(rdi, &miss);
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax);
__ j(not_equal, &miss);
// Check the shared function info. Make sure it hasn't changed. GenerateLoadFunctionFromCell(cell, function, &miss);
__ Move(rax, Handle<SharedFunctionInfo>(function->shared()));
__ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax);
__ j(not_equal, &miss);
} else {
__ Cmp(rdi, Handle<JSFunction>(function));
__ j(not_equal, &miss);
}
// Patch the receiver on the stack with the global proxy. // Patch the receiver on the stack with the global proxy.
if (object->IsGlobalObject()) { if (object->IsGlobalObject()) {
......
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Test String.fromCharCode.
// Test various receivers and arguments passed to String.fromCharCode.
Object.prototype.fromCharCode = function(x) { return this; };
var fcc = String.fromCharCode;
var fcc2 = fcc;
function constFun(x) { return function(y) { return x; }; }
function test(num) {
assertEquals(" ", String.fromCharCode(0x20));
assertEquals(" ", String.fromCharCode(0x20 + 0x10000));
assertEquals(" ", String.fromCharCode(0x20 - 0x10000));
assertEquals(" ", String.fromCharCode(0x20 + 0.5));
assertEquals("\u1234", String.fromCharCode(0x1234));
assertEquals("\u1234", String.fromCharCode(0x1234 + 0x10000));
assertEquals("\u1234", String.fromCharCode(0x1234 - 0x10000));
assertEquals("\u1234", String.fromCharCode(0x1234 + 0.5));
assertEquals(" ", String.fromCharCode(0x20, 0x20));
assertEquals(" ", String.fromCharCode(0x20 + 0.5, 0x20));
assertEquals(" ", fcc(0x20));
assertEquals(" ", fcc(0x20 + 0x10000));
assertEquals(" ", fcc(0x20 - 0x10000));
assertEquals(" ", fcc(0x20 + 0.5));
assertEquals("\u1234", fcc(0x1234));
assertEquals("\u1234", fcc(0x1234 + 0x10000));
assertEquals("\u1234", fcc(0x1234 - 0x10000));
assertEquals("\u1234", fcc(0x1234 + 0.5));
assertEquals(" ", fcc(0x20, 0x20));
assertEquals(" ", fcc(0x20 + 0.5, 0x20));
var receiver = (num < 5) ? String : (num < 9) ? "dummy" : 42;
fcc2 = (num < 5) ? fcc : (num < 9) ? constFun("dummy") : constFun(42);
var expected = (num < 5) ? " " : (num < 9) ? "dummy" : 42;
assertEquals(expected, receiver.fromCharCode(0x20));
assertEquals(expected, receiver.fromCharCode(0x20 - 0x10000));
assertEquals(expected, receiver.fromCharCode(0x20 + 0.5));
assertEquals(expected, fcc2(0x20));
assertEquals(expected, fcc2(0x20 - 0x10000));
assertEquals(expected, fcc2(0x20 + 0.5));
}
// Use loop to test the custom IC.
for (var i = 0; i < 10; i++) {
test(i);
}
// Test the custom IC works correctly when the map changes.
for (var i = 0; i < 10; i++) {
var expected = (i < 5) ? " " : 42;
if (i == 5) String.fromCharCode = function() { return 42; };
assertEquals(expected, String.fromCharCode(0x20));
}
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