diff options
author | Steve Block <steveblock@google.com> | 2010-09-22 15:07:15 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2010-09-29 18:15:43 +0100 |
commit | 59151504615d929945dc59db37bf1166937748c6 (patch) | |
tree | 2199adfe73b4618f685bae891d2d54f2cd997f77 /src/x64 | |
parent | 9ac36c9faca11611ada13b4054edbaa0738661d0 (diff) | |
download | android_external_v8-59151504615d929945dc59db37bf1166937748c6.tar.gz android_external_v8-59151504615d929945dc59db37bf1166937748c6.tar.bz2 android_external_v8-59151504615d929945dc59db37bf1166937748c6.zip |
Update V8 to r5447 as required by WebKit r67908
Change-Id: I5af6ccf18523cb7e28460e6bbc044444256cdb97
Diffstat (limited to 'src/x64')
-rw-r--r-- | src/x64/assembler-x64.cc | 1 | ||||
-rw-r--r-- | src/x64/full-codegen-x64.cc | 225 | ||||
-rw-r--r-- | src/x64/stub-cache-x64.cc | 216 |
3 files changed, 361 insertions, 81 deletions
diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc index 9ad94ce0..9318bb85 100644 --- a/src/x64/assembler-x64.cc +++ b/src/x64/assembler-x64.cc @@ -829,6 +829,7 @@ void Assembler::call(Label* L) { void Assembler::call(Handle<Code> target, RelocInfo::Mode rmode) { + WriteRecordedPositions(); EnsureSpace ensure_space(this); last_pc_ = pc_; // 1110 1000 #32-bit disp. diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index ccd0392a..40e1e35f 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -507,7 +507,7 @@ MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { int context_chain_length = scope()->ContextChainLength(slot->var()->scope()); __ LoadContext(scratch, context_chain_length); - return CodeGenerator::ContextOperand(scratch, slot->index()); + return ContextOperand(scratch, slot->index()); } case Slot::LOOKUP: UNREACHABLE(); @@ -568,20 +568,17 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); if (FLAG_debug_code) { // Check if we have the correct context pointer. - __ movq(rbx, - CodeGenerator::ContextOperand(rsi, Context::FCONTEXT_INDEX)); + __ movq(rbx, ContextOperand(rsi, Context::FCONTEXT_INDEX)); __ cmpq(rbx, rsi); __ Check(equal, "Unexpected declaration in current context."); } if (mode == Variable::CONST) { __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); - __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), - kScratchRegister); + __ movq(ContextOperand(rsi, slot->index()), kScratchRegister); // No write barrier since the hole value is in old space. } else if (function != NULL) { VisitForValue(function, kAccumulator); - __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), - result_register()); + __ movq(ContextOperand(rsi, slot->index()), result_register()); int offset = Context::SlotOffset(slot->index()); __ movq(rbx, rsi); __ RecordWrite(rbx, offset, result_register(), rcx); @@ -749,11 +746,10 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ bind(&done_convert); __ push(rax); - // TODO(kasperl): Check cache validity in generated code. This is a - // fast case for the JSObject::IsSimpleEnum cache validity - // checks. If we cannot guarantee cache validity, call the runtime - // system to check cache validity or get the property names in a - // fixed array. + // BUG(867): Check cache validity in generated code. This is a fast + // case for the JSObject::IsSimpleEnum cache validity checks. If we + // cannot guarantee cache validity, call the runtime system to check + // cache validity or get the property names in a fixed array. // Get the set of properties to enumerate. __ push(rax); // Duplicate the enumerable object on the stack. @@ -881,6 +877,152 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { } +void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( + Slot* slot, + TypeofState typeof_state, + Label* slow) { + Register context = rsi; + Register temp = rdx; + + Scope* s = scope(); + while (s != NULL) { + if (s->num_heap_slots() > 0) { + if (s->calls_eval()) { + // Check that extension is NULL. + __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), + Immediate(0)); + __ j(not_equal, slow); + } + // Load next context in chain. + __ movq(temp, ContextOperand(context, Context::CLOSURE_INDEX)); + __ movq(temp, FieldOperand(temp, JSFunction::kContextOffset)); + // Walk the rest of the chain without clobbering rsi. + context = temp; + } + // If no outer scope calls eval, we do not need to check more + // context extensions. If we have reached an eval scope, we check + // all extensions from this point. + if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; + s = s->outer_scope(); + } + + if (s != NULL && s->is_eval_scope()) { + // Loop up the context chain. There is no frame effect so it is + // safe to use raw labels here. + Label next, fast; + if (!context.is(temp)) { + __ movq(temp, context); + } + // Load map for comparison into register, outside loop. + __ LoadRoot(kScratchRegister, Heap::kGlobalContextMapRootIndex); + __ bind(&next); + // Terminate at global context. + __ cmpq(kScratchRegister, FieldOperand(temp, HeapObject::kMapOffset)); + __ j(equal, &fast); + // Check that extension is NULL. + __ cmpq(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0)); + __ j(not_equal, slow); + // Load next context in chain. + __ movq(temp, ContextOperand(temp, Context::CLOSURE_INDEX)); + __ movq(temp, FieldOperand(temp, JSFunction::kContextOffset)); + __ jmp(&next); + __ bind(&fast); + } + + // All extension objects were empty and it is safe to use a global + // load IC call. + __ movq(rax, CodeGenerator::GlobalObject()); + __ Move(rcx, slot->var()->name()); + Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); + RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) + ? RelocInfo::CODE_TARGET + : RelocInfo::CODE_TARGET_CONTEXT; + __ call(ic, mode); +} + + +MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( + Slot* slot, + Label* slow) { + ASSERT(slot->type() == Slot::CONTEXT); + Register context = rsi; + Register temp = rbx; + + for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { + if (s->num_heap_slots() > 0) { + if (s->calls_eval()) { + // Check that extension is NULL. + __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), + Immediate(0)); + __ j(not_equal, slow); + } + __ movq(temp, ContextOperand(context, Context::CLOSURE_INDEX)); + __ movq(temp, FieldOperand(temp, JSFunction::kContextOffset)); + // Walk the rest of the chain without clobbering rsi. + context = temp; + } + } + // Check that last extension is NULL. + __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); + __ j(not_equal, slow); + __ movq(temp, ContextOperand(context, Context::FCONTEXT_INDEX)); + return ContextOperand(temp, slot->index()); +} + + +void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( + Slot* slot, + TypeofState typeof_state, + Label* slow, + Label* done) { + // Generate fast-case code for variables that might be shadowed by + // eval-introduced variables. Eval is used a lot without + // introducing variables. In those cases, we do not want to + // perform a runtime call for all variables in the scope + // containing the eval. + if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { + EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); + __ jmp(done); + } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { + Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); + Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); + if (potential_slot != NULL) { + // Generate fast case for locals that rewrite to slots. + __ movq(rax, + ContextSlotOperandCheckExtensions(potential_slot, slow)); + if (potential_slot->var()->mode() == Variable::CONST) { + __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); + __ j(not_equal, done); + __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); + } + __ jmp(done); + } else if (rewrite != NULL) { + // Generate fast case for calls of an argument function. + Property* property = rewrite->AsProperty(); + if (property != NULL) { + VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); + Literal* key_literal = property->key()->AsLiteral(); + if (obj_proxy != NULL && + key_literal != NULL && + obj_proxy->IsArguments() && + key_literal->handle()->IsSmi()) { + // Load arguments object if there are no eval-introduced + // variables. Then load the argument from the arguments + // object using keyed load. + __ movq(rdx, + ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), + slow)); + __ Move(rax, key_literal->handle()); + Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); + __ call(ic, RelocInfo::CODE_TARGET); + __ jmp(done); + } + } + } + } +} + + void FullCodeGenerator::EmitVariableLoad(Variable* var, Expression::Context context) { // Four cases: non-this global variables, lookup slots, all other @@ -904,10 +1046,19 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var, Apply(context, rax); } else if (slot != NULL && slot->type() == Slot::LOOKUP) { + Label done, slow; + + // Generate code for loading from variables potentially shadowed + // by eval-introduced variables. + EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); + + __ bind(&slow); Comment cmnt(masm_, "Lookup slot"); __ push(rsi); // Context. __ Push(var->name()); __ CallRuntime(Runtime::kLoadContextSlot, 2); + __ bind(&done); + Apply(context, rax); } else if (slot != NULL) { @@ -1713,15 +1864,42 @@ void FullCodeGenerator::VisitCall(Call* expr) { EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); } else if (var != NULL && var->slot() != NULL && var->slot()->type() == Slot::LOOKUP) { - // Call to a lookup slot (dynamically introduced variable). Call - // the runtime to find the function to call (returned in rax) and - // the object holding it (returned in rdx). + // Call to a lookup slot (dynamically introduced variable). + Label slow, done; + + // Generate code for loading from variables potentially shadowed + // by eval-introduced variables. + EmitDynamicLoadFromSlotFastCase(var->slot(), + NOT_INSIDE_TYPEOF, + &slow, + &done); + + __ bind(&slow); + // Call the runtime to find the function to call (returned in rax) + // and the object holding it (returned in rdx). __ push(context_register()); __ Push(var->name()); __ CallRuntime(Runtime::kLoadContextSlot, 2); __ push(rax); // Function. __ push(rdx); // Receiver. + + // If fast case code has been generated, emit code to push the + // function and receiver and have the slow path jump around this + // code. + if (done.is_linked()) { + Label call; + __ jmp(&call); + __ bind(&done); + // Push function. + __ push(rax); + // Push global receiver. + __ movq(rbx, CodeGenerator::GlobalObject()); + __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); + __ bind(&call); + } + EmitCallWithStub(expr); + } else if (fun->AsProperty() != NULL) { // Call to an object property. Property* prop = fun->AsProperty(); @@ -2522,12 +2700,11 @@ void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) { Register key = rax; Register cache = rbx; Register tmp = rcx; - __ movq(cache, CodeGenerator::ContextOperand(rsi, Context::GLOBAL_INDEX)); + __ movq(cache, ContextOperand(rsi, Context::GLOBAL_INDEX)); __ movq(cache, FieldOperand(cache, GlobalObject::kGlobalContextOffset)); __ movq(cache, - CodeGenerator::ContextOperand( - cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); + ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); __ movq(cache, FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id))); @@ -3001,9 +3178,19 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr, Location where) { } else if (proxy != NULL && proxy->var()->slot() != NULL && proxy->var()->slot()->type() == Slot::LOOKUP) { + Label done, slow; + + // Generate code for loading from variables potentially shadowed + // by eval-introduced variables. + Slot* slot = proxy->var()->slot(); + EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); + + __ bind(&slow); __ push(rsi); __ Push(proxy->name()); __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); + __ bind(&done); + if (where == kStack) __ push(rax); } else { // This expression cannot throw a reference error at the top level. @@ -3243,7 +3430,7 @@ void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { void FullCodeGenerator::LoadContextField(Register dst, int context_index) { - __ movq(dst, CodeGenerator::ContextOperand(rsi, context_index)); + __ movq(dst, ContextOperand(rsi, context_index)); } diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index f500ce64..765a90c0 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -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* obj = StubCache::ComputeCallMiss(arguments().immediate(), kind_); if (obj->IsFailure()) return obj; @@ -847,12 +900,10 @@ 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; - } + if (!result->IsUndefined()) return result; } Label miss_in_smi_check; @@ -1043,9 +1094,9 @@ 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 ------------- // -- rcx : name // -- rsp[0] : return address @@ -1053,12 +1104,9 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object, // -- ... // -- rsp[(argc + 1) * 8] : receiver // ----------------------------------- - ASSERT(check == RECEIVER_MAP_CHECK); // If object is not an array, bail out to regular call. - if (!object->IsJSArray()) { - return Heap::undefined_value(); - } + if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value(); Label miss; @@ -1204,9 +1252,9 @@ 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 ------------- // -- rcx : name // -- rsp[0] : return address @@ -1214,12 +1262,9 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object, // -- ... // -- rsp[(argc + 1) * 8] : receiver // ----------------------------------- - ASSERT(check == RECEIVER_MAP_CHECK); // If object is not an array, bail out to regular call. - if (!object->IsJSArray()) { - return Heap::undefined_value(); - } + if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value(); Label miss, return_undefined, call_builtin; @@ -1289,9 +1334,9 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object, Object* CallStubCompiler::CompileStringCharAtCall(Object* object, JSObject* holder, + JSGlobalPropertyCell* cell, JSFunction* function, - String* name, - CheckType check) { + String* name) { // ----------- S t a t e ------------- // -- rcx : function name // -- rsp[0] : return address @@ -1301,7 +1346,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(); @@ -1358,11 +1403,12 @@ Object* CallStubCompiler::CompileStringCharAtCall(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 ------------- // -- rcx : function name // -- rsp[0] : return address @@ -1372,7 +1418,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(); @@ -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, JSObject* holder, String* name) { @@ -1498,7 +1613,6 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, JSFunction* function, String* name) { // ----------- S t a t e ------------- - // ----------------------------------- // rcx : function name // rsp[0] : return address // rsp[8] : argument argc @@ -1506,6 +1620,17 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, // ... // rsp[argc * 8] : argument 1 // 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; GenerateNameCheck(name, &miss); @@ -1513,42 +1638,9 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, // 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); - - // Get the value from the cell. - __ Move(rdi, Handle<JSGlobalPropertyCell>(cell)); - __ movq(rdi, FieldOperand(rdi, JSGlobalPropertyCell::kValueOffset)); + GenerateGlobalReceiverCheck(object, holder, name, &miss); - // 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); - } + GenerateLoadFunctionFromCell(cell, function, &miss); // Patch the receiver on the stack with the global proxy. if (object->IsGlobalObject()) { |