blob: 57ae55170b40acba4740915af83b2e758f40bd2f [file] [log] [blame]
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "platform/globals.h"
#if defined(TARGET_ARCH_X64)
#include "vm/compiler/assembler/assembler.h"
#include "vm/compiler/runtime_api.h"
#include "vm/constants.h"
#include "vm/object.h"
#include "vm/stack_frame.h"
#include "vm/symbols.h"
#define __ assembler->
namespace dart {
void GenerateInvokeTTSStub(compiler::Assembler* assembler) {
__ EnterDartFrame(0);
intptr_t sum = 0;
for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
if (((1 << i) & kDartAvailableCpuRegs) == 0) continue;
if (((1 << i) & TypeTestABI::kAbiRegisters) != 0) continue;
if (((1 << i) & TTSInternalRegs::kInternalRegisters) != 0) continue;
__ movq(static_cast<Register>(i), compiler::Immediate(0x10 + 2 * i));
sum += 0x10 + 2 * i;
}
// Load the arguments into the right TTS calling convention registers.
__ movq(TypeTestABI::kInstanceReg,
compiler::Address(
RBP, (kCallerSpSlotFromFp + 3) * compiler::target::kWordSize));
__ movq(TypeTestABI::kInstantiatorTypeArgumentsReg,
compiler::Address(
RBP, (kCallerSpSlotFromFp + 2) * compiler::target::kWordSize));
__ movq(TypeTestABI::kFunctionTypeArgumentsReg,
compiler::Address(
RBP, (kCallerSpSlotFromFp + 1) * compiler::target::kWordSize));
__ movq(TypeTestABI::kDstTypeReg,
compiler::Address(
RBP, (kCallerSpSlotFromFp + 0) * compiler::target::kWordSize));
const intptr_t sub_type_cache_index = __ object_pool_builder().AddObject(
Object::null_object(), compiler::ObjectPoolBuilderEntry::kPatchable);
const intptr_t sub_type_cache_offset =
ObjectPool::element_offset(sub_type_cache_index) - kHeapObjectTag;
const intptr_t dst_name_index = __ object_pool_builder().AddObject(
Symbols::OptimizedOut(), compiler::ObjectPoolBuilderEntry::kPatchable);
ASSERT((sub_type_cache_index + 1) == dst_name_index);
ASSERT(__ constant_pool_allowed());
// Call the TTS.
__ movq(TypeTestABI::kSubtypeTestCacheReg,
compiler::Address(PP, sub_type_cache_offset));
__ call(compiler::FieldAddress(
TypeTestABI::kDstTypeReg,
AbstractType::type_test_stub_entry_point_offset()));
// We have the guarantee that TTS preserve all registers except for one
// scratch register atm (if the TTS handles the type test successfully).
//
// Let the test know whether TTS abi registers were preserved.
compiler::Label abi_regs_modified, store_abi_regs_modified_bool;
__ cmpq(TypeTestABI::kInstanceReg,
compiler::Address(
RBP, (kCallerSpSlotFromFp + 3) * compiler::target::kWordSize));
__ BranchIf(NOT_EQUAL, &abi_regs_modified);
__ cmpq(TypeTestABI::kInstantiatorTypeArgumentsReg,
compiler::Address(
RBP, (kCallerSpSlotFromFp + 2) * compiler::target::kWordSize));
__ BranchIf(NOT_EQUAL, &abi_regs_modified);
__ cmpq(TypeTestABI::kFunctionTypeArgumentsReg,
compiler::Address(
RBP, (kCallerSpSlotFromFp + 1) * compiler::target::kWordSize));
__ BranchIf(NOT_EQUAL, &abi_regs_modified);
__ cmpq(TypeTestABI::kDstTypeReg,
compiler::Address(
RBP, (kCallerSpSlotFromFp + 0) * compiler::target::kWordSize));
__ BranchIf(NOT_EQUAL, &abi_regs_modified);
__ movq(RAX, compiler::Address(THR, Thread::bool_false_offset()));
__ jmp(&store_abi_regs_modified_bool);
__ Bind(&abi_regs_modified);
__ movq(RAX, compiler::Address(THR, Thread::bool_true_offset()));
__ Bind(&store_abi_regs_modified_bool);
__ movq(TMP, compiler::Address(RBP, (kCallerSpSlotFromFp + 5) *
compiler::target::kWordSize));
__ movq(compiler::FieldAddress(TMP, Array::element_offset(0)), RAX);
// Let the test know whether the non-TTS abi registers were preserved.
compiler::Label rest_regs_modified, store_rest_regs_modified_bool;
__ movq(TMP, compiler::Immediate(0));
for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
if (((1 << i) & kDartAvailableCpuRegs) == 0) continue;
if (((1 << i) & TypeTestABI::kAbiRegisters) != 0) continue;
if (((1 << i) & TTSInternalRegs::kInternalRegisters) != 0) continue;
__ addq(TMP, static_cast<Register>(i));
}
__ cmpq(TMP, compiler::Immediate(sum));
__ BranchIf(NOT_EQUAL, &rest_regs_modified);
__ movq(RAX, compiler::Address(THR, Thread::bool_false_offset()));
__ jmp(&store_rest_regs_modified_bool);
__ Bind(&rest_regs_modified);
__ movq(RAX, compiler::Address(THR, Thread::bool_true_offset()));
__ Bind(&store_rest_regs_modified_bool);
__ movq(TMP, compiler::Address(RBP, (kCallerSpSlotFromFp + 4) *
compiler::target::kWordSize));
__ movq(compiler::FieldAddress(TMP, Array::element_offset(0)), RAX);
__ LoadObject(RAX, Object::null_object());
__ LeaveDartFrame();
__ Ret();
}
} // namespace dart
#endif // defined(TARGET_ARCH_X64)