| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 801 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 812 InvokeFlag flag, | 812 InvokeFlag flag, |
| 813 const CallWrapper& call_wrapper) { | 813 const CallWrapper& call_wrapper) { |
| 814 // Calls are not allowed in some stubs. | 814 // Calls are not allowed in some stubs. |
| 815 ASSERT(flag == JUMP_FUNCTION || allow_stub_calls()); | 815 ASSERT(flag == JUMP_FUNCTION || allow_stub_calls()); |
| 816 | 816 |
| 817 // Rely on the assertion to check that the number of provided | 817 // Rely on the assertion to check that the number of provided |
| 818 // arguments match the expected number of arguments. Fake a | 818 // arguments match the expected number of arguments. Fake a |
| 819 // parameter count to avoid emitting code to do the check. | 819 // parameter count to avoid emitting code to do the check. |
| 820 ParameterCount expected(0); | 820 ParameterCount expected(0); |
| 821 GetBuiltinEntry(rdx, id); | 821 GetBuiltinEntry(rdx, id); |
| 822 InvokeCode(rdx, expected, expected, flag, call_wrapper); | 822 InvokeCode(rdx, expected, expected, flag, call_wrapper, CALL_AS_METHOD); |
| 823 } | 823 } |
| 824 | 824 |
| 825 | 825 |
| 826 void MacroAssembler::GetBuiltinFunction(Register target, | 826 void MacroAssembler::GetBuiltinFunction(Register target, |
| 827 Builtins::JavaScript id) { | 827 Builtins::JavaScript id) { |
| 828 // Load the builtins object into target register. | 828 // Load the builtins object into target register. |
| 829 movq(target, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); | 829 movq(target, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 830 movq(target, FieldOperand(target, GlobalObject::kBuiltinsOffset)); | 830 movq(target, FieldOperand(target, GlobalObject::kBuiltinsOffset)); |
| 831 movq(target, FieldOperand(target, | 831 movq(target, FieldOperand(target, |
| 832 JSBuiltinsObject::OffsetOfFunctionWithId(id))); | 832 JSBuiltinsObject::OffsetOfFunctionWithId(id))); |
| (...skipping 1788 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2621 CmpInstanceType(map, type); | 2621 CmpInstanceType(map, type); |
| 2622 } | 2622 } |
| 2623 | 2623 |
| 2624 | 2624 |
| 2625 void MacroAssembler::CmpInstanceType(Register map, InstanceType type) { | 2625 void MacroAssembler::CmpInstanceType(Register map, InstanceType type) { |
| 2626 cmpb(FieldOperand(map, Map::kInstanceTypeOffset), | 2626 cmpb(FieldOperand(map, Map::kInstanceTypeOffset), |
| 2627 Immediate(static_cast<int8_t>(type))); | 2627 Immediate(static_cast<int8_t>(type))); |
| 2628 } | 2628 } |
| 2629 | 2629 |
| 2630 | 2630 |
| 2631 void MacroAssembler::CheckFastElements(Register map, |
| 2632 Label* fail, |
| 2633 Label::Distance distance) { |
| 2634 STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0); |
| 2635 cmpb(FieldOperand(map, Map::kBitField2Offset), |
| 2636 Immediate(Map::kMaximumBitField2FastElementValue)); |
| 2637 j(above, fail, distance); |
| 2638 } |
| 2639 |
| 2640 |
| 2631 void MacroAssembler::CheckMap(Register obj, | 2641 void MacroAssembler::CheckMap(Register obj, |
| 2632 Handle<Map> map, | 2642 Handle<Map> map, |
| 2633 Label* fail, | 2643 Label* fail, |
| 2634 SmiCheckType smi_check_type) { | 2644 SmiCheckType smi_check_type) { |
| 2635 if (smi_check_type == DO_SMI_CHECK) { | 2645 if (smi_check_type == DO_SMI_CHECK) { |
| 2636 JumpIfSmi(obj, fail); | 2646 JumpIfSmi(obj, fail); |
| 2637 } | 2647 } |
| 2638 Cmp(FieldOperand(obj, HeapObject::kMapOffset), map); | 2648 Cmp(FieldOperand(obj, HeapObject::kMapOffset), map); |
| 2639 j(not_equal, fail); | 2649 j(not_equal, fail); |
| 2640 } | 2650 } |
| (...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2941 movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); | 2951 movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); |
| 2942 | 2952 |
| 2943 ParameterCount expected(rbx); | 2953 ParameterCount expected(rbx); |
| 2944 InvokeCode(rdx, expected, actual, flag, call_wrapper, call_kind); | 2954 InvokeCode(rdx, expected, actual, flag, call_wrapper, call_kind); |
| 2945 } | 2955 } |
| 2946 | 2956 |
| 2947 | 2957 |
| 2948 void MacroAssembler::InvokeFunction(JSFunction* function, | 2958 void MacroAssembler::InvokeFunction(JSFunction* function, |
| 2949 const ParameterCount& actual, | 2959 const ParameterCount& actual, |
| 2950 InvokeFlag flag, | 2960 InvokeFlag flag, |
| 2951 const CallWrapper& call_wrapper) { | 2961 const CallWrapper& call_wrapper, |
| 2962 CallKind call_kind) { |
| 2952 ASSERT(function->is_compiled()); | 2963 ASSERT(function->is_compiled()); |
| 2953 // Get the function and setup the context. | 2964 // Get the function and setup the context. |
| 2954 Move(rdi, Handle<JSFunction>(function)); | 2965 Move(rdi, Handle<JSFunction>(function)); |
| 2955 movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); | 2966 movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); |
| 2956 | 2967 |
| 2957 if (V8::UseCrankshaft()) { | 2968 if (V8::UseCrankshaft()) { |
| 2958 // Since Crankshaft can recompile a function, we need to load | 2969 // Since Crankshaft can recompile a function, we need to load |
| 2959 // the Code object every time we call the function. | 2970 // the Code object every time we call the function. |
| 2960 movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); | 2971 movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); |
| 2961 ParameterCount expected(function->shared()->formal_parameter_count()); | 2972 ParameterCount expected(function->shared()->formal_parameter_count()); |
| 2962 InvokeCode(rdx, expected, actual, flag, call_wrapper); | 2973 InvokeCode(rdx, expected, actual, flag, call_wrapper, call_kind); |
| 2963 } else { | 2974 } else { |
| 2964 // Invoke the cached code. | 2975 // Invoke the cached code. |
| 2965 Handle<Code> code(function->code()); | 2976 Handle<Code> code(function->code()); |
| 2966 ParameterCount expected(function->shared()->formal_parameter_count()); | 2977 ParameterCount expected(function->shared()->formal_parameter_count()); |
| 2967 InvokeCode(code, | 2978 InvokeCode(code, |
| 2968 expected, | 2979 expected, |
| 2969 actual, | 2980 actual, |
| 2970 RelocInfo::CODE_TARGET, | 2981 RelocInfo::CODE_TARGET, |
| 2971 flag, | 2982 flag, |
| 2972 call_wrapper); | 2983 call_wrapper, |
| 2984 call_kind); |
| 2973 } | 2985 } |
| 2974 } | 2986 } |
| 2975 | 2987 |
| 2976 | 2988 |
| 2977 void MacroAssembler::InvokePrologue(const ParameterCount& expected, | 2989 void MacroAssembler::InvokePrologue(const ParameterCount& expected, |
| 2978 const ParameterCount& actual, | 2990 const ParameterCount& actual, |
| 2979 Handle<Code> code_constant, | 2991 Handle<Code> code_constant, |
| 2980 Register code_register, | 2992 Register code_register, |
| 2981 Label* done, | 2993 Label* done, |
| 2982 InvokeFlag flag, | 2994 InvokeFlag flag, |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3255 int token_offset = | 3267 int token_offset = |
| 3256 Context::kHeaderSize + Context::SECURITY_TOKEN_INDEX * kPointerSize; | 3268 Context::kHeaderSize + Context::SECURITY_TOKEN_INDEX * kPointerSize; |
| 3257 movq(scratch, FieldOperand(scratch, token_offset)); | 3269 movq(scratch, FieldOperand(scratch, token_offset)); |
| 3258 cmpq(scratch, FieldOperand(kScratchRegister, token_offset)); | 3270 cmpq(scratch, FieldOperand(kScratchRegister, token_offset)); |
| 3259 j(not_equal, miss); | 3271 j(not_equal, miss); |
| 3260 | 3272 |
| 3261 bind(&same_contexts); | 3273 bind(&same_contexts); |
| 3262 } | 3274 } |
| 3263 | 3275 |
| 3264 | 3276 |
| 3277 void MacroAssembler::LoadFromNumberDictionary(Label* miss, |
| 3278 Register elements, |
| 3279 Register key, |
| 3280 Register r0, |
| 3281 Register r1, |
| 3282 Register r2, |
| 3283 Register result) { |
| 3284 // Register use: |
| 3285 // |
| 3286 // elements - holds the slow-case elements of the receiver on entry. |
| 3287 // Unchanged unless 'result' is the same register. |
| 3288 // |
| 3289 // key - holds the smi key on entry. |
| 3290 // Unchanged unless 'result' is the same register. |
| 3291 // |
| 3292 // Scratch registers: |
| 3293 // |
| 3294 // r0 - holds the untagged key on entry and holds the hash once computed. |
| 3295 // |
| 3296 // r1 - used to hold the capacity mask of the dictionary |
| 3297 // |
| 3298 // r2 - used for the index into the dictionary. |
| 3299 // |
| 3300 // result - holds the result on exit if the load succeeded. |
| 3301 // Allowed to be the same as 'key' or 'result'. |
| 3302 // Unchanged on bailout so 'key' or 'result' can be used |
| 3303 // in further computation. |
| 3304 |
| 3305 Label done; |
| 3306 |
| 3307 // Compute the hash code from the untagged key. This must be kept in sync |
| 3308 // with ComputeIntegerHash in utils.h. |
| 3309 // |
| 3310 // hash = ~hash + (hash << 15); |
| 3311 movl(r1, r0); |
| 3312 notl(r0); |
| 3313 shll(r1, Immediate(15)); |
| 3314 addl(r0, r1); |
| 3315 // hash = hash ^ (hash >> 12); |
| 3316 movl(r1, r0); |
| 3317 shrl(r1, Immediate(12)); |
| 3318 xorl(r0, r1); |
| 3319 // hash = hash + (hash << 2); |
| 3320 leal(r0, Operand(r0, r0, times_4, 0)); |
| 3321 // hash = hash ^ (hash >> 4); |
| 3322 movl(r1, r0); |
| 3323 shrl(r1, Immediate(4)); |
| 3324 xorl(r0, r1); |
| 3325 // hash = hash * 2057; |
| 3326 imull(r0, r0, Immediate(2057)); |
| 3327 // hash = hash ^ (hash >> 16); |
| 3328 movl(r1, r0); |
| 3329 shrl(r1, Immediate(16)); |
| 3330 xorl(r0, r1); |
| 3331 |
| 3332 // Compute capacity mask. |
| 3333 SmiToInteger32(r1, |
| 3334 FieldOperand(elements, NumberDictionary::kCapacityOffset)); |
| 3335 decl(r1); |
| 3336 |
| 3337 // Generate an unrolled loop that performs a few probes before giving up. |
| 3338 const int kProbes = 4; |
| 3339 for (int i = 0; i < kProbes; i++) { |
| 3340 // Use r2 for index calculations and keep the hash intact in r0. |
| 3341 movq(r2, r0); |
| 3342 // Compute the masked index: (hash + i + i * i) & mask. |
| 3343 if (i > 0) { |
| 3344 addl(r2, Immediate(NumberDictionary::GetProbeOffset(i))); |
| 3345 } |
| 3346 and_(r2, r1); |
| 3347 |
| 3348 // Scale the index by multiplying by the entry size. |
| 3349 ASSERT(NumberDictionary::kEntrySize == 3); |
| 3350 lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3 |
| 3351 |
| 3352 // Check if the key matches. |
| 3353 cmpq(key, FieldOperand(elements, |
| 3354 r2, |
| 3355 times_pointer_size, |
| 3356 NumberDictionary::kElementsStartOffset)); |
| 3357 if (i != (kProbes - 1)) { |
| 3358 j(equal, &done); |
| 3359 } else { |
| 3360 j(not_equal, miss); |
| 3361 } |
| 3362 } |
| 3363 |
| 3364 bind(&done); |
| 3365 // Check that the value is a normal propety. |
| 3366 const int kDetailsOffset = |
| 3367 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; |
| 3368 ASSERT_EQ(NORMAL, 0); |
| 3369 Test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), |
| 3370 Smi::FromInt(PropertyDetails::TypeField::mask())); |
| 3371 j(not_zero, miss); |
| 3372 |
| 3373 // Get the value at the masked, scaled index. |
| 3374 const int kValueOffset = |
| 3375 NumberDictionary::kElementsStartOffset + kPointerSize; |
| 3376 movq(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset)); |
| 3377 } |
| 3378 |
| 3379 |
| 3265 void MacroAssembler::LoadAllocationTopHelper(Register result, | 3380 void MacroAssembler::LoadAllocationTopHelper(Register result, |
| 3266 Register scratch, | 3381 Register scratch, |
| 3267 AllocationFlags flags) { | 3382 AllocationFlags flags) { |
| 3268 ExternalReference new_space_allocation_top = | 3383 ExternalReference new_space_allocation_top = |
| 3269 ExternalReference::new_space_allocation_top_address(isolate()); | 3384 ExternalReference::new_space_allocation_top_address(isolate()); |
| 3270 | 3385 |
| 3271 // Just return if allocation top is already known. | 3386 // Just return if allocation top is already known. |
| 3272 if ((flags & RESULT_CONTAINS_TOP) != 0) { | 3387 if ((flags & RESULT_CONTAINS_TOP) != 0) { |
| 3273 // No use of scratch if allocation top is provided. | 3388 // No use of scratch if allocation top is provided. |
| 3274 ASSERT(!scratch.is_valid()); | 3389 ASSERT(!scratch.is_valid()); |
| (...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3668 j(not_equal, &short_loop); | 3783 j(not_equal, &short_loop); |
| 3669 | 3784 |
| 3670 bind(&done); | 3785 bind(&done); |
| 3671 } | 3786 } |
| 3672 } | 3787 } |
| 3673 | 3788 |
| 3674 | 3789 |
| 3675 void MacroAssembler::LoadContext(Register dst, int context_chain_length) { | 3790 void MacroAssembler::LoadContext(Register dst, int context_chain_length) { |
| 3676 if (context_chain_length > 0) { | 3791 if (context_chain_length > 0) { |
| 3677 // Move up the chain of contexts to the context containing the slot. | 3792 // Move up the chain of contexts to the context containing the slot. |
| 3678 movq(dst, Operand(rsi, Context::SlotOffset(Context::CLOSURE_INDEX))); | 3793 movq(dst, Operand(rsi, Context::SlotOffset(Context::PREVIOUS_INDEX))); |
| 3679 // Load the function context (which is the incoming, outer context). | |
| 3680 movq(dst, FieldOperand(dst, JSFunction::kContextOffset)); | |
| 3681 for (int i = 1; i < context_chain_length; i++) { | 3794 for (int i = 1; i < context_chain_length; i++) { |
| 3682 movq(dst, Operand(dst, Context::SlotOffset(Context::CLOSURE_INDEX))); | 3795 movq(dst, Operand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX))); |
| 3683 movq(dst, FieldOperand(dst, JSFunction::kContextOffset)); | |
| 3684 } | 3796 } |
| 3685 // The context may be an intermediate context, not a function context. | |
| 3686 movq(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX))); | |
| 3687 } else { | 3797 } else { |
| 3688 // Slot is in the current function context. Move it into the | 3798 // Slot is in the current function context. Move it into the |
| 3689 // destination register in case we store into it (the write barrier | 3799 // destination register in case we store into it (the write barrier |
| 3690 // cannot be allowed to destroy the context in rsi). | 3800 // cannot be allowed to destroy the context in rsi). |
| 3691 movq(dst, rsi); | 3801 movq(dst, rsi); |
| 3692 } | 3802 } |
| 3693 | 3803 |
| 3694 // We should not have found a 'with' context by walking the context chain | 3804 // We should not have found a with context by walking the context |
| 3695 // (i.e., the static scope chain and runtime context chain do not agree). | 3805 // chain (i.e., the static scope chain and runtime context chain do |
| 3696 // A variable occurring in such a scope should have slot type LOOKUP and | 3806 // not agree). A variable occurring in such a scope should have |
| 3697 // not CONTEXT. | 3807 // slot type LOOKUP and not CONTEXT. |
| 3698 if (emit_debug_code()) { | 3808 if (emit_debug_code()) { |
| 3699 cmpq(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX))); | 3809 CompareRoot(FieldOperand(dst, HeapObject::kMapOffset), |
| 3700 Check(equal, "Yo dawg, I heard you liked function contexts " | 3810 Heap::kWithContextMapRootIndex); |
| 3701 "so I put function contexts in all your contexts"); | 3811 Check(not_equal, "Variable resolved to with context."); |
| 3702 } | 3812 } |
| 3703 } | 3813 } |
| 3704 | 3814 |
| 3705 #ifdef _WIN64 | 3815 #ifdef _WIN64 |
| 3706 static const int kRegisterPassedArguments = 4; | 3816 static const int kRegisterPassedArguments = 4; |
| 3707 #else | 3817 #else |
| 3708 static const int kRegisterPassedArguments = 6; | 3818 static const int kRegisterPassedArguments = 6; |
| 3709 #endif | 3819 #endif |
| 3710 | 3820 |
| 3711 void MacroAssembler::LoadGlobalFunction(int index, Register function) { | 3821 void MacroAssembler::LoadGlobalFunction(int index, Register function) { |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3910 movq(rcx, addr_reg); | 4020 movq(rcx, addr_reg); |
| 3911 shrl(rcx, Immediate(kPointerSizeLog2)); | 4021 shrl(rcx, Immediate(kPointerSizeLog2)); |
| 3912 and_(rcx, Immediate((1 << Bitmap::kBitsPerCellLog2) - 1)); | 4022 and_(rcx, Immediate((1 << Bitmap::kBitsPerCellLog2) - 1)); |
| 3913 movl(mask_reg, Immediate(1)); | 4023 movl(mask_reg, Immediate(1)); |
| 3914 shl_cl(mask_reg); | 4024 shl_cl(mask_reg); |
| 3915 } | 4025 } |
| 3916 | 4026 |
| 3917 } } // namespace v8::internal | 4027 } } // namespace v8::internal |
| 3918 | 4028 |
| 3919 #endif // V8_TARGET_ARCH_X64 | 4029 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |