1 // Copyright 2017 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/parsing/preparsed-scope-data.h" 6 7 #include "src/ast/scopes.h" 8 #include "src/ast/variables.h" 9 #include "src/handles.h" 10 #include "src/objects-inl.h" 11 #include "src/objects/shared-function-info.h" 12 #include "src/parsing/preparser.h" 13 14 namespace v8 { 15 namespace internal { 16 17 namespace { 18 19 class ScopeCallsSloppyEvalField : public BitField<bool, 0, 1> {}; 20 class InnerScopeCallsEvalField 21 : public BitField<bool, ScopeCallsSloppyEvalField::kNext, 1> {}; 22 23 class VariableMaybeAssignedField : public BitField8<bool, 0, 1> {}; 24 class VariableContextAllocatedField 25 : public BitField8<bool, VariableMaybeAssignedField::kNext, 1> {}; 26 27 28 #ifdef DEBUG 29 const int kMagicValue = 0xC0DE0DE; 30 31 const size_t kUint32Size = 5; 32 const size_t kUint8Size = 2; 33 const size_t kQuarterMarker = 0; 34 const size_t kPlaceholderSize = kUint32Size; 35 #else 36 const size_t kUint32Size = 4; 37 const size_t kUint8Size = 1; 38 const size_t kPlaceholderSize = 0; 39 #endif 40 41 const size_t kSkippableFunctionDataSize = 4 * kUint32Size + 1 * kUint8Size; 42 43 class LanguageField : public BitField8<LanguageMode, 0, 1> {}; 44 class UsesSuperField : public BitField8<bool, LanguageField::kNext, 1> {}; 45 STATIC_ASSERT(LanguageModeSize <= LanguageField::kNumValues); 46 47 } // namespace 48 49 /* 50 51 Internal data format for the backing store of ProducedPreparsedScopeData and 52 PreParsedScopeData::scope_data (on the heap): 53 54 (Skippable function data:) 55 ------------------------------------ 56 | scope_data_start (debug only) | 57 ------------------------------------ 58 | data for inner function 1 | 59 | ... | 60 ------------------------------------ 61 | data for inner function n | 62 | ... | 63 ------------------------------------ 64 (Scope allocation data:) << scope_data_start points here in debug 65 ------------------------------------ 66 magic value (debug only) 67 ------------------------------------ 68 scope positions (debug only) 69 ------------------------------------ 70 | scope type << only in debug | 71 | eval | 72 | ---------------------- | 73 | | data for variables | | 74 | | ... | | 75 | ---------------------- | 76 ------------------------------------ 77 ------------------------------------ 78 | data for inner scope 1 | << but not for function scopes 79 | ... | 80 ------------------------------------ 81 ... 82 ------------------------------------ 83 | data for inner scope m | 84 | ... | 85 ------------------------------------ 86 87 PreParsedScopeData::child_data is an array of PreParsedScopeData objects, one 88 for each skippable inner function. 89 90 ConsumedPreParsedScopeData wraps a PreParsedScopeData and reads data from it. 91 92 */ 93 94 void ProducedPreParsedScopeData::ByteData::WriteUint32(uint32_t data) { 95 #ifdef DEBUG 96 // Save expected item size in debug mode. 97 backing_store_.push_back(kUint32Size); 98 #endif 99 const uint8_t* d = reinterpret_cast<uint8_t*>(&data); 100 for (int i = 0; i < 4; ++i) { 101 backing_store_.push_back(*d++); 102 } 103 free_quarters_in_last_byte_ = 0; 104 } 105 106 #ifdef DEBUG 107 void ProducedPreParsedScopeData::ByteData::OverwriteFirstUint32(uint32_t data) { 108 auto it = backing_store_.begin(); 109 // Check that that position already holds an item of the expected size. 110 DCHECK_GE(backing_store_.size(), kUint32Size); 111 DCHECK_EQ(*it, kUint32Size); 112 ++it; 113 const uint8_t* d = reinterpret_cast<uint8_t*>(&data); 114 for (size_t i = 0; i < 4; ++i) { 115 *it++ = *d++; 116 } 117 } 118 #endif 119 120 void ProducedPreParsedScopeData::ByteData::WriteUint8(uint8_t data) { 121 #ifdef DEBUG 122 // Save expected item size in debug mode. 123 backing_store_.push_back(kUint8Size); 124 #endif 125 backing_store_.push_back(data); 126 free_quarters_in_last_byte_ = 0; 127 } 128 129 void ProducedPreParsedScopeData::ByteData::WriteQuarter(uint8_t data) { 130 DCHECK_LE(data, 3); 131 if (free_quarters_in_last_byte_ == 0) { 132 #ifdef DEBUG 133 // Save a marker in debug mode. 134 backing_store_.push_back(kQuarterMarker); 135 #endif 136 backing_store_.push_back(0); 137 free_quarters_in_last_byte_ = 3; 138 } else { 139 --free_quarters_in_last_byte_; 140 } 141 142 uint8_t shift_amount = free_quarters_in_last_byte_ * 2; 143 DCHECK_EQ(backing_store_.back() & (3 << shift_amount), 0); 144 backing_store_.back() |= (data << shift_amount); 145 } 146 147 Handle<PodArray<uint8_t>> ProducedPreParsedScopeData::ByteData::Serialize( 148 Isolate* isolate) { 149 Handle<PodArray<uint8_t>> array = PodArray<uint8_t>::New( 150 isolate, static_cast<int>(backing_store_.size()), TENURED); 151 152 DisallowHeapAllocation no_gc; 153 PodArray<uint8_t>* raw_array = *array; 154 155 int i = 0; 156 for (uint8_t item : backing_store_) { 157 raw_array->set(i++, item); 158 } 159 return array; 160 } 161 162 ProducedPreParsedScopeData::ProducedPreParsedScopeData( 163 Zone* zone, ProducedPreParsedScopeData* parent) 164 : parent_(parent), 165 byte_data_(new (zone) ByteData(zone)), 166 data_for_inner_functions_(zone), 167 bailed_out_(false) { 168 if (parent != nullptr) { 169 parent->data_for_inner_functions_.push_back(this); 170 } 171 #ifdef DEBUG 172 // Reserve space for scope_data_start, written later: 173 byte_data_->WriteUint32(0); 174 #endif 175 } 176 177 // Create a ProducedPreParsedScopeData which is just a proxy for a previous 178 // produced PreParsedScopeData. 179 ProducedPreParsedScopeData::ProducedPreParsedScopeData( 180 Handle<PreParsedScopeData> data, Zone* zone) 181 : parent_(nullptr), 182 byte_data_(nullptr), 183 data_for_inner_functions_(zone), 184 bailed_out_(false), 185 previously_produced_preparsed_scope_data_(data) {} 186 187 ProducedPreParsedScopeData::DataGatheringScope::DataGatheringScope( 188 DeclarationScope* function_scope, PreParser* preparser) 189 : function_scope_(function_scope), 190 preparser_(preparser), 191 produced_preparsed_scope_data_(nullptr) { 192 if (FLAG_preparser_scope_analysis) { 193 ProducedPreParsedScopeData* parent = 194 preparser->produced_preparsed_scope_data(); 195 Zone* main_zone = preparser->main_zone(); 196 produced_preparsed_scope_data_ = 197 new (main_zone) ProducedPreParsedScopeData(main_zone, parent); 198 preparser->set_produced_preparsed_scope_data( 199 produced_preparsed_scope_data_); 200 function_scope->set_produced_preparsed_scope_data( 201 produced_preparsed_scope_data_); 202 } 203 } 204 205 ProducedPreParsedScopeData::DataGatheringScope::~DataGatheringScope() { 206 if (FLAG_preparser_scope_analysis) { 207 preparser_->set_produced_preparsed_scope_data( 208 produced_preparsed_scope_data_->parent_); 209 } 210 } 211 212 void ProducedPreParsedScopeData::DataGatheringScope::MarkFunctionAsSkippable( 213 int end_position, int num_inner_functions) { 214 DCHECK(FLAG_preparser_scope_analysis); 215 DCHECK_NOT_NULL(produced_preparsed_scope_data_); 216 DCHECK_NOT_NULL(produced_preparsed_scope_data_->parent_); 217 produced_preparsed_scope_data_->parent_->AddSkippableFunction( 218 function_scope_->start_position(), end_position, 219 function_scope_->num_parameters(), num_inner_functions, 220 function_scope_->language_mode(), function_scope_->NeedsHomeObject()); 221 } 222 223 void ProducedPreParsedScopeData::AddSkippableFunction( 224 int start_position, int end_position, int num_parameters, 225 int num_inner_functions, LanguageMode language_mode, 226 bool uses_super_property) { 227 DCHECK(FLAG_preparser_scope_analysis); 228 DCHECK(previously_produced_preparsed_scope_data_.is_null()); 229 230 if (bailed_out_) { 231 return; 232 } 233 234 // Start position is used for a sanity check when consuming the data, we could 235 // remove it in the future if we're very pressed for space but it's been good 236 // at catching bugs in the wild so far. 237 byte_data_->WriteUint32(start_position); 238 byte_data_->WriteUint32(end_position); 239 byte_data_->WriteUint32(num_parameters); 240 byte_data_->WriteUint32(num_inner_functions); 241 242 uint8_t language_and_super = LanguageField::encode(language_mode) | 243 UsesSuperField::encode(uses_super_property); 244 245 byte_data_->WriteQuarter(language_and_super); 246 } 247 248 void ProducedPreParsedScopeData::SaveScopeAllocationData( 249 DeclarationScope* scope) { 250 DCHECK(FLAG_preparser_scope_analysis); 251 DCHECK(previously_produced_preparsed_scope_data_.is_null()); 252 // The data contains a uint32 (reserved space for scope_data_start) and 253 // function data items, kSkippableFunctionDataSize each. 254 DCHECK_GE(byte_data_->size(), kPlaceholderSize); 255 DCHECK_LE(byte_data_->size(), std::numeric_limits<uint32_t>::max()); 256 DCHECK_EQ(byte_data_->size() % kSkippableFunctionDataSize, kPlaceholderSize); 257 258 if (bailed_out_) { 259 return; 260 } 261 262 uint32_t scope_data_start = static_cast<uint32_t>(byte_data_->size()); 263 264 // If there are no skippable inner functions, we don't need to save anything. 265 if (scope_data_start == kPlaceholderSize) { 266 return; 267 } 268 269 #ifdef DEBUG 270 byte_data_->OverwriteFirstUint32(scope_data_start); 271 272 // For a data integrity check, write a value between data about skipped inner 273 // funcs and data about variables. 274 byte_data_->WriteUint32(kMagicValue); 275 byte_data_->WriteUint32(scope->start_position()); 276 byte_data_->WriteUint32(scope->end_position()); 277 #endif 278 279 SaveDataForScope(scope); 280 } 281 282 bool ProducedPreParsedScopeData::ContainsInnerFunctions() const { 283 return byte_data_->size() > kPlaceholderSize; 284 } 285 286 MaybeHandle<PreParsedScopeData> ProducedPreParsedScopeData::Serialize( 287 Isolate* isolate) { 288 if (!previously_produced_preparsed_scope_data_.is_null()) { 289 DCHECK(!bailed_out_); 290 DCHECK_EQ(data_for_inner_functions_.size(), 0); 291 return previously_produced_preparsed_scope_data_; 292 } 293 if (bailed_out_) { 294 return MaybeHandle<PreParsedScopeData>(); 295 } 296 297 DCHECK(!ThisOrParentBailedOut()); 298 299 if (byte_data_->size() <= kPlaceholderSize) { 300 // The data contains only the placeholder. 301 return MaybeHandle<PreParsedScopeData>(); 302 } 303 304 int child_data_length = static_cast<int>(data_for_inner_functions_.size()); 305 Handle<PreParsedScopeData> data = 306 isolate->factory()->NewPreParsedScopeData(child_data_length); 307 308 Handle<PodArray<uint8_t>> scope_data_array = byte_data_->Serialize(isolate); 309 data->set_scope_data(*scope_data_array); 310 311 int i = 0; 312 for (const auto& item : data_for_inner_functions_) { 313 Handle<PreParsedScopeData> child_data; 314 if (item->Serialize(isolate).ToHandle(&child_data)) { 315 data->set_child_data(i, *child_data); 316 } else { 317 DCHECK(data->child_data(i)->IsNull()); 318 } 319 i++; 320 } 321 322 return data; 323 } 324 325 bool ProducedPreParsedScopeData::ScopeNeedsData(Scope* scope) { 326 if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) { 327 // Default constructors don't need data (they cannot contain inner functions 328 // defined by the user). Other functions do. 329 return !IsDefaultConstructor(scope->AsDeclarationScope()->function_kind()); 330 } 331 if (!scope->is_hidden()) { 332 for (Variable* var : *scope->locals()) { 333 if (IsDeclaredVariableMode(var->mode())) { 334 return true; 335 } 336 } 337 } 338 for (Scope* inner = scope->inner_scope(); inner != nullptr; 339 inner = inner->sibling()) { 340 if (ScopeNeedsData(inner)) { 341 return true; 342 } 343 } 344 return false; 345 } 346 347 bool ProducedPreParsedScopeData::ScopeIsSkippableFunctionScope(Scope* scope) { 348 // Lazy non-arrow function scopes are skippable. Lazy functions are exactly 349 // those Scopes which have their own ProducedPreParsedScopeData object. This 350 // logic ensures that the scope allocation data is consistent with the 351 // skippable function data (both agree on where the lazy function boundaries 352 // are). 353 if (scope->scope_type() != ScopeType::FUNCTION_SCOPE) { 354 return false; 355 } 356 DeclarationScope* declaration_scope = scope->AsDeclarationScope(); 357 return !declaration_scope->is_arrow_scope() && 358 declaration_scope->produced_preparsed_scope_data() != nullptr; 359 } 360 361 void ProducedPreParsedScopeData::SaveDataForScope(Scope* scope) { 362 DCHECK_NE(scope->end_position(), kNoSourcePosition); 363 364 if (!ScopeNeedsData(scope)) { 365 return; 366 } 367 368 #ifdef DEBUG 369 byte_data_->WriteUint8(scope->scope_type()); 370 #endif 371 372 uint8_t eval = 373 ScopeCallsSloppyEvalField::encode( 374 scope->is_declaration_scope() && 375 scope->AsDeclarationScope()->calls_sloppy_eval()) | 376 InnerScopeCallsEvalField::encode(scope->inner_scope_calls_eval()); 377 byte_data_->WriteUint8(eval); 378 379 if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) { 380 Variable* function = scope->AsDeclarationScope()->function_var(); 381 if (function != nullptr) { 382 SaveDataForVariable(function); 383 } 384 } 385 386 for (Variable* var : *scope->locals()) { 387 if (IsDeclaredVariableMode(var->mode())) { 388 SaveDataForVariable(var); 389 } 390 } 391 392 SaveDataForInnerScopes(scope); 393 } 394 395 void ProducedPreParsedScopeData::SaveDataForVariable(Variable* var) { 396 #ifdef DEBUG 397 // Store the variable name in debug mode; this way we can check that we 398 // restore data to the correct variable. 399 const AstRawString* name = var->raw_name(); 400 byte_data_->WriteUint8(name->is_one_byte()); 401 byte_data_->WriteUint32(name->length()); 402 for (int i = 0; i < name->length(); ++i) { 403 byte_data_->WriteUint8(name->raw_data()[i]); 404 } 405 #endif 406 byte variable_data = VariableMaybeAssignedField::encode( 407 var->maybe_assigned() == kMaybeAssigned) | 408 VariableContextAllocatedField::encode( 409 var->has_forced_context_allocation()); 410 byte_data_->WriteQuarter(variable_data); 411 } 412 413 void ProducedPreParsedScopeData::SaveDataForInnerScopes(Scope* scope) { 414 // Inner scopes are stored in the reverse order, but we'd like to write the 415 // data in the logical order. There might be many inner scopes, so we don't 416 // want to recurse here. 417 std::vector<Scope*> scopes; 418 for (Scope* inner = scope->inner_scope(); inner != nullptr; 419 inner = inner->sibling()) { 420 if (ScopeIsSkippableFunctionScope(inner)) { 421 // Don't save data about function scopes, since they'll have their own 422 // ProducedPreParsedScopeData where their data is saved. 423 DCHECK_NOT_NULL( 424 inner->AsDeclarationScope()->produced_preparsed_scope_data()); 425 continue; 426 } 427 scopes.push_back(inner); 428 } 429 for (auto it = scopes.rbegin(); it != scopes.rend(); ++it) { 430 SaveDataForScope(*it); 431 } 432 } 433 434 ConsumedPreParsedScopeData::ByteData::ReadingScope::ReadingScope( 435 ConsumedPreParsedScopeData* parent) 436 : ReadingScope(parent->scope_data_.get(), parent->data_->scope_data()) {} 437 438 int32_t ConsumedPreParsedScopeData::ByteData::ReadUint32() { 439 DCHECK_NOT_NULL(data_); 440 DCHECK_GE(RemainingBytes(), kUint32Size); 441 #ifdef DEBUG 442 // Check that there indeed is an integer following. 443 DCHECK_EQ(data_->get(index_++), kUint32Size); 444 #endif 445 int32_t result = 0; 446 byte* p = reinterpret_cast<byte*>(&result); 447 for (int i = 0; i < 4; ++i) { 448 *p++ = data_->get(index_++); 449 } 450 stored_quarters_ = 0; 451 return result; 452 } 453 454 uint8_t ConsumedPreParsedScopeData::ByteData::ReadUint8() { 455 DCHECK_NOT_NULL(data_); 456 DCHECK_GE(RemainingBytes(), kUint8Size); 457 #ifdef DEBUG 458 // Check that there indeed is a byte following. 459 DCHECK_EQ(data_->get(index_++), kUint8Size); 460 #endif 461 stored_quarters_ = 0; 462 return data_->get(index_++); 463 } 464 465 uint8_t ConsumedPreParsedScopeData::ByteData::ReadQuarter() { 466 DCHECK_NOT_NULL(data_); 467 if (stored_quarters_ == 0) { 468 DCHECK_GE(RemainingBytes(), kUint8Size); 469 #ifdef DEBUG 470 // Check that there indeed are quarters following. 471 DCHECK_EQ(data_->get(index_++), kQuarterMarker); 472 #endif 473 stored_byte_ = data_->get(index_++); 474 stored_quarters_ = 4; 475 } 476 // Read the first 2 bits from stored_byte_. 477 uint8_t result = (stored_byte_ >> 6) & 3; 478 DCHECK_LE(result, 3); 479 --stored_quarters_; 480 stored_byte_ <<= 2; 481 return result; 482 } 483 484 size_t ConsumedPreParsedScopeData::ByteData::RemainingBytes() const { 485 DCHECK_NOT_NULL(data_); 486 return data_->length() - index_; 487 } 488 489 ConsumedPreParsedScopeData::ConsumedPreParsedScopeData() 490 : isolate_(nullptr), scope_data_(new ByteData()), child_index_(0) {} 491 492 ConsumedPreParsedScopeData::~ConsumedPreParsedScopeData() {} 493 494 void ConsumedPreParsedScopeData::SetData(Isolate* isolate, 495 Handle<PreParsedScopeData> data) { 496 DCHECK_NOT_NULL(isolate); 497 DCHECK(data->IsPreParsedScopeData()); 498 isolate_ = isolate; 499 data_ = data; 500 #ifdef DEBUG 501 ByteData::ReadingScope reading_scope(this); 502 int scope_data_start = scope_data_->ReadUint32(); 503 scope_data_->SetPosition(scope_data_start); 504 DCHECK_EQ(scope_data_->ReadUint32(), kMagicValue); 505 // The first data item is scope_data_start. Skip over it. 506 scope_data_->SetPosition(kPlaceholderSize); 507 #endif 508 } 509 510 ProducedPreParsedScopeData* 511 ConsumedPreParsedScopeData::GetDataForSkippableFunction( 512 Zone* zone, int start_position, int* end_position, int* num_parameters, 513 int* num_inner_functions, bool* uses_super_property, 514 LanguageMode* language_mode) { 515 // The skippable function *must* be the next function in the data. Use the 516 // start position as a sanity check. 517 ByteData::ReadingScope reading_scope(this); 518 CHECK_GE(scope_data_->RemainingBytes(), kSkippableFunctionDataSize); 519 int start_position_from_data = scope_data_->ReadUint32(); 520 CHECK_EQ(start_position, start_position_from_data); 521 522 *end_position = scope_data_->ReadUint32(); 523 DCHECK_GT(*end_position, start_position); 524 *num_parameters = scope_data_->ReadUint32(); 525 *num_inner_functions = scope_data_->ReadUint32(); 526 527 uint8_t language_and_super = scope_data_->ReadQuarter(); 528 *language_mode = LanguageMode(LanguageField::decode(language_and_super)); 529 *uses_super_property = UsesSuperField::decode(language_and_super); 530 531 // Retrieve the corresponding PreParsedScopeData and associate it to the 532 // skipped function. If the skipped functions contains inner functions, those 533 // can be skipped when the skipped function is eagerly parsed. 534 CHECK_GT(data_->length(), child_index_); 535 Object* child_data = data_->child_data(child_index_++); 536 if (!child_data->IsPreParsedScopeData()) { 537 return nullptr; 538 } 539 Handle<PreParsedScopeData> child_data_handle( 540 PreParsedScopeData::cast(child_data), isolate_); 541 return new (zone) ProducedPreParsedScopeData(child_data_handle, zone); 542 } 543 544 void ConsumedPreParsedScopeData::RestoreScopeAllocationData( 545 DeclarationScope* scope) { 546 DCHECK(FLAG_preparser_scope_analysis); 547 DCHECK_EQ(scope->scope_type(), ScopeType::FUNCTION_SCOPE); 548 DCHECK(!data_.is_null()); 549 550 ByteData::ReadingScope reading_scope(this); 551 552 #ifdef DEBUG 553 int magic_value_from_data = scope_data_->ReadUint32(); 554 // Check that we've consumed all inner function data. 555 DCHECK_EQ(magic_value_from_data, kMagicValue); 556 557 int start_position_from_data = scope_data_->ReadUint32(); 558 int end_position_from_data = scope_data_->ReadUint32(); 559 DCHECK_EQ(start_position_from_data, scope->start_position()); 560 DCHECK_EQ(end_position_from_data, scope->end_position()); 561 #endif 562 563 RestoreData(scope); 564 565 // Check that we consumed all scope data. 566 DCHECK_EQ(scope_data_->RemainingBytes(), 0); 567 } 568 569 void ConsumedPreParsedScopeData::RestoreData(Scope* scope) { 570 if (scope->is_declaration_scope() && 571 scope->AsDeclarationScope()->is_skipped_function()) { 572 return; 573 } 574 575 // It's possible that scope is not present in the data at all (since PreParser 576 // doesn't create the corresponding scope). In this case, the Scope won't 577 // contain any variables for which we need the data. 578 if (!ProducedPreParsedScopeData::ScopeNeedsData(scope)) { 579 return; 580 } 581 582 if (scope_data_->RemainingBytes() < kUint8Size) { 583 // Temporary debugging code for detecting inconsistent data. Write debug 584 // information on the stack, then crash. 585 isolate_->PushStackTraceAndDie(); 586 } 587 588 // scope_type is stored only in debug mode. 589 CHECK_GE(scope_data_->RemainingBytes(), kUint8Size); 590 DCHECK_EQ(scope_data_->ReadUint8(), scope->scope_type()); 591 592 uint32_t eval = scope_data_->ReadUint8(); 593 if (ScopeCallsSloppyEvalField::decode(eval)) { 594 scope->RecordEvalCall(); 595 } 596 if (InnerScopeCallsEvalField::decode(eval)) { 597 scope->RecordInnerScopeEvalCall(); 598 } 599 600 if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) { 601 Variable* function = scope->AsDeclarationScope()->function_var(); 602 if (function != nullptr) { 603 RestoreDataForVariable(function); 604 } 605 } 606 607 for (Variable* var : *scope->locals()) { 608 if (IsDeclaredVariableMode(var->mode())) { 609 RestoreDataForVariable(var); 610 } 611 } 612 613 RestoreDataForInnerScopes(scope); 614 } 615 616 void ConsumedPreParsedScopeData::RestoreDataForVariable(Variable* var) { 617 #ifdef DEBUG 618 const AstRawString* name = var->raw_name(); 619 bool data_one_byte = scope_data_->ReadUint8(); 620 DCHECK_IMPLIES(name->is_one_byte(), data_one_byte); 621 DCHECK_EQ(scope_data_->ReadUint32(), static_cast<uint32_t>(name->length())); 622 if (!name->is_one_byte() && data_one_byte) { 623 // It's possible that "name" is a two-byte representation of the string 624 // stored in the data. 625 for (int i = 0; i < 2 * name->length(); i += 2) { 626 #if defined(V8_TARGET_LITTLE_ENDIAN) 627 DCHECK_EQ(scope_data_->ReadUint8(), name->raw_data()[i]); 628 DCHECK_EQ(0, name->raw_data()[i + 1]); 629 #else 630 DCHECK_EQ(scope_data_->ReadUint8(), name->raw_data()[i + 1]); 631 DCHECK_EQ(0, name->raw_data()[i]); 632 #endif // V8_TARGET_LITTLE_ENDIAN 633 } 634 } else { 635 for (int i = 0; i < name->length(); ++i) { 636 DCHECK_EQ(scope_data_->ReadUint8(), name->raw_data()[i]); 637 } 638 } 639 #endif 640 uint8_t variable_data = scope_data_->ReadQuarter(); 641 if (VariableMaybeAssignedField::decode(variable_data)) { 642 var->set_maybe_assigned(); 643 } 644 if (VariableContextAllocatedField::decode(variable_data)) { 645 var->set_is_used(); 646 var->ForceContextAllocation(); 647 } 648 } 649 650 void ConsumedPreParsedScopeData::RestoreDataForInnerScopes(Scope* scope) { 651 std::vector<Scope*> scopes; 652 for (Scope* inner = scope->inner_scope(); inner != nullptr; 653 inner = inner->sibling()) { 654 scopes.push_back(inner); 655 } 656 for (auto it = scopes.rbegin(); it != scopes.rend(); ++it) { 657 RestoreData(*it); 658 } 659 } 660 661 } // namespace internal 662 } // namespace v8 663