// Copyright 2012 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/parsing/parser.h" #include #include #include "src/ast/ast-function-literal-id-reindexer.h" #include "src/ast/ast-traversal-visitor.h" #include "src/ast/ast.h" #include "src/ast/source-range-ast-visitor.h" #include "src/base/ieee754.h" #include "src/base/overflowing-math.h" #include "src/base/platform/platform.h" #include "src/codegen/bailout-reason.h" #include "src/common/globals.h" #include "src/common/message-template.h" #include "src/compiler-dispatcher/compiler-dispatcher.h" #include "src/logging/counters.h" #include "src/logging/log.h" #include "src/numbers/conversions-inl.h" #include "src/objects/scope-info.h" #include "src/parsing/parse-info.h" #include "src/parsing/rewriter.h" #include "src/runtime/runtime.h" #include "src/strings/char-predicates-inl.h" #include "src/strings/string-stream.h" #include "src/tracing/trace-event.h" #include "src/zone/zone-list-inl.h" namespace v8 { namespace internal { FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name, bool call_super, int pos, int end_pos) { int expected_property_count = 0; const int parameter_count = 0; FunctionKind kind = call_super ? FunctionKind::kDefaultDerivedConstructor : FunctionKind::kDefaultBaseConstructor; DeclarationScope* function_scope = NewFunctionScope(kind); SetLanguageMode(function_scope, LanguageMode::kStrict); // Set start and end position to the same value function_scope->set_start_position(pos); function_scope->set_end_position(pos); ScopedPtrList body(pointer_buffer()); { FunctionState function_state(&function_state_, &scope_, function_scope); if (call_super) { // Create a SuperCallReference and handle in BytecodeGenerator. auto constructor_args_name = ast_value_factory()->empty_string(); bool is_rest = true; bool is_optional = false; Variable* constructor_args = function_scope->DeclareParameter( constructor_args_name, VariableMode::kTemporary, is_optional, is_rest, ast_value_factory(), pos); Expression* call; { ScopedPtrList args(pointer_buffer()); Spread* spread_args = factory()->NewSpread( factory()->NewVariableProxy(constructor_args), pos, pos); args.Add(spread_args); Expression* super_call_ref = NewSuperCallReference(pos); call = factory()->NewCall(super_call_ref, args, pos); } body.Add(factory()->NewReturnStatement(call, pos)); } expected_property_count = function_state.expected_property_count(); } FunctionLiteral* function_literal = factory()->NewFunctionLiteral( name, function_scope, body, expected_property_count, parameter_count, parameter_count, FunctionLiteral::kNoDuplicateParameters, FunctionSyntaxKind::kAnonymousExpression, default_eager_compile_hint(), pos, true, GetNextFunctionLiteralId()); return function_literal; } void Parser::ReportUnexpectedTokenAt(Scanner::Location location, Token::Value token, MessageTemplate message) { const char* arg = nullptr; switch (token) { case Token::EOS: message = MessageTemplate::kUnexpectedEOS; break; case Token::SMI: case Token::NUMBER: case Token::BIGINT: message = MessageTemplate::kUnexpectedTokenNumber; break; case Token::STRING: message = MessageTemplate::kUnexpectedTokenString; break; case Token::PRIVATE_NAME: case Token::IDENTIFIER: message = MessageTemplate::kUnexpectedTokenIdentifier; break; case Token::AWAIT: case Token::ENUM: message = MessageTemplate::kUnexpectedReserved; break; case Token::LET: case Token::STATIC: case Token::YIELD: case Token::FUTURE_STRICT_RESERVED_WORD: message = is_strict(language_mode()) ? MessageTemplate::kUnexpectedStrictReserved : MessageTemplate::kUnexpectedTokenIdentifier; break; case Token::TEMPLATE_SPAN: case Token::TEMPLATE_TAIL: message = MessageTemplate::kUnexpectedTemplateString; break; case Token::ESCAPED_STRICT_RESERVED_WORD: case Token::ESCAPED_KEYWORD: message = MessageTemplate::kInvalidEscapedReservedWord; break; case Token::ILLEGAL: if (scanner()->has_error()) { message = scanner()->error(); location = scanner()->error_location(); } else { message = MessageTemplate::kInvalidOrUnexpectedToken; } break; case Token::REGEXP_LITERAL: message = MessageTemplate::kUnexpectedTokenRegExp; break; default: const char* name = Token::String(token); DCHECK_NOT_NULL(name); arg = name; break; } ReportMessageAt(location, message, arg); } // ---------------------------------------------------------------------------- // Implementation of Parser bool Parser::ShortcutNumericLiteralBinaryExpression(Expression** x, Expression* y, Token::Value op, int pos) { if ((*x)->IsNumberLiteral() && y->IsNumberLiteral()) { double x_val = (*x)->AsLiteral()->AsNumber(); double y_val = y->AsLiteral()->AsNumber(); switch (op) { case Token::ADD: *x = factory()->NewNumberLiteral(x_val + y_val, pos); return true; case Token::SUB: *x = factory()->NewNumberLiteral(x_val - y_val, pos); return true; case Token::MUL: *x = factory()->NewNumberLiteral(x_val * y_val, pos); return true; case Token::DIV: *x = factory()->NewNumberLiteral(base::Divide(x_val, y_val), pos); return true; case Token::BIT_OR: { int value = DoubleToInt32(x_val) | DoubleToInt32(y_val); *x = factory()->NewNumberLiteral(value, pos); return true; } case Token::BIT_AND: { int value = DoubleToInt32(x_val) & DoubleToInt32(y_val); *x = factory()->NewNumberLiteral(value, pos); return true; } case Token::BIT_XOR: { int value = DoubleToInt32(x_val) ^ DoubleToInt32(y_val); *x = factory()->NewNumberLiteral(value, pos); return true; } case Token::SHL: { int value = base::ShlWithWraparound(DoubleToInt32(x_val), DoubleToInt32(y_val)); *x = factory()->NewNumberLiteral(value, pos); return true; } case Token::SHR: { uint32_t shift = DoubleToInt32(y_val) & 0x1F; uint32_t value = DoubleToUint32(x_val) >> shift; *x = factory()->NewNumberLiteral(value, pos); return true; } case Token::SAR: { uint32_t shift = DoubleToInt32(y_val) & 0x1F; int value = ArithmeticShiftRight(DoubleToInt32(x_val), shift); *x = factory()->NewNumberLiteral(value, pos); return true; } case Token::EXP: *x = factory()->NewNumberLiteral(base::ieee754::pow(x_val, y_val), pos); return true; default: break; } } return false; } bool Parser::CollapseNaryExpression(Expression** x, Expression* y, Token::Value op, int pos, const SourceRange& range) { // Filter out unsupported ops. if (!Token::IsBinaryOp(op) || op == Token::EXP) return false; // Convert *x into an nary operation with the given op, returning false if // this is not possible. NaryOperation* nary = nullptr; if ((*x)->IsBinaryOperation()) { BinaryOperation* binop = (*x)->AsBinaryOperation(); if (binop->op() != op) return false; nary = factory()->NewNaryOperation(op, binop->left(), 2); nary->AddSubsequent(binop->right(), binop->position()); ConvertBinaryToNaryOperationSourceRange(binop, nary); *x = nary; } else if ((*x)->IsNaryOperation()) { nary = (*x)->AsNaryOperation(); if (nary->op() != op) return false; } else { return false; } // Append our current expression to the nary operation. // TODO(leszeks): Do some literal collapsing here if we're appending Smi or // String literals. nary->AddSubsequent(y, pos); nary->clear_parenthesized(); AppendNaryOperationSourceRange(nary, range); return true; } Expression* Parser::BuildUnaryExpression(Expression* expression, Token::Value op, int pos) { DCHECK_NOT_NULL(expression); const Literal* literal = expression->AsLiteral(); if (literal != nullptr) { if (op == Token::NOT) { // Convert the literal to a boolean condition and negate it. return factory()->NewBooleanLiteral(literal->ToBooleanIsFalse(), pos); } else if (literal->IsNumberLiteral()) { // Compute some expressions involving only number literals. double value = literal->AsNumber(); switch (op) { case Token::ADD: return expression; case Token::SUB: return factory()->NewNumberLiteral(-value, pos); case Token::BIT_NOT: return factory()->NewNumberLiteral(~DoubleToInt32(value), pos); default: break; } } } return factory()->NewUnaryOperation(op, expression, pos); } Expression* Parser::NewThrowError(Runtime::FunctionId id, MessageTemplate message, const AstRawString* arg, int pos) { ScopedPtrList args(pointer_buffer()); args.Add(factory()->NewSmiLiteral(static_cast(message), pos)); args.Add(factory()->NewStringLiteral(arg, pos)); CallRuntime* call_constructor = factory()->NewCallRuntime(id, args, pos); return factory()->NewThrow(call_constructor, pos); } Expression* Parser::NewSuperPropertyReference(int pos) { // this_function[home_object_symbol] VariableProxy* this_function_proxy = NewUnresolved(ast_value_factory()->this_function_string(), pos); Expression* home_object_symbol_literal = factory()->NewSymbolLiteral( AstSymbol::kHomeObjectSymbol, kNoSourcePosition); Expression* home_object = factory()->NewProperty( this_function_proxy, home_object_symbol_literal, pos); return factory()->NewSuperPropertyReference(home_object, pos); } Expression* Parser::NewSuperCallReference(int pos) { VariableProxy* new_target_proxy = NewUnresolved(ast_value_factory()->new_target_string(), pos); VariableProxy* this_function_proxy = NewUnresolved(ast_value_factory()->this_function_string(), pos); return factory()->NewSuperCallReference(new_target_proxy, this_function_proxy, pos); } Expression* Parser::NewTargetExpression(int pos) { auto proxy = NewUnresolved(ast_value_factory()->new_target_string(), pos); proxy->set_is_new_target(); return proxy; } Expression* Parser::ImportMetaExpression(int pos) { ScopedPtrList args(pointer_buffer()); return factory()->NewCallRuntime(Runtime::kInlineGetImportMetaObject, args, pos); } Expression* Parser::ExpressionFromLiteral(Token::Value token, int pos) { switch (token) { case Token::NULL_LITERAL: return factory()->NewNullLiteral(pos); case Token::TRUE_LITERAL: return factory()->NewBooleanLiteral(true, pos); case Token::FALSE_LITERAL: return factory()->NewBooleanLiteral(false, pos); case Token::SMI: { uint32_t value = scanner()->smi_value(); return factory()->NewSmiLiteral(value, pos); } case Token::NUMBER: { double value = scanner()->DoubleValue(); return factory()->NewNumberLiteral(value, pos); } case Token::BIGINT: return factory()->NewBigIntLiteral( AstBigInt(scanner()->CurrentLiteralAsCString(zone())), pos); case Token::STRING: { return factory()->NewStringLiteral(GetSymbol(), pos); } default: DCHECK(false); } return FailureExpression(); } Expression* Parser::NewV8Intrinsic(const AstRawString* name, const ScopedPtrList& args, int pos) { if (extension_ != nullptr) { // The extension structures are only accessible while parsing the // very first time, not when reparsing because of lazy compilation. GetClosureScope()->ForceEagerCompilation(); } if (!name->is_one_byte()) { // There are no two-byte named intrinsics. ReportMessage(MessageTemplate::kNotDefined, name); return FailureExpression(); } const Runtime::Function* function = Runtime::FunctionForName(name->raw_data(), name->length()); // Be more permissive when fuzzing. Intrinsics are not supported. if (FLAG_fuzzing) { return NewV8RuntimeFunctionForFuzzing(function, args, pos); } if (function != nullptr) { // Check for possible name clash. DCHECK_EQ(Context::kNotFound, Context::IntrinsicIndexForName(name->raw_data(), name->length())); // Check that the expected number of arguments are being passed. if (function->nargs != -1 && function->nargs != args.length()) { ReportMessage(MessageTemplate::kRuntimeWrongNumArgs); return FailureExpression(); } return factory()->NewCallRuntime(function, args, pos); } int context_index = Context::IntrinsicIndexForName(name->raw_data(), name->length()); // Check that the function is defined. if (context_index == Context::kNotFound) { ReportMessage(MessageTemplate::kNotDefined, name); return FailureExpression(); } return factory()->NewCallRuntime(context_index, args, pos); } // More permissive runtime-function creation on fuzzers. Expression* Parser::NewV8RuntimeFunctionForFuzzing( const Runtime::Function* function, const ScopedPtrList& args, int pos) { CHECK(FLAG_fuzzing); // Intrinsics are not supported for fuzzing. Only allow allowlisted runtime // functions. Also prevent later errors due to too few arguments and just // ignore this call. if (function == nullptr || !Runtime::IsAllowListedForFuzzing(function->function_id) || function->nargs > args.length()) { return factory()->NewUndefinedLiteral(kNoSourcePosition); } // Flexible number of arguments permitted. if (function->nargs == -1) { return factory()->NewCallRuntime(function, args, pos); } // Otherwise ignore superfluous arguments. ScopedPtrList permissive_args(pointer_buffer()); for (int i = 0; i < function->nargs; i++) { permissive_args.Add(args.at(i)); } return factory()->NewCallRuntime(function, permissive_args, pos); } Parser::Parser(ParseInfo* info) : ParserBase( info->zone(), &scanner_, info->stack_limit(), info->extension(), info->GetOrCreateAstValueFactory(), info->pending_error_handler(), info->runtime_call_stats(), info->logger(), info->flags(), true), info_(info), scanner_(info->character_stream(), flags()), preparser_zone_(info->zone()->allocator(), ZONE_NAME), reusable_preparser_(nullptr), mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly. source_range_map_(info->source_range_map()), total_preparse_skipped_(0), consumed_preparse_data_(info->consumed_preparse_data()), preparse_data_buffer_(), parameters_end_pos_(info->parameters_end_pos()) { // Even though we were passed ParseInfo, we should not store it in // Parser - this makes sure that Isolate is not accidentally accessed via // ParseInfo during background parsing. DCHECK_NOT_NULL(info->character_stream()); // Determine if functions can be lazily compiled. This is necessary to // allow some of our builtin JS files to be lazily compiled. These // builtins cannot be handled lazily by the parser, since we have to know // if a function uses the special natives syntax, which is something the // parser records. // If the debugger requests compilation for break points, we cannot be // aggressive about lazy compilation, because it might trigger compilation // of functions without an outer context when setting a breakpoint through // Debug::FindSharedFunctionInfoInScript // We also compile eagerly for kProduceExhaustiveCodeCache. bool can_compile_lazily = flags().allow_lazy_compile() && !flags().is_eager(); set_default_eager_compile_hint(can_compile_lazily ? FunctionLiteral::kShouldLazyCompile : FunctionLiteral::kShouldEagerCompile); allow_lazy_ = flags().allow_lazy_compile() && flags().allow_lazy_parsing() && info->extension() == nullptr && can_compile_lazily; for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; ++feature) { use_counts_[feature] = 0; } } void Parser::InitializeEmptyScopeChain(ParseInfo* info) { DCHECK_NULL(original_scope_); DCHECK_NULL(info->script_scope()); DeclarationScope* script_scope = NewScriptScope(flags().is_repl_mode() ? REPLMode::kYes : REPLMode::kNo); info->set_script_scope(script_scope); original_scope_ = script_scope; } void Parser::DeserializeScopeChain( Isolate* isolate, ParseInfo* info, MaybeHandle maybe_outer_scope_info, Scope::DeserializationMode mode) { InitializeEmptyScopeChain(info); Handle outer_scope_info; if (maybe_outer_scope_info.ToHandle(&outer_scope_info)) { DCHECK_EQ(ThreadId::Current(), isolate->thread_id()); original_scope_ = Scope::DeserializeScopeChain( isolate, zone(), *outer_scope_info, info->script_scope(), ast_value_factory(), mode); if (flags().is_eval() || IsArrowFunction(flags().function_kind())) { original_scope_->GetReceiverScope()->DeserializeReceiver( ast_value_factory()); } } } namespace { void MaybeResetCharacterStream(ParseInfo* info, FunctionLiteral* literal) { // Don't reset the character stream if there is an asm.js module since it will // be used again by the asm-parser. if (info->contains_asm_module()) { if (FLAG_stress_validate_asm) return; if (literal != nullptr && literal->scope()->ContainsAsmModule()) return; } info->ResetCharacterStream(); } void MaybeProcessSourceRanges(ParseInfo* parse_info, Expression* root, uintptr_t stack_limit_) { if (root != nullptr && parse_info->source_range_map() != nullptr) { SourceRangeAstVisitor visitor(stack_limit_, root, parse_info->source_range_map()); visitor.Run(); } } } // namespace void Parser::ParseProgram(Isolate* isolate, Handle