summaryrefslogtreecommitdiffstats
path: root/src/x64
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2010-09-22 15:07:15 +0100
committerSteve Block <steveblock@google.com>2010-09-29 18:15:43 +0100
commit59151504615d929945dc59db37bf1166937748c6 (patch)
tree2199adfe73b4618f685bae891d2d54f2cd997f77 /src/x64
parent9ac36c9faca11611ada13b4054edbaa0738661d0 (diff)
downloadandroid_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.cc1
-rw-r--r--src/x64/full-codegen-x64.cc225
-rw-r--r--src/x64/stub-cache-x64.cc216
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()) {