diff options
Diffstat (limited to 'deps/v8/src/x64/stub-cache-x64.cc')
-rw-r--r-- | deps/v8/src/x64/stub-cache-x64.cc | 712 |
1 files changed, 531 insertions, 181 deletions
diff --git a/deps/v8/src/x64/stub-cache-x64.cc b/deps/v8/src/x64/stub-cache-x64.cc index a78f8b11b..7d4410cb0 100644 --- a/deps/v8/src/x64/stub-cache-x64.cc +++ b/deps/v8/src/x64/stub-cache-x64.cc @@ -327,8 +327,7 @@ void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper); // Load length directly from the string. - __ movl(rax, FieldOperand(receiver, String::kLengthOffset)); - __ Integer32ToSmi(rax, rax); + __ movq(rax, FieldOperand(receiver, String::kLengthOffset)); __ ret(0); // Check if the object is a JSValue wrapper. @@ -340,8 +339,7 @@ void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, // directly if it is. __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset)); GenerateStringCheck(masm, scratch2, scratch1, miss, miss); - __ movl(rax, FieldOperand(scratch2, String::kLengthOffset)); - __ Integer32ToSmi(rax, rax); + __ movq(rax, FieldOperand(scratch2, String::kLengthOffset)); __ ret(0); } @@ -555,76 +553,234 @@ class LoadInterceptorCompiler BASE_EMBEDDED { }; +// Reserves space for the extra arguments to FastHandleApiCall in the +// caller's frame. +// +// These arguments are set by CheckPrototypes and GenerateFastApiCall. +static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { + // ----------- S t a t e ------------- + // -- rsp[0] : return address + // -- rsp[8] : last argument in the internal frame of the caller + // ----------------------------------- + __ movq(scratch, Operand(rsp, 0)); + __ subq(rsp, Immediate(4 * kPointerSize)); + __ movq(Operand(rsp, 0), scratch); + __ Move(scratch, Smi::FromInt(0)); + __ movq(Operand(rsp, 1 * kPointerSize), scratch); + __ movq(Operand(rsp, 2 * kPointerSize), scratch); + __ movq(Operand(rsp, 3 * kPointerSize), scratch); + __ movq(Operand(rsp, 4 * kPointerSize), scratch); +} + + +// Undoes the effects of ReserveSpaceForFastApiCall. +static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { + // ----------- S t a t e ------------- + // -- rsp[0] : return address + // -- rsp[8] : last fast api call extra argument + // -- ... + // -- rsp[32] : first fast api call extra argument + // -- rsp[40] : last argument in the internal frame + // ----------------------------------- + __ movq(scratch, Operand(rsp, 0)); + __ movq(Operand(rsp, 4 * kPointerSize), scratch); + __ addq(rsp, Immediate(kPointerSize * 4)); +} + + +// Generates call to FastHandleApiCall builtin. +static void GenerateFastApiCall(MacroAssembler* masm, + const CallOptimization& optimization, + int argc) { + // ----------- S t a t e ------------- + // -- rsp[0] : return address + // -- rsp[8] : object passing the type check + // (last fast api call extra argument, + // set by CheckPrototypes) + // -- rsp[16] : api call data + // -- rsp[24] : api callback + // -- rsp[32] : api function + // (first fast api call extra argument) + // -- rsp[40] : last argument + // -- ... + // -- rsp[(argc + 5) * 8] : first argument + // -- rsp[(argc + 6) * 8] : receiver + // ----------------------------------- + + // Get the function and setup the context. + JSFunction* function = optimization.constant_function(); + __ Move(rdi, Handle<JSFunction>(function)); + __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); + + // Pass the additional arguments FastHandleApiCall expects. + __ movq(Operand(rsp, 4 * kPointerSize), rdi); + bool info_loaded = false; + Object* callback = optimization.api_call_info()->callback(); + if (Heap::InNewSpace(callback)) { + info_loaded = true; + __ Move(rcx, Handle<CallHandlerInfo>(optimization.api_call_info())); + __ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kCallbackOffset)); + __ movq(Operand(rsp, 3 * kPointerSize), rbx); + } else { + __ Move(Operand(rsp, 3 * kPointerSize), Handle<Object>(callback)); + } + Object* call_data = optimization.api_call_info()->data(); + if (Heap::InNewSpace(call_data)) { + if (!info_loaded) { + __ Move(rcx, Handle<CallHandlerInfo>(optimization.api_call_info())); + } + __ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kDataOffset)); + __ movq(Operand(rsp, 2 * kPointerSize), rbx); + } else { + __ Move(Operand(rsp, 2 * kPointerSize), Handle<Object>(call_data)); + } + + // Set the number of arguments. + __ movq(rax, Immediate(argc + 4)); + + // Jump to the fast api call builtin (tail call). + Handle<Code> code = Handle<Code>( + Builtins::builtin(Builtins::FastHandleApiCall)); + ParameterCount expected(0); + __ InvokeCode(code, expected, expected, + RelocInfo::CODE_TARGET, JUMP_FUNCTION); +} + + class CallInterceptorCompiler BASE_EMBEDDED { public: - CallInterceptorCompiler(const ParameterCount& arguments, Register name) - : arguments_(arguments), name_(name) {} + CallInterceptorCompiler(StubCompiler* stub_compiler, + const ParameterCount& arguments, + Register name) + : stub_compiler_(stub_compiler), + arguments_(arguments), + name_(name) {} + + void Compile(MacroAssembler* masm, + JSObject* object, + JSObject* holder, + String* name, + LookupResult* lookup, + Register receiver, + Register scratch1, + Register scratch2, + Label* miss) { + ASSERT(holder->HasNamedInterceptor()); + ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); + + // Check that the receiver isn't a smi. + __ JumpIfSmi(receiver, miss); + + CallOptimization optimization(lookup); + + if (optimization.is_constant_call()) { + CompileCacheable(masm, + object, + receiver, + scratch1, + scratch2, + holder, + lookup, + name, + optimization, + miss); + } else { + CompileRegular(masm, + object, + receiver, + scratch1, + scratch2, + name, + holder, + miss); + } + } + private: void CompileCacheable(MacroAssembler* masm, - StubCompiler* stub_compiler, + JSObject* object, Register receiver, - Register holder, Register scratch1, Register scratch2, JSObject* holder_obj, LookupResult* lookup, String* name, + const CallOptimization& optimization, Label* miss_label) { - JSFunction* function = 0; - bool optimize = false; - // So far the most popular case for failed interceptor is - // CONSTANT_FUNCTION sitting below. - if (lookup->type() == CONSTANT_FUNCTION) { - function = lookup->GetConstantFunction(); - // JSArray holder is a special case for call constant function - // (see the corresponding code). - if (function->is_compiled() && !holder_obj->IsJSArray()) { - optimize = true; + ASSERT(optimization.is_constant_call()); + ASSERT(!lookup->holder()->IsGlobalObject()); + + int depth1 = kInvalidProtoDepth; + int depth2 = kInvalidProtoDepth; + bool can_do_fast_api_call = false; + if (optimization.is_simple_api_call() && + !lookup->holder()->IsGlobalObject()) { + depth1 = optimization.GetPrototypeDepthOfExpectedType(object, holder_obj); + if (depth1 == kInvalidProtoDepth) { + depth2 = optimization.GetPrototypeDepthOfExpectedType(holder_obj, + lookup->holder()); } + can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || + (depth2 != kInvalidProtoDepth); } - if (!optimize) { - CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label); - return; + __ IncrementCounter(&Counters::call_const_interceptor, 1); + + if (can_do_fast_api_call) { + __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1); + ReserveSpaceForFastApiCall(masm, scratch1); } - ASSERT(!lookup->holder()->IsGlobalObject()); + Label miss_cleanup; + Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; + Register holder = + stub_compiler_->CheckPrototypes(object, receiver, holder_obj, + scratch1, scratch2, name, + depth1, miss); - __ EnterInternalFrame(); - __ push(holder); // Save the holder. - __ push(name_); // Save the name. + Label regular_invoke; + LoadWithInterceptor(masm, receiver, holder, holder_obj, ®ular_invoke); - CompileCallLoadPropertyWithInterceptor(masm, - receiver, - holder, - name_, - holder_obj); + // Generate code for the failed interceptor case. - __ pop(name_); // Restore the name. - __ pop(receiver); // Restore the holder. - __ LeaveInternalFrame(); - - __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); - Label invoke; - __ j(not_equal, &invoke); + // Check the lookup is still valid. + stub_compiler_->CheckPrototypes(holder_obj, receiver, + lookup->holder(), + scratch1, scratch2, name, + depth2, miss); - stub_compiler->CheckPrototypes(holder_obj, receiver, - lookup->holder(), scratch1, - scratch2, - name, - miss_label); + if (can_do_fast_api_call) { + GenerateFastApiCall(masm, optimization, arguments_.immediate()); + } else { + __ InvokeFunction(optimization.constant_function(), arguments_, + JUMP_FUNCTION); + } - __ InvokeFunction(function, arguments_, JUMP_FUNCTION); + if (can_do_fast_api_call) { + __ bind(&miss_cleanup); + FreeSpaceForFastApiCall(masm, scratch1); + __ jmp(miss_label); + } - __ bind(&invoke); + __ bind(®ular_invoke); + if (can_do_fast_api_call) { + FreeSpaceForFastApiCall(masm, scratch1); + } } void CompileRegular(MacroAssembler* masm, + JSObject* object, Register receiver, - Register holder, - Register scratch, + Register scratch1, + Register scratch2, + String* name, JSObject* holder_obj, Label* miss_label) { + Register holder = + stub_compiler_->CheckPrototypes(object, receiver, holder_obj, + scratch1, scratch2, name, + miss_label); + __ EnterInternalFrame(); // Save the name_ register across the call. __ push(name_); @@ -639,11 +795,35 @@ class CallInterceptorCompiler BASE_EMBEDDED { ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall)), 5); + // Restore the name_ register. __ pop(name_); __ LeaveInternalFrame(); } - private: + void LoadWithInterceptor(MacroAssembler* masm, + Register receiver, + Register holder, + JSObject* holder_obj, + Label* interceptor_succeeded) { + __ EnterInternalFrame(); + __ push(holder); // Save the holder. + __ push(name_); // Save the name. + + CompileCallLoadPropertyWithInterceptor(masm, + receiver, + holder, + name_, + holder_obj); + + __ pop(name_); // Restore the name. + __ pop(receiver); // Restore the holder. + __ LeaveInternalFrame(); + + __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); + __ j(not_equal, interceptor_succeeded); + } + + StubCompiler* stub_compiler_; const ParameterCount& arguments_; Register name_; }; @@ -673,119 +853,6 @@ static Object* GenerateCheckPropertyCell(MacroAssembler* masm, #define __ ACCESS_MASM((masm())) - -Object* CallStubCompiler::CompileArrayPushCall(Object* object, - JSObject* holder, - JSFunction* function, - String* name, - CheckType check) { - // ----------- S t a t e ------------- - // rcx : function name - // rsp[0] : return address - // rsp[8] : argument argc - // rsp[16] : argument argc - 1 - // ... - // rsp[argc * 8] : argument 1 - // rsp[(argc + 1) * 8] : argument 0 = receiver - // ----------------------------------- - - // TODO(639): faster implementation. - ASSERT(check == RECEIVER_MAP_CHECK); - - Label miss; - - // Get the receiver from the stack. - const int argc = arguments().immediate(); - __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); - - // Check that the receiver isn't a smi. - __ JumpIfSmi(rdx, &miss); - - // Check that the maps haven't changed. - CheckPrototypes(JSObject::cast(object), rdx, holder, - rbx, rax, name, &miss); - - // Patch the receiver on the stack with the global proxy if - // necessary. - if (object->IsGlobalObject()) { - __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); - __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); - } - - __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush), - argc + 1, - 1); - - // Handle call cache miss. - __ bind(&miss); - Handle<Code> ic = ComputeCallMiss(arguments().immediate()); - __ Jump(ic, RelocInfo::CODE_TARGET); - - // Return the generated code. - String* function_name = NULL; - if (function->shared()->name()->IsString()) { - function_name = String::cast(function->shared()->name()); - } - return GetCode(CONSTANT_FUNCTION, function_name); -} - - -Object* CallStubCompiler::CompileArrayPopCall(Object* object, - JSObject* holder, - JSFunction* function, - String* name, - CheckType check) { - // ----------- S t a t e ------------- - // rcx : function name - // rsp[0] : return address - // rsp[8] : argument argc - // rsp[16] : argument argc - 1 - // ... - // rsp[argc * 8] : argument 1 - // rsp[(argc + 1) * 8] : argument 0 = receiver - // ----------------------------------- - - // TODO(642): faster implementation. - ASSERT(check == RECEIVER_MAP_CHECK); - - Label miss; - - // Get the receiver from the stack. - const int argc = arguments().immediate(); - __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); - - // Check that the receiver isn't a smi. - __ JumpIfSmi(rdx, &miss); - - // Check that the maps haven't changed. - CheckPrototypes(JSObject::cast(object), rdx, holder, - rbx, rax, name, &miss); - - // Patch the receiver on the stack with the global proxy if - // necessary. - if (object->IsGlobalObject()) { - __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); - __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); - } - - __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop), - argc + 1, - 1); - - // Handle call cache miss. - __ bind(&miss); - Handle<Code> ic = ComputeCallMiss(arguments().immediate()); - __ Jump(ic, RelocInfo::CODE_TARGET); - - // Return the generated code. - String* function_name = NULL; - if (function->shared()->name()->IsString()) { - function_name = String::cast(function->shared()->name()); - } - return GetCode(CONSTANT_FUNCTION, function_name); -} - - Object* CallStubCompiler::CompileCallConstant(Object* object, JSObject* holder, JSFunction* function, @@ -805,10 +872,14 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, if (function_info->HasCustomCallGenerator()) { CustomCallGenerator generator = ToCData<CustomCallGenerator>(function_info->function_data()); - return generator(this, object, holder, function, name, check); + Object* result = generator(this, object, holder, function, name, check); + // undefined means bail out to regular compiler. + if (!result->IsUndefined()) { + return result; + } } - Label miss; + Label miss_in_smi_check; // Get the receiver from the stack. const int argc = arguments().immediate(); @@ -816,22 +887,39 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, // Check that the receiver isn't a smi. if (check != NUMBER_CHECK) { - __ JumpIfSmi(rdx, &miss); + __ JumpIfSmi(rdx, &miss_in_smi_check); } // Make sure that it's okay not to patch the on stack receiver // unless we're doing a receiver map check. ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); + CallOptimization optimization(function); + int depth = kInvalidProtoDepth; + Label miss; + switch (check) { case RECEIVER_MAP_CHECK: + __ IncrementCounter(&Counters::call_const, 1); + + if (optimization.is_simple_api_call() && !object->IsGlobalObject()) { + depth = optimization.GetPrototypeDepthOfExpectedType( + JSObject::cast(object), holder); + } + + if (depth != kInvalidProtoDepth) { + __ IncrementCounter(&Counters::call_const_fast_api, 1); + ReserveSpaceForFastApiCall(masm(), rax); + } + // Check that the maps haven't changed. CheckPrototypes(JSObject::cast(object), rdx, holder, - rbx, rax, name, &miss); + rbx, rax, name, depth, &miss); // Patch the receiver on the stack with the global proxy if // necessary. if (object->IsGlobalObject()) { + ASSERT(depth == kInvalidProtoDepth); __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); } @@ -901,10 +989,20 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, UNREACHABLE(); } - __ InvokeFunction(function, arguments(), JUMP_FUNCTION); + if (depth != kInvalidProtoDepth) { + GenerateFastApiCall(masm(), optimization, argc); + } else { + __ InvokeFunction(function, arguments(), JUMP_FUNCTION); + } // Handle call cache miss. __ bind(&miss); + if (depth != kInvalidProtoDepth) { + FreeSpaceForFastApiCall(masm(), rax); + } + + // Handle call cache miss. + __ bind(&miss_in_smi_check); Handle<Code> ic = ComputeCallMiss(arguments().immediate()); __ Jump(ic, RelocInfo::CODE_TARGET); @@ -969,6 +1067,257 @@ Object* CallStubCompiler::CompileCallField(JSObject* object, } +Object* CallStubCompiler::CompileArrayPushCall(Object* object, + JSObject* holder, + JSFunction* function, + String* name, + CheckType check) { + // ----------- S t a t e ------------- + // -- rcx : name + // -- rsp[0] : return address + // -- rsp[(argc - n) * 8] : arg[n] (zero-based) + // -- ... + // -- 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(); + } + + Label miss; + + // Get the receiver from the stack. + const int argc = arguments().immediate(); + __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); + + // Check that the receiver isn't a smi. + __ JumpIfSmi(rdx, &miss); + + CheckPrototypes(JSObject::cast(object), + rdx, + holder, + rbx, + rax, + name, + &miss); + + if (argc == 0) { + // Noop, return the length. + __ movq(rax, FieldOperand(rdx, JSArray::kLengthOffset)); + __ ret((argc + 1) * kPointerSize); + } else { + // Get the elements array of the object. + __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset)); + + // Check that the elements are in fast mode (not dictionary). + __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset), + Factory::fixed_array_map()); + __ j(not_equal, &miss); + + if (argc == 1) { // Otherwise fall through to call builtin. + Label call_builtin, exit, with_rset_update, attempt_to_grow_elements; + + // Get the array's length into rax and calculate new length. + __ movq(rax, FieldOperand(rdx, JSArray::kLengthOffset)); + STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue); + __ SmiAddConstant(rax, rax, Smi::FromInt(argc)); + + // Get the element's length into rcx. + __ movl(rcx, FieldOperand(rbx, FixedArray::kLengthOffset)); + __ Integer32ToSmi(rcx, rcx); + + // Check if we could survive without allocation. + __ SmiCompare(rax, rcx); + __ j(greater, &attempt_to_grow_elements); + + // Save new length. + __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rax); + + // Push the element. + __ movq(rcx, Operand(rsp, argc * kPointerSize)); + SmiIndex index = + masm()->SmiToIndex(kScratchRegister, rax, times_pointer_size); + __ lea(rdx, FieldOperand(rbx, + index.reg, index.scale, + FixedArray::kHeaderSize - argc * kPointerSize)); + __ movq(Operand(rdx, 0), rcx); + + // Check if value is a smi. + __ JumpIfNotSmi(rcx, &with_rset_update); + + __ bind(&exit); + __ ret((argc + 1) * kPointerSize); + + __ bind(&with_rset_update); + + __ InNewSpace(rbx, rcx, equal, &exit); + + RecordWriteStub stub(rbx, rdx, rcx); + __ CallStub(&stub); + __ ret((argc + 1) * kPointerSize); + + __ bind(&attempt_to_grow_elements); + ExternalReference new_space_allocation_top = + ExternalReference::new_space_allocation_top_address(); + ExternalReference new_space_allocation_limit = + ExternalReference::new_space_allocation_limit_address(); + + const int kAllocationDelta = 4; + // Load top. + __ movq(rcx, new_space_allocation_top); + __ movq(rcx, Operand(rcx, 0)); + + // Check if it's the end of elements. + index = masm()->SmiToIndex(kScratchRegister, rax, times_pointer_size); + __ lea(rdx, FieldOperand(rbx, + index.reg, index.scale, + FixedArray::kHeaderSize - argc * kPointerSize)); + __ cmpq(rdx, rcx); + __ j(not_equal, &call_builtin); + __ addq(rcx, Immediate(kAllocationDelta * kPointerSize)); + __ movq(kScratchRegister, new_space_allocation_limit); + __ cmpq(rcx, Operand(kScratchRegister, 0)); + __ j(above, &call_builtin); + + // We fit and could grow elements. + __ movq(kScratchRegister, new_space_allocation_top); + __ movq(Operand(kScratchRegister, 0), rcx); + __ movq(rcx, Operand(rsp, argc * kPointerSize)); + + // Push the argument... + __ movq(Operand(rdx, 0), rcx); + // ... and fill the rest with holes. + __ Move(kScratchRegister, Factory::the_hole_value()); + for (int i = 1; i < kAllocationDelta; i++) { + __ movq(Operand(rdx, i * kPointerSize), kScratchRegister); + } + + // Restore receiver to rdx as finish sequence assumes it's here. + __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); + + // Increment element's and array's sizes. + __ addq(FieldOperand(rbx, FixedArray::kLengthOffset), + Immediate(kAllocationDelta)); + __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rax); + + // Elements are in new space, so no remembered set updates are necessary. + __ ret((argc + 1) * kPointerSize); + + __ bind(&call_builtin); + } + + __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush), + argc + 1, + 1); + } + + __ bind(&miss); + + Handle<Code> ic = ComputeCallMiss(arguments().immediate()); + __ jmp(ic, RelocInfo::CODE_TARGET); + + // Return the generated code. + String* function_name = NULL; + if (function->shared()->name()->IsString()) { + function_name = String::cast(function->shared()->name()); + } + return GetCode(CONSTANT_FUNCTION, function_name); +} + + +Object* CallStubCompiler::CompileArrayPopCall(Object* object, + JSObject* holder, + JSFunction* function, + String* name, + CheckType check) { + // ----------- S t a t e ------------- + // -- ecx : name + // -- esp[0] : return address + // -- esp[(argc - n) * 4] : arg[n] (zero-based) + // -- ... + // -- esp[(argc + 1) * 4] : receiver + // ----------------------------------- + ASSERT(check == RECEIVER_MAP_CHECK); + + // If object is not an array, bail out to regular call. + if (!object->IsJSArray()) { + return Heap::undefined_value(); + } + + Label miss, return_undefined, call_builtin; + + // Get the receiver from the stack. + const int argc = arguments().immediate(); + __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); + + // Check that the receiver isn't a smi. + __ JumpIfSmi(rdx, &miss); + + CheckPrototypes(JSObject::cast(object), rdx, + holder, rbx, + rax, name, &miss); + + // Get the elements array of the object. + __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset)); + + // Check that the elements are in fast mode (not dictionary). + __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset), Factory::fixed_array_map()); + __ j(not_equal, &miss); + + // Get the array's length into rcx and calculate new length. + __ movq(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); + __ SmiSubConstant(rcx, rcx, Smi::FromInt(1)); + __ SmiTest(rcx); + __ j(negative, &return_undefined); + + // Get the last element. + __ Move(r9, Factory::the_hole_value()); + SmiIndex index = + masm()->SmiToIndex(r8, rcx, times_pointer_size); + __ movq(rax, FieldOperand(rbx, + index.reg, index.scale, + FixedArray::kHeaderSize)); + // Check if element is already the hole. + __ cmpq(rax, r9); + __ j(equal, &call_builtin); + + // Set the array's length. + __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rcx); + + // Fill with the hole and return original value.. + __ movq(FieldOperand(rbx, + index.reg, index.scale, + FixedArray::kHeaderSize), + r9); + __ ret((argc + 1) * kPointerSize); + + __ bind(&return_undefined); + + __ Move(rax, Factory::undefined_value()); + __ ret((argc + 1) * kPointerSize); + + __ bind(&call_builtin); + __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop), + argc + 1, + 1); + __ bind(&miss); + + Handle<Code> ic = ComputeCallMiss(arguments().immediate()); + __ jmp(ic, RelocInfo::CODE_TARGET); + + // Return the generated code. + String* function_name = NULL; + if (function->shared()->name()->IsString()) { + function_name = String::cast(function->shared()->name()); + } + return GetCode(CONSTANT_FUNCTION, function_name); +} + + + + Object* CallStubCompiler::CompileCallInterceptor(JSObject* object, JSObject* holder, String* name) { @@ -992,18 +1341,16 @@ Object* CallStubCompiler::CompileCallInterceptor(JSObject* object, // Get the receiver from the stack. __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); - CallInterceptorCompiler compiler(arguments(), rcx); - CompileLoadInterceptor(&compiler, - this, - masm(), - object, - holder, - name, - &lookup, - rdx, - rbx, - rdi, - &miss); + CallInterceptorCompiler compiler(this, arguments(), rcx); + compiler.Compile(masm(), + object, + holder, + name, + &lookup, + rdx, + rbx, + rdi, + &miss); // Restore receiver. __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); @@ -1822,12 +2169,15 @@ Register StubCompiler::CheckPrototypes(JSObject* object, String* name, int save_at_depth, Label* miss) { - // TODO(602): support object saving. - ASSERT(save_at_depth == kInvalidProtoDepth); - // Check that the maps haven't changed. Register result = - __ CheckMaps(object, object_reg, holder, holder_reg, scratch, miss); + masm()->CheckMaps(object, + object_reg, + holder, + holder_reg, + scratch, + save_at_depth, + miss); // If we've skipped any global objects, it's not enough to verify // that their maps haven't changed. We also need to check that the |