1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2015 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "stack_map_stream.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include <memory>
20*795d594fSAndroid Build Coastguard Worker #include <vector>
21*795d594fSAndroid Build Coastguard Worker
22*795d594fSAndroid Build Coastguard Worker #include "art_method-inl.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/globals.h"
24*795d594fSAndroid Build Coastguard Worker #include "base/stl_util.h"
25*795d594fSAndroid Build Coastguard Worker #include "class_linker.h"
26*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file.h"
27*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file_types.h"
28*795d594fSAndroid Build Coastguard Worker #include "driver/compiler_options.h"
29*795d594fSAndroid Build Coastguard Worker #include "oat/stack_map.h"
30*795d594fSAndroid Build Coastguard Worker #include "optimizing/code_generator.h"
31*795d594fSAndroid Build Coastguard Worker #include "optimizing/nodes.h"
32*795d594fSAndroid Build Coastguard Worker #include "optimizing/optimizing_compiler.h"
33*795d594fSAndroid Build Coastguard Worker #include "runtime.h"
34*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
35*795d594fSAndroid Build Coastguard Worker
36*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
37*795d594fSAndroid Build Coastguard Worker
38*795d594fSAndroid Build Coastguard Worker constexpr static bool kVerifyStackMaps = kIsDebugBuild;
39*795d594fSAndroid Build Coastguard Worker
GetStackMapNativePcOffset(size_t i)40*795d594fSAndroid Build Coastguard Worker uint32_t StackMapStream::GetStackMapNativePcOffset(size_t i) {
41*795d594fSAndroid Build Coastguard Worker return StackMap::UnpackNativePc(stack_maps_[i][StackMap::kPackedNativePc], instruction_set_);
42*795d594fSAndroid Build Coastguard Worker }
43*795d594fSAndroid Build Coastguard Worker
SetStackMapNativePcOffset(size_t i,uint32_t native_pc_offset)44*795d594fSAndroid Build Coastguard Worker void StackMapStream::SetStackMapNativePcOffset(size_t i, uint32_t native_pc_offset) {
45*795d594fSAndroid Build Coastguard Worker stack_maps_[i][StackMap::kPackedNativePc] =
46*795d594fSAndroid Build Coastguard Worker StackMap::PackNativePc(native_pc_offset, instruction_set_);
47*795d594fSAndroid Build Coastguard Worker }
48*795d594fSAndroid Build Coastguard Worker
BeginMethod(size_t frame_size_in_bytes,size_t core_spill_mask,size_t fp_spill_mask,uint32_t num_dex_registers,bool baseline,bool debuggable,bool has_should_deoptimize_flag)49*795d594fSAndroid Build Coastguard Worker void StackMapStream::BeginMethod(size_t frame_size_in_bytes,
50*795d594fSAndroid Build Coastguard Worker size_t core_spill_mask,
51*795d594fSAndroid Build Coastguard Worker size_t fp_spill_mask,
52*795d594fSAndroid Build Coastguard Worker uint32_t num_dex_registers,
53*795d594fSAndroid Build Coastguard Worker bool baseline,
54*795d594fSAndroid Build Coastguard Worker bool debuggable,
55*795d594fSAndroid Build Coastguard Worker bool has_should_deoptimize_flag) {
56*795d594fSAndroid Build Coastguard Worker DCHECK(!in_method_) << "Mismatched Begin/End calls";
57*795d594fSAndroid Build Coastguard Worker in_method_ = true;
58*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(packed_frame_size_, 0u) << "BeginMethod was already called";
59*795d594fSAndroid Build Coastguard Worker
60*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(frame_size_in_bytes, kStackAlignment);
61*795d594fSAndroid Build Coastguard Worker packed_frame_size_ = frame_size_in_bytes / kStackAlignment;
62*795d594fSAndroid Build Coastguard Worker core_spill_mask_ = core_spill_mask;
63*795d594fSAndroid Build Coastguard Worker fp_spill_mask_ = fp_spill_mask;
64*795d594fSAndroid Build Coastguard Worker num_dex_registers_ = num_dex_registers;
65*795d594fSAndroid Build Coastguard Worker baseline_ = baseline;
66*795d594fSAndroid Build Coastguard Worker debuggable_ = debuggable;
67*795d594fSAndroid Build Coastguard Worker has_should_deoptimize_flag_ = has_should_deoptimize_flag;
68*795d594fSAndroid Build Coastguard Worker
69*795d594fSAndroid Build Coastguard Worker if (kVerifyStackMaps) {
70*795d594fSAndroid Build Coastguard Worker dchecks_.emplace_back([=](const CodeInfo& code_info) {
71*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(code_info.packed_frame_size_, frame_size_in_bytes / kStackAlignment);
72*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(code_info.core_spill_mask_, core_spill_mask);
73*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(code_info.fp_spill_mask_, fp_spill_mask);
74*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(code_info.number_of_dex_registers_, num_dex_registers);
75*795d594fSAndroid Build Coastguard Worker });
76*795d594fSAndroid Build Coastguard Worker }
77*795d594fSAndroid Build Coastguard Worker }
78*795d594fSAndroid Build Coastguard Worker
EndMethod(size_t code_size)79*795d594fSAndroid Build Coastguard Worker void StackMapStream::EndMethod(size_t code_size) {
80*795d594fSAndroid Build Coastguard Worker DCHECK(in_method_) << "Mismatched Begin/End calls";
81*795d594fSAndroid Build Coastguard Worker in_method_ = false;
82*795d594fSAndroid Build Coastguard Worker code_size_ = code_size;
83*795d594fSAndroid Build Coastguard Worker
84*795d594fSAndroid Build Coastguard Worker // Read the stack masks now. The compiler might have updated them.
85*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < lazy_stack_masks_.size(); i++) {
86*795d594fSAndroid Build Coastguard Worker BitVector* stack_mask = lazy_stack_masks_[i];
87*795d594fSAndroid Build Coastguard Worker if (stack_mask != nullptr && stack_mask->GetNumberOfBits() != 0) {
88*795d594fSAndroid Build Coastguard Worker stack_maps_[i][StackMap::kStackMaskIndex] =
89*795d594fSAndroid Build Coastguard Worker stack_masks_.Dedup(stack_mask->GetRawStorage(), stack_mask->GetNumberOfBits());
90*795d594fSAndroid Build Coastguard Worker }
91*795d594fSAndroid Build Coastguard Worker }
92*795d594fSAndroid Build Coastguard Worker
93*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
94*795d594fSAndroid Build Coastguard Worker uint32_t packed_code_size = StackMap::PackNativePc(code_size, instruction_set_);
95*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < stack_maps_.size(); i++) {
96*795d594fSAndroid Build Coastguard Worker DCHECK_LE(stack_maps_[i][StackMap::kPackedNativePc], packed_code_size);
97*795d594fSAndroid Build Coastguard Worker }
98*795d594fSAndroid Build Coastguard Worker }
99*795d594fSAndroid Build Coastguard Worker
100*795d594fSAndroid Build Coastguard Worker if (kVerifyStackMaps) {
101*795d594fSAndroid Build Coastguard Worker dchecks_.emplace_back([=](const CodeInfo& code_info) {
102*795d594fSAndroid Build Coastguard Worker CHECK_EQ(code_info.code_size_, code_size);
103*795d594fSAndroid Build Coastguard Worker });
104*795d594fSAndroid Build Coastguard Worker }
105*795d594fSAndroid Build Coastguard Worker }
106*795d594fSAndroid Build Coastguard Worker
BeginStackMapEntry(uint32_t dex_pc,uint32_t native_pc_offset,uint32_t register_mask,BitVector * stack_mask,StackMap::Kind kind,bool needs_vreg_info,const std::vector<uint32_t> & dex_pc_list_for_catch_verification)107*795d594fSAndroid Build Coastguard Worker void StackMapStream::BeginStackMapEntry(
108*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc,
109*795d594fSAndroid Build Coastguard Worker uint32_t native_pc_offset,
110*795d594fSAndroid Build Coastguard Worker uint32_t register_mask,
111*795d594fSAndroid Build Coastguard Worker BitVector* stack_mask,
112*795d594fSAndroid Build Coastguard Worker StackMap::Kind kind,
113*795d594fSAndroid Build Coastguard Worker bool needs_vreg_info,
114*795d594fSAndroid Build Coastguard Worker const std::vector<uint32_t>& dex_pc_list_for_catch_verification) {
115*795d594fSAndroid Build Coastguard Worker DCHECK(in_method_) << "Call BeginMethod first";
116*795d594fSAndroid Build Coastguard Worker DCHECK(!in_stack_map_) << "Mismatched Begin/End calls";
117*795d594fSAndroid Build Coastguard Worker in_stack_map_ = true;
118*795d594fSAndroid Build Coastguard Worker
119*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(!dex_pc_list_for_catch_verification.empty(), kind == StackMap::Kind::Catch);
120*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(!dex_pc_list_for_catch_verification.empty(), kIsDebugBuild);
121*795d594fSAndroid Build Coastguard Worker
122*795d594fSAndroid Build Coastguard Worker current_stack_map_ = BitTableBuilder<StackMap>::Entry();
123*795d594fSAndroid Build Coastguard Worker current_stack_map_[StackMap::kKind] = static_cast<uint32_t>(kind);
124*795d594fSAndroid Build Coastguard Worker current_stack_map_[StackMap::kPackedNativePc] =
125*795d594fSAndroid Build Coastguard Worker StackMap::PackNativePc(native_pc_offset, instruction_set_);
126*795d594fSAndroid Build Coastguard Worker current_stack_map_[StackMap::kDexPc] = dex_pc;
127*795d594fSAndroid Build Coastguard Worker if (stack_maps_.size() > 0) {
128*795d594fSAndroid Build Coastguard Worker // Check that non-catch stack maps are sorted by pc.
129*795d594fSAndroid Build Coastguard Worker // Catch stack maps are at the end and may be unordered.
130*795d594fSAndroid Build Coastguard Worker if (stack_maps_.back()[StackMap::kKind] == StackMap::Kind::Catch) {
131*795d594fSAndroid Build Coastguard Worker DCHECK(current_stack_map_[StackMap::kKind] == StackMap::Kind::Catch);
132*795d594fSAndroid Build Coastguard Worker } else if (current_stack_map_[StackMap::kKind] != StackMap::Kind::Catch) {
133*795d594fSAndroid Build Coastguard Worker DCHECK_LE(stack_maps_.back()[StackMap::kPackedNativePc],
134*795d594fSAndroid Build Coastguard Worker current_stack_map_[StackMap::kPackedNativePc]);
135*795d594fSAndroid Build Coastguard Worker }
136*795d594fSAndroid Build Coastguard Worker }
137*795d594fSAndroid Build Coastguard Worker if (register_mask != 0) {
138*795d594fSAndroid Build Coastguard Worker uint32_t shift = LeastSignificantBit(register_mask);
139*795d594fSAndroid Build Coastguard Worker BitTableBuilder<RegisterMask>::Entry entry;
140*795d594fSAndroid Build Coastguard Worker entry[RegisterMask::kValue] = register_mask >> shift;
141*795d594fSAndroid Build Coastguard Worker entry[RegisterMask::kShift] = shift;
142*795d594fSAndroid Build Coastguard Worker current_stack_map_[StackMap::kRegisterMaskIndex] = register_masks_.Dedup(&entry);
143*795d594fSAndroid Build Coastguard Worker }
144*795d594fSAndroid Build Coastguard Worker // The compiler assumes the bit vector will be read during PrepareForFillIn(),
145*795d594fSAndroid Build Coastguard Worker // and it might modify the data before that. Therefore, just store the pointer.
146*795d594fSAndroid Build Coastguard Worker // See ClearSpillSlotsFromLoopPhisInStackMap in code_generator.h.
147*795d594fSAndroid Build Coastguard Worker lazy_stack_masks_.push_back(stack_mask);
148*795d594fSAndroid Build Coastguard Worker current_inline_infos_.clear();
149*795d594fSAndroid Build Coastguard Worker current_dex_registers_.clear();
150*795d594fSAndroid Build Coastguard Worker expected_num_dex_registers_ = needs_vreg_info ? num_dex_registers_ : 0u;
151*795d594fSAndroid Build Coastguard Worker
152*795d594fSAndroid Build Coastguard Worker if (kVerifyStackMaps) {
153*795d594fSAndroid Build Coastguard Worker size_t stack_map_index = stack_maps_.size();
154*795d594fSAndroid Build Coastguard Worker // Create lambda method, which will be executed at the very end to verify data.
155*795d594fSAndroid Build Coastguard Worker // Parameters and local variables will be captured(stored) by the lambda "[=]".
156*795d594fSAndroid Build Coastguard Worker dchecks_.emplace_back([=, this](const CodeInfo& code_info) {
157*795d594fSAndroid Build Coastguard Worker // The `native_pc_offset` may have been overridden using `SetStackMapNativePcOffset(.)`.
158*795d594fSAndroid Build Coastguard Worker uint32_t final_native_pc_offset = GetStackMapNativePcOffset(stack_map_index);
159*795d594fSAndroid Build Coastguard Worker if (kind == StackMap::Kind::Default || kind == StackMap::Kind::OSR) {
160*795d594fSAndroid Build Coastguard Worker StackMap stack_map = code_info.GetStackMapForNativePcOffset(final_native_pc_offset,
161*795d594fSAndroid Build Coastguard Worker instruction_set_);
162*795d594fSAndroid Build Coastguard Worker CHECK_EQ(stack_map.Row(), stack_map_index);
163*795d594fSAndroid Build Coastguard Worker } else if (kind == StackMap::Kind::Catch) {
164*795d594fSAndroid Build Coastguard Worker StackMap stack_map = code_info.GetCatchStackMapForDexPc(
165*795d594fSAndroid Build Coastguard Worker ArrayRef<const uint32_t>(dex_pc_list_for_catch_verification));
166*795d594fSAndroid Build Coastguard Worker CHECK_EQ(stack_map.Row(), stack_map_index);
167*795d594fSAndroid Build Coastguard Worker }
168*795d594fSAndroid Build Coastguard Worker StackMap stack_map = code_info.GetStackMapAt(stack_map_index);
169*795d594fSAndroid Build Coastguard Worker CHECK_EQ(stack_map.GetNativePcOffset(instruction_set_), final_native_pc_offset);
170*795d594fSAndroid Build Coastguard Worker CHECK_EQ(stack_map.GetKind(), static_cast<uint32_t>(kind));
171*795d594fSAndroid Build Coastguard Worker CHECK_EQ(stack_map.GetDexPc(), dex_pc);
172*795d594fSAndroid Build Coastguard Worker CHECK_EQ(code_info.GetRegisterMaskOf(stack_map), register_mask);
173*795d594fSAndroid Build Coastguard Worker BitMemoryRegion seen_stack_mask = code_info.GetStackMaskOf(stack_map);
174*795d594fSAndroid Build Coastguard Worker CHECK_GE(seen_stack_mask.size_in_bits(), stack_mask ? stack_mask->GetNumberOfBits() : 0);
175*795d594fSAndroid Build Coastguard Worker for (size_t b = 0; b < seen_stack_mask.size_in_bits(); b++) {
176*795d594fSAndroid Build Coastguard Worker CHECK_EQ(seen_stack_mask.LoadBit(b), stack_mask != nullptr && stack_mask->IsBitSet(b));
177*795d594fSAndroid Build Coastguard Worker }
178*795d594fSAndroid Build Coastguard Worker });
179*795d594fSAndroid Build Coastguard Worker }
180*795d594fSAndroid Build Coastguard Worker }
181*795d594fSAndroid Build Coastguard Worker
EndStackMapEntry()182*795d594fSAndroid Build Coastguard Worker void StackMapStream::EndStackMapEntry() {
183*795d594fSAndroid Build Coastguard Worker DCHECK(in_stack_map_) << "Mismatched Begin/End calls";
184*795d594fSAndroid Build Coastguard Worker in_stack_map_ = false;
185*795d594fSAndroid Build Coastguard Worker
186*795d594fSAndroid Build Coastguard Worker // Generate index into the InlineInfo table.
187*795d594fSAndroid Build Coastguard Worker size_t inlining_depth = current_inline_infos_.size();
188*795d594fSAndroid Build Coastguard Worker if (!current_inline_infos_.empty()) {
189*795d594fSAndroid Build Coastguard Worker current_inline_infos_.back()[InlineInfo::kIsLast] = InlineInfo::kLast;
190*795d594fSAndroid Build Coastguard Worker current_stack_map_[StackMap::kInlineInfoIndex] =
191*795d594fSAndroid Build Coastguard Worker inline_infos_.Dedup(current_inline_infos_.data(), current_inline_infos_.size());
192*795d594fSAndroid Build Coastguard Worker }
193*795d594fSAndroid Build Coastguard Worker
194*795d594fSAndroid Build Coastguard Worker // Generate delta-compressed dex register map.
195*795d594fSAndroid Build Coastguard Worker size_t num_dex_registers = current_dex_registers_.size();
196*795d594fSAndroid Build Coastguard Worker if (!current_dex_registers_.empty()) {
197*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(expected_num_dex_registers_, current_dex_registers_.size());
198*795d594fSAndroid Build Coastguard Worker CreateDexRegisterMap();
199*795d594fSAndroid Build Coastguard Worker }
200*795d594fSAndroid Build Coastguard Worker
201*795d594fSAndroid Build Coastguard Worker stack_maps_.Add(current_stack_map_);
202*795d594fSAndroid Build Coastguard Worker
203*795d594fSAndroid Build Coastguard Worker if (kVerifyStackMaps) {
204*795d594fSAndroid Build Coastguard Worker size_t stack_map_index = stack_maps_.size() - 1;
205*795d594fSAndroid Build Coastguard Worker dchecks_.emplace_back([=](const CodeInfo& code_info) {
206*795d594fSAndroid Build Coastguard Worker StackMap stack_map = code_info.GetStackMapAt(stack_map_index);
207*795d594fSAndroid Build Coastguard Worker CHECK_EQ(stack_map.HasDexRegisterMap(), (num_dex_registers != 0));
208*795d594fSAndroid Build Coastguard Worker CHECK_EQ(stack_map.HasInlineInfo(), (inlining_depth != 0));
209*795d594fSAndroid Build Coastguard Worker CHECK_EQ(code_info.GetInlineInfosOf(stack_map).size(), inlining_depth);
210*795d594fSAndroid Build Coastguard Worker });
211*795d594fSAndroid Build Coastguard Worker }
212*795d594fSAndroid Build Coastguard Worker }
213*795d594fSAndroid Build Coastguard Worker
BeginInlineInfoEntry(ArtMethod * method,uint32_t dex_pc,uint32_t num_dex_registers,const DexFile * outer_dex_file,const CodeGenerator * codegen)214*795d594fSAndroid Build Coastguard Worker void StackMapStream::BeginInlineInfoEntry(ArtMethod* method,
215*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc,
216*795d594fSAndroid Build Coastguard Worker uint32_t num_dex_registers,
217*795d594fSAndroid Build Coastguard Worker const DexFile* outer_dex_file,
218*795d594fSAndroid Build Coastguard Worker const CodeGenerator* codegen) {
219*795d594fSAndroid Build Coastguard Worker DCHECK(in_stack_map_) << "Call BeginStackMapEntry first";
220*795d594fSAndroid Build Coastguard Worker DCHECK(!in_inline_info_) << "Mismatched Begin/End calls";
221*795d594fSAndroid Build Coastguard Worker in_inline_info_ = true;
222*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(expected_num_dex_registers_, current_dex_registers_.size());
223*795d594fSAndroid Build Coastguard Worker
224*795d594fSAndroid Build Coastguard Worker expected_num_dex_registers_ += num_dex_registers;
225*795d594fSAndroid Build Coastguard Worker
226*795d594fSAndroid Build Coastguard Worker BitTableBuilder<InlineInfo>::Entry entry;
227*795d594fSAndroid Build Coastguard Worker entry[InlineInfo::kIsLast] = InlineInfo::kMore;
228*795d594fSAndroid Build Coastguard Worker entry[InlineInfo::kDexPc] = dex_pc;
229*795d594fSAndroid Build Coastguard Worker entry[InlineInfo::kNumberOfDexRegisters] = static_cast<uint32_t>(expected_num_dex_registers_);
230*795d594fSAndroid Build Coastguard Worker if (EncodeArtMethodInInlineInfo(method)) {
231*795d594fSAndroid Build Coastguard Worker entry[InlineInfo::kArtMethodHi] = High32Bits(reinterpret_cast<uintptr_t>(method));
232*795d594fSAndroid Build Coastguard Worker entry[InlineInfo::kArtMethodLo] = Low32Bits(reinterpret_cast<uintptr_t>(method));
233*795d594fSAndroid Build Coastguard Worker } else {
234*795d594fSAndroid Build Coastguard Worker uint32_t is_in_bootclasspath = MethodInfo::kKindNonBCP;
235*795d594fSAndroid Build Coastguard Worker uint32_t dexfile_index = MethodInfo::kSameDexFile;
236*795d594fSAndroid Build Coastguard Worker if (dex_pc != static_cast<uint32_t>(-1)) {
237*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
238*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file = method->GetDexFile();
239*795d594fSAndroid Build Coastguard Worker if (!IsSameDexFile(*outer_dex_file, *dex_file)) {
240*795d594fSAndroid Build Coastguard Worker if (method->GetDeclaringClass()->IsBootStrapClassLoaded()) {
241*795d594fSAndroid Build Coastguard Worker ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
242*795d594fSAndroid Build Coastguard Worker const std::vector<const DexFile*>& boot_class_path = class_linker->GetBootClassPath();
243*795d594fSAndroid Build Coastguard Worker auto it = std::find_if(
244*795d594fSAndroid Build Coastguard Worker boot_class_path.begin(), boot_class_path.end(), [dex_file](const DexFile* df) {
245*795d594fSAndroid Build Coastguard Worker return IsSameDexFile(*df, *dex_file);
246*795d594fSAndroid Build Coastguard Worker });
247*795d594fSAndroid Build Coastguard Worker is_in_bootclasspath = MethodInfo::kKindBCP;
248*795d594fSAndroid Build Coastguard Worker dexfile_index = std::distance(boot_class_path.begin(), it);
249*795d594fSAndroid Build Coastguard Worker } else {
250*795d594fSAndroid Build Coastguard Worker const std::vector<const DexFile*>& dex_files =
251*795d594fSAndroid Build Coastguard Worker codegen->GetCompilerOptions().GetDexFilesForOatFile();
252*795d594fSAndroid Build Coastguard Worker auto it = std::find_if(dex_files.begin(), dex_files.end(), [dex_file](const DexFile* df) {
253*795d594fSAndroid Build Coastguard Worker return IsSameDexFile(*df, *dex_file);
254*795d594fSAndroid Build Coastguard Worker });
255*795d594fSAndroid Build Coastguard Worker // No need to set is_in_bootclasspath since the default value works.
256*795d594fSAndroid Build Coastguard Worker dexfile_index = std::distance(dex_files.begin(), it);
257*795d594fSAndroid Build Coastguard Worker }
258*795d594fSAndroid Build Coastguard Worker }
259*795d594fSAndroid Build Coastguard Worker }
260*795d594fSAndroid Build Coastguard Worker uint32_t dex_method_index = method->GetDexMethodIndex();
261*795d594fSAndroid Build Coastguard Worker entry[InlineInfo::kMethodInfoIndex] =
262*795d594fSAndroid Build Coastguard Worker method_infos_.Dedup({dex_method_index, is_in_bootclasspath, dexfile_index});
263*795d594fSAndroid Build Coastguard Worker }
264*795d594fSAndroid Build Coastguard Worker current_inline_infos_.push_back(entry);
265*795d594fSAndroid Build Coastguard Worker
266*795d594fSAndroid Build Coastguard Worker if (kVerifyStackMaps) {
267*795d594fSAndroid Build Coastguard Worker size_t stack_map_index = stack_maps_.size();
268*795d594fSAndroid Build Coastguard Worker size_t depth = current_inline_infos_.size() - 1;
269*795d594fSAndroid Build Coastguard Worker dchecks_.emplace_back([=](const CodeInfo& code_info) {
270*795d594fSAndroid Build Coastguard Worker StackMap stack_map = code_info.GetStackMapAt(stack_map_index);
271*795d594fSAndroid Build Coastguard Worker InlineInfo inline_info = code_info.GetInlineInfosOf(stack_map)[depth];
272*795d594fSAndroid Build Coastguard Worker CHECK_EQ(inline_info.GetDexPc(), dex_pc);
273*795d594fSAndroid Build Coastguard Worker bool encode_art_method = EncodeArtMethodInInlineInfo(method);
274*795d594fSAndroid Build Coastguard Worker CHECK_EQ(inline_info.EncodesArtMethod(), encode_art_method);
275*795d594fSAndroid Build Coastguard Worker if (encode_art_method) {
276*795d594fSAndroid Build Coastguard Worker CHECK_EQ(inline_info.GetArtMethod(), method);
277*795d594fSAndroid Build Coastguard Worker } else {
278*795d594fSAndroid Build Coastguard Worker MethodInfo method_info = code_info.GetMethodInfoOf(inline_info);
279*795d594fSAndroid Build Coastguard Worker CHECK_EQ(method_info.GetMethodIndex(), method->GetDexMethodIndex());
280*795d594fSAndroid Build Coastguard Worker CHECK(method_info.GetDexFileIndexKind() == MethodInfo::kKindNonBCP ||
281*795d594fSAndroid Build Coastguard Worker method_info.GetDexFileIndexKind() == MethodInfo::kKindBCP);
282*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
283*795d594fSAndroid Build Coastguard Worker if (inline_info.GetDexPc() != static_cast<uint32_t>(-1) &&
284*795d594fSAndroid Build Coastguard Worker !IsSameDexFile(*outer_dex_file, *method->GetDexFile())) {
285*795d594fSAndroid Build Coastguard Worker if (method->GetDeclaringClass()->IsBootStrapClassLoaded()) {
286*795d594fSAndroid Build Coastguard Worker CHECK_EQ(method_info.GetDexFileIndexKind(), MethodInfo::kKindBCP);
287*795d594fSAndroid Build Coastguard Worker ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
288*795d594fSAndroid Build Coastguard Worker const std::vector<const DexFile*>& boot_class_path = class_linker->GetBootClassPath();
289*795d594fSAndroid Build Coastguard Worker DCHECK_LT(method_info.GetDexFileIndex(), boot_class_path.size());
290*795d594fSAndroid Build Coastguard Worker CHECK(IsSameDexFile(*boot_class_path[method_info.GetDexFileIndex()],
291*795d594fSAndroid Build Coastguard Worker *method->GetDexFile()));
292*795d594fSAndroid Build Coastguard Worker } else {
293*795d594fSAndroid Build Coastguard Worker CHECK_EQ(method_info.GetDexFileIndexKind(), MethodInfo::kKindNonBCP);
294*795d594fSAndroid Build Coastguard Worker const std::vector<const DexFile*>& dex_files =
295*795d594fSAndroid Build Coastguard Worker codegen->GetCompilerOptions().GetDexFilesForOatFile();
296*795d594fSAndroid Build Coastguard Worker DCHECK_LT(method_info.GetDexFileIndex(), dex_files.size());
297*795d594fSAndroid Build Coastguard Worker CHECK(IsSameDexFile(*dex_files[method_info.GetDexFileIndex()], *method->GetDexFile()));
298*795d594fSAndroid Build Coastguard Worker }
299*795d594fSAndroid Build Coastguard Worker }
300*795d594fSAndroid Build Coastguard Worker }
301*795d594fSAndroid Build Coastguard Worker });
302*795d594fSAndroid Build Coastguard Worker }
303*795d594fSAndroid Build Coastguard Worker }
304*795d594fSAndroid Build Coastguard Worker
EndInlineInfoEntry()305*795d594fSAndroid Build Coastguard Worker void StackMapStream::EndInlineInfoEntry() {
306*795d594fSAndroid Build Coastguard Worker DCHECK(in_inline_info_) << "Mismatched Begin/End calls";
307*795d594fSAndroid Build Coastguard Worker in_inline_info_ = false;
308*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(expected_num_dex_registers_, current_dex_registers_.size());
309*795d594fSAndroid Build Coastguard Worker }
310*795d594fSAndroid Build Coastguard Worker
311*795d594fSAndroid Build Coastguard Worker // Create delta-compressed dex register map based on the current list of DexRegisterLocations.
312*795d594fSAndroid Build Coastguard Worker // All dex registers for a stack map are concatenated - inlined registers are just appended.
CreateDexRegisterMap()313*795d594fSAndroid Build Coastguard Worker void StackMapStream::CreateDexRegisterMap() {
314*795d594fSAndroid Build Coastguard Worker // These are fields rather than local variables so that we can reuse the reserved memory.
315*795d594fSAndroid Build Coastguard Worker temp_dex_register_mask_.ClearAllBits();
316*795d594fSAndroid Build Coastguard Worker temp_dex_register_map_.clear();
317*795d594fSAndroid Build Coastguard Worker
318*795d594fSAndroid Build Coastguard Worker // Ensure that the arrays that hold previous state are big enough to be safely indexed below.
319*795d594fSAndroid Build Coastguard Worker if (previous_dex_registers_.size() < current_dex_registers_.size()) {
320*795d594fSAndroid Build Coastguard Worker previous_dex_registers_.resize(current_dex_registers_.size(), DexRegisterLocation::None());
321*795d594fSAndroid Build Coastguard Worker dex_register_timestamp_.resize(current_dex_registers_.size(), 0u);
322*795d594fSAndroid Build Coastguard Worker }
323*795d594fSAndroid Build Coastguard Worker
324*795d594fSAndroid Build Coastguard Worker // Set bit in the mask for each register that has been changed since the previous stack map.
325*795d594fSAndroid Build Coastguard Worker // Modified registers are stored in the catalogue and the catalogue index added to the list.
326*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < current_dex_registers_.size(); i++) {
327*795d594fSAndroid Build Coastguard Worker DexRegisterLocation reg = current_dex_registers_[i];
328*795d594fSAndroid Build Coastguard Worker // Distance is difference between this index and the index of last modification.
329*795d594fSAndroid Build Coastguard Worker uint32_t distance = stack_maps_.size() - dex_register_timestamp_[i];
330*795d594fSAndroid Build Coastguard Worker if (previous_dex_registers_[i] != reg || distance > kMaxDexRegisterMapSearchDistance) {
331*795d594fSAndroid Build Coastguard Worker BitTableBuilder<DexRegisterInfo>::Entry entry;
332*795d594fSAndroid Build Coastguard Worker entry[DexRegisterInfo::kKind] = static_cast<uint32_t>(reg.GetKind());
333*795d594fSAndroid Build Coastguard Worker entry[DexRegisterInfo::kPackedValue] =
334*795d594fSAndroid Build Coastguard Worker DexRegisterInfo::PackValue(reg.GetKind(), reg.GetValue());
335*795d594fSAndroid Build Coastguard Worker uint32_t index = reg.IsLive() ? dex_register_catalog_.Dedup(&entry) : kNoValue;
336*795d594fSAndroid Build Coastguard Worker temp_dex_register_mask_.SetBit(i);
337*795d594fSAndroid Build Coastguard Worker temp_dex_register_map_.push_back({index});
338*795d594fSAndroid Build Coastguard Worker previous_dex_registers_[i] = reg;
339*795d594fSAndroid Build Coastguard Worker dex_register_timestamp_[i] = stack_maps_.size();
340*795d594fSAndroid Build Coastguard Worker }
341*795d594fSAndroid Build Coastguard Worker }
342*795d594fSAndroid Build Coastguard Worker
343*795d594fSAndroid Build Coastguard Worker // Set the mask and map for the current StackMap (which includes inlined registers).
344*795d594fSAndroid Build Coastguard Worker if (temp_dex_register_mask_.GetNumberOfBits() != 0) {
345*795d594fSAndroid Build Coastguard Worker current_stack_map_[StackMap::kDexRegisterMaskIndex] =
346*795d594fSAndroid Build Coastguard Worker dex_register_masks_.Dedup(temp_dex_register_mask_.GetRawStorage(),
347*795d594fSAndroid Build Coastguard Worker temp_dex_register_mask_.GetNumberOfBits());
348*795d594fSAndroid Build Coastguard Worker }
349*795d594fSAndroid Build Coastguard Worker if (!current_dex_registers_.empty()) {
350*795d594fSAndroid Build Coastguard Worker current_stack_map_[StackMap::kDexRegisterMapIndex] =
351*795d594fSAndroid Build Coastguard Worker dex_register_maps_.Dedup(temp_dex_register_map_.data(),
352*795d594fSAndroid Build Coastguard Worker temp_dex_register_map_.size());
353*795d594fSAndroid Build Coastguard Worker }
354*795d594fSAndroid Build Coastguard Worker
355*795d594fSAndroid Build Coastguard Worker if (kVerifyStackMaps) {
356*795d594fSAndroid Build Coastguard Worker size_t stack_map_index = stack_maps_.size();
357*795d594fSAndroid Build Coastguard Worker // We need to make copy of the current registers for later (when the check is run).
358*795d594fSAndroid Build Coastguard Worker auto expected_dex_registers = std::make_shared<dchecked_vector<DexRegisterLocation>>(
359*795d594fSAndroid Build Coastguard Worker current_dex_registers_.begin(), current_dex_registers_.end());
360*795d594fSAndroid Build Coastguard Worker dchecks_.emplace_back([=](const CodeInfo& code_info) {
361*795d594fSAndroid Build Coastguard Worker StackMap stack_map = code_info.GetStackMapAt(stack_map_index);
362*795d594fSAndroid Build Coastguard Worker uint32_t expected_reg = 0;
363*795d594fSAndroid Build Coastguard Worker for (DexRegisterLocation reg : code_info.GetDexRegisterMapOf(stack_map)) {
364*795d594fSAndroid Build Coastguard Worker CHECK_EQ((*expected_dex_registers)[expected_reg++], reg);
365*795d594fSAndroid Build Coastguard Worker }
366*795d594fSAndroid Build Coastguard Worker for (InlineInfo inline_info : code_info.GetInlineInfosOf(stack_map)) {
367*795d594fSAndroid Build Coastguard Worker DexRegisterMap map = code_info.GetInlineDexRegisterMapOf(stack_map, inline_info);
368*795d594fSAndroid Build Coastguard Worker for (DexRegisterLocation reg : map) {
369*795d594fSAndroid Build Coastguard Worker CHECK_EQ((*expected_dex_registers)[expected_reg++], reg);
370*795d594fSAndroid Build Coastguard Worker }
371*795d594fSAndroid Build Coastguard Worker }
372*795d594fSAndroid Build Coastguard Worker CHECK_EQ(expected_reg, expected_dex_registers->size());
373*795d594fSAndroid Build Coastguard Worker });
374*795d594fSAndroid Build Coastguard Worker }
375*795d594fSAndroid Build Coastguard Worker }
376*795d594fSAndroid Build Coastguard Worker
Encode()377*795d594fSAndroid Build Coastguard Worker ScopedArenaVector<uint8_t> StackMapStream::Encode() {
378*795d594fSAndroid Build Coastguard Worker DCHECK(in_stack_map_ == false) << "Mismatched Begin/End calls";
379*795d594fSAndroid Build Coastguard Worker DCHECK(in_inline_info_ == false) << "Mismatched Begin/End calls";
380*795d594fSAndroid Build Coastguard Worker
381*795d594fSAndroid Build Coastguard Worker uint32_t flags = 0;
382*795d594fSAndroid Build Coastguard Worker flags |= (inline_infos_.size() > 0) ? CodeInfo::kHasInlineInfo : 0;
383*795d594fSAndroid Build Coastguard Worker flags |= baseline_ ? CodeInfo::kIsBaseline : 0;
384*795d594fSAndroid Build Coastguard Worker flags |= debuggable_ ? CodeInfo::kIsDebuggable : 0;
385*795d594fSAndroid Build Coastguard Worker flags |= has_should_deoptimize_flag_ ? CodeInfo::kHasShouldDeoptimizeFlag : 0;
386*795d594fSAndroid Build Coastguard Worker
387*795d594fSAndroid Build Coastguard Worker uint32_t bit_table_flags = 0;
388*795d594fSAndroid Build Coastguard Worker ForEachBitTable([&bit_table_flags](size_t i, auto bit_table) {
389*795d594fSAndroid Build Coastguard Worker if (bit_table->size() != 0) { // Record which bit-tables are stored.
390*795d594fSAndroid Build Coastguard Worker bit_table_flags |= 1 << i;
391*795d594fSAndroid Build Coastguard Worker }
392*795d594fSAndroid Build Coastguard Worker });
393*795d594fSAndroid Build Coastguard Worker
394*795d594fSAndroid Build Coastguard Worker ScopedArenaVector<uint8_t> buffer(allocator_->Adapter(kArenaAllocStackMapStream));
395*795d594fSAndroid Build Coastguard Worker BitMemoryWriter<ScopedArenaVector<uint8_t>> out(&buffer);
396*795d594fSAndroid Build Coastguard Worker out.WriteInterleavedVarints(std::array<uint32_t, CodeInfo::kNumHeaders>{
397*795d594fSAndroid Build Coastguard Worker flags,
398*795d594fSAndroid Build Coastguard Worker code_size_,
399*795d594fSAndroid Build Coastguard Worker packed_frame_size_,
400*795d594fSAndroid Build Coastguard Worker core_spill_mask_,
401*795d594fSAndroid Build Coastguard Worker fp_spill_mask_,
402*795d594fSAndroid Build Coastguard Worker num_dex_registers_,
403*795d594fSAndroid Build Coastguard Worker bit_table_flags,
404*795d594fSAndroid Build Coastguard Worker });
405*795d594fSAndroid Build Coastguard Worker ForEachBitTable([&out](size_t, auto bit_table) {
406*795d594fSAndroid Build Coastguard Worker if (bit_table->size() != 0) { // Skip empty bit-tables.
407*795d594fSAndroid Build Coastguard Worker bit_table->Encode(out);
408*795d594fSAndroid Build Coastguard Worker }
409*795d594fSAndroid Build Coastguard Worker });
410*795d594fSAndroid Build Coastguard Worker
411*795d594fSAndroid Build Coastguard Worker // Verify that we can load the CodeInfo and check some essentials.
412*795d594fSAndroid Build Coastguard Worker size_t number_of_read_bits;
413*795d594fSAndroid Build Coastguard Worker CodeInfo code_info(buffer.data(), &number_of_read_bits);
414*795d594fSAndroid Build Coastguard Worker CHECK_EQ(number_of_read_bits, out.NumberOfWrittenBits());
415*795d594fSAndroid Build Coastguard Worker CHECK_EQ(code_info.GetNumberOfStackMaps(), stack_maps_.size());
416*795d594fSAndroid Build Coastguard Worker CHECK_EQ(CodeInfo::HasInlineInfo(buffer.data()), inline_infos_.size() > 0);
417*795d594fSAndroid Build Coastguard Worker CHECK_EQ(CodeInfo::IsBaseline(buffer.data()), baseline_);
418*795d594fSAndroid Build Coastguard Worker CHECK_EQ(CodeInfo::IsDebuggable(buffer.data()), debuggable_);
419*795d594fSAndroid Build Coastguard Worker CHECK_EQ(CodeInfo::HasShouldDeoptimizeFlag(buffer.data()), has_should_deoptimize_flag_);
420*795d594fSAndroid Build Coastguard Worker
421*795d594fSAndroid Build Coastguard Worker // Verify all written data (usually only in debug builds).
422*795d594fSAndroid Build Coastguard Worker if (kVerifyStackMaps) {
423*795d594fSAndroid Build Coastguard Worker for (const auto& dcheck : dchecks_) {
424*795d594fSAndroid Build Coastguard Worker dcheck(code_info);
425*795d594fSAndroid Build Coastguard Worker }
426*795d594fSAndroid Build Coastguard Worker }
427*795d594fSAndroid Build Coastguard Worker
428*795d594fSAndroid Build Coastguard Worker return buffer;
429*795d594fSAndroid Build Coastguard Worker }
430*795d594fSAndroid Build Coastguard Worker
431*795d594fSAndroid Build Coastguard Worker } // namespace art
432