OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 3275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3286 | 3286 |
3287 __ Push(function); | 3287 __ Push(function); |
3288 __ RecordWrite(feedback_vector, scratch1, function, kLRHasNotBeenSaved, | 3288 __ RecordWrite(feedback_vector, scratch1, function, kLRHasNotBeenSaved, |
3289 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | 3289 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
3290 __ Pop(function); | 3290 __ Pop(function); |
3291 | 3291 |
3292 __ Bind(&done); | 3292 __ Bind(&done); |
3293 } | 3293 } |
3294 | 3294 |
3295 | 3295 |
3296 void CallFunctionStub::Generate(MacroAssembler* masm) { | 3296 static void GenericCallHelper(MacroAssembler* masm, |
3297 ASM_LOCATION("CallFunctionStub::Generate"); | 3297 const CallIC::State& state, |
| 3298 bool wrap_and_call = false) { |
3298 // x1 function the function to call | 3299 // x1 function the function to call |
3299 // x2 : feedback vector | 3300 |
3300 // x3 : slot in feedback vector (smi) (if x2 is not the megamorphic symbol) | 3301 // wrap_and_call can only be true if we are compiling a monomorphic method. |
| 3302 ASSERT(!(wrap_and_call && state.IsGeneric())); |
| 3303 ASSERT(!wrap_and_call || state.CallAsMethod()); |
3301 Register function = x1; | 3304 Register function = x1; |
3302 Register cache_cell = x2; | |
3303 Register slot = x3; | |
3304 Register type = x4; | 3305 Register type = x4; |
3305 Label slow, non_function, wrap, cont; | 3306 Label slow, non_function, wrap, cont; |
3306 | 3307 |
3307 // TODO(jbramley): This function has a lot of unnamed registers. Name them, | 3308 // TODO(jbramley): This function has a lot of unnamed registers. Name them, |
3308 // and tidy things up a bit. | 3309 // and tidy things up a bit. |
3309 | 3310 |
3310 if (NeedsChecks()) { | 3311 if (state.IsGeneric()) { |
3311 // Check that the function is really a JavaScript function. | 3312 // Check that the function is really a JavaScript function. |
3312 __ JumpIfSmi(function, &non_function); | 3313 __ JumpIfSmi(function, &non_function); |
3313 | 3314 |
3314 // Goto slow case if we do not have a function. | 3315 // Goto slow case if we do not have a function. |
3315 __ JumpIfNotObjectType(function, x10, type, JS_FUNCTION_TYPE, &slow); | 3316 __ JumpIfNotObjectType(function, x10, type, JS_FUNCTION_TYPE, &slow); |
3316 | |
3317 if (RecordCallTarget()) { | |
3318 GenerateRecordCallTarget(masm, x0, function, cache_cell, slot, x4, x5); | |
3319 // Type information was updated. Because we may call Array, which | |
3320 // expects either undefined or an AllocationSite in ebx we need | |
3321 // to set ebx to undefined. | |
3322 __ LoadRoot(cache_cell, Heap::kUndefinedValueRootIndex); | |
3323 } | |
3324 } | 3317 } |
3325 | 3318 |
3326 // Fast-case: Invoke the function now. | 3319 // Fast-case: Invoke the function now. |
3327 // x1 function pushed function | 3320 // x1 function pushed function |
3328 ParameterCount actual(argc_); | 3321 int argc = state.arg_count(); |
| 3322 ParameterCount actual(argc); |
3329 | 3323 |
3330 if (CallAsMethod()) { | 3324 if (state.CallAsMethod()) { |
3331 if (NeedsChecks()) { | 3325 if (state.IsGeneric()) { |
3332 // Do not transform the receiver for strict mode functions. | 3326 // Do not transform the receiver for strict mode functions. |
3333 __ Ldr(x3, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset)); | 3327 __ Ldr(x3, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset)); |
3334 __ Ldr(w4, FieldMemOperand(x3, SharedFunctionInfo::kCompilerHintsOffset)); | 3328 __ Ldr(w4, FieldMemOperand(x3, SharedFunctionInfo::kCompilerHintsOffset)); |
3335 __ Tbnz(w4, SharedFunctionInfo::kStrictModeFunction, &cont); | 3329 __ Tbnz(w4, SharedFunctionInfo::kStrictModeFunction, &cont); |
3336 | 3330 |
3337 // Do not transform the receiver for native (Compilerhints already in x3). | 3331 // Do not transform the receiver for native (Compilerhints already in x3). |
3338 __ Tbnz(w4, SharedFunctionInfo::kNative, &cont); | 3332 __ Tbnz(w4, SharedFunctionInfo::kNative, &cont); |
3339 } | 3333 } |
3340 | 3334 |
3341 // Compute the receiver in sloppy mode. | 3335 if (state.IsGeneric() || state.IsSloppy() || wrap_and_call) { |
3342 __ Peek(x3, argc_ * kPointerSize); | 3336 // Compute the receiver in sloppy mode. |
| 3337 __ Peek(x3, argc * kPointerSize); |
3343 | 3338 |
3344 if (NeedsChecks()) { | 3339 if (state.IsGeneric()) { |
3345 __ JumpIfSmi(x3, &wrap); | 3340 __ JumpIfSmi(x3, &wrap); |
3346 __ JumpIfObjectType(x3, x10, type, FIRST_SPEC_OBJECT_TYPE, &wrap, lt); | 3341 __ JumpIfObjectType(x3, x10, type, FIRST_SPEC_OBJECT_TYPE, &wrap, lt); |
3347 } else { | 3342 } else { |
3348 __ B(&wrap); | 3343 __ B(&wrap); |
| 3344 } |
3349 } | 3345 } |
3350 | 3346 |
3351 __ Bind(&cont); | 3347 __ Bind(&cont); |
3352 } | 3348 } |
3353 __ InvokeFunction(function, | |
3354 actual, | |
3355 JUMP_FUNCTION, | |
3356 NullCallWrapper()); | |
3357 | 3349 |
3358 if (NeedsChecks()) { | 3350 if (state.ArgumentsMustMatch()) { |
| 3351 __ InvokeFunction(function, |
| 3352 actual, |
| 3353 actual, |
| 3354 JUMP_FUNCTION, |
| 3355 NullCallWrapper()); |
| 3356 } else { |
| 3357 __ InvokeFunction(function, |
| 3358 actual, |
| 3359 JUMP_FUNCTION, |
| 3360 NullCallWrapper()); |
| 3361 } |
| 3362 |
| 3363 if (state.IsGeneric()) { |
3359 // Slow-case: Non-function called. | 3364 // Slow-case: Non-function called. |
3360 __ Bind(&slow); | 3365 __ Bind(&slow); |
3361 if (RecordCallTarget()) { | |
3362 // If there is a call target cache, mark it megamorphic in the | |
3363 // non-function case. MegamorphicSentinel is an immortal immovable object | |
3364 // (megamorphic symbol) so no write barrier is needed. | |
3365 ASSERT_EQ(*TypeFeedbackInfo::MegamorphicSentinel(masm->isolate()), | |
3366 masm->isolate()->heap()->megamorphic_symbol()); | |
3367 __ Add(x12, cache_cell, Operand::UntagSmiAndScale(slot, | |
3368 kPointerSizeLog2)); | |
3369 __ LoadRoot(x11, Heap::kMegamorphicSymbolRootIndex); | |
3370 __ Str(x11, FieldMemOperand(x12, FixedArray::kHeaderSize)); | |
3371 } | |
3372 // Check for function proxy. | 3366 // Check for function proxy. |
3373 // x10 : function type. | 3367 // x10 : function type. |
3374 __ CompareAndBranch(type, JS_FUNCTION_PROXY_TYPE, ne, &non_function); | 3368 __ CompareAndBranch(type, JS_FUNCTION_PROXY_TYPE, ne, &non_function); |
3375 __ Push(function); // put proxy as additional argument | 3369 __ Push(function); // put proxy as additional argument |
3376 __ Mov(x0, argc_ + 1); | 3370 __ Mov(x0, argc + 1); |
3377 __ Mov(x2, 0); | 3371 __ Mov(x2, 0); |
3378 __ GetBuiltinFunction(x1, Builtins::CALL_FUNCTION_PROXY); | 3372 __ GetBuiltinFunction(x1, Builtins::CALL_FUNCTION_PROXY); |
3379 { | 3373 { |
3380 Handle<Code> adaptor = | 3374 Handle<Code> adaptor = |
3381 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); | 3375 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); |
3382 __ Jump(adaptor, RelocInfo::CODE_TARGET); | 3376 __ Jump(adaptor, RelocInfo::CODE_TARGET); |
3383 } | 3377 } |
3384 | 3378 |
3385 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead | 3379 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead |
3386 // of the original receiver from the call site). | 3380 // of the original receiver from the call site). |
3387 __ Bind(&non_function); | 3381 __ Bind(&non_function); |
3388 __ Poke(function, argc_ * kXRegSize); | 3382 __ Poke(function, argc * kXRegSize); |
3389 __ Mov(x0, argc_); // Set up the number of arguments. | 3383 __ Mov(x0, argc); // Set up the number of arguments. |
3390 __ Mov(x2, 0); | 3384 __ Mov(x2, 0); |
3391 __ GetBuiltinFunction(function, Builtins::CALL_NON_FUNCTION); | 3385 __ GetBuiltinFunction(function, Builtins::CALL_NON_FUNCTION); |
3392 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | 3386 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
3393 RelocInfo::CODE_TARGET); | 3387 RelocInfo::CODE_TARGET); |
3394 } | 3388 } |
3395 | 3389 |
3396 if (CallAsMethod()) { | 3390 if (state.CallAsMethod()) { |
3397 __ Bind(&wrap); | 3391 __ Bind(&wrap); |
| 3392 |
| 3393 if (!state.IsGeneric() && !wrap_and_call) { |
| 3394 __ Ldr(x5, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset)); |
| 3395 __ Ldr(w4, FieldMemOperand(x5, SharedFunctionInfo::kCompilerHintsOffset)); |
| 3396 |
| 3397 // Do not transform the receiver for native |
| 3398 __ Tbnz(w4, SharedFunctionInfo::kNative, &cont); |
| 3399 } |
| 3400 |
3398 // Wrap the receiver and patch it back onto the stack. | 3401 // Wrap the receiver and patch it back onto the stack. |
3399 { FrameScope frame_scope(masm, StackFrame::INTERNAL); | 3402 { FrameScope frame_scope(masm, StackFrame::INTERNAL); |
3400 __ Push(x1, x3); | 3403 __ Push(x1, x3); |
3401 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 3404 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
3402 __ Pop(x1); | 3405 __ Pop(x1); |
3403 } | 3406 } |
3404 __ Poke(x0, argc_ * kPointerSize); | 3407 __ Poke(x0, argc * kPointerSize); |
3405 __ B(&cont); | 3408 __ B(&cont); |
3406 } | 3409 } |
3407 } | 3410 } |
3408 | 3411 |
3409 | 3412 |
| 3413 void CallFunctionStub::Generate(MacroAssembler* masm) { |
| 3414 ASM_LOCATION("CallFunctionStub::Generate"); |
| 3415 // x1 function the function to call |
| 3416 |
| 3417 // GenericCallHelper expresses it's options in terms of CallIC::State. |
| 3418 CallIC::CallType call_type = CallAsMethod() ? |
| 3419 CallIC::METHOD : CallIC::FUNCTION; |
| 3420 |
| 3421 if (NeedsChecks()) { |
| 3422 GenericCallHelper(masm, |
| 3423 CallIC::State::SlowCallState( |
| 3424 argc_, |
| 3425 call_type)); |
| 3426 } else { |
| 3427 GenericCallHelper(masm, |
| 3428 CallIC::State::MonomorphicCallState( |
| 3429 argc_, |
| 3430 call_type, |
| 3431 CallIC::ARGUMENTS_COUNT_UNKNOWN, |
| 3432 SLOPPY), |
| 3433 true); |
| 3434 } |
| 3435 } |
| 3436 |
| 3437 |
3410 void CallConstructStub::Generate(MacroAssembler* masm) { | 3438 void CallConstructStub::Generate(MacroAssembler* masm) { |
3411 ASM_LOCATION("CallConstructStub::Generate"); | 3439 ASM_LOCATION("CallConstructStub::Generate"); |
3412 // x0 : number of arguments | 3440 // x0 : number of arguments |
3413 // x1 : the function to call | 3441 // x1 : the function to call |
3414 // x2 : feedback vector | 3442 // x2 : feedback vector |
3415 // x3 : slot in feedback vector (smi) (if r2 is not the megamorphic symbol) | 3443 // x3 : slot in feedback vector (smi) (if r2 is not the megamorphic symbol) |
3416 Register function = x1; | 3444 Register function = x1; |
3417 Label slow, non_function_call; | 3445 Label slow, non_function_call; |
3418 | 3446 |
3419 // Check that the function is not a smi. | 3447 // Check that the function is not a smi. |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3470 __ GetBuiltinFunction(x1, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); | 3498 __ GetBuiltinFunction(x1, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); |
3471 | 3499 |
3472 __ Bind(&do_call); | 3500 __ Bind(&do_call); |
3473 // Set expected number of arguments to zero (not changing x0). | 3501 // Set expected number of arguments to zero (not changing x0). |
3474 __ Mov(x2, 0); | 3502 __ Mov(x2, 0); |
3475 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | 3503 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
3476 RelocInfo::CODE_TARGET); | 3504 RelocInfo::CODE_TARGET); |
3477 } | 3505 } |
3478 | 3506 |
3479 | 3507 |
| 3508 void CallICStub::GenerateMonomorphicCall(MacroAssembler* masm) { |
| 3509 GenericCallHelper(masm, |
| 3510 CallIC::State::MonomorphicCallState( |
| 3511 state_.arg_count(), |
| 3512 state_.call_type(), |
| 3513 state_.argument_check(), |
| 3514 state_.strict_mode())); |
| 3515 } |
| 3516 |
| 3517 |
| 3518 void CallICStub::GenerateSlowCall(MacroAssembler* masm) { |
| 3519 GenericCallHelper(masm, |
| 3520 CallIC::State::SlowCallState( |
| 3521 state_.arg_count(), |
| 3522 state_.call_type())); |
| 3523 } |
| 3524 |
| 3525 |
| 3526 void CallICStub::Generate(MacroAssembler* masm) { |
| 3527 ASM_LOCATION("CallICStub"); |
| 3528 |
| 3529 // x1 - function |
| 3530 // x2 - vector |
| 3531 // x3 - slot id (Smi) |
| 3532 Label extra_checks_or_miss, slow; |
| 3533 Register function = x1; |
| 3534 Register feedback_vector = x2; |
| 3535 Register index = x3; |
| 3536 |
| 3537 // The checks. First, does x1 match the recorded monomorphic target? |
| 3538 __ Add(x4, feedback_vector, |
| 3539 Operand::UntagSmiAndScale(index, kPointerSizeLog2)); |
| 3540 __ Ldr(x4, FieldMemOperand(x4, FixedArray::kHeaderSize)); |
| 3541 |
| 3542 __ Cmp(x4, function); |
| 3543 __ B(ne, &extra_checks_or_miss); |
| 3544 |
| 3545 GenerateMonomorphicCall(masm); |
| 3546 |
| 3547 __ bind(&extra_checks_or_miss); |
| 3548 if (IsGeneric()) { |
| 3549 Label miss_uninit; |
| 3550 |
| 3551 __ JumpIfRoot(x4, Heap::kMegamorphicSymbolRootIndex, &slow); |
| 3552 __ JumpIfRoot(x4, Heap::kUninitializedSymbolRootIndex, &miss_uninit); |
| 3553 // If we get here, go from monomorphic to megamorphic, Don't bother missing, |
| 3554 // just update. |
| 3555 __ Add(x4, feedback_vector, |
| 3556 Operand::UntagSmiAndScale(index, kPointerSizeLog2)); |
| 3557 __ LoadRoot(x5, Heap::kMegamorphicSymbolRootIndex); |
| 3558 __ Str(x5, FieldMemOperand(x4, FixedArray::kHeaderSize)); |
| 3559 __ B(&slow); |
| 3560 |
| 3561 __ bind(&miss_uninit); |
| 3562 } |
| 3563 |
| 3564 GenerateMiss(masm); |
| 3565 |
| 3566 // the slow case |
| 3567 __ bind(&slow); |
| 3568 GenerateSlowCall(masm); |
| 3569 } |
| 3570 |
| 3571 |
| 3572 void CallICStub::GenerateMiss(MacroAssembler* masm) { |
| 3573 ASM_LOCATION("CallICStub[Miss]"); |
| 3574 |
| 3575 // Get the receiver of the function from the stack; 1 ~ return address. |
| 3576 __ Peek(x4, (state_.arg_count() + 1) * kPointerSize); |
| 3577 |
| 3578 { |
| 3579 FrameScope scope(masm, StackFrame::INTERNAL); |
| 3580 |
| 3581 // Push the receiver and the function and feedback info. |
| 3582 __ Push(x4, x1, x2, x3); |
| 3583 |
| 3584 // Call the entry. |
| 3585 ExternalReference miss = ExternalReference(IC_Utility(IC::kCallIC_Miss), |
| 3586 masm->isolate()); |
| 3587 __ CallExternalReference(miss, 4); |
| 3588 |
| 3589 // Move result to edi and exit the internal frame. |
| 3590 __ Mov(x1, x0); |
| 3591 } |
| 3592 } |
| 3593 |
| 3594 |
3480 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { | 3595 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
3481 // If the receiver is a smi trigger the non-string case. | 3596 // If the receiver is a smi trigger the non-string case. |
3482 __ JumpIfSmi(object_, receiver_not_string_); | 3597 __ JumpIfSmi(object_, receiver_not_string_); |
3483 | 3598 |
3484 // Fetch the instance type of the receiver into result register. | 3599 // Fetch the instance type of the receiver into result register. |
3485 __ Ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); | 3600 __ Ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); |
3486 __ Ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); | 3601 __ Ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); |
3487 | 3602 |
3488 // If the receiver is not a string trigger the non-string case. | 3603 // If the receiver is not a string trigger the non-string case. |
3489 __ TestAndBranchIfAnySet(result_, kIsNotStringMask, receiver_not_string_); | 3604 __ TestAndBranchIfAnySet(result_, kIsNotStringMask, receiver_not_string_); |
(...skipping 2243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5733 MemOperand(fp, 6 * kPointerSize), | 5848 MemOperand(fp, 6 * kPointerSize), |
5734 NULL); | 5849 NULL); |
5735 } | 5850 } |
5736 | 5851 |
5737 | 5852 |
5738 #undef __ | 5853 #undef __ |
5739 | 5854 |
5740 } } // namespace v8::internal | 5855 } } // namespace v8::internal |
5741 | 5856 |
5742 #endif // V8_TARGET_ARCH_ARM64 | 5857 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |