• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env ruby
2
3# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16include_relative 'common.irt'
17
18if Options.arch == :arm64
19    # In case of Aarch64 6 registers are enough: use 4 callee regs and 2 temp regs.
20    $monitors_mask = RegMask.new($full_regmap, :tmp1, :tmp2, :callee0, :callee2, :callee3, :callee4)
21else
22    $monitors_mask = $panda_mask
23end
24
25function(:MonitorEnterFastPath,
26          params: {monitor: 'ptr'},
27          regmap: $full_regmap,
28          regalloc_set: $monitors_mask,
29          mode: [:FastPath]) {
30    if Options.arch == :arm32
31        Intrinsic(:UNREACHABLE).ptr
32        next
33    end
34
35    # Load native thread id, go to slow path if it is unknown
36    ntid := Cast(LoadI(%tr).Imm(Constants::INTERNAL_THREAD_ID_OFFSET).u32).SrcType("DataType::Type::UINT32").mw
37    If(ntid, 0).CC(:CC_EQ).mw { Goto(:SlowPath) }
38
39    # Load MTManagedThread::local_objects_locked_ size and capacity, go to slow path if list should be extended
40    locked_list_capacity := LoadI(%tr).Imm(Constants::LOCKED_OBJECTS_CAPACITY_OFFSET).u32
41    locked_list_size := LoadI(%tr).Imm(Constants::LOCKED_OBJECTS_SIZE_OFFSET).u32
42    If(locked_list_capacity, locked_list_size).CC(:CC_LE).u32 { Goto(:SlowPath) }
43
44Label(:CasLoop)
45    if Options.arch == :x86_64
46        mark_word := LoadI(monitor).Imm(Constants::MARK_WORD_OFFSET).mw
47    else
48        mark_word := Intrinsic(:LOAD_ACQUIRE_MARK_WORD_EXCLUSIVE, monitor).mw
49    end
50
51    # Go to slow path if mark word's state is neither Unlock, nor Lightweight lock
52    If(And(mark_word, Constants::MARK_WORD_STATUS_MASK).mw, 0).CC(:CC_NE).mw { Goto(:SlowPath) }
53
54    # If both thread id and locks count fields are zero then set thread id to current thread's id
55    If(And(mark_word, Constants::MARK_WORD_LWL_THREAD_ID_AND_COUNTER_MASK).mw, 0).CC(:CC_EQ).mw {
56        shifted_ntid := Shl(ntid, Constants::MARK_WORD_LWL_THREAD_ID_OFFSET).mw
57        new_mark_word := Or(mark_word, shifted_ntid).mw
58    }
59    phi_mw := Phi(mark_word, new_mark_word).mw
60
61    # Increment locks count by 1
62    final_mark_word := Add(phi_mw, Constants::MARK_WORD_LWL_COUNTER_INC).mw
63    # Check that locks count didn't overflow and go to slow path if it did
64    If(Shr(final_mark_word, Constants::MARK_WORD_LWL_THREAD_ID_OFFSET).mw, ntid).CC(:CC_NE).mw {
65        Goto(:SlowPath)
66    }
67    # Try to update mark word, retry on failure
68    if Options.arch == :x86_64
69        If(Intrinsic(:COMPARE_AND_SET_MARK_WORD, monitor, mark_word, final_mark_word).b, 0).CC(:CC_EQ).b {
70            Goto(:CasLoop)
71        }
72    else
73        If(Intrinsic(:STORE_RELEASE_MARK_WORD_EXCLUSIVE, monitor, final_mark_word).b, 0).CC(:CC_NE).b {
74            Goto(:CasLoop)
75        }
76    end
77
78    # Push new LockObjectInfo instance to MTManagedThread's local_objects_locked_ list
79    locked_objects_base := LoadI(%tr).Imm(Constants::LOCKED_OBJECTS_DATA_OFFSET).ptr
80    locked_objects_offset_u32 := Mul(locked_list_size, Constants::LOCKED_OBJECT_INFO_SIZE).u32
81    if Options.arch_64_bits?
82        locked_objects_offset := Cast(locked_objects_offset_u32).SrcType("DataType::Type::UINT32").u64
83    else
84        locked_objects_offset := locked_objects_offset_u32
85    end
86    locked_objects_addr := Add(locked_objects_base, locked_objects_offset).ptr
87    StoreI(locked_objects_addr, monitor).Imm(Constants::LOCKED_OBJECT_INFO_MONITOR_OFFSET).ptr
88    StoreI(locked_objects_addr, %fp).Imm(Constants::LOCKED_OBJECT_INFO_FRAME_OFFSET).ptr
89
90    # Increment local_objects_locked_ size
91    new_len := Add(locked_list_size, 1).u32
92    StoreI(%tr, new_len).Imm(Constants::LOCKED_OBJECTS_SIZE_OFFSET).u32
93    Goto(:Exit)
94
95Label(:SlowPath)
96    Intrinsic(:SLOW_PATH_ENTRY, monitor).AddImm(Constants::MONITOR_ENTER_SLOW_PATH).v0id
97    Intrinsic(:UNREACHABLE).ptr if defines.DEBUG
98Label(:Exit)
99    ReturnVoid()
100}
101
102function(:MonitorExitFastPath,
103          params: {monitor: 'ptr'},
104          regmap: $full_regmap,
105          regalloc_set: $monitors_mask,
106          mode: [:FastPath]) {
107    if Options.arch == :arm32
108        Intrinsic(:UNREACHABLE).ptr
109        next
110    end
111
112    # Load native thread id, go to slow path if it is unknown
113    ntid := Cast(LoadI(%tr).Imm(Constants::INTERNAL_THREAD_ID_OFFSET).u32).SrcType("DataType::Type::UINT32").mw
114    If(ntid, 0).CC(:CC_EQ).mw { Goto(:SlowPath) }
115    shifted_ntid := Shl(ntid, Constants::MARK_WORD_LWL_THREAD_ID_OFFSET).mw
116
117Label(:CasLoop)
118    if Options.arch == :x86_64
119        mark_word := LoadI(monitor).Imm(Constants::MARK_WORD_OFFSET).mw
120    else
121        mark_word := Intrinsic(:LOAD_ACQUIRE_MARK_WORD_EXCLUSIVE, monitor).mw
122    end
123
124    # Xor current thread id and mark word's thread id and then check that:
125    # 1) thread id is zero (that means that mark word's thread id equal to current thread id);
126    # 2) mark word state is zero too (it corresponds to Lightweight lock in case of non-zero thread id).
127    # If one of these conditions does not holds go to slow path.
128    If(And(Xor(mark_word, shifted_ntid).mw, Constants::MARK_WORD_STATUS_MASK_AND_LWL_THREAD_ID_MASK).mw, 0).CC(:CC_NE).mw {
129        Goto(:SlowPath)
130    }
131
132    # Decrement locks count by 1
133    decremented_mw := Sub(mark_word, Constants::MARK_WORD_LWL_COUNTER_INC).mw
134
135    # Clear the thread id field if locks count was decremented down to 0
136    If(And(decremented_mw, Constants::MARK_WORD_LWL_COUNTER_MASK).mw, 0).CC(:CC_EQ).mw {
137        new_mark_word := Xor(decremented_mw, shifted_ntid).mw
138    }
139    final_mark_word := Phi(decremented_mw, new_mark_word).mw
140
141    # Try to update mark word, retry on failure
142    if Options.arch == :x86_64
143        If(Intrinsic(:COMPARE_AND_SET_MARK_WORD, monitor, mark_word, final_mark_word).b, 0).CC(:CC_EQ).b {
144            Goto(:CasLoop)
145        }
146    else
147        If(Intrinsic(:STORE_RELEASE_MARK_WORD_EXCLUSIVE, monitor, final_mark_word).b, 0).CC(:CC_NE).b {
148            Goto(:CasLoop)
149        }
150    end
151
152    # Decrement size of MTManagedThread's local_objects_locked_ list
153    locked_list_size := LoadI(%tr).Imm(Constants::LOCKED_OBJECTS_SIZE_OFFSET).u32
154    new_len := Sub(locked_list_size, 1).u32
155    StoreI(%tr, new_len).Imm(Constants::LOCKED_OBJECTS_SIZE_OFFSET).u32
156    Goto(:Exit)
157
158Label(:SlowPath)
159    Intrinsic(:SLOW_PATH_ENTRY, monitor).AddImm(Constants::MONITOR_EXIT_SLOW_PATH).v0id
160    Intrinsic(:UNREACHABLE).ptr if defines.DEBUG
161Label(:Exit)
162    ReturnVoid()
163}
164