Chromium Code Reviews| Index: src/arm/stub-cache-arm.cc |
| diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc |
| index 344cb6fb9031da5ed2909a27692de72fbfec07c5..f87a53559f000d96977c9377908991c5aaae119f 100644 |
| --- a/src/arm/stub-cache-arm.cc |
| +++ b/src/arm/stub-cache-arm.cc |
| @@ -1220,6 +1220,60 @@ void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) { |
| } |
| +void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object, |
| + JSObject* holder, |
|
antonm
2010/09/08 15:26:05
is it true that holder is always a global object?
|
| + String* name, |
| + Label* miss) { |
| + // 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. |
| + __ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared()))); |
|
antonm
2010/09/08 15:26:05
maybe __ Move(r3, Handle<...). But I don't know i
|
| + __ 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* obj = StubCache::ComputeCallMiss(arguments().immediate(), kind_); |
| if (obj->IsFailure()) return obj; |
| @@ -1266,21 +1320,18 @@ Object* CallStubCompiler::CompileCallField(JSObject* object, |
| Object* CallStubCompiler::CompileArrayPushCall(Object* object, |
| JSObject* holder, |
| + JSGlobalPropertyCell* cell, |
| JSFunction* function, |
| - String* name, |
| - CheckType check) { |
| + String* name) { |
| // ----------- S t a t e ------------- |
| // -- r2 : name |
| // -- 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. |
| - 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; |
| @@ -1313,21 +1364,18 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object, |
| Object* CallStubCompiler::CompileArrayPopCall(Object* object, |
| JSObject* holder, |
| + JSGlobalPropertyCell* cell, |
| JSFunction* function, |
| - String* name, |
| - CheckType check) { |
| + String* name) { |
| // ----------- S t a t e ------------- |
| // -- r2 : name |
| // -- 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. |
| - 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; |
| @@ -1358,11 +1406,12 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object, |
| } |
| -Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object, |
| - JSObject* holder, |
| - JSFunction* function, |
| - String* name, |
| - CheckType check) { |
| +Object* CallStubCompiler::CompileStringCharCodeAtCall( |
| + Object* object, |
| + JSObject* holder, |
| + JSGlobalPropertyCell* cell, |
| + JSFunction* function, |
| + String* name) { |
| // ----------- S t a t e ------------- |
| // -- r2 : function name |
| // -- lr : return address |
| @@ -1372,7 +1421,7 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object, |
| // ----------------------------------- |
| // 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(); |
| @@ -1430,9 +1479,9 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object, |
| Object* CallStubCompiler::CompileStringCharAtCall(Object* object, |
| JSObject* holder, |
| + JSGlobalPropertyCell* cell, |
| JSFunction* function, |
| - String* name, |
| - CheckType check) { |
| + String* name) { |
| // ----------- S t a t e ------------- |
| // -- r2 : function name |
| // -- lr : return address |
| @@ -1442,7 +1491,7 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object, |
| // ----------------------------------- |
| // 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(); |
| @@ -1501,6 +1550,79 @@ 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; |
|
antonm
2010/09/08 15:26:05
sorry, that's probably only me, but could you rena
|
| + __ 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); |
|
antonm
2010/09/08 15:26:05
just to double check: that is necessary for ::Gene
|
| + |
| + // Tail call the full function. |
| + __ 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, |
| JSObject* holder, |
| JSFunction* function, |
| @@ -1513,8 +1635,8 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, |
| SharedFunctionInfo* function_info = function->shared(); |
| if (function_info->HasCustomCallGenerator()) { |
| const int id = function_info->custom_call_generator_id(); |
| - Object* result = |
| - CompileCustomCall(id, object, holder, function, name, check); |
| + Object* result = CompileCustomCall( |
| + id, object, holder, NULL, function, name); |
| // undefined means bail out to regular compiler. |
| if (!result->IsUndefined()) { |
| return result; |
| @@ -1714,6 +1836,16 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, |
| // -- r2 : name |
| // -- 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; |
| GenerateNameCheck(name, &miss); |
| @@ -1721,45 +1853,9 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, |
| // 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); |
| + GenerateGlobalReceiverCheck(object, holder, name, &miss); |
|
antonm
2010/09/08 15:26:05
aha, looks like holder must be a global object, ma
|
| - // 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. |
| - __ 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); |
| - } |
| + GenerateLoadFunctionFromCell(cell, function, &miss); |
| // Patch the receiver on the stack with the global proxy if |
| // necessary. |