| 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 30 matching lines...) Expand all Loading... |
| 41 | 41 |
| 42 // Define a fake double underscore to use with the ASM_UNIMPLEMENTED macros. | 42 // Define a fake double underscore to use with the ASM_UNIMPLEMENTED macros. |
| 43 #define __ | 43 #define __ |
| 44 | 44 |
| 45 | 45 |
| 46 MacroAssembler::MacroAssembler(Isolate* arg_isolate, | 46 MacroAssembler::MacroAssembler(Isolate* arg_isolate, |
| 47 byte * buffer, | 47 byte * buffer, |
| 48 unsigned buffer_size) | 48 unsigned buffer_size) |
| 49 : Assembler(arg_isolate, buffer, buffer_size), | 49 : Assembler(arg_isolate, buffer, buffer_size), |
| 50 generating_stub_(false), | 50 generating_stub_(false), |
| 51 allow_stub_calls_(true), | |
| 52 #if DEBUG | 51 #if DEBUG |
| 53 allow_macro_instructions_(true), | 52 allow_macro_instructions_(true), |
| 54 #endif | 53 #endif |
| 55 has_frame_(false), | 54 has_frame_(false), |
| 56 use_real_aborts_(true), | 55 use_real_aborts_(true), |
| 57 sp_(jssp), tmp0_(ip0), tmp1_(ip1), fptmp0_(fp_scratch) { | 56 sp_(jssp), tmp0_(ip0), tmp1_(ip1), fptmp0_(fp_scratch) { |
| 58 if (isolate() != NULL) { | 57 if (isolate() != NULL) { |
| 59 code_object_ = Handle<Object>(isolate()->heap()->undefined_value(), | 58 code_object_ = Handle<Object>(isolate()->heap()->undefined_value(), |
| 60 isolate()); | 59 isolate()); |
| 61 } | 60 } |
| (...skipping 1211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1273 } | 1272 } |
| 1274 | 1273 |
| 1275 | 1274 |
| 1276 void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id) { | 1275 void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id) { |
| 1277 ASSERT(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs. | 1276 ASSERT(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs. |
| 1278 Call(stub->GetCode(isolate()), RelocInfo::CODE_TARGET, ast_id); | 1277 Call(stub->GetCode(isolate()), RelocInfo::CODE_TARGET, ast_id); |
| 1279 } | 1278 } |
| 1280 | 1279 |
| 1281 | 1280 |
| 1282 void MacroAssembler::TailCallStub(CodeStub* stub) { | 1281 void MacroAssembler::TailCallStub(CodeStub* stub) { |
| 1283 ASSERT(allow_stub_calls_ || | |
| 1284 stub->CompilingCallsToThisStubIsGCSafe(isolate())); | |
| 1285 Jump(stub->GetCode(isolate()), RelocInfo::CODE_TARGET); | 1282 Jump(stub->GetCode(isolate()), RelocInfo::CODE_TARGET); |
| 1286 } | 1283 } |
| 1287 | 1284 |
| 1288 | 1285 |
| 1289 void MacroAssembler::CallRuntime(const Runtime::Function* f, | 1286 void MacroAssembler::CallRuntime(const Runtime::Function* f, |
| 1290 int num_arguments, | 1287 int num_arguments, |
| 1291 SaveFPRegsMode save_doubles) { | 1288 SaveFPRegsMode save_doubles) { |
| 1292 // All arguments must be on the stack before this function is called. | 1289 // All arguments must be on the stack before this function is called. |
| 1293 // x0 holds the return value after the call. | 1290 // x0 holds the return value after the call. |
| 1294 | 1291 |
| (...skipping 1192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2487 FieldMemOperand(expected_reg, | 2484 FieldMemOperand(expected_reg, |
| 2488 SharedFunctionInfo::kFormalParameterCountOffset)); | 2485 SharedFunctionInfo::kFormalParameterCountOffset)); |
| 2489 Ldr(code_reg, | 2486 Ldr(code_reg, |
| 2490 FieldMemOperand(function, JSFunction::kCodeEntryOffset)); | 2487 FieldMemOperand(function, JSFunction::kCodeEntryOffset)); |
| 2491 | 2488 |
| 2492 ParameterCount expected(expected_reg); | 2489 ParameterCount expected(expected_reg); |
| 2493 InvokeCode(code_reg, expected, actual, flag, call_wrapper, call_kind); | 2490 InvokeCode(code_reg, expected, actual, flag, call_wrapper, call_kind); |
| 2494 } | 2491 } |
| 2495 | 2492 |
| 2496 | 2493 |
| 2494 void MacroAssembler::InvokeFunction(Register function, |
| 2495 const ParameterCount& expected, |
| 2496 const ParameterCount& actual, |
| 2497 InvokeFlag flag, |
| 2498 const CallWrapper& call_wrapper, |
| 2499 CallKind call_kind) { |
| 2500 // You can't call a function without a valid frame. |
| 2501 ASSERT(flag == JUMP_FUNCTION || has_frame()); |
| 2502 |
| 2503 // Contract with called JS functions requires that function is passed in x1. |
| 2504 // (See FullCodeGenerator::Generate().) |
| 2505 ASSERT(function.Is(x1)); |
| 2506 |
| 2507 Register code_reg = x3; |
| 2508 |
| 2509 // Set up the context. |
| 2510 Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset)); |
| 2511 |
| 2512 // We call indirectly through the code field in the function to |
| 2513 // allow recompilation to take effect without changing any of the |
| 2514 // call sites. |
| 2515 Ldr(code_reg, FieldMemOperand(function, JSFunction::kCodeEntryOffset)); |
| 2516 InvokeCode(code_reg, expected, actual, flag, call_wrapper, call_kind); |
| 2517 } |
| 2518 |
| 2519 |
| 2497 void MacroAssembler::InvokeFunction(Handle<JSFunction> function, | 2520 void MacroAssembler::InvokeFunction(Handle<JSFunction> function, |
| 2498 const ParameterCount& expected, | 2521 const ParameterCount& expected, |
| 2499 const ParameterCount& actual, | 2522 const ParameterCount& actual, |
| 2500 InvokeFlag flag, | 2523 InvokeFlag flag, |
| 2501 const CallWrapper& call_wrapper, | 2524 const CallWrapper& call_wrapper, |
| 2502 CallKind call_kind, | 2525 CallKind call_kind) { |
| 2503 Register function_reg) { | 2526 // Contract with called JS functions requires that function is passed in x1. |
| 2504 // You can't call a function without a valid frame. | 2527 // (See FullCodeGenerator::Generate().) |
| 2505 ASSERT(flag == JUMP_FUNCTION || has_frame()); | 2528 __ LoadObject(x1, function); |
| 2506 | 2529 InvokeFunction(x1, expected, actual, flag, call_wrapper, call_kind); |
| 2507 // Load the function object, if it isn't already loaded. | |
| 2508 ASSERT(function_reg.Is(x1) || function_reg.IsNone()); | |
| 2509 if (function_reg.IsNone()) { | |
| 2510 function_reg = x1; | |
| 2511 LoadObject(function_reg, function); | |
| 2512 } | |
| 2513 | |
| 2514 Register code_reg = x3; | |
| 2515 | |
| 2516 // Set up the context. | |
| 2517 Ldr(cp, FieldMemOperand(function_reg, JSFunction::kContextOffset)); | |
| 2518 | |
| 2519 // We call indirectly through the code field in the function to | |
| 2520 // allow recompilation to take effect without changing any of the | |
| 2521 // call sites. | |
| 2522 Ldr(code_reg, FieldMemOperand(function_reg, JSFunction::kCodeEntryOffset)); | |
| 2523 InvokeCode(code_reg, expected, actual, flag, call_wrapper, call_kind); | |
| 2524 } | 2530 } |
| 2525 | 2531 |
| 2526 | 2532 |
| 2527 void MacroAssembler::ECMA262ToInt32(Register result, | 2533 void MacroAssembler::ECMA262ToInt32(Register result, |
| 2528 DoubleRegister input, | 2534 DoubleRegister input, |
| 2529 Register scratch1, | 2535 Register scratch1, |
| 2530 Register scratch2, | 2536 Register scratch2, |
| 2531 ECMA262ToInt32Result format) { | 2537 ECMA262ToInt32Result format) { |
| 2532 ASSERT(!AreAliased(result, scratch1, scratch2)); | 2538 ASSERT(!AreAliased(result, scratch1, scratch2)); |
| 2533 ASSERT(result.Is64Bits() && scratch1.Is64Bits() && scratch2.Is64Bits()); | 2539 ASSERT(result.Is64Bits() && scratch1.Is64Bits() && scratch2.Is64Bits()); |
| (...skipping 1067 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3601 | 3607 |
| 3602 // Store the result. | 3608 // Store the result. |
| 3603 Bind(&store_num); | 3609 Bind(&store_num); |
| 3604 Add(scratch1, elements_reg, | 3610 Add(scratch1, elements_reg, |
| 3605 Operand::UntagSmiAndScale(key_reg, kDoubleSizeLog2)); | 3611 Operand::UntagSmiAndScale(key_reg, kDoubleSizeLog2)); |
| 3606 Str(fpscratch1, FieldMemOperand(scratch1, FixedDoubleArray::kHeaderSize)); | 3612 Str(fpscratch1, FieldMemOperand(scratch1, FixedDoubleArray::kHeaderSize)); |
| 3607 } | 3613 } |
| 3608 | 3614 |
| 3609 | 3615 |
| 3610 bool MacroAssembler::AllowThisStubCall(CodeStub* stub) { | 3616 bool MacroAssembler::AllowThisStubCall(CodeStub* stub) { |
| 3611 if (!has_frame_ && stub->SometimesSetsUpAFrame()) return false; | 3617 return has_frame_ || !stub->SometimesSetsUpAFrame(); |
| 3612 return allow_stub_calls_ || stub->CompilingCallsToThisStubIsGCSafe(isolate()); | |
| 3613 } | 3618 } |
| 3614 | 3619 |
| 3615 | 3620 |
| 3616 void MacroAssembler::IndexFromHash(Register hash, Register index) { | 3621 void MacroAssembler::IndexFromHash(Register hash, Register index) { |
| 3617 // If the hash field contains an array index pick it out. The assert checks | 3622 // If the hash field contains an array index pick it out. The assert checks |
| 3618 // that the constants for the maximum number of digits for an array index | 3623 // that the constants for the maximum number of digits for an array index |
| 3619 // cached in the hash field and the number of bits reserved for it does not | 3624 // cached in the hash field and the number of bits reserved for it does not |
| 3620 // conflict. | 3625 // conflict. |
| 3621 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < | 3626 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < |
| 3622 (1 << String::kArrayIndexValueBits)); | 3627 (1 << String::kArrayIndexValueBits)); |
| (...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3957 | 3962 |
| 3958 | 3963 |
| 3959 void MacroAssembler::RecordWriteField( | 3964 void MacroAssembler::RecordWriteField( |
| 3960 Register object, | 3965 Register object, |
| 3961 int offset, | 3966 int offset, |
| 3962 Register value, | 3967 Register value, |
| 3963 Register scratch, | 3968 Register scratch, |
| 3964 LinkRegisterStatus lr_status, | 3969 LinkRegisterStatus lr_status, |
| 3965 SaveFPRegsMode save_fp, | 3970 SaveFPRegsMode save_fp, |
| 3966 RememberedSetAction remembered_set_action, | 3971 RememberedSetAction remembered_set_action, |
| 3967 SmiCheck smi_check, | 3972 SmiCheck smi_check) { |
| 3968 PregenExpectation pregen_expectation) { | |
| 3969 // First, check if a write barrier is even needed. The tests below | 3973 // First, check if a write barrier is even needed. The tests below |
| 3970 // catch stores of Smis. | 3974 // catch stores of Smis. |
| 3971 Label done; | 3975 Label done; |
| 3972 | 3976 |
| 3973 // Skip the barrier if writing a smi. | 3977 // Skip the barrier if writing a smi. |
| 3974 if (smi_check == INLINE_SMI_CHECK) { | 3978 if (smi_check == INLINE_SMI_CHECK) { |
| 3975 JumpIfSmi(value, &done); | 3979 JumpIfSmi(value, &done); |
| 3976 } | 3980 } |
| 3977 | 3981 |
| 3978 // Although the object register is tagged, the offset is relative to the start | 3982 // Although the object register is tagged, the offset is relative to the start |
| 3979 // of the object, so offset must be a multiple of kPointerSize. | 3983 // of the object, so offset must be a multiple of kPointerSize. |
| 3980 ASSERT(IsAligned(offset, kPointerSize)); | 3984 ASSERT(IsAligned(offset, kPointerSize)); |
| 3981 | 3985 |
| 3982 Add(scratch, object, offset - kHeapObjectTag); | 3986 Add(scratch, object, offset - kHeapObjectTag); |
| 3983 if (emit_debug_code()) { | 3987 if (emit_debug_code()) { |
| 3984 Label ok; | 3988 Label ok; |
| 3985 Tst(scratch, (1 << kPointerSizeLog2) - 1); | 3989 Tst(scratch, (1 << kPointerSizeLog2) - 1); |
| 3986 B(eq, &ok); | 3990 B(eq, &ok); |
| 3987 Abort(kUnalignedCellInWriteBarrier); | 3991 Abort(kUnalignedCellInWriteBarrier); |
| 3988 Bind(&ok); | 3992 Bind(&ok); |
| 3989 } | 3993 } |
| 3990 | 3994 |
| 3991 RecordWrite(object, | 3995 RecordWrite(object, |
| 3992 scratch, | 3996 scratch, |
| 3993 value, | 3997 value, |
| 3994 lr_status, | 3998 lr_status, |
| 3995 save_fp, | 3999 save_fp, |
| 3996 remembered_set_action, | 4000 remembered_set_action, |
| 3997 OMIT_SMI_CHECK, | 4001 OMIT_SMI_CHECK); |
| 3998 pregen_expectation); | |
| 3999 | 4002 |
| 4000 Bind(&done); | 4003 Bind(&done); |
| 4001 | 4004 |
| 4002 // Clobber clobbered input registers when running with the debug-code flag | 4005 // Clobber clobbered input registers when running with the debug-code flag |
| 4003 // turned on to provoke errors. | 4006 // turned on to provoke errors. |
| 4004 if (emit_debug_code()) { | 4007 if (emit_debug_code()) { |
| 4005 Mov(value, Operand(BitCast<int64_t>(kZapValue + 4))); | 4008 Mov(value, Operand(BitCast<int64_t>(kZapValue + 4))); |
| 4006 Mov(scratch, Operand(BitCast<int64_t>(kZapValue + 8))); | 4009 Mov(scratch, Operand(BitCast<int64_t>(kZapValue + 8))); |
| 4007 } | 4010 } |
| 4008 } | 4011 } |
| 4009 | 4012 |
| 4010 | 4013 |
| 4011 // Will clobber: object, address, value, Tmp0(), Tmp1(). | 4014 // Will clobber: object, address, value, Tmp0(), Tmp1(). |
| 4012 // If lr_status is kLRHasBeenSaved, lr will also be clobbered. | 4015 // If lr_status is kLRHasBeenSaved, lr will also be clobbered. |
| 4013 // | 4016 // |
| 4014 // The register 'object' contains a heap object pointer. The heap object tag is | 4017 // The register 'object' contains a heap object pointer. The heap object tag is |
| 4015 // shifted away. | 4018 // shifted away. |
| 4016 // | |
| 4017 // If pregen_expectation is EXPECT_PREGENERATED, this will assert that the | |
| 4018 // stub used was pregenerated. This is done to ensure that | |
| 4019 // RecordWriteStub::kAheadOfTime stays in sync with real usage. If | |
| 4020 // pregen_expectation is false, no assertion is made, since another call site | |
| 4021 // might pregenerate the stub with the same parameters. | |
| 4022 void MacroAssembler::RecordWrite(Register object, | 4019 void MacroAssembler::RecordWrite(Register object, |
| 4023 Register address, | 4020 Register address, |
| 4024 Register value, | 4021 Register value, |
| 4025 LinkRegisterStatus lr_status, | 4022 LinkRegisterStatus lr_status, |
| 4026 SaveFPRegsMode fp_mode, | 4023 SaveFPRegsMode fp_mode, |
| 4027 RememberedSetAction remembered_set_action, | 4024 RememberedSetAction remembered_set_action, |
| 4028 SmiCheck smi_check, | 4025 SmiCheck smi_check) { |
| 4029 PregenExpectation pregen_expectation) { | |
| 4030 // The compiled code assumes that record write doesn't change the | 4026 // The compiled code assumes that record write doesn't change the |
| 4031 // context register, so we check that none of the clobbered | 4027 // context register, so we check that none of the clobbered |
| 4032 // registers are cp. | 4028 // registers are cp. |
| 4033 ASSERT(!address.is(cp) && !value.is(cp)); | 4029 ASSERT(!address.is(cp) && !value.is(cp)); |
| 4034 | 4030 |
| 4035 if (emit_debug_code()) { | 4031 if (emit_debug_code()) { |
| 4036 Ldr(Tmp0(), MemOperand(address)); | 4032 Ldr(Tmp0(), MemOperand(address)); |
| 4037 Cmp(Tmp0(), value); | 4033 Cmp(Tmp0(), value); |
| 4038 Check(eq, kWrongAddressOrValuePassedToRecordWrite); | 4034 Check(eq, kWrongAddressOrValuePassedToRecordWrite); |
| 4039 } | 4035 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 4058 CheckPageFlagClear(object, | 4054 CheckPageFlagClear(object, |
| 4059 value, // Used as scratch. | 4055 value, // Used as scratch. |
| 4060 MemoryChunk::kPointersFromHereAreInterestingMask, | 4056 MemoryChunk::kPointersFromHereAreInterestingMask, |
| 4061 &done); | 4057 &done); |
| 4062 | 4058 |
| 4063 // Record the actual write. | 4059 // Record the actual write. |
| 4064 if (lr_status == kLRHasNotBeenSaved) { | 4060 if (lr_status == kLRHasNotBeenSaved) { |
| 4065 Push(lr); | 4061 Push(lr); |
| 4066 } | 4062 } |
| 4067 RecordWriteStub stub(object, value, address, remembered_set_action, fp_mode); | 4063 RecordWriteStub stub(object, value, address, remembered_set_action, fp_mode); |
| 4068 if (pregen_expectation == EXPECT_PREGENERATED) { | |
| 4069 // If we expected a pregenerated stub, ensure that we get one. | |
| 4070 // A failure at this assertion probably indicates that the | |
| 4071 // RecordWriteStub::kAheadOfTime list needs to be updated. | |
| 4072 ASSERT(stub.IsPregenerated(isolate())); | |
| 4073 } | |
| 4074 CallStub(&stub); | 4064 CallStub(&stub); |
| 4075 if (lr_status == kLRHasNotBeenSaved) { | 4065 if (lr_status == kLRHasNotBeenSaved) { |
| 4076 Pop(lr); | 4066 Pop(lr); |
| 4077 } | 4067 } |
| 4078 | 4068 |
| 4079 Bind(&done); | 4069 Bind(&done); |
| 4080 | 4070 |
| 4081 // Clobber clobbered registers when running with the debug-code flag | 4071 // Clobber clobbered registers when running with the debug-code flag |
| 4082 // turned on to provoke errors. | 4072 // turned on to provoke errors. |
| 4083 if (emit_debug_code()) { | 4073 if (emit_debug_code()) { |
| (...skipping 766 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4850 } | 4840 } |
| 4851 } | 4841 } |
| 4852 | 4842 |
| 4853 | 4843 |
| 4854 #undef __ | 4844 #undef __ |
| 4855 | 4845 |
| 4856 | 4846 |
| 4857 } } // namespace v8::internal | 4847 } } // namespace v8::internal |
| 4858 | 4848 |
| 4859 #endif // V8_TARGET_ARCH_A64 | 4849 #endif // V8_TARGET_ARCH_A64 |
| OLD | NEW |