OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2017, 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_KERNEL_BINARY_H_ |
| 6 #define RUNTIME_VM_KERNEL_BINARY_H_ |
| 7 |
| 8 #if !defined(DART_PRECOMPILED_RUNTIME) |
| 9 |
| 10 #include <map> |
| 11 |
| 12 #include "vm/kernel.h" |
| 13 #include "vm/kernel_to_il.h" |
| 14 #include "vm/object.h" |
| 15 |
| 16 namespace dart { |
| 17 namespace kernel { |
| 18 |
| 19 |
| 20 static const uint32_t kMagicProgramFile = 0x90ABCDEFu; |
| 21 |
| 22 |
| 23 // Keep in sync with package:dynamo/lib/binary/tag.dart |
| 24 enum Tag { |
| 25 kNothing = 0, |
| 26 kSomething = 1, |
| 27 |
| 28 kClass = 2, |
| 29 |
| 30 kField = 4, |
| 31 kConstructor = 5, |
| 32 kProcedure = 6, |
| 33 |
| 34 kInvalidInitializer = 7, |
| 35 kFieldInitializer = 8, |
| 36 kSuperInitializer = 9, |
| 37 kRedirectingInitializer = 10, |
| 38 kLocalInitializer = 11, |
| 39 |
| 40 kDirectPropertyGet = 15, |
| 41 kDirectPropertySet = 16, |
| 42 kDirectMethodInvocation = 17, |
| 43 kConstStaticInvocation = 18, |
| 44 kInvalidExpression = 19, |
| 45 kVariableGet = 20, |
| 46 kVariableSet = 21, |
| 47 kPropertyGet = 22, |
| 48 kPropertySet = 23, |
| 49 kSuperPropertyGet = 24, |
| 50 kSuperPropertySet = 25, |
| 51 kStaticGet = 26, |
| 52 kStaticSet = 27, |
| 53 kMethodInvocation = 28, |
| 54 kSuperMethodInvocation = 29, |
| 55 kStaticInvocation = 30, |
| 56 kConstructorInvocation = 31, |
| 57 kConstConstructorInvocation = 32, |
| 58 kNot = 33, |
| 59 kLogicalExpression = 34, |
| 60 kConditionalExpression = 35, |
| 61 kStringConcatenation = 36, |
| 62 kIsExpression = 37, |
| 63 kAsExpression = 38, |
| 64 kStringLiteral = 39, |
| 65 kDoubleLiteral = 40, |
| 66 kTrueLiteral = 41, |
| 67 kFalseLiteral = 42, |
| 68 kNullLiteral = 43, |
| 69 kSymbolLiteral = 44, |
| 70 kTypeLiteral = 45, |
| 71 kThisExpression = 46, |
| 72 kRethrow = 47, |
| 73 kThrow = 48, |
| 74 kListLiteral = 49, |
| 75 kMapLiteral = 50, |
| 76 kAwaitExpression = 51, |
| 77 kFunctionExpression = 52, |
| 78 kLet = 53, |
| 79 |
| 80 kPositiveIntLiteral = 55, |
| 81 kNegativeIntLiteral = 56, |
| 82 kBigIntLiteral = 57, |
| 83 kConstListLiteral = 58, |
| 84 kConstMapLiteral = 59, |
| 85 |
| 86 kInvalidStatement = 60, |
| 87 kExpressionStatement = 61, |
| 88 kBlock = 62, |
| 89 kEmptyStatement = 63, |
| 90 kAssertStatement = 64, |
| 91 kLabeledStatement = 65, |
| 92 kBreakStatement = 66, |
| 93 kWhileStatement = 67, |
| 94 kDoStatement = 68, |
| 95 kForStatement = 69, |
| 96 kForInStatement = 70, |
| 97 kSwitchStatement = 71, |
| 98 kContinueSwitchStatement = 72, |
| 99 kIfStatement = 73, |
| 100 kReturnStatement = 74, |
| 101 kTryCatch = 75, |
| 102 kTryFinally = 76, |
| 103 kYieldStatement = 77, |
| 104 kVariableDeclaration = 78, |
| 105 kFunctionDeclaration = 79, |
| 106 kAsyncForInStatement = 80, |
| 107 |
| 108 kInvalidType = 90, |
| 109 kDynamicType = 91, |
| 110 kVoidType = 92, |
| 111 kInterfaceType = 93, |
| 112 kFunctionType = 94, |
| 113 kTypeParameterType = 95, |
| 114 kSimpleInterfaceType = 96, |
| 115 kSimpleFunctionType = 97, |
| 116 |
| 117 kSpecializedTagHighBit = 0x80, // 10000000 |
| 118 kSpecializedTagMask = 0xF8, // 11111000 |
| 119 kSpecializedPayloadMask = 0x7, // 00000111 |
| 120 |
| 121 kSpecializedVariableGet = 128, |
| 122 kSpecializedVariableSet = 136, |
| 123 kSpecialIntLiteral = 144, |
| 124 }; |
| 125 |
| 126 |
| 127 static const int SpecializedIntLiteralBias = 3; |
| 128 |
| 129 |
| 130 template <typename T> |
| 131 class BlockStack { |
| 132 public: |
| 133 BlockStack() : current_count_(0) {} |
| 134 |
| 135 void EnterScope() { |
| 136 variable_count_.Add(current_count_); |
| 137 current_count_ = 0; |
| 138 } |
| 139 |
| 140 void LeaveScope() { |
| 141 variables_.TruncateTo(variables_.length() - current_count_); |
| 142 current_count_ = variable_count_[variable_count_.length() - 1]; |
| 143 variable_count_.RemoveLast(); |
| 144 } |
| 145 |
| 146 T* Lookup(int index) { |
| 147 ASSERT(index < variables_.length()); |
| 148 return variables_[index]; |
| 149 } |
| 150 |
| 151 void Push(T* v) { |
| 152 variables_.Add(v); |
| 153 current_count_++; |
| 154 } |
| 155 |
| 156 void Push(List<T>* decl) { |
| 157 for (intptr_t i = 0; i < decl->length(); i++) { |
| 158 variables_.Add(decl[i]); |
| 159 current_count_++; |
| 160 } |
| 161 } |
| 162 |
| 163 void Pop(T* decl) { |
| 164 variables_.RemoveLast(); |
| 165 current_count_--; |
| 166 } |
| 167 |
| 168 void Pop(List<T>* decl) { |
| 169 variables_.TruncateTo(variables_.length() - decl->length()); |
| 170 current_count_ -= decl->length(); |
| 171 } |
| 172 |
| 173 private: |
| 174 int current_count_; |
| 175 MallocGrowableArray<T*> variables_; |
| 176 MallocGrowableArray<int> variable_count_; |
| 177 }; |
| 178 |
| 179 |
| 180 template <typename T> |
| 181 class BlockMap { |
| 182 public: |
| 183 BlockMap() : current_count_(0), stack_height_(0) {} |
| 184 |
| 185 void EnterScope() { |
| 186 variable_count_.Add(current_count_); |
| 187 current_count_ = 0; |
| 188 } |
| 189 |
| 190 void LeaveScope() { |
| 191 stack_height_ -= current_count_; |
| 192 current_count_ = variable_count_[variable_count_.length() - 1]; |
| 193 variable_count_.RemoveLast(); |
| 194 } |
| 195 |
| 196 int Lookup(T* object) { |
| 197 typename MallocMap<T, int>::Pair* result = variables_.LookupPair(object); |
| 198 ASSERT(result != NULL); |
| 199 if (result == NULL) FATAL("lookup failure"); |
| 200 return RawPointerKeyValueTrait<T, int>::ValueOf(*result); |
| 201 } |
| 202 |
| 203 void Push(T* v) { |
| 204 ASSERT(variables_.LookupPair(v) == NULL); |
| 205 int index = stack_height_++; |
| 206 variables_.Insert(v, index); |
| 207 current_count_++; |
| 208 } |
| 209 |
| 210 void Set(T* v, int index) { |
| 211 typename MallocMap<T, int>::Pair* entry = variables_.LookupPair(v); |
| 212 ASSERT(entry != NULL); |
| 213 entry->value = index; |
| 214 } |
| 215 |
| 216 void Push(List<T>* decl) { |
| 217 for (intptr_t i = 0; i < decl->length(); i++) { |
| 218 Push(decl[i]); |
| 219 } |
| 220 } |
| 221 |
| 222 void Pop(T* v) { |
| 223 current_count_--; |
| 224 stack_height_--; |
| 225 } |
| 226 |
| 227 private: |
| 228 int current_count_; |
| 229 int stack_height_; |
| 230 MallocMap<T, int> variables_; |
| 231 MallocGrowableArray<int> variable_count_; |
| 232 }; |
| 233 |
| 234 |
| 235 template <typename T> |
| 236 class VariableScope { |
| 237 public: |
| 238 explicit VariableScope(T* builder) : builder_(builder) { |
| 239 builder_->variables().EnterScope(); |
| 240 } |
| 241 ~VariableScope() { builder_->variables().LeaveScope(); } |
| 242 |
| 243 private: |
| 244 T* builder_; |
| 245 }; |
| 246 |
| 247 |
| 248 template <typename T> |
| 249 class TypeParameterScope { |
| 250 public: |
| 251 explicit TypeParameterScope(T* builder) : builder_(builder) { |
| 252 builder_->type_parameters().EnterScope(); |
| 253 } |
| 254 ~TypeParameterScope() { builder_->type_parameters().LeaveScope(); } |
| 255 |
| 256 private: |
| 257 T* builder_; |
| 258 }; |
| 259 |
| 260 |
| 261 template <typename T> |
| 262 class SwitchCaseScope { |
| 263 public: |
| 264 explicit SwitchCaseScope(T* builder) : builder_(builder) { |
| 265 builder_->switch_cases().EnterScope(); |
| 266 } |
| 267 ~SwitchCaseScope() { builder_->switch_cases().LeaveScope(); } |
| 268 |
| 269 private: |
| 270 T* builder_; |
| 271 }; |
| 272 |
| 273 |
| 274 // Unlike other scopes, labels from enclosing functions are not visible in |
| 275 // nested functions. The LabelScope class is used to hide outer labels. |
| 276 template <typename Builder, typename Block> |
| 277 class LabelScope { |
| 278 public: |
| 279 explicit LabelScope(Builder* builder) : builder_(builder) { |
| 280 outer_block_ = builder_->labels(); |
| 281 builder_->set_labels(&block_); |
| 282 } |
| 283 ~LabelScope() { builder_->set_labels(outer_block_); } |
| 284 |
| 285 private: |
| 286 Builder* builder_; |
| 287 Block block_; |
| 288 Block* outer_block_; |
| 289 }; |
| 290 |
| 291 |
| 292 class ReaderHelper { |
| 293 public: |
| 294 ReaderHelper() : program_(NULL), labels_(NULL) {} |
| 295 |
| 296 Program* program() { return program_; } |
| 297 void set_program(Program* program) { program_ = program; } |
| 298 |
| 299 BlockStack<VariableDeclaration>& variables() { return scope_; } |
| 300 BlockStack<TypeParameter>& type_parameters() { return type_parameters_; } |
| 301 BlockStack<SwitchCase>& switch_cases() { return switch_cases_; } |
| 302 |
| 303 BlockStack<LabeledStatement>* labels() { return labels_; } |
| 304 void set_labels(BlockStack<LabeledStatement>* labels) { labels_ = labels; } |
| 305 |
| 306 CanonicalName* GetCanonicalName(int index) { return canonical_names_[index]; } |
| 307 void SetCanonicalName(int index, CanonicalName* name) { |
| 308 canonical_names_[index] = name; |
| 309 } |
| 310 void SetCanonicalNameCount(int count) { canonical_names_.SetLength(count); } |
| 311 |
| 312 private: |
| 313 Program* program_; |
| 314 MallocGrowableArray<CanonicalName*> canonical_names_; |
| 315 BlockStack<VariableDeclaration> scope_; |
| 316 BlockStack<TypeParameter> type_parameters_; |
| 317 BlockStack<SwitchCase> switch_cases_; |
| 318 BlockStack<LabeledStatement>* labels_; |
| 319 }; |
| 320 |
| 321 |
| 322 class Reader { |
| 323 public: |
| 324 Reader(const uint8_t* buffer, intptr_t size) |
| 325 : buffer_(buffer), size_(size), offset_(0) {} |
| 326 |
| 327 uint32_t ReadUInt32() { |
| 328 ASSERT(offset_ + 4 <= size_); |
| 329 |
| 330 uint32_t value = (buffer_[offset_ + 0] << 24) | |
| 331 (buffer_[offset_ + 1] << 16) | |
| 332 (buffer_[offset_ + 2] << 8) | (buffer_[offset_ + 3] << 0); |
| 333 offset_ += 4; |
| 334 return value; |
| 335 } |
| 336 |
| 337 uint32_t ReadUInt() { |
| 338 ASSERT(offset_ + 1 <= size_); |
| 339 uint8_t byte0 = buffer_[offset_]; |
| 340 if ((byte0 & 0x80) == 0) { |
| 341 // 0... |
| 342 offset_++; |
| 343 return byte0; |
| 344 } else if ((byte0 & 0xc0) == 0x80) { |
| 345 // 10... |
| 346 ASSERT(offset_ + 2 <= size_); |
| 347 uint32_t value = ((byte0 & ~0x80) << 8) | (buffer_[offset_ + 1]); |
| 348 offset_ += 2; |
| 349 return value; |
| 350 } else { |
| 351 // 11... |
| 352 ASSERT(offset_ + 4 <= size_); |
| 353 uint32_t value = ((byte0 & ~0xc0) << 24) | (buffer_[offset_ + 1] << 16) | |
| 354 (buffer_[offset_ + 2] << 8) | |
| 355 (buffer_[offset_ + 3] << 0); |
| 356 offset_ += 4; |
| 357 return value; |
| 358 } |
| 359 } |
| 360 |
| 361 void add_token_position( |
| 362 MallocGrowableArray<MallocGrowableArray<intptr_t>*>* list, |
| 363 TokenPosition position) { |
| 364 intptr_t size = list->length(); |
| 365 while (size <= current_script_id_) { |
| 366 MallocGrowableArray<intptr_t>* tmp = new MallocGrowableArray<intptr_t>(); |
| 367 list->Add(tmp); |
| 368 size = list->length(); |
| 369 } |
| 370 list->At(current_script_id_)->Add(position.value()); |
| 371 } |
| 372 |
| 373 void record_token_position(TokenPosition position) { |
| 374 if (position.IsReal() && helper()->program() != NULL) { |
| 375 add_token_position(&helper()->program()->valid_token_positions, position); |
| 376 } |
| 377 } |
| 378 |
| 379 void record_yield_token_position(TokenPosition position) { |
| 380 if (helper()->program() != NULL) { |
| 381 add_token_position(&helper()->program()->yield_token_positions, position); |
| 382 } |
| 383 } |
| 384 |
| 385 /** |
| 386 * Read and return a TokenPosition from this reader. |
| 387 * @param record specifies whether or not the read position is saved as a |
| 388 * valid token position in the current script. |
| 389 * If not be sure to record it later by calling record_token_position (after |
| 390 * setting the correct current_script_id). |
| 391 */ |
| 392 TokenPosition ReadPosition(bool record = true) { |
| 393 // Position is saved as unsigned, |
| 394 // but actually ranges from -1 and up (thus the -1) |
| 395 intptr_t value = ReadUInt() - 1; |
| 396 TokenPosition result = TokenPosition(value); |
| 397 max_position_ = Utils::Maximum(max_position_, result); |
| 398 if (min_position_.IsNoSource()) { |
| 399 min_position_ = result; |
| 400 } else if (result.IsReal()) { |
| 401 min_position_ = Utils::Minimum(min_position_, result); |
| 402 } |
| 403 |
| 404 if (record) { |
| 405 record_token_position(result); |
| 406 } |
| 407 return result; |
| 408 } |
| 409 |
| 410 intptr_t ReadListLength() { return ReadUInt(); } |
| 411 |
| 412 uint8_t ReadByte() { return buffer_[offset_++]; } |
| 413 |
| 414 bool ReadBool() { return (ReadByte() & 1) == 1; } |
| 415 |
| 416 word ReadFlags() { return ReadByte(); } |
| 417 |
| 418 Tag ReadTag(uint8_t* payload = NULL) { |
| 419 uint8_t byte = ReadByte(); |
| 420 bool has_payload = (byte & kSpecializedTagHighBit) != 0; |
| 421 if (has_payload) { |
| 422 if (payload != NULL) { |
| 423 *payload = byte & kSpecializedPayloadMask; |
| 424 } |
| 425 return static_cast<Tag>(byte & kSpecializedTagMask); |
| 426 } else { |
| 427 return static_cast<Tag>(byte); |
| 428 } |
| 429 } |
| 430 |
| 431 const uint8_t* Consume(int count) { |
| 432 ASSERT(offset_ + count <= size_); |
| 433 const uint8_t* old = buffer_ + offset_; |
| 434 offset_ += count; |
| 435 return old; |
| 436 } |
| 437 |
| 438 void EnsureEnd() { |
| 439 if (offset_ != size_) { |
| 440 FATAL2( |
| 441 "Reading Kernel file: Expected to be at EOF " |
| 442 "(offset: %" Pd ", size: %" Pd ")", |
| 443 offset_, size_); |
| 444 } |
| 445 } |
| 446 |
| 447 void DumpOffset(const char* str) { |
| 448 OS::PrintErr("@%" Pd " %s\n", offset_, str); |
| 449 } |
| 450 |
| 451 // The largest position read yet (since last reset). |
| 452 // This is automatically updated when calling ReadPosition, |
| 453 // but can be overwritten (e.g. via the PositionScope class). |
| 454 TokenPosition max_position() { return max_position_; } |
| 455 // The smallest position read yet (since last reset). |
| 456 // This is automatically updated when calling ReadPosition, |
| 457 // but can be overwritten (e.g. via the PositionScope class). |
| 458 TokenPosition min_position() { return min_position_; } |
| 459 // The current script id for what we are currently processing. |
| 460 // Note though that this is only a convenience helper and has to be set |
| 461 // manually. |
| 462 intptr_t current_script_id() { return current_script_id_; } |
| 463 void set_current_script_id(intptr_t script_id) { |
| 464 current_script_id_ = script_id; |
| 465 } |
| 466 |
| 467 template <typename T, typename RT> |
| 468 T* ReadOptional() { |
| 469 Tag tag = ReadTag(); |
| 470 if (tag == kNothing) { |
| 471 return NULL; |
| 472 } |
| 473 ASSERT(tag == kSomething); |
| 474 return RT::ReadFrom(this); |
| 475 } |
| 476 |
| 477 template <typename T> |
| 478 T* ReadOptional() { |
| 479 return ReadOptional<T, T>(); |
| 480 } |
| 481 |
| 482 ReaderHelper* helper() { return &builder_; } |
| 483 |
| 484 CanonicalName* ReadCanonicalNameReference() { |
| 485 int index = ReadUInt(); |
| 486 if (index == 0) return NULL; |
| 487 CanonicalName* name = builder_.GetCanonicalName(index - 1); |
| 488 ASSERT(name != NULL); |
| 489 return name; |
| 490 } |
| 491 |
| 492 intptr_t offset() { return offset_; } |
| 493 void set_offset(intptr_t offset) { offset_ = offset; } |
| 494 intptr_t size() { return size_; } |
| 495 |
| 496 const uint8_t* buffer() { return buffer_; } |
| 497 |
| 498 private: |
| 499 const uint8_t* buffer_; |
| 500 intptr_t size_; |
| 501 intptr_t offset_; |
| 502 ReaderHelper builder_; |
| 503 TokenPosition max_position_; |
| 504 TokenPosition min_position_; |
| 505 intptr_t current_script_id_; |
| 506 |
| 507 friend class PositionScope; |
| 508 }; |
| 509 |
| 510 |
| 511 // A helper class that resets the readers min and max positions both upon |
| 512 // initialization and upon destruction, i.e. when created the min an max |
| 513 // positions will be reset to "noSource", when destructing the min and max will |
| 514 // be reset to have they value they would have had, if they hadn't been reset in |
| 515 // the first place. |
| 516 class PositionScope { |
| 517 public: |
| 518 explicit PositionScope(Reader* reader) |
| 519 : reader_(reader), |
| 520 min_(reader->min_position_), |
| 521 max_(reader->max_position_) { |
| 522 reader->min_position_ = reader->max_position_ = TokenPosition::kNoSource; |
| 523 } |
| 524 |
| 525 ~PositionScope() { |
| 526 if (reader_->min_position_.IsNoSource()) { |
| 527 reader_->min_position_ = min_; |
| 528 } else if (min_.IsReal()) { |
| 529 reader_->min_position_ = Utils::Minimum(reader_->min_position_, min_); |
| 530 } |
| 531 reader_->max_position_ = Utils::Maximum(reader_->max_position_, max_); |
| 532 } |
| 533 |
| 534 private: |
| 535 Reader* reader_; |
| 536 TokenPosition min_; |
| 537 TokenPosition max_; |
| 538 }; |
| 539 |
| 540 } // namespace kernel |
| 541 } // namespace dart |
| 542 |
| 543 #endif // !defined(DART_PRECOMPILED_RUNTIME) |
| 544 #endif // RUNTIME_VM_KERNEL_BINARY_H_ |
OLD | NEW |