LCOV - code coverage report
Current view: top level - src/parsing - preparsed-scope-data.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 114 116 98.3 %
Date: 2017-04-26 Functions: 14 15 93.3 %

          Line data    Source code
       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             : 
      12             : namespace v8 {
      13             : namespace internal {
      14             : 
      15             : namespace {
      16             : 
      17             : class VariableIsUsedField : public BitField16<bool, 0, 1> {};
      18             : class VariableMaybeAssignedField
      19             :     : public BitField16<bool, VariableIsUsedField::kNext, 1> {};
      20             : class VariableContextAllocatedField
      21             :     : public BitField16<bool, VariableMaybeAssignedField::kNext, 1> {};
      22             : 
      23             : const int kFunctionDataSize = 8;
      24             : 
      25             : }  // namespace
      26             : 
      27             : /*
      28             : 
      29             :   Internal data format for the backing store:
      30             : 
      31             :   ------------------------------------
      32             :   | scope type << only in debug      |
      33             :   | inner_scope_calls_eval_          |
      34             :   | data end index                   |
      35             :   | ----------------------           |
      36             :   | | data for variables |           |
      37             :   | | ...                |           |
      38             :   | ----------------------           |
      39             :   ------------------------------------
      40             :   ------------------------------------
      41             :   | data for inner scope_1           |
      42             :   | ...                              |
      43             :   ------------------------------------
      44             :   ...
      45             :   ------------------------------------
      46             :   | data for inner scope_n           |
      47             :   | ...                              |
      48             :   ------------------------------------
      49             :   << data end index points here
      50             :  */
      51             : 
      52       65460 : void PreParsedScopeData::SaveData(Scope* scope) {
      53             :   DCHECK(!has_data_);
      54             : 
      55       71501 :   if (scope->scope_type() == ScopeType::FUNCTION_SCOPE &&
      56       31498 :       !scope->AsDeclarationScope()->is_arrow_scope()) {
      57             :     // This cast is OK since we're not going to have more than 2^32 elements in
      58             :     // the data. FIXME(marja): Implement limits for the data size.
      59       50914 :     function_data_positions_[scope->start_position()] =
      60      170545 :         static_cast<uint32_t>(backing_store_.size());
      61             :   }
      62             : 
      63       40003 :   if (!ScopeNeedsData(scope)) {
      64       40003 :     return;
      65             :   }
      66             : 
      67             : #ifdef DEBUG
      68             :   backing_store_.push_back(scope->scope_type());
      69             : #endif
      70       79754 :   backing_store_.push_back(scope->inner_scope_calls_eval());
      71             :   // Reserve space for the data end index (which we don't know yet). The end
      72             :   // index is needed for skipping over data for a function scope when we skip
      73             :   // parsing of the corresponding function.
      74             :   size_t data_end_index = backing_store_.size();
      75       79754 :   backing_store_.push_back(0);
      76             : 
      77       39877 :   if (!scope->is_hidden()) {
      78      289344 :     for (Variable* var : *scope->locals()) {
      79      106685 :       if (IsDeclaredVariableMode(var->mode())) {
      80      106685 :         SaveDataForVariable(var);
      81             :       }
      82             :     }
      83             :   }
      84             : 
      85       39877 :   SaveDataForInnerScopes(scope);
      86             : 
      87             :   // FIXME(marja): see above.
      88       39877 :   backing_store_[data_end_index] = static_cast<uint32_t>(backing_store_.size());
      89             : }
      90             : 
      91       10656 : void PreParsedScopeData::AddSkippableFunction(
      92             :     int start_position, const PreParseData::FunctionData& function_data) {
      93             :   AddFunction(start_position, function_data);
      94       21312 :   skippable_functions_.insert(start_position);
      95       10656 : }
      96             : 
      97       14801 : void PreParsedScopeData::AddFunction(
      98             :     int start_position, const PreParseData::FunctionData& function_data) {
      99       25457 :   function_index_.AddFunctionData(start_position, function_data);
     100       14801 : }
     101             : 
     102          14 : void PreParsedScopeData::RestoreData(DeclarationScope* scope) const {
     103          14 :   uint32_t index = 0;
     104             : 
     105             :   DCHECK_EQ(scope->scope_type(), ScopeType::FUNCTION_SCOPE);
     106             : 
     107          14 :   bool success = FindFunctionData(scope->start_position(), &index);
     108             :   DCHECK(success);
     109             :   USE(success);
     110             : 
     111          14 :   RestoreData(scope, &index);
     112          14 : }
     113             : 
     114       49490 : void PreParsedScopeData::RestoreData(Scope* scope, uint32_t* index_ptr) const {
     115             :   // It's possible that scope is not present in the data at all (since PreParser
     116             :   // doesn't create the corresponding scope). In this case, the Scope won't
     117             :   // contain any variables for which we need the data.
     118       49490 :   if (!ScopeNeedsData(scope) && !IsSkippedFunctionScope(scope)) {
     119             :     return;
     120             :   }
     121             : 
     122             :   uint32_t& index = *index_ptr;
     123             : 
     124             : #ifdef DEBUG
     125             :   // Data integrity check.
     126             :   if (scope->scope_type() == ScopeType::FUNCTION_SCOPE &&
     127             :       !scope->AsDeclarationScope()->is_arrow_scope()) {
     128             :     const PreParseData::FunctionData& data =
     129             :         function_index_.GetFunctionData(scope->start_position());
     130             :     DCHECK_EQ(data.end, scope->end_position());
     131             :     // FIXME(marja): unify num_parameters too and DCHECK here.
     132             :     DCHECK_EQ(data.language_mode, scope->language_mode());
     133             :     DCHECK_EQ(data.uses_super_property,
     134             :               scope->AsDeclarationScope()->uses_super_property());
     135             :     uint32_t index_from_data = 0;
     136             :     FindFunctionData(scope->start_position(), &index_from_data);
     137             :     DCHECK_EQ(index_from_data, index);
     138             :   }
     139             : #endif
     140             : 
     141       39816 :   if (IsSkippedFunctionScope(scope)) {
     142             :     // This scope is a function scope representing a function we want to
     143             :     // skip. So just skip over its data.
     144             :     DCHECK(!scope->must_use_preparsed_scope_data());
     145             :     // Check that we're moving forward (not backward) in the data.
     146             :     DCHECK_GT(backing_store_[index + 2], index);
     147       39830 :     index = backing_store_[index + 2];
     148          14 :     return;
     149             :   }
     150             : 
     151             :   DCHECK_EQ(backing_store_[index++], scope->scope_type());
     152             : 
     153       79604 :   if (backing_store_[index++]) {
     154             :     scope->RecordEvalCall();
     155             :   }
     156       39802 :   uint32_t data_end_index = backing_store_[index++];
     157             :   USE(data_end_index);
     158             : 
     159       39802 :   if (!scope->is_hidden()) {
     160      375186 :     for (Variable* var : *scope->locals()) {
     161      149681 :       if (var->mode() == VAR || var->mode() == LET || var->mode() == CONST) {
     162      106246 :         RestoreDataForVariable(var, index_ptr);
     163             :       }
     164             :     }
     165             :   }
     166             : 
     167       39802 :   RestoreDataForInnerScopes(scope, index_ptr);
     168             : 
     169             :   DCHECK_EQ(data_end_index, index);
     170             : }
     171             : 
     172          23 : Handle<PodArray<uint32_t>> PreParsedScopeData::Serialize(
     173             :     Isolate* isolate) const {
     174             :   // FIXME(marja): save space by using a byte array and converting
     175             :   // function_index_ to bytes.
     176             :   size_t length =
     177         678 :       function_index_.size() * kFunctionDataSize + backing_store_.size() + 1;
     178             :   Handle<PodArray<uint32_t>> array =
     179          23 :       PodArray<uint32_t>::New(isolate, static_cast<int>(length), TENURED);
     180             : 
     181          46 :   array->set(0, static_cast<uint32_t>(function_index_.size()));
     182             :   int i = 1;
     183         123 :   for (const auto& item : function_index_) {
     184         154 :     const auto& it = function_data_positions_.find(item.first);
     185             :     DCHECK(it != function_data_positions_.end());
     186             :     const PreParseData::FunctionData& function_data = item.second;
     187         154 :     array->set(i++, item.first);  // start position
     188          77 :     array->set(i++, it->second);  // position in data
     189         154 :     array->set(i++, function_data.end);
     190         154 :     array->set(i++, function_data.num_parameters);
     191         154 :     array->set(i++, function_data.num_inner_functions);
     192         154 :     array->set(i++, function_data.language_mode);
     193         154 :     array->set(i++, function_data.uses_super_property);
     194         154 :     array->set(i++, skippable_functions_.find(item.first) !=
     195         154 :                         skippable_functions_.end());
     196             :   }
     197             : 
     198        1264 :   for (size_t j = 0; j < backing_store_.size(); ++j) {
     199        1218 :     array->set(i++, static_cast<uint32_t>(backing_store_[j]));
     200             :   }
     201             :   DCHECK_EQ(array->length(), length);
     202          23 :   return array;
     203             : }
     204             : 
     205          42 : void PreParsedScopeData::Deserialize(PodArray<uint32_t>* array) {
     206          42 :   has_data_ = true;
     207             :   DCHECK_NOT_NULL(array);
     208          42 :   if (array->length() == 0) {
     209             :     return;
     210             :   }
     211          42 :   int function_count = array->get(0);
     212          42 :   CHECK(array->length() > function_count * kFunctionDataSize);
     213          42 :   if (function_count == 0) {
     214             :     return;
     215             :   }
     216             :   int i = 1;
     217         210 :   for (; i < function_count * kFunctionDataSize + 1; i += kFunctionDataSize) {
     218         210 :     int start = array->get(i);
     219         630 :     function_data_positions_[start] = array->get(i + 1);
     220             :     function_index_.AddFunctionData(
     221             :         start, PreParseData::FunctionData(
     222         630 :                    array->get(i + 2), array->get(i + 3), array->get(i + 4),
     223        1260 :                    LanguageMode(array->get(i + 5)), array->get(i + 6)));
     224         420 :     if (array->get(i + 7)) {
     225         112 :       skippable_functions_.insert(start);
     226             :     }
     227             :   }
     228          84 :   CHECK_EQ(function_index_.size(), function_count);
     229             : 
     230          42 :   backing_store_.reserve(array->length() - i);
     231        3248 :   for (; i < array->length(); ++i) {
     232        3164 :     backing_store_.push_back(array->get(i));
     233             :   }
     234             : }
     235             : 
     236          14 : PreParseData::FunctionData PreParsedScopeData::FindSkippableFunction(
     237             :     int start_pos) const {
     238          28 :   if (skippable_functions_.find(start_pos) == skippable_functions_.end()) {
     239             :     return PreParseData::FunctionData();
     240             :   }
     241          14 :   return function_index_.GetFunctionData(start_pos);
     242             : }
     243             : 
     244      106685 : void PreParsedScopeData::SaveDataForVariable(Variable* var) {
     245             : #ifdef DEBUG
     246             :   // Store the variable name in debug mode; this way we can check that we
     247             :   // restore data to the correct variable.
     248             :   const AstRawString* name = var->raw_name();
     249             :   backing_store_.push_back(name->length());
     250             :   for (int i = 0; i < name->length(); ++i) {
     251             :     backing_store_.push_back(name->raw_data()[i]);
     252             :   }
     253             : #endif
     254             :   // FIXME(marja): Only 3 bits needed, not a full byte.
     255             :   byte variable_data = VariableIsUsedField::encode(var->is_used()) |
     256             :                        VariableMaybeAssignedField::encode(
     257      106685 :                            var->maybe_assigned() == kMaybeAssigned) |
     258             :                        VariableContextAllocatedField::encode(
     259      320055 :                            var->has_forced_context_allocation());
     260             : 
     261      213370 :   backing_store_.push_back(variable_data);
     262      106685 : }
     263             : 
     264      106246 : void PreParsedScopeData::RestoreDataForVariable(Variable* var,
     265             :                                                 uint32_t* index_ptr) const {
     266             :   uint32_t& index = *index_ptr;
     267             : #ifdef DEBUG
     268             :   const AstRawString* name = var->raw_name();
     269             :   DCHECK_EQ(backing_store_[index++], static_cast<uint32_t>(name->length()));
     270             :   for (int i = 0; i < name->length(); ++i) {
     271             :     DCHECK_EQ(backing_store_[index++], name->raw_data()[i]);
     272             :   }
     273             : #endif
     274      212492 :   byte variable_data = backing_store_[index++];
     275      106246 :   if (VariableIsUsedField::decode(variable_data)) {
     276             :     var->set_is_used();
     277             :   }
     278      106246 :   if (VariableMaybeAssignedField::decode(variable_data)) {
     279             :     var->set_maybe_assigned();
     280             :   }
     281      106246 :   if (VariableContextAllocatedField::decode(variable_data)) {
     282             :     var->ForceContextAllocation();
     283             :   }
     284      106246 : }
     285             : 
     286       79754 : void PreParsedScopeData::SaveDataForInnerScopes(Scope* scope) {
     287             :   // Inner scopes are stored in the reverse order, but we'd like to write the
     288             :   // data in the logical order. There might be many inner scopes, so we don't
     289             :   // want to recurse here.
     290             :   std::vector<Scope*> scopes;
     291       65079 :   for (Scope* inner = scope->inner_scope(); inner != nullptr;
     292       25202 :        inner = inner->sibling()) {
     293       25202 :     scopes.push_back(inner);
     294             :   }
     295      104956 :   for (int i = static_cast<int>(scopes.size()) - 1; i >= 0; --i) {
     296       50404 :     SaveData(scopes[i]);
     297             :   }
     298       39877 : }
     299             : 
     300       79604 : void PreParsedScopeData::RestoreDataForInnerScopes(Scope* scope,
     301             :                                                    uint32_t* index_ptr) const {
     302             :   std::vector<Scope*> scopes;
     303       74550 :   for (Scope* inner = scope->inner_scope(); inner != nullptr;
     304       34748 :        inner = inner->sibling()) {
     305       34748 :     scopes.push_back(inner);
     306             :   }
     307      114352 :   for (int i = static_cast<int>(scopes.size()) - 1; i >= 0; --i) {
     308       69496 :     RestoreData(scopes[i], index_ptr);
     309             :   }
     310       39802 : }
     311             : 
     312           0 : bool PreParsedScopeData::FindFunctionData(int start_pos,
     313             :                                           uint32_t* index) const {
     314          28 :   auto it = function_data_positions_.find(start_pos);
     315          14 :   if (it == function_data_positions_.end()) {
     316             :     return false;
     317             :   }
     318          14 :   *index = it->second;
     319           0 :   return true;
     320             : }
     321             : 
     322      112397 : bool PreParsedScopeData::ScopeNeedsData(Scope* scope) {
     323       96045 :   if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) {
     324             :     return true;
     325             :   }
     326       33110 :   if (!scope->is_hidden()) {
     327       50946 :     for (Variable* var : *scope->locals()) {
     328       16758 :       if (var->mode() == VAR || var->mode() == LET || var->mode() == CONST) {
     329             :         return true;
     330             :       }
     331             :     }
     332             :   }
     333       19124 :   for (Scope* inner = scope->inner_scope(); inner != nullptr;
     334             :        inner = inner->sibling()) {
     335        6552 :     if (ScopeNeedsData(inner)) {
     336             :       return true;
     337             :     }
     338             :   }
     339             :   return false;
     340             : }
     341             : 
     342       49490 : bool PreParsedScopeData::IsSkippedFunctionScope(Scope* scope) {
     343       81515 :   return scope->is_declaration_scope() &&
     344       81515 :          scope->AsDeclarationScope()->is_skipped_function();
     345             : }
     346             : 
     347             : }  // namespace internal
     348             : }  // namespace v8

Generated by: LCOV version 1.10