From: yangguo Date: Mon, 3 Aug 2015 09:14:19 +0000 (-0700) Subject: Create function name const assignment after parsing language mode. X-Git-Tag: upstream/4.7.83~1074 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f7d808847feaa87f1635dd64650790d8b0d42021;p=platform%2Fupstream%2Fv8.git Create function name const assignment after parsing language mode. 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} --- diff --git a/src/objects-debug.cc b/src/objects-debug.cc index 5babfdf1a..3a2ec3e55 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -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 diff --git a/src/objects-inl.h b/src/objects-inl.h index 4929c0d2d..05cb6aa23 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -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); diff --git a/src/objects.h b/src/objects.h index d84690fbd..9663398ad 100644 --- a/src/objects.h +++ b/src/objects.h @@ -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() { diff --git a/src/parser.cc b/src/parser.cc index ae1a8c14c..e8f3a6419 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -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* 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* result = new(zone()) ZoneList(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* 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; } diff --git a/src/parser.h b/src/parser.h index 87269ed61..df1b439d0 100644 --- a/src/parser.h +++ b/src/parser.h @@ -802,8 +802,8 @@ class ParserTraits { Scanner::BookmarkScope* bookmark = nullptr); V8_INLINE ZoneList* 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 { // Consumes the ending }. ZoneList* 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