Create function name const assignment after parsing language mode.
authoryangguo <yangguo@chromium.org>
Mon, 3 Aug 2015 09:14:19 +0000 (02:14 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 3 Aug 2015 09:14:26 +0000 (09:14 +0000)
Otherwise we may choose sloppy const or strict const depending on
whether the function is parsed the first time.

R=mvstanton@chromium.org
BUG=v8:4336
LOG=N

Review URL: https://codereview.chromium.org/1260053004

Cr-Commit-Position: refs/heads/master@{#29966}

src/objects-debug.cc
src/objects-inl.h
src/objects.h
src/parser.cc
src/parser.h
src/preparser.h

index 5babfdf..3a2ec3e 100644 (file)
@@ -1277,6 +1277,57 @@ void Code::VerifyEmbeddedObjects(VerifyMode mode) {
 }
 
 
+// Verify that the debugger can redirect old code to the new code.
+void Code::VerifyRecompiledCode(Code* old_code, Code* new_code) {
+  if (old_code->kind() != FUNCTION) return;
+  if (new_code->kind() != FUNCTION) return;
+  static const int mask = RelocInfo::kCodeTargetMask;
+
+  Isolate* isolate = old_code->GetIsolate();
+  RelocIterator old_it(old_code, mask);
+  RelocIterator new_it(new_code, mask);
+  Code* stack_check = isolate->builtins()->builtin(Builtins::kStackCheck);
+
+  while (!old_it.done()) {
+    RelocInfo* rinfo = old_it.rinfo();
+    Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
+    CHECK(!target->is_handler() && !target->is_inline_cache_stub());
+    if (target == stack_check) break;
+    old_it.next();
+  }
+
+  while (!new_it.done()) {
+    RelocInfo* rinfo = new_it.rinfo();
+    Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
+    CHECK(!target->is_handler() && !target->is_inline_cache_stub());
+    if (target == stack_check) break;
+    new_it.next();
+  }
+
+  // Either both are done because there is no stack check.
+  // Or we are past the prologue for both.
+  CHECK_EQ(new_it.done(), old_it.done());
+
+  // After the prologue, each call in the old code has a corresponding call
+  // in the new code.
+  while (!old_it.done() && !new_it.done()) {
+    Code* old_target =
+        Code::GetCodeFromTargetAddress(old_it.rinfo()->target_address());
+    Code* new_target =
+        Code::GetCodeFromTargetAddress(new_it.rinfo()->target_address());
+    CHECK_EQ(old_target->kind(), new_target->kind());
+    if (!old_target->is_handler() && !old_target->is_inline_cache_stub()) {
+      CHECK_EQ(old_target, new_target);
+    }
+    old_it.next();
+    new_it.next();
+  }
+
+  // Both are done at the same time.
+  CHECK_EQ(new_it.done(), old_it.done());
+}
+
+
 #endif  // DEBUG
 
 }  // namespace internal
index 4929c0d..05cb6aa 100644 (file)
@@ -5228,7 +5228,10 @@ void SharedFunctionInfo::ReplaceCode(Code* value) {
     flusher->EvictCandidate(this);
   }
 
+#ifdef DEBUG
   DCHECK(code()->gc_metadata() == NULL && value->gc_metadata() == NULL);
+  Code::VerifyRecompiledCode(code(), value);
+#endif  // DEBUG
 
   set_code(value);
 
index d84690f..9663398 100644 (file)
@@ -4992,6 +4992,7 @@ class Code: public HeapObject {
 #ifdef DEBUG
   enum VerifyMode { kNoContextSpecificPointers, kNoContextRetainingPointers };
   void VerifyEmbeddedObjects(VerifyMode mode = kNoContextRetainingPointers);
+  static void VerifyRecompiledCode(Code* old_code, Code* new_code);
 #endif  // DEBUG
 
   inline bool CanContainWeakObjects() {
index ae1a8c1..e8f3a64 100644 (file)
@@ -4039,31 +4039,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
                            formals_end_position, CHECK_OK);
     Expect(Token::LBRACE, CHECK_OK);
 
-    // If we have a named function expression, we add a local variable
-    // declaration to the body of the function with the name of the
-    // function and let it refer to the function itself (closure).
-    // NOTE: We create a proxy and resolve it here so that in the
-    // future we can change the AST to only refer to VariableProxies
-    // instead of Variables and Proxis as is the case now.
-    Variable* fvar = NULL;
-    Token::Value fvar_init_op = Token::INIT_CONST_LEGACY;
-    if (function_type == FunctionLiteral::NAMED_EXPRESSION) {
-      bool use_strict_const = is_strict(language_mode) ||
-                              (!allow_legacy_const() && allow_harmony_sloppy());
-      if (use_strict_const) {
-        fvar_init_op = Token::INIT_CONST;
-      }
-      VariableMode fvar_mode = use_strict_const ? CONST : CONST_LEGACY;
-      DCHECK(function_name != NULL);
-      fvar = new (zone())
-          Variable(scope_, function_name, fvar_mode, Variable::NORMAL,
-                   kCreatedInitialized, kNotAssigned);
-      VariableProxy* proxy = factory()->NewVariableProxy(fvar);
-      VariableDeclaration* fvar_declaration = factory()->NewVariableDeclaration(
-          proxy, fvar_mode, scope_, RelocInfo::kNoPosition);
-      scope_->DeclareFunctionVar(fvar_declaration);
-    }
-
     // Determine if the function can be parsed lazily. Lazy parsing is different
     // from lazy compilation; we need to parse more eagerly than we compile.
 
@@ -4127,8 +4102,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
       }
     }
     if (!is_lazily_parsed) {
-      body = ParseEagerFunctionBody(function_name, pos, formals, fvar,
-                                    fvar_init_op, kind, CHECK_OK);
+      body = ParseEagerFunctionBody(function_name, pos, formals, kind,
+                                    function_type, CHECK_OK);
       materialized_literal_count = function_state.materialized_literal_count();
       expected_property_count = function_state.expected_property_count();
     }
@@ -4344,23 +4319,24 @@ Block* Parser::BuildParameterInitializationBlock(
 
 ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
     const AstRawString* function_name, int pos,
-    const ParserFormalParameters& parameters, Variable* fvar,
-    Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
+    const ParserFormalParameters& parameters, FunctionKind kind,
+    FunctionLiteral::FunctionType function_type, bool* ok) {
   // Everything inside an eagerly parsed function will be parsed eagerly
   // (see comment above).
   ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
   ZoneList<Statement*>* result = new(zone()) ZoneList<Statement*>(8, zone());
-  if (fvar != NULL) {
-    VariableProxy* fproxy = scope_->NewUnresolved(factory(), function_name);
-    fproxy->BindTo(fvar);
-    result->Add(factory()->NewExpressionStatement(
-        factory()->NewAssignment(fvar_init_op,
-                                 fproxy,
-                                 factory()->NewThisFunction(pos),
-                                 RelocInfo::kNoPosition),
-        RelocInfo::kNoPosition), zone());
-  }
 
+  static const int kFunctionNameAssignmentIndex = 0;
+  if (function_type == FunctionLiteral::NAMED_EXPRESSION) {
+    DCHECK(function_name != NULL);
+    // If we have a named function expression, we add a local variable
+    // declaration to the body of the function with the name of the
+    // function and let it refer to the function itself (closure).
+    // Not having parsed the function body, the language mode may still change,
+    // so we reserve a spot and create the actual const assignment later.
+    DCHECK_EQ(kFunctionNameAssignmentIndex, result->length());
+    result->Add(NULL, zone());
+  }
 
   // For concise constructors, check that they are constructed,
   // not called.
@@ -4445,6 +4421,37 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
     result->Add(inner_block, zone());
   }
 
+  if (function_type == FunctionLiteral::NAMED_EXPRESSION) {
+    // Now that we know the language mode, we can create the const assignment
+    // in the previously reserved spot.
+    // NOTE: We create a proxy and resolve it here so that in the
+    // future we can change the AST to only refer to VariableProxies
+    // instead of Variables and Proxies as is the case now.
+    Token::Value fvar_init_op = Token::INIT_CONST_LEGACY;
+    bool use_strict_const = is_strict(scope_->language_mode()) ||
+                            (!allow_legacy_const() && allow_harmony_sloppy());
+    if (use_strict_const) {
+      fvar_init_op = Token::INIT_CONST;
+    }
+    VariableMode fvar_mode = use_strict_const ? CONST : CONST_LEGACY;
+    Variable* fvar = new (zone())
+        Variable(scope_, function_name, fvar_mode, Variable::NORMAL,
+                 kCreatedInitialized, kNotAssigned);
+    VariableProxy* proxy = factory()->NewVariableProxy(fvar);
+    VariableDeclaration* fvar_declaration = factory()->NewVariableDeclaration(
+        proxy, fvar_mode, scope_, RelocInfo::kNoPosition);
+    scope_->DeclareFunctionVar(fvar_declaration);
+
+    VariableProxy* fproxy = scope_->NewUnresolved(factory(), function_name);
+    fproxy->BindTo(fvar);
+    result->Set(kFunctionNameAssignmentIndex,
+                factory()->NewExpressionStatement(
+                    factory()->NewAssignment(fvar_init_op, fproxy,
+                                             factory()->NewThisFunction(pos),
+                                             RelocInfo::kNoPosition),
+                    RelocInfo::kNoPosition));
+  }
+
   return result;
 }
 
index 87269ed..df1b439 100644 (file)
@@ -802,8 +802,8 @@ class ParserTraits {
       Scanner::BookmarkScope* bookmark = nullptr);
   V8_INLINE ZoneList<Statement*>* ParseEagerFunctionBody(
       const AstRawString* name, int pos,
-      const ParserFormalParameters& parameters,
-      Variable* fvar, Token::Value fvar_init_op, FunctionKind kind, bool* ok);
+      const ParserFormalParameters& parameters, FunctionKind kind,
+      FunctionLiteral::FunctionType function_type, bool* ok);
 
   ClassLiteral* ParseClassLiteral(const AstRawString* name,
                                   Scanner::Location class_name_location,
@@ -1160,8 +1160,8 @@ class Parser : public ParserBase<ParserTraits> {
   // Consumes the ending }.
   ZoneList<Statement*>* ParseEagerFunctionBody(
       const AstRawString* function_name, int pos,
-      const ParserFormalParameters& parameters,
-      Variable* fvar, Token::Value fvar_init_op, FunctionKind kind, bool* ok);
+      const ParserFormalParameters& parameters, FunctionKind kind,
+      FunctionLiteral::FunctionType function_type, bool* ok);
 
   void ThrowPendingError(Isolate* isolate, Handle<Script> script);
 
@@ -1225,11 +1225,10 @@ void ParserTraits::SkipLazyFunctionBody(int* materialized_literal_count,
 
 
 ZoneList<Statement*>* ParserTraits::ParseEagerFunctionBody(
-    const AstRawString* name, int pos,
-    const ParserFormalParameters& parameters, Variable* fvar,
-    Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
-  return parser_->ParseEagerFunctionBody(name, pos, parameters, fvar,
-                                         fvar_init_op, kind, ok);
+    const AstRawString* name, int pos, const ParserFormalParameters& parameters,
+    FunctionKind kind, FunctionLiteral::FunctionType function_type, bool* ok) {
+  return parser_->ParseEagerFunctionBody(name, pos, parameters, kind,
+                                         function_type, ok);
 }
 
 void ParserTraits::CheckConflictingVarDeclarations(v8::internal::Scope* scope,
index 18a0162..a3ae91c 100644 (file)
@@ -1601,8 +1601,8 @@ class PreParserTraits {
 
   V8_INLINE PreParserStatementList ParseEagerFunctionBody(
       PreParserIdentifier function_name, int pos,
-      const PreParserFormalParameters& parameters,
-      Variable* fvar, Token::Value fvar_init_op, FunctionKind kind, bool* ok);
+      const PreParserFormalParameters& parameters, FunctionKind kind,
+      FunctionLiteral::FunctionType function_type, bool* ok);
 
   V8_INLINE void ParseArrowFunctionFormalParameters(
       PreParserFormalParameters* parameters,
@@ -1786,11 +1786,10 @@ class PreParser : public ParserBase<PreParserTraits> {
 
   V8_INLINE void SkipLazyFunctionBody(int* materialized_literal_count,
                                       int* expected_property_count, bool* ok);
-  V8_INLINE PreParserStatementList
-  ParseEagerFunctionBody(PreParserIdentifier function_name, int pos,
-                         const PreParserFormalParameters& parameters,
-                         Variable* fvar, Token::Value fvar_init_op,
-                         FunctionKind kind, bool* ok);
+  V8_INLINE PreParserStatementList ParseEagerFunctionBody(
+      PreParserIdentifier function_name, int pos,
+      const PreParserFormalParameters& parameters, FunctionKind kind,
+      FunctionLiteral::FunctionType function_type, bool* ok);
 
   Expression ParseFunctionLiteral(
       Identifier name, Scanner::Location function_name_location,
@@ -1845,8 +1844,8 @@ void PreParserTraits::ParseArrowFunctionFormalParameters(
 
 PreParserStatementList PreParser::ParseEagerFunctionBody(
     PreParserIdentifier function_name, int pos,
-    const PreParserFormalParameters& parameters,
-    Variable* fvar, Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
+    const PreParserFormalParameters& parameters, FunctionKind kind,
+    FunctionLiteral::FunctionType function_type, bool* ok) {
   ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
 
   ParseStatementList(Token::RBRACE, ok);
@@ -1859,10 +1858,10 @@ PreParserStatementList PreParser::ParseEagerFunctionBody(
 
 PreParserStatementList PreParserTraits::ParseEagerFunctionBody(
     PreParserIdentifier function_name, int pos,
-    const PreParserFormalParameters& parameters,
-    Variable* fvar, Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
-  return pre_parser_->ParseEagerFunctionBody(
-      function_name, pos, parameters, fvar, fvar_init_op, kind, ok);
+    const PreParserFormalParameters& parameters, FunctionKind kind,
+    FunctionLiteral::FunctionType function_type, bool* ok) {
+  return pre_parser_->ParseEagerFunctionBody(function_name, pos, parameters,
+                                             kind, function_type, ok);
 }
 
 
@@ -3768,7 +3767,7 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
       } else {
         body = this->ParseEagerFunctionBody(
             this->EmptyIdentifier(), RelocInfo::kNoPosition, formal_parameters,
-            NULL, Token::INIT_VAR, kArrowFunction, CHECK_OK);
+            kArrowFunction, FunctionLiteral::ANONYMOUS_EXPRESSION, CHECK_OK);
         materialized_literal_count =
             function_state.materialized_literal_count();
         expected_property_count = function_state.expected_property_count();