Flutter Engine
The Flutter Engine
code_descriptors.h
Go to the documentation of this file.
1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_CODE_DESCRIPTORS_H_
6#define RUNTIME_VM_CODE_DESCRIPTORS_H_
7
8#include "vm/datastream.h"
9#include "vm/globals.h"
10#include "vm/growable_array.h"
11#include "vm/log.h"
12#include "vm/runtime_entry.h"
13#include "vm/token_position.h"
14
15namespace dart {
16
17static constexpr intptr_t kInvalidTryIndex = -1;
18
20 public:
21 explicit DescriptorList(
22 Zone* zone,
23 const GrowableArray<const Function*>* inline_id_to_function = nullptr);
24
26
28 intptr_t pc_offset,
29 intptr_t deopt_id,
30 TokenPosition token_pos,
31 intptr_t try_index,
32 intptr_t yield_index);
33
34 PcDescriptorsPtr FinalizePcDescriptors(uword entry_point);
35
36 private:
37 static constexpr intptr_t kInitialStreamSize = 64;
38
39 const Function& function_;
40 const Script& script_;
41 ZoneWriteStream encoded_data_;
42
43 intptr_t prev_pc_offset;
44 intptr_t prev_deopt_id;
45 int32_t prev_token_pos;
46
47 DISALLOW_COPY_AND_ASSIGN(DescriptorList);
48};
49
51 public:
53 : encoded_bytes_(zone, kInitialStreamSize) {}
54
55 void AddEntry(intptr_t pc_offset,
57 intptr_t spill_slot_bit_count);
58
59 CompressedStackMapsPtr Finalize() const;
60
61 private:
62 static constexpr intptr_t kInitialStreamSize = 16;
63
64 ZoneWriteStream encoded_bytes_;
65 intptr_t last_pc_offset_ = 0;
66 DISALLOW_COPY_AND_ASSIGN(CompressedStackMapsBuilder);
67};
68
70 public:
71 struct HandlerDesc {
72 intptr_t outer_try_index; // Try block in which this try block is nested.
73 intptr_t pc_offset; // Handler PC offset value.
74 bool is_generated; // False if this is directly from Dart code.
75 const Array* handler_types; // Catch clause guards.
77 };
78
80 : list_(),
81 has_async_handler_(function.IsAsyncFunction() ||
82 function.IsAsyncGenerator()) {}
83
84 intptr_t Length() const { return list_.length(); }
85
87 struct HandlerDesc data;
88 data.outer_try_index = -1;
90 data.is_generated = true;
91 data.handler_types = nullptr;
92 data.needs_stacktrace = false;
93 list_.Add(data);
94 }
95
96 void AddHandler(intptr_t try_index,
97 intptr_t outer_try_index,
98 intptr_t pc_offset,
99 bool is_generated,
100 const Array& handler_types,
101 bool needs_stacktrace) {
102 ASSERT(try_index >= 0);
103 while (Length() <= try_index) {
105 }
106 list_[try_index].outer_try_index = outer_try_index;
107 ASSERT(list_[try_index].pc_offset == ExceptionHandlers::kInvalidPcOffset);
108 list_[try_index].pc_offset = pc_offset;
109 list_[try_index].is_generated = is_generated;
110 DEBUG_ASSERT(handler_types.IsNotTemporaryScopedHandle());
111 list_[try_index].handler_types = &handler_types;
112 list_[try_index].needs_stacktrace |= needs_stacktrace;
113 }
114
115 // Called by rethrows, to mark their enclosing handlers.
116 void SetNeedsStackTrace(intptr_t try_index) {
117 // Rethrows can be generated outside a try by the compiler.
118 if (try_index == kInvalidTryIndex) {
119 return;
120 }
121 ASSERT(try_index >= 0);
122 while (Length() <= try_index) {
124 }
125 list_[try_index].needs_stacktrace = true;
126 }
127
128 static bool ContainsCatchAllType(const Array& array) {
129 auto& type = AbstractType::Handle();
130 for (intptr_t i = 0; i < array.Length(); i++) {
131 type ^= array.At(i);
132 if (type.IsCatchAllType()) {
133 return true;
134 }
135 }
136 return false;
137 }
138
139 ExceptionHandlersPtr FinalizeExceptionHandlers(uword entry_point) const;
140
141 private:
143 const bool has_async_handler_;
145};
146
147#if !defined(DART_PRECOMPILED_RUNTIME)
148// Used to construct CatchEntryMoves for the AOT mode of compilation.
150 public:
152
153 void NewMapping(intptr_t pc_offset);
154 void Append(const CatchEntryMove& move);
155 void EndMapping();
156 TypedDataPtr FinalizeCatchEntryMovesMap();
157
158 private:
159 class TrieNode;
160
161 Zone* zone_;
162 TrieNode* root_;
163 intptr_t current_pc_offset_;
165 ZoneWriteStream stream_;
166
168};
169#endif // !defined(DART_PRECOMPILED_RUNTIME)
170
171// Instructions have two pieces of information needed to get accurate source
172// locations: the token position and the inlining id. The inlining id tells us
173// which function, and thus which script, to use for this instruction and the
174// token position, when real, tells us the position in the source for the
175// script for the instruction.
176//
177// Thus, we bundle the two pieces of information in InstructionSource structs
178// when copying or retrieving to lower the likelihood that the token position
179// is used without the appropriate inlining id.
181 // Treat an instruction source without inlining id information as unset.
186
188 const intptr_t inlining_id;
189
191};
192
194 static constexpr uint8_t kChangePosition = 0;
195 static constexpr uint8_t kAdvancePC = 1;
196 static constexpr uint8_t kPushFunction = 2;
197 static constexpr uint8_t kPopFunction = 3;
198 static constexpr uint8_t kNullCheck = 4;
199
200 static uint8_t Read(ReadStream* stream,
201 int32_t* arg1,
202 int32_t* arg2 = nullptr);
203
204 static void Write(BaseWriteStream* stream,
205 uint8_t op,
206 int32_t arg1 = 0,
207 int32_t arg2 = 0);
208
209 private:
210 static constexpr intptr_t kOpBits = 3;
211
214
215 static constexpr int32_t kMaxArgValue =
216 Utils::NBitMask<int32_t>(ArgField::bitsize() - 1);
217 static constexpr int32_t kMinArgValue = ~kMaxArgValue;
218 static constexpr int32_t kSignBits = static_cast<uint32_t>(kMinArgValue) << 1;
219};
220
221// A CodeSourceMap maps from pc offsets to a stack of inlined functions and
222// their positions. This is encoded as a little bytecode that pushes and pops
223// functions and changes the top function's position as the PC advances.
224// Decoding happens by running this bytecode until we reach the desired PC.
225//
226// The implementation keeps track of two sets of state: one written to the byte
227// stream and one that is buffered. On the JIT, this buffering effectively gives
228// us a peephole optimization that merges adjacent advance PC bytecodes. On AOT,
229// this allows to skip encoding our position until we reach a PC where we might
230// throw.
232 public:
234 Zone* zone,
235 bool stack_traces_only,
236 const GrowableArray<intptr_t>& caller_inline_id,
237 const GrowableArray<TokenPosition>& inline_id_to_token_pos,
239
240 // The position at which a function implicitly starts, for both the root and
241 // after a push bytecode. We use the classifying position kDartCodePrologue
242 // since it is the most common.
244
245 void BeginCodeSourceRange(int32_t pc_offset, const InstructionSource& source);
246 void EndCodeSourceRange(int32_t pc_offset, const InstructionSource& source);
248 int32_t pc_offset,
250 void NoteNullCheck(int32_t pc_offset,
252 intptr_t name_index);
254
255 // If source is from an inlined call, returns the token position of the
256 // original call in the root function, otherwise the source's token position.
258 ArrayPtr InliningIdToFunction();
259 CodeSourceMapPtr Finalize();
260
262 return inline_id_to_function_;
263 }
264
265 private:
266 intptr_t GetFunctionId(intptr_t inline_id);
267 void StartInliningInterval(int32_t pc_offset,
269
270 void BufferChangePosition(TokenPosition pos);
271 void WriteChangePosition(TokenPosition pos);
272 void BufferAdvancePC(int32_t distance) { buffered_pc_offset_ += distance; }
273 void WriteAdvancePC(int32_t distance) {
275 written_pc_offset_ += distance;
276 }
277 void BufferPush(intptr_t inline_id) {
278 buffered_inline_id_stack_.Add(inline_id);
279 buffered_token_pos_stack_.Add(kInitialPosition);
280 }
281 void WritePush(intptr_t inline_id) {
283 GetFunctionId(inline_id));
284 written_inline_id_stack_.Add(inline_id);
285 written_token_pos_stack_.Add(kInitialPosition);
286 }
287 void BufferPop() {
288 buffered_inline_id_stack_.RemoveLast();
289 buffered_token_pos_stack_.RemoveLast();
290 }
291 void WritePop() {
293 written_inline_id_stack_.RemoveLast();
294 written_token_pos_stack_.RemoveLast();
295 }
296 void WriteNullCheck(int32_t name_index) {
298 }
299
300 void FlushBuffer();
301
302 bool IsOnBufferedStack(intptr_t inline_id) {
303 for (intptr_t i = 0; i < buffered_inline_id_stack_.length(); i++) {
304 if (buffered_inline_id_stack_[i] == inline_id) return true;
305 }
306 return false;
307 }
308
309 Zone* const zone_;
310 intptr_t buffered_pc_offset_;
311 GrowableArray<intptr_t> buffered_inline_id_stack_;
312 GrowableArray<TokenPosition> buffered_token_pos_stack_;
313
314 intptr_t written_pc_offset_;
315 GrowableArray<intptr_t> written_inline_id_stack_;
316 GrowableArray<TokenPosition> written_token_pos_stack_;
317
318 const GrowableArray<intptr_t>& caller_inline_id_;
319 const GrowableArray<TokenPosition>& inline_id_to_token_pos_;
320 const GrowableArray<const Function*>& inline_id_to_function_;
321
322 const GrowableObjectArray& inlined_functions_;
323
324 Script& script_;
325 ZoneWriteStream stream_;
326
327 const bool stack_traces_only_;
328
329 DISALLOW_COPY_AND_ASSIGN(CodeSourceMapBuilder);
330};
331
333 public:
335 const Array& functions,
336 const Function& root)
337 : map_(map), functions_(functions), root_(root) {}
338
339 void GetInlinedFunctionsAt(int32_t pc_offset,
340 GrowableArray<const Function*>* function_stack,
341 GrowableArray<TokenPosition>* token_positions);
342 NOT_IN_PRODUCT(void PrintJSONInlineIntervals(JSONObject* jsobj));
343 void DumpInlineIntervals(uword start);
344 void DumpSourcePositions(uword start);
345
346 intptr_t GetNullCheckNameIndexAt(int32_t pc_offset);
347
348 private:
349 static const TokenPosition& InitialPosition() {
350 if (FLAG_precompiled_mode) {
351 // In precompiled mode, the CodeSourceMap stores lines instead of
352 // real token positions and uses kNoSourcePos for no line information.
353 return TokenPosition::kNoSource;
354 } else {
356 }
357 }
358
359 // Reads a TokenPosition value from a CSM, handling the different encoding for
360 // when non-symbolic stack traces are enabled.
361 static TokenPosition ReadPosition(ReadStream* stream);
362
363 const CodeSourceMap& map_;
364 const Array& functions_;
365 const Function& root_;
366
367 DISALLOW_COPY_AND_ASSIGN(CodeSourceMapReader);
368};
369
370} // namespace dart
371
372#endif // RUNTIME_VM_CODE_DESCRIPTORS_H_
SkPoint pos
#define DEBUG_ASSERT(cond)
Definition: assert.h:321
GLenum type
ObjectPtr At(intptr_t index) const
Definition: object.h:10875
intptr_t Length() const
Definition: object.h:10829
void Add(const T &value)
intptr_t length() const
static constexpr int bitsize()
Definition: bitfield.h:162
void NewMapping(intptr_t pc_offset)
void Append(const CatchEntryMove &move)
TokenPosition RootPosition(const InstructionSource &source)
void EndCodeSourceRange(int32_t pc_offset, const InstructionSource &source)
void WriteFunctionEntrySourcePosition(const InstructionSource &source)
CodeSourceMapBuilder(Zone *zone, bool stack_traces_only, const GrowableArray< intptr_t > &caller_inline_id, const GrowableArray< TokenPosition > &inline_id_to_token_pos, const GrowableArray< const Function * > &inline_id_to_function)
void NoteNullCheck(int32_t pc_offset, const InstructionSource &source, intptr_t name_index)
static const TokenPosition & kInitialPosition
const GrowableArray< const Function * > & inline_id_to_function() const
void BeginCodeSourceRange(int32_t pc_offset, const InstructionSource &source)
void NoteDescriptor(UntaggedPcDescriptors::Kind kind, int32_t pc_offset, const InstructionSource &source)
intptr_t GetNullCheckNameIndexAt(int32_t pc_offset)
CodeSourceMapReader(const CodeSourceMap &map, const Array &functions, const Function &root)
void DumpInlineIntervals(uword start)
void GetInlinedFunctionsAt(int32_t pc_offset, GrowableArray< const Function * > *function_stack, GrowableArray< TokenPosition > *token_positions)
void DumpSourcePositions(uword start)
NOT_IN_PRODUCT(void PrintJSONInlineIntervals(JSONObject *jsobj))
CompressedStackMapsPtr Finalize() const
void AddEntry(intptr_t pc_offset, BitmapBuilder *bitmap, intptr_t spill_slot_bit_count)
void AddDescriptor(UntaggedPcDescriptors::Kind kind, intptr_t pc_offset, intptr_t deopt_id, TokenPosition token_pos, intptr_t try_index, intptr_t yield_index)
PcDescriptorsPtr FinalizePcDescriptors(uword entry_point)
DescriptorList(Zone *zone, const GrowableArray< const Function * > *inline_id_to_function=nullptr)
void AddHandler(intptr_t try_index, intptr_t outer_try_index, intptr_t pc_offset, bool is_generated, const Array &handler_types, bool needs_stacktrace)
ExceptionHandlersPtr FinalizeExceptionHandlers(uword entry_point) const
void SetNeedsStackTrace(intptr_t try_index)
static bool ContainsCatchAllType(const Array &array)
ExceptionHandlerList(const Function &function)
static constexpr intptr_t kInvalidPcOffset
Definition: object.h:6574
static Object & Handle()
Definition: object.h:407
#define ASSERT(E)
SkBitmap source
Definition: examples.cpp:28
Dart_NativeFunction function
Definition: fuchsia.cc:51
Definition: bitmap.py:1
Definition: dart_vm.cc:33
uintptr_t uword
Definition: globals.h:501
static int8_t data[kExtLength]
static constexpr intptr_t kInvalidTryIndex
string root
Definition: scale_cpu.py:20
SI auto map(std::index_sequence< I... >, Fn &&fn, const Args &... args) -> skvx::Vec< sizeof...(I), decltype(fn(args[0]...))>
Definition: SkVx.h:680
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: globals.h:581
static constexpr uint8_t kAdvancePC
static constexpr uint8_t kNullCheck
static uint8_t Read(ReadStream *stream, int32_t *arg1, int32_t *arg2=nullptr)
static void Write(BaseWriteStream *stream, uint8_t op, int32_t arg1=0, int32_t arg2=0)
static constexpr uint8_t kPopFunction
static constexpr uint8_t kPushFunction
static constexpr uint8_t kChangePosition
InstructionSource(TokenPosition pos, intptr_t id)
const TokenPosition token_pos
InstructionSource(TokenPosition pos)
const uintptr_t id