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 3178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3189 | 3189 |
3190 __ Push(function); | 3190 __ Push(function); |
3191 __ RecordWrite(feedback_vector, scratch1, function, kLRHasNotBeenSaved, | 3191 __ RecordWrite(feedback_vector, scratch1, function, kLRHasNotBeenSaved, |
3192 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | 3192 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
3193 __ Pop(function); | 3193 __ Pop(function); |
3194 | 3194 |
3195 __ Bind(&done); | 3195 __ Bind(&done); |
3196 } | 3196 } |
3197 | 3197 |
3198 | 3198 |
| 3199 static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) { |
| 3200 // Do not transform the receiver for strict mode functions. |
| 3201 __ Ldr(x3, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset)); |
| 3202 __ Ldr(w4, FieldMemOperand(x3, SharedFunctionInfo::kCompilerHintsOffset)); |
| 3203 __ Tbnz(w4, SharedFunctionInfo::kStrictModeFunction, cont); |
| 3204 |
| 3205 // Do not transform the receiver for native (Compilerhints already in x3). |
| 3206 __ Tbnz(w4, SharedFunctionInfo::kNative, cont); |
| 3207 } |
| 3208 |
| 3209 |
| 3210 static void EmitSlowCase(MacroAssembler* masm, |
| 3211 int argc, |
| 3212 Register function, |
| 3213 Register type, |
| 3214 Label* non_function) { |
| 3215 // Check for function proxy. |
| 3216 // x10 : function type. |
| 3217 __ CompareAndBranch(type, JS_FUNCTION_PROXY_TYPE, ne, non_function); |
| 3218 __ Push(function); // put proxy as additional argument |
| 3219 __ Mov(x0, argc + 1); |
| 3220 __ Mov(x2, 0); |
| 3221 __ GetBuiltinFunction(x1, Builtins::CALL_FUNCTION_PROXY); |
| 3222 { |
| 3223 Handle<Code> adaptor = |
| 3224 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); |
| 3225 __ Jump(adaptor, RelocInfo::CODE_TARGET); |
| 3226 } |
| 3227 |
| 3228 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead |
| 3229 // of the original receiver from the call site). |
| 3230 __ Bind(non_function); |
| 3231 __ Poke(function, argc * kXRegSize); |
| 3232 __ Mov(x0, argc); // Set up the number of arguments. |
| 3233 __ Mov(x2, 0); |
| 3234 __ GetBuiltinFunction(function, Builtins::CALL_NON_FUNCTION); |
| 3235 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
| 3236 RelocInfo::CODE_TARGET); |
| 3237 } |
| 3238 |
| 3239 |
| 3240 static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) { |
| 3241 // Wrap the receiver and patch it back onto the stack. |
| 3242 { FrameScope frame_scope(masm, StackFrame::INTERNAL); |
| 3243 __ Push(x1, x3); |
| 3244 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
| 3245 __ Pop(x1); |
| 3246 } |
| 3247 __ Poke(x0, argc * kPointerSize); |
| 3248 __ B(cont); |
| 3249 } |
| 3250 |
| 3251 |
3199 void CallFunctionStub::Generate(MacroAssembler* masm) { | 3252 void CallFunctionStub::Generate(MacroAssembler* masm) { |
3200 ASM_LOCATION("CallFunctionStub::Generate"); | 3253 ASM_LOCATION("CallFunctionStub::Generate"); |
3201 // x1 function the function to call | 3254 // x1 function the function to call |
3202 // x2 : feedback vector | 3255 |
3203 // x3 : slot in feedback vector (smi) (if x2 is not the megamorphic symbol) | |
3204 Register function = x1; | 3256 Register function = x1; |
3205 Register cache_cell = x2; | |
3206 Register slot = x3; | |
3207 Register type = x4; | 3257 Register type = x4; |
3208 Label slow, non_function, wrap, cont; | 3258 Label slow, non_function, wrap, cont; |
3209 | 3259 |
3210 // TODO(jbramley): This function has a lot of unnamed registers. Name them, | 3260 // TODO(jbramley): This function has a lot of unnamed registers. Name them, |
3211 // and tidy things up a bit. | 3261 // and tidy things up a bit. |
3212 | 3262 |
3213 if (NeedsChecks()) { | 3263 if (NeedsChecks()) { |
3214 // Check that the function is really a JavaScript function. | 3264 // Check that the function is really a JavaScript function. |
3215 __ JumpIfSmi(function, &non_function); | 3265 __ JumpIfSmi(function, &non_function); |
3216 | 3266 |
3217 // Goto slow case if we do not have a function. | 3267 // Goto slow case if we do not have a function. |
3218 __ JumpIfNotObjectType(function, x10, type, JS_FUNCTION_TYPE, &slow); | 3268 __ JumpIfNotObjectType(function, x10, type, JS_FUNCTION_TYPE, &slow); |
3219 | |
3220 if (RecordCallTarget()) { | |
3221 GenerateRecordCallTarget(masm, x0, function, cache_cell, slot, x4, x5); | |
3222 // Type information was updated. Because we may call Array, which | |
3223 // expects either undefined or an AllocationSite in ebx we need | |
3224 // to set ebx to undefined. | |
3225 __ LoadRoot(cache_cell, Heap::kUndefinedValueRootIndex); | |
3226 } | |
3227 } | 3269 } |
3228 | 3270 |
3229 // Fast-case: Invoke the function now. | 3271 // Fast-case: Invoke the function now. |
3230 // x1 function pushed function | 3272 // x1 function pushed function |
3231 ParameterCount actual(argc_); | 3273 int argc = argc_; |
| 3274 ParameterCount actual(argc); |
3232 | 3275 |
3233 if (CallAsMethod()) { | 3276 if (CallAsMethod()) { |
3234 if (NeedsChecks()) { | 3277 if (NeedsChecks()) { |
3235 // Do not transform the receiver for strict mode functions. | 3278 EmitContinueIfStrictOrNative(masm, &cont); |
3236 __ Ldr(x3, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset)); | |
3237 __ Ldr(w4, FieldMemOperand(x3, SharedFunctionInfo::kCompilerHintsOffset)); | |
3238 __ Tbnz(w4, SharedFunctionInfo::kStrictModeFunction, &cont); | |
3239 | |
3240 // Do not transform the receiver for native (Compilerhints already in x3). | |
3241 __ Tbnz(w4, SharedFunctionInfo::kNative, &cont); | |
3242 } | 3279 } |
3243 | 3280 |
3244 // Compute the receiver in sloppy mode. | 3281 // Compute the receiver in sloppy mode. |
3245 __ Peek(x3, argc_ * kPointerSize); | 3282 __ Peek(x3, argc * kPointerSize); |
3246 | 3283 |
3247 if (NeedsChecks()) { | 3284 if (NeedsChecks()) { |
3248 __ JumpIfSmi(x3, &wrap); | 3285 __ JumpIfSmi(x3, &wrap); |
3249 __ JumpIfObjectType(x3, x10, type, FIRST_SPEC_OBJECT_TYPE, &wrap, lt); | 3286 __ JumpIfObjectType(x3, x10, type, FIRST_SPEC_OBJECT_TYPE, &wrap, lt); |
3250 } else { | 3287 } else { |
3251 __ B(&wrap); | 3288 __ B(&wrap); |
3252 } | 3289 } |
3253 | 3290 |
3254 __ Bind(&cont); | 3291 __ Bind(&cont); |
3255 } | 3292 } |
| 3293 |
3256 __ InvokeFunction(function, | 3294 __ InvokeFunction(function, |
3257 actual, | 3295 actual, |
3258 JUMP_FUNCTION, | 3296 JUMP_FUNCTION, |
3259 NullCallWrapper()); | 3297 NullCallWrapper()); |
3260 | 3298 |
3261 if (NeedsChecks()) { | 3299 if (NeedsChecks()) { |
3262 // Slow-case: Non-function called. | 3300 // Slow-case: Non-function called. |
3263 __ Bind(&slow); | 3301 __ Bind(&slow); |
3264 if (RecordCallTarget()) { | 3302 EmitSlowCase(masm, argc, function, type, &non_function); |
3265 // If there is a call target cache, mark it megamorphic in the | |
3266 // non-function case. MegamorphicSentinel is an immortal immovable object | |
3267 // (megamorphic symbol) so no write barrier is needed. | |
3268 ASSERT_EQ(*TypeFeedbackInfo::MegamorphicSentinel(masm->isolate()), | |
3269 masm->isolate()->heap()->megamorphic_symbol()); | |
3270 __ Add(x12, cache_cell, Operand::UntagSmiAndScale(slot, | |
3271 kPointerSizeLog2)); | |
3272 __ LoadRoot(x11, Heap::kMegamorphicSymbolRootIndex); | |
3273 __ Str(x11, FieldMemOperand(x12, FixedArray::kHeaderSize)); | |
3274 } | |
3275 // Check for function proxy. | |
3276 // x10 : function type. | |
3277 __ CompareAndBranch(type, JS_FUNCTION_PROXY_TYPE, ne, &non_function); | |
3278 __ Push(function); // put proxy as additional argument | |
3279 __ Mov(x0, argc_ + 1); | |
3280 __ Mov(x2, 0); | |
3281 __ GetBuiltinFunction(x1, Builtins::CALL_FUNCTION_PROXY); | |
3282 { | |
3283 Handle<Code> adaptor = | |
3284 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); | |
3285 __ Jump(adaptor, RelocInfo::CODE_TARGET); | |
3286 } | |
3287 | |
3288 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead | |
3289 // of the original receiver from the call site). | |
3290 __ Bind(&non_function); | |
3291 __ Poke(function, argc_ * kXRegSize); | |
3292 __ Mov(x0, argc_); // Set up the number of arguments. | |
3293 __ Mov(x2, 0); | |
3294 __ GetBuiltinFunction(function, Builtins::CALL_NON_FUNCTION); | |
3295 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | |
3296 RelocInfo::CODE_TARGET); | |
3297 } | 3303 } |
3298 | 3304 |
3299 if (CallAsMethod()) { | 3305 if (CallAsMethod()) { |
3300 __ Bind(&wrap); | 3306 __ Bind(&wrap); |
3301 // Wrap the receiver and patch it back onto the stack. | 3307 EmitWrapCase(masm, argc, &cont); |
3302 { FrameScope frame_scope(masm, StackFrame::INTERNAL); | |
3303 __ Push(x1, x3); | |
3304 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | |
3305 __ Pop(x1); | |
3306 } | |
3307 __ Poke(x0, argc_ * kPointerSize); | |
3308 __ B(&cont); | |
3309 } | 3308 } |
3310 } | 3309 } |
3311 | 3310 |
3312 | 3311 |
3313 void CallConstructStub::Generate(MacroAssembler* masm) { | 3312 void CallConstructStub::Generate(MacroAssembler* masm) { |
3314 ASM_LOCATION("CallConstructStub::Generate"); | 3313 ASM_LOCATION("CallConstructStub::Generate"); |
3315 // x0 : number of arguments | 3314 // x0 : number of arguments |
3316 // x1 : the function to call | 3315 // x1 : the function to call |
3317 // x2 : feedback vector | 3316 // x2 : feedback vector |
3318 // x3 : slot in feedback vector (smi) (if r2 is not the megamorphic symbol) | 3317 // x3 : slot in feedback vector (smi) (if r2 is not the megamorphic symbol) |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3373 __ GetBuiltinFunction(x1, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); | 3372 __ GetBuiltinFunction(x1, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); |
3374 | 3373 |
3375 __ Bind(&do_call); | 3374 __ Bind(&do_call); |
3376 // Set expected number of arguments to zero (not changing x0). | 3375 // Set expected number of arguments to zero (not changing x0). |
3377 __ Mov(x2, 0); | 3376 __ Mov(x2, 0); |
3378 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | 3377 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
3379 RelocInfo::CODE_TARGET); | 3378 RelocInfo::CODE_TARGET); |
3380 } | 3379 } |
3381 | 3380 |
3382 | 3381 |
| 3382 static void EmitLoadTypeFeedbackVector(MacroAssembler* masm, Register vector) { |
| 3383 __ Ldr(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
| 3384 __ Ldr(vector, FieldMemOperand(vector, |
| 3385 JSFunction::kSharedFunctionInfoOffset)); |
| 3386 __ Ldr(vector, FieldMemOperand(vector, |
| 3387 SharedFunctionInfo::kFeedbackVectorOffset)); |
| 3388 } |
| 3389 |
| 3390 |
| 3391 void CallICStub::Generate(MacroAssembler* masm) { |
| 3392 ASM_LOCATION("CallICStub"); |
| 3393 |
| 3394 // x1 - function |
| 3395 // x3 - slot id (Smi) |
| 3396 Label extra_checks_or_miss, slow_start; |
| 3397 Label slow, non_function, wrap, cont; |
| 3398 Label have_js_function; |
| 3399 int argc = state_.arg_count(); |
| 3400 ParameterCount actual(argc); |
| 3401 |
| 3402 Register function = x1; |
| 3403 Register feedback_vector = x2; |
| 3404 Register index = x3; |
| 3405 Register type = x4; |
| 3406 |
| 3407 EmitLoadTypeFeedbackVector(masm, feedback_vector); |
| 3408 |
| 3409 // The checks. First, does x1 match the recorded monomorphic target? |
| 3410 __ Add(x4, feedback_vector, |
| 3411 Operand::UntagSmiAndScale(index, kPointerSizeLog2)); |
| 3412 __ Ldr(x4, FieldMemOperand(x4, FixedArray::kHeaderSize)); |
| 3413 |
| 3414 __ Cmp(x4, function); |
| 3415 __ B(ne, &extra_checks_or_miss); |
| 3416 |
| 3417 __ bind(&have_js_function); |
| 3418 if (state_.CallAsMethod()) { |
| 3419 EmitContinueIfStrictOrNative(masm, &cont); |
| 3420 |
| 3421 // Compute the receiver in sloppy mode. |
| 3422 __ Peek(x3, argc * kPointerSize); |
| 3423 |
| 3424 __ JumpIfSmi(x3, &wrap); |
| 3425 __ JumpIfObjectType(x3, x10, type, FIRST_SPEC_OBJECT_TYPE, &wrap, lt); |
| 3426 |
| 3427 __ Bind(&cont); |
| 3428 } |
| 3429 |
| 3430 __ InvokeFunction(function, |
| 3431 actual, |
| 3432 JUMP_FUNCTION, |
| 3433 NullCallWrapper()); |
| 3434 |
| 3435 __ bind(&slow); |
| 3436 EmitSlowCase(masm, argc, function, type, &non_function); |
| 3437 |
| 3438 if (state_.CallAsMethod()) { |
| 3439 __ bind(&wrap); |
| 3440 EmitWrapCase(masm, argc, &cont); |
| 3441 } |
| 3442 |
| 3443 __ bind(&extra_checks_or_miss); |
| 3444 Label miss; |
| 3445 |
| 3446 __ JumpIfRoot(x4, Heap::kMegamorphicSymbolRootIndex, &slow_start); |
| 3447 __ JumpIfRoot(x4, Heap::kUninitializedSymbolRootIndex, &miss); |
| 3448 |
| 3449 if (!FLAG_trace_ic) { |
| 3450 // We are going megamorphic, and we don't want to visit the runtime. |
| 3451 __ Add(x4, feedback_vector, |
| 3452 Operand::UntagSmiAndScale(index, kPointerSizeLog2)); |
| 3453 __ LoadRoot(x5, Heap::kMegamorphicSymbolRootIndex); |
| 3454 __ Str(x5, FieldMemOperand(x4, FixedArray::kHeaderSize)); |
| 3455 __ B(&slow_start); |
| 3456 } |
| 3457 |
| 3458 // We are here because tracing is on or we are going monomorphic. |
| 3459 __ bind(&miss); |
| 3460 GenerateMiss(masm); |
| 3461 |
| 3462 // the slow case |
| 3463 __ bind(&slow_start); |
| 3464 |
| 3465 // Check that the function is really a JavaScript function. |
| 3466 __ JumpIfSmi(function, &non_function); |
| 3467 |
| 3468 // Goto slow case if we do not have a function. |
| 3469 __ JumpIfNotObjectType(function, x10, type, JS_FUNCTION_TYPE, &slow); |
| 3470 __ B(&have_js_function); |
| 3471 } |
| 3472 |
| 3473 |
| 3474 void CallICStub::GenerateMiss(MacroAssembler* masm) { |
| 3475 ASM_LOCATION("CallICStub[Miss]"); |
| 3476 |
| 3477 // Get the receiver of the function from the stack; 1 ~ return address. |
| 3478 __ Peek(x4, (state_.arg_count() + 1) * kPointerSize); |
| 3479 |
| 3480 { |
| 3481 FrameScope scope(masm, StackFrame::INTERNAL); |
| 3482 |
| 3483 // Push the receiver and the function and feedback info. |
| 3484 __ Push(x4, x1, x2, x3); |
| 3485 |
| 3486 // Call the entry. |
| 3487 ExternalReference miss = ExternalReference(IC_Utility(IC::kCallIC_Miss), |
| 3488 masm->isolate()); |
| 3489 __ CallExternalReference(miss, 4); |
| 3490 |
| 3491 // Move result to edi and exit the internal frame. |
| 3492 __ Mov(x1, x0); |
| 3493 } |
| 3494 } |
| 3495 |
| 3496 |
3383 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { | 3497 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
3384 // If the receiver is a smi trigger the non-string case. | 3498 // If the receiver is a smi trigger the non-string case. |
3385 __ JumpIfSmi(object_, receiver_not_string_); | 3499 __ JumpIfSmi(object_, receiver_not_string_); |
3386 | 3500 |
3387 // Fetch the instance type of the receiver into result register. | 3501 // Fetch the instance type of the receiver into result register. |
3388 __ Ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); | 3502 __ Ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); |
3389 __ Ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); | 3503 __ Ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); |
3390 | 3504 |
3391 // If the receiver is not a string trigger the non-string case. | 3505 // If the receiver is not a string trigger the non-string case. |
3392 __ TestAndBranchIfAnySet(result_, kIsNotStringMask, receiver_not_string_); | 3506 __ TestAndBranchIfAnySet(result_, kIsNotStringMask, receiver_not_string_); |
(...skipping 2034 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5427 MemOperand(fp, 6 * kPointerSize), | 5541 MemOperand(fp, 6 * kPointerSize), |
5428 NULL); | 5542 NULL); |
5429 } | 5543 } |
5430 | 5544 |
5431 | 5545 |
5432 #undef __ | 5546 #undef __ |
5433 | 5547 |
5434 } } // namespace v8::internal | 5548 } } // namespace v8::internal |
5435 | 5549 |
5436 #endif // V8_TARGET_ARCH_ARM64 | 5550 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |