From d21b9a142241ffd9593416d5a04cbea18ed1930e Mon Sep 17 00:00:00 2001 From: marja Date: Thu, 5 Feb 2015 06:11:34 -0800 Subject: [PATCH] Add strong mode. It doesn't do anything for now, but it implies strict mode. Added tests to test-parsing.cc to test that. BUG= Review URL: https://codereview.chromium.org/898983002 Cr-Commit-Position: refs/heads/master@{#26460} --- src/ast-value-factory.h | 1 + src/code-stubs.h | 6 +- src/compiler.cc | 4 +- src/compiler.h | 48 +++--- src/flag-definitions.h | 1 + src/globals.h | 34 ++++- src/hydrogen-instructions.h | 4 +- src/ic/ic.h | 10 +- src/objects-inl.h | 10 +- src/objects.cc | 3 +- src/objects.h | 15 +- src/parser.cc | 68 +++++---- src/preparser.cc | 9 +- src/preparser.h | 27 +++- src/runtime/runtime.h | 4 +- test/cctest/test-parsing.cc | 168 ++++++++++++++++----- .../compiler/js-typed-lowering-unittest.cc | 4 +- 17 files changed, 289 insertions(+), 127 deletions(-) diff --git a/src/ast-value-factory.h b/src/ast-value-factory.h index dd079d3..e88819c 100644 --- a/src/ast-value-factory.h +++ b/src/ast-value-factory.h @@ -259,6 +259,7 @@ class AstValue : public ZoneObject { F(prototype, "prototype") \ F(this, "this") \ F(use_asm, "use asm") \ + F(use_strong, "use strong") \ F(use_strict, "use strict") \ F(value, "value") diff --git a/src/code-stubs.h b/src/code-stubs.h index 3e6ea44..2edeb8f 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -593,9 +593,9 @@ class FastNewClosureStub : public HydrogenCodeStub { bool is_default_constructor() const { return IsDefaultConstructor(kind()); } private: - STATIC_ASSERT(LANGUAGE_END == 2); - class LanguageModeBits : public BitField {}; - class FunctionKindBits : public BitField {}; + STATIC_ASSERT(LANGUAGE_END == 3); + class LanguageModeBits : public BitField {}; + class FunctionKindBits : public BitField {}; DEFINE_CALL_INTERFACE_DESCRIPTOR(FastNewClosure); DEFINE_HYDROGEN_CODE_STUB(FastNewClosure, HydrogenCodeStub); diff --git a/src/compiler.cc b/src/compiler.cc index 5ac6353..9aab688 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -1355,7 +1355,7 @@ Handle Compiler::CompileScript( } if (FLAG_use_strict) { info.SetLanguageMode( - static_cast(info.language_mode() | STRICT)); + static_cast(info.language_mode() | STRICT_BIT)); } result = CompileToplevel(&info); @@ -1389,7 +1389,7 @@ Handle Compiler::CompileStreamedScript( if (FLAG_use_strict) { info->SetLanguageMode( - static_cast(info->language_mode() | STRICT)); + static_cast(info->language_mode() | STRICT_BIT)); } // TODO(marja): FLAG_serialize_toplevel is not honoured and won't be; when the // real code caching lands, streaming needs to be adapted to use it. diff --git a/src/compiler.h b/src/compiler.h index d1a16b0..b9d1ddb 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -73,25 +73,26 @@ class CompilationInfo { kEval = 1 << 1, kGlobal = 1 << 2, kStrictMode = 1 << 3, - kThisHasUses = 1 << 4, - kNative = 1 << 5, - kDeferredCalling = 1 << 6, - kNonDeferredCalling = 1 << 7, - kSavesCallerDoubles = 1 << 8, - kRequiresFrame = 1 << 9, - kMustNotHaveEagerFrame = 1 << 10, - kDeoptimizationSupport = 1 << 11, - kDebug = 1 << 12, - kCompilingForDebugging = 1 << 13, - kParseRestriction = 1 << 14, - kSerializing = 1 << 15, - kContextSpecializing = 1 << 16, - kInliningEnabled = 1 << 17, - kTypingEnabled = 1 << 18, - kDisableFutureOptimization = 1 << 19, - kModule = 1 << 20, - kToplevel = 1 << 21, - kSplittingEnabled = 1 << 22 + kStrongMode = 1 << 4, + kThisHasUses = 1 << 5, + kNative = 1 << 6, + kDeferredCalling = 1 << 7, + kNonDeferredCalling = 1 << 8, + kSavesCallerDoubles = 1 << 9, + kRequiresFrame = 1 << 10, + kMustNotHaveEagerFrame = 1 << 11, + kDeoptimizationSupport = 1 << 12, + kDebug = 1 << 13, + kCompilingForDebugging = 1 << 14, + kParseRestriction = 1 << 15, + kSerializing = 1 << 16, + kContextSpecializing = 1 << 17, + kInliningEnabled = 1 << 18, + kTypingEnabled = 1 << 19, + kDisableFutureOptimization = 1 << 20, + kModule = 1 << 21, + kToplevel = 1 << 22, + kSplittingEnabled = 1 << 23 }; CompilationInfo(Handle closure, Zone* zone); @@ -109,8 +110,8 @@ class CompilationInfo { bool is_global() const { return GetFlag(kGlobal); } bool is_module() const { return GetFlag(kModule); } LanguageMode language_mode() const { - STATIC_ASSERT(LANGUAGE_END == 2); - return GetFlag(kStrictMode) ? STRICT : SLOPPY; + STATIC_ASSERT(LANGUAGE_END == 3); + return construct_language_mode(GetFlag(kStrictMode), GetFlag(kStrongMode)); } FunctionLiteral* function() const { return function_; } Scope* scope() const { return scope_; } @@ -167,8 +168,9 @@ class CompilationInfo { bool this_has_uses() { return GetFlag(kThisHasUses); } void SetLanguageMode(LanguageMode language_mode) { - STATIC_ASSERT(LANGUAGE_END == 2); - SetFlag(kStrictMode, language_mode & STRICT); + STATIC_ASSERT(LANGUAGE_END == 3); + SetFlag(kStrictMode, language_mode & STRICT_BIT); + SetFlag(kStrongMode, language_mode & STRONG_BIT); } void MarkAsNative() { SetFlag(kNative); } diff --git a/src/flag-definitions.h b/src/flag-definitions.h index d458aae..3c4909f 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -259,6 +259,7 @@ DEFINE_BOOL(smi_binop, true, "support smi representation in binary operations") DEFINE_BOOL(vector_ics, false, "support vector-based ics") DEFINE_BOOL(experimental_classes, false, "experimental new semantics for super() calls") +DEFINE_BOOL(strong_mode, false, "experimental strong language mode") DEFINE_IMPLICATION(experimental_classes, harmony_classes) DEFINE_IMPLICATION(experimental_classes, harmony_object_literals) diff --git a/src/globals.h b/src/globals.h index 83fa2fa..761a85d 100644 --- a/src/globals.h +++ b/src/globals.h @@ -227,25 +227,47 @@ template class List; enum LanguageMode { // LanguageMode is expressed as a bitmask. Descriptions of the bits: - STRICT = 1 << 0, + STRICT_BIT = 1 << 0, + STRONG_BIT = 1 << 1, LANGUAGE_END, // Shorthands for some common language modes. - SLOPPY = 0 + SLOPPY = 0, + STRICT = STRICT_BIT, + STRONG = STRICT_BIT | STRONG_BIT }; + +inline bool is_sloppy(LanguageMode language_mode) { + return (language_mode & STRICT_BIT) == 0; +} + + inline bool is_strict(LanguageMode language_mode) { - return language_mode & STRICT; + return language_mode & STRICT_BIT; } -inline bool is_sloppy(LanguageMode language_mode) { - return (language_mode & STRICT) == 0; + +inline bool is_strong(LanguageMode language_mode) { + return language_mode & STRONG_BIT; } + inline bool is_valid_language_mode(int language_mode) { - return language_mode == SLOPPY || language_mode == STRICT; + return language_mode == SLOPPY || language_mode == STRICT || + language_mode == STRONG; +} + + +inline LanguageMode construct_language_mode(bool strict_bit, bool strong_bit) { + int language_mode = 0; + if (strict_bit) language_mode |= STRICT_BIT; + if (strong_bit) language_mode |= STRONG_BIT; + DCHECK(is_valid_language_mode(language_mode)); + return static_cast(language_mode); } + // Mask for the sign bit in a smi. const intptr_t kSmiSignMask = kIntptrSignBit; diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index c13be91..c35236a 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -7618,8 +7618,8 @@ class HFunctionLiteral FINAL : public HTemplateInstruction<1> { class FunctionKindField : public BitField {}; class PretenureField : public BitField {}; class HasNoLiteralsField : public BitField {}; - STATIC_ASSERT(LANGUAGE_END == 2); - class LanguageModeField : public BitField {}; + STATIC_ASSERT(LANGUAGE_END == 3); + class LanguageModeField : public BitField {}; Handle shared_info_; uint32_t bit_field_; diff --git a/src/ic/ic.h b/src/ic/ic.h index 5f66e88..6ef601b 100644 --- a/src/ic/ic.h +++ b/src/ic/ic.h @@ -520,8 +520,8 @@ class KeyedLoadIC : public LoadIC { class StoreIC : public IC { public: - STATIC_ASSERT(i::LANGUAGE_END == 2); - class LanguageModeState : public BitField {}; + STATIC_ASSERT(i::LANGUAGE_END == 3); + class LanguageModeState : public BitField {}; static ExtraICState ComputeExtraICState(LanguageMode flag) { return LanguageModeState::encode(flag); } @@ -605,10 +605,12 @@ class KeyedStoreIC : public StoreIC { public: // ExtraICState bits (building on IC) // ExtraICState bits + // When more language modes are added, these BitFields need to move too. + STATIC_ASSERT(i::LANGUAGE_END == 3); class ExtraICStateKeyedAccessStoreMode - : public BitField {}; // NOLINT + : public BitField {}; // NOLINT - class IcCheckTypeField : public BitField {}; + class IcCheckTypeField : public BitField {}; static ExtraICState ComputeExtraICState(LanguageMode flag, KeyedAccessStoreMode mode) { diff --git a/src/objects-inl.h b/src/objects-inl.h index 54cef6f..9e9bd59 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -5820,19 +5820,21 @@ void SharedFunctionInfo::set_optimization_disabled(bool disable) { LanguageMode SharedFunctionInfo::language_mode() { - STATIC_ASSERT(LANGUAGE_END == 2); - return BooleanBit::get(compiler_hints(), kStrictModeFunction) - ? STRICT : SLOPPY; + STATIC_ASSERT(LANGUAGE_END == 3); + return construct_language_mode( + BooleanBit::get(compiler_hints(), kStrictModeFunction), + BooleanBit::get(compiler_hints(), kStrongModeFunction)); } void SharedFunctionInfo::set_language_mode(LanguageMode language_mode) { - STATIC_ASSERT(LANGUAGE_END == 2); + STATIC_ASSERT(LANGUAGE_END == 3); // We only allow language mode transitions that set the same language mode // again or go up in the chain: DCHECK(is_sloppy(this->language_mode()) || is_strict(language_mode)); int hints = compiler_hints(); hints = BooleanBit::set(hints, kStrictModeFunction, is_strict(language_mode)); + hints = BooleanBit::set(hints, kStrongModeFunction, is_strong(language_mode)); set_compiler_hints(hints); } diff --git a/src/objects.cc b/src/objects.cc index 1eaea79..3ca3b2d 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -14039,8 +14039,9 @@ class StringSharedKey : public HashTableKey { // collection. Script* script(Script::cast(shared->script())); hash ^= String::cast(script->source())->Hash(); - STATIC_ASSERT(LANGUAGE_END == 2); + STATIC_ASSERT(LANGUAGE_END == 3); if (is_strict(language_mode)) hash ^= 0x8000; + if (is_strong(language_mode)) hash ^= 0x10000; hash += scope_position; } return hash; diff --git a/src/objects.h b/src/objects.h index 286f6fb..b49efaa 100644 --- a/src/objects.h +++ b/src/objects.h @@ -4325,12 +4325,12 @@ class ScopeInfo : public FixedArray { // Properties of scopes. class ScopeTypeField : public BitField {}; class CallsEvalField : public BitField {}; - STATIC_ASSERT(LANGUAGE_END == 2); - class LanguageModeField : public BitField {}; - class FunctionVariableField : public BitField {}; - class FunctionVariableMode : public BitField {}; - class AsmModuleField : public BitField {}; - class AsmFunctionField : public BitField {}; + STATIC_ASSERT(LANGUAGE_END == 3); + class LanguageModeField : public BitField {}; + class FunctionVariableField : public BitField {}; + class FunctionVariableMode : public BitField {}; + class AsmModuleField : public BitField {}; + class AsmFunctionField : public BitField {}; // BitFields representing the encoded information for context locals in the // ContextLocalInfoEntries part. @@ -7181,6 +7181,7 @@ class SharedFunctionInfo: public HeapObject { kAllowLazyCompilationWithoutContext, kOptimizationDisabled, kStrictModeFunction, + kStrongModeFunction, kUsesArguments, kUsesSuperProperty, kUsesSuperConstructorCall, @@ -7203,7 +7204,7 @@ class SharedFunctionInfo: public HeapObject { kCompilerHintsCount // Pseudo entry }; // Add hints for other modes when they're added. - STATIC_ASSERT(LANGUAGE_END == 2); + STATIC_ASSERT(LANGUAGE_END == 3); class FunctionKindBits : public BitField {}; diff --git a/src/parser.cc b/src/parser.cc index 0dbfe5d..124f521 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -289,7 +289,7 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope, Scope* function_scope = NewScope(scope, FUNCTION_SCOPE, FunctionKind::kDefaultConstructor); function_scope->SetLanguageMode( - static_cast(scope->language_mode() | STRICT)); + static_cast(scope->language_mode() | STRICT_BIT)); // Set start and end position to the same value function_scope->set_start_position(pos); function_scope->set_end_position(pos); @@ -824,6 +824,7 @@ Parser::Parser(CompilationInfo* info, ParseInfo* parse_info) set_allow_harmony_computed_property_names( FLAG_harmony_computed_property_names); set_allow_harmony_rest_params(FLAG_harmony_rest_parameters); + set_allow_strong_mode(FLAG_strong_mode); for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; ++feature) { use_counts_[feature] = 0; @@ -1145,34 +1146,48 @@ void* Parser::ParseStatementList(ZoneList* body, int end_token, if ((e_stat = stat->AsExpressionStatement()) != NULL && (literal = e_stat->expression()->AsLiteral()) != NULL && literal->raw_value()->IsString()) { - // Check "use strict" directive (ES5 14.1) and "use asm" directive. Only - // one can be present. - if (is_sloppy(language_mode()) && + // Check "use strict" directive (ES5 14.1), "use asm" directive, and + // "use strong" directive (experimental). + bool use_strict_found = literal->raw_value()->AsString() == ast_value_factory()->use_strict_string() && token_loc.end_pos - token_loc.beg_pos == - ast_value_factory()->use_strict_string()->length() + 2) { - // TODO(mstarzinger): Global strict eval calls, need their own scope - // as specified in ES5 10.4.2(3). The correct fix would be to always - // add this scope in DoParseProgram(), but that requires adaptations - // all over the code base, so we go with a quick-fix for now. - // In the same manner, we have to patch the parsing mode. - if (is_eval && !scope_->is_eval_scope()) { - DCHECK(scope_->is_script_scope()); - Scope* scope = NewScope(scope_, EVAL_SCOPE); - scope->set_start_position(scope_->start_position()); - scope->set_end_position(scope_->end_position()); - scope_ = scope; - if (eval_scope != NULL) { - // Caller will correct the positions of the ad hoc eval scope. - *eval_scope = scope; + ast_value_factory()->use_strict_string()->length() + 2; + bool use_strong_found = + allow_strong_mode() && + literal->raw_value()->AsString() == + ast_value_factory()->use_strong_string() && + token_loc.end_pos - token_loc.beg_pos == + ast_value_factory()->use_strong_string()->length() + 2; + if (use_strict_found || use_strong_found) { + // Strong mode implies strict mode. If there are several "use strict" + // / "use strong" directives, do the strict mode changes only once. + if (is_sloppy(scope_->language_mode())) { + // TODO(mstarzinger): Global strict eval calls, need their own scope + // as specified in ES5 10.4.2(3). The correct fix would be to always + // add this scope in DoParseProgram(), but that requires adaptations + // all over the code base, so we go with a quick-fix for now. + // In the same manner, we have to patch the parsing mode. + if (is_eval && !scope_->is_eval_scope()) { + DCHECK(scope_->is_script_scope()); + Scope* scope = NewScope(scope_, EVAL_SCOPE); + scope->set_start_position(scope_->start_position()); + scope->set_end_position(scope_->end_position()); + scope_ = scope; + if (eval_scope != NULL) { + // Caller will correct the positions of the ad hoc eval scope. + *eval_scope = scope; + } + mode_ = PARSE_EAGERLY; } - mode_ = PARSE_EAGERLY; + scope_->SetLanguageMode(static_cast( + scope_->language_mode() | STRICT_BIT)); + } + + if (use_strong_found) { + scope_->SetLanguageMode(static_cast( + scope_->language_mode() | STRONG_BIT)); } - scope_->SetLanguageMode( - static_cast(scope_->language_mode() | STRICT)); - // "use strict" is the only directive for now. - directive_prologue = false; } else if (literal->raw_value()->AsString() == ast_value_factory()->use_asm_string() && token_loc.end_pos - token_loc.beg_pos == @@ -1257,7 +1272,7 @@ Module* Parser::ParseModule(bool* ok) { scope->set_start_position(scanner()->location().beg_pos); scope->SetLanguageMode( - static_cast(scope->language_mode() | STRICT)); + static_cast(scope->language_mode() | STRICT_BIT)); { BlockState block_state(&scope_, scope); @@ -4007,6 +4022,7 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( allow_harmony_computed_property_names()); reusable_preparser_->set_allow_harmony_rest_params( allow_harmony_rest_params()); + reusable_preparser_->set_allow_strong_mode(allow_strong_mode()); } PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction( language_mode(), is_generator(), logger); @@ -4036,7 +4052,7 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name, Scope* block_scope = NewScope(scope_, BLOCK_SCOPE); BlockState block_state(&scope_, block_scope); scope_->SetLanguageMode( - static_cast(scope_->language_mode() | STRICT)); + static_cast(scope_->language_mode() | STRICT_BIT)); scope_->SetScopeName(name); VariableProxy* proxy = NULL; diff --git a/src/preparser.cc b/src/preparser.cc index 2bed193..170c9e7 100644 --- a/src/preparser.cc +++ b/src/preparser.cc @@ -80,6 +80,8 @@ PreParserExpression PreParserTraits::ExpressionFromString( int pos, Scanner* scanner, PreParserFactory* factory) { if (scanner->UnescapedLiteralMatches("use strict", 10)) { return PreParserExpression::UseStrictStringLiteral(); + } else if (scanner->UnescapedLiteralMatches("use strong", 10)) { + return PreParserExpression::UseStrongStringLiteral(); } return PreParserExpression::StringLiteral(); } @@ -212,7 +214,10 @@ PreParser::SourceElements PreParser::ParseSourceElements(int end_token, if (directive_prologue) { if (statement.IsUseStrictLiteral()) { scope_->SetLanguageMode( - static_cast(scope_->language_mode() | STRICT)); + static_cast(scope_->language_mode() | STRICT_BIT)); + } else if (statement.IsUseStrongLiteral() && allow_strong_mode()) { + scope_->SetLanguageMode(static_cast( + scope_->language_mode() | STRICT_BIT | STRONG_BIT)); } else if (!statement.IsStringLiteral()) { directive_prologue = false; } @@ -1002,7 +1007,7 @@ PreParserExpression PreParser::ParseClassLiteral( PreParserScope scope = NewScope(scope_, BLOCK_SCOPE); BlockState block_state(&scope_, &scope); scope_->SetLanguageMode( - static_cast(scope_->language_mode() | STRICT)); + static_cast(scope_->language_mode() | STRICT_BIT)); scope_->SetScopeName(name); bool has_extends = Check(Token::EXTENDS); diff --git a/src/preparser.h b/src/preparser.h index be27be7..5be009d 100644 --- a/src/preparser.h +++ b/src/preparser.h @@ -90,7 +90,8 @@ class ParserBase : public Traits { allow_harmony_object_literals_(false), allow_harmony_sloppy_(false), allow_harmony_computed_property_names_(false), - allow_harmony_rest_params_(false) {} + allow_harmony_rest_params_(false), + allow_strong_mode_(false) {} // Getters that indicate whether certain syntactical constructs are // allowed to be parsed by this instance of the parser. @@ -118,6 +119,8 @@ class ParserBase : public Traits { return allow_harmony_rest_params_; } + bool allow_strong_mode() const { return allow_strong_mode_; } + // Setters that determine whether certain syntactical constructs are // allowed to be parsed by this instance of the parser. void set_allow_lazy(bool allow) { allow_lazy_ = allow; } @@ -155,6 +158,7 @@ class ParserBase : public Traits { void set_allow_harmony_rest_params(bool allow) { allow_harmony_rest_params_ = allow; } + void set_allow_strong_mode(bool allow) { allow_strong_mode_ = allow; } protected: enum AllowEvalOrArgumentsAsIdentifier { @@ -634,6 +638,7 @@ class ParserBase : public Traits { bool allow_harmony_sloppy_; bool allow_harmony_computed_property_names_; bool allow_harmony_rest_params_; + bool allow_strong_mode_; }; @@ -754,8 +759,7 @@ class PreParserExpression { } static PreParserExpression StringLiteral() { - return PreParserExpression(TypeField::encode(kStringLiteralExpression) | - IsUseStrictField::encode(false)); + return PreParserExpression(TypeField::encode(kStringLiteralExpression)); } static PreParserExpression UseStrictStringLiteral() { @@ -763,6 +767,11 @@ class PreParserExpression { IsUseStrictField::encode(true)); } + static PreParserExpression UseStrongStringLiteral() { + return PreParserExpression(TypeField::encode(kStringLiteralExpression) | + IsUseStrongField::encode(true)); + } + static PreParserExpression This() { return PreParserExpression(TypeField::encode(kExpression) | ExpressionTypeField::encode(kThisExpression)); @@ -814,6 +823,11 @@ class PreParserExpression { IsUseStrictField::decode(code_); } + bool IsUseStrongLiteral() const { + return TypeField::decode(code_) == kStringLiteralExpression && + IsUseStrongField::decode(code_); + } + bool IsThis() const { return TypeField::decode(code_) == kExpression && ExpressionTypeField::decode(code_) == kThisExpression; @@ -922,6 +936,7 @@ class PreParserExpression { typedef BitField ExpressionTypeField; typedef BitField IsUseStrictField; + typedef BitField IsUseStrongField; typedef BitField IsValidArrowParamListField; typedef BitField @@ -963,6 +978,9 @@ class PreParserStatement { if (expression.IsUseStrictLiteral()) { return PreParserStatement(kUseStrictExpressionStatement); } + if (expression.IsUseStrongLiteral()) { + return PreParserStatement(kUseStrongExpressionStatement); + } if (expression.IsStringLiteral()) { return PreParserStatement(kStringLiteralExpressionStatement); } @@ -977,6 +995,8 @@ class PreParserStatement { return code_ == kUseStrictExpressionStatement; } + bool IsUseStrongLiteral() { return code_ == kUseStrongExpressionStatement; } + bool IsFunctionDeclaration() { return code_ == kFunctionDeclaration; } @@ -986,6 +1006,7 @@ class PreParserStatement { kUnknownStatement, kStringLiteralExpressionStatement, kUseStrictExpressionStatement, + kUseStrongExpressionStatement, kFunctionDeclaration }; diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 1bcfd6e..4c3752b 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -894,8 +894,8 @@ class AllocateTargetSpace : public BitField {}; class DeclareGlobalsEvalFlag : public BitField {}; class DeclareGlobalsNativeFlag : public BitField {}; -STATIC_ASSERT(LANGUAGE_END == 2); -class DeclareGlobalsLanguageMode : public BitField {}; +STATIC_ASSERT(LANGUAGE_END == 3); +class DeclareGlobalsLanguageMode : public BitField {}; } // namespace internal } // namespace v8 diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc index ec1c9dd..41d8dfe 100644 --- a/test/cctest/test-parsing.cc +++ b/test/cctest/test-parsing.cc @@ -1360,7 +1360,8 @@ enum ParserFlag { kAllowHarmonyTemplates, kAllowHarmonySloppy, kAllowHarmonyUnicode, - kAllowHarmonyComputedPropertyNames + kAllowHarmonyComputedPropertyNames, + kAllowStrongMode }; @@ -1391,6 +1392,7 @@ void SetParserFlags(i::ParserBase* parser, parser->set_allow_harmony_unicode(flags.Contains(kAllowHarmonyUnicode)); parser->set_allow_harmony_computed_property_names( flags.Contains(kAllowHarmonyComputedPropertyNames)); + parser->set_allow_strong_mode(flags.Contains(kAllowStrongMode)); } @@ -1760,10 +1762,11 @@ TEST(ErrorsEvalAndArguments) { // ok to use "eval" or "arguments" as identifiers. With the strict mode, it // isn't. const char* context_data[][2] = { - { "\"use strict\";", "" }, - { "var eval; function test_func() {\"use strict\"; ", "}"}, - { NULL, NULL } - }; + {"\"use strict\";", ""}, + {"\"use strong\";", ""}, + {"var eval; function test_func() {\"use strict\"; ", "}"}, + {"var eval; function test_func() {\"use strong\"; ", "}"}, + {NULL, NULL}}; const char* statement_data[] = { "var eval;", @@ -1793,7 +1796,9 @@ TEST(ErrorsEvalAndArguments) { NULL }; - RunParserSyncTest(context_data, statement_data, kError); + static const ParserFlag always_flags[] = {kAllowStrongMode}; + RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags, + arraysize(always_flags)); } @@ -1900,18 +1905,22 @@ TEST(ErrorsFutureStrictReservedWords) { // it's ok to use future strict reserved words as identifiers. With the strict // mode, it isn't. const char* context_data[][2] = { - { "function test_func() {\"use strict\"; ", "}"}, - { "() => { \"use strict\"; ", "}" }, - { NULL, NULL } - }; + {"function test_func() {\"use strict\"; ", "}"}, + {"() => { \"use strict\"; ", "}"}, + {"function test_func() {\"use strong\"; ", "}"}, + {"() => { \"use strong\"; ", "}"}, + {NULL, NULL}}; const char* statement_data[] { LIMITED_FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS) NULL }; - RunParserSyncTest(context_data, statement_data, kError); - RunParserSyncTest(context_data, statement_data, kError); + static const ParserFlag always_flags[] = {kAllowStrongMode}; + RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags, + arraysize(always_flags)); + RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags, + arraysize(always_flags)); } @@ -2089,15 +2098,21 @@ TEST(NoErrorsYieldSloppyGeneratorsEnabled) { TEST(ErrorsYieldStrict) { const char* context_data[][2] = { - { "\"use strict\";", "" }, - { "\"use strict\"; function not_gen() {", "}" }, - { "function test_func() {\"use strict\"; ", "}"}, - { "\"use strict\"; function * gen() { function not_gen() {", "} }" }, - { "\"use strict\"; (function not_gen() {", "})" }, - { "\"use strict\"; (function * gen() { (function not_gen() {", "}) })" }, - { "() => {\"use strict\"; ", "}" }, - { NULL, NULL } - }; + {"\"use strict\";", ""}, + {"\"use strict\"; function not_gen() {", "}"}, + {"function test_func() {\"use strict\"; ", "}"}, + {"\"use strict\"; function * gen() { function not_gen() {", "} }"}, + {"\"use strict\"; (function not_gen() {", "})"}, + {"\"use strict\"; (function * gen() { (function not_gen() {", "}) })"}, + {"() => {\"use strict\"; ", "}"}, + {"\"use strong\";", ""}, + {"\"use strong\"; function not_gen() {", "}"}, + {"function test_func() {\"use strong\"; ", "}"}, + {"\"use strong\"; function * gen() { function not_gen() {", "} }"}, + {"\"use strong\"; (function not_gen() {", "})"}, + {"\"use strong\"; (function * gen() { (function not_gen() {", "}) })"}, + {"() => {\"use strong\"; ", "}"}, + {NULL, NULL}}; const char* statement_data[] = { "var yield;", @@ -2117,7 +2132,9 @@ TEST(ErrorsYieldStrict) { NULL }; - RunParserSyncTest(context_data, statement_data, kError); + static const ParserFlag always_flags[] = {kAllowStrongMode}; + RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags, + arraysize(always_flags)); } @@ -2235,8 +2252,10 @@ TEST(ErrorsNameOfStrictFunction) { const char* context_data[][2] = { { "function ", ""}, { "\"use strict\"; function", ""}, + { "\"use strong\"; function", ""}, { "function * ", ""}, { "\"use strict\"; function * ", ""}, + { "\"use strong\"; function * ", ""}, { NULL, NULL } }; @@ -2251,7 +2270,9 @@ TEST(ErrorsNameOfStrictFunction) { NULL }; - RunParserSyncTest(context_data, statement_data, kError); + static const ParserFlag always_flags[] = {kAllowStrongMode}; + RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags, + arraysize(always_flags)); } @@ -2312,11 +2333,13 @@ TEST(ErrorsIllegalWordsAsLabelsSloppy) { TEST(ErrorsIllegalWordsAsLabelsStrict) { // Tests that illegal tokens as labels produce the correct errors. const char* context_data[][2] = { - { "\"use strict\";", "" }, - { "function test_func() {\"use strict\"; ", "}"}, - { "() => {\"use strict\"; ", "}" }, - { NULL, NULL } - }; + {"\"use strict\";", ""}, + {"function test_func() {\"use strict\"; ", "}"}, + {"() => {\"use strict\"; ", "}"}, + {"\"use strong\";", ""}, + {"function test_func() {\"use strong\"; ", "}"}, + {"() => {\"use strong\"; ", "}"}, + {NULL, NULL}}; #define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }", const char* statement_data[] = { @@ -2326,7 +2349,9 @@ TEST(ErrorsIllegalWordsAsLabelsStrict) { }; #undef LABELLED_WHILE - RunParserSyncTest(context_data, statement_data, kError); + static const ParserFlag always_flags[] = {kAllowStrongMode}; + RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags, + arraysize(always_flags)); } @@ -2403,10 +2428,13 @@ TEST(NoErrorsParenthesizedDirectivePrologue) { const char* statement_data[] = { "(\"use strict\"); var eval;", + "(\"use strong\"); var eval;", NULL }; - RunParserSyncTest(context_data, statement_data, kSuccess); + static const ParserFlag always_flags[] = {kAllowStrongMode}; + RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, + always_flags, arraysize(always_flags)); } @@ -2530,6 +2558,7 @@ TEST(FunctionDeclaresItselfStrict) { const char* strict_statement_data[] = { "\"use strict\";", + "\"use strong\";", NULL }; @@ -2538,8 +2567,11 @@ TEST(FunctionDeclaresItselfStrict) { NULL }; - RunParserSyncTest(context_data, strict_statement_data, kError); - RunParserSyncTest(context_data, non_strict_statement_data, kSuccess); + static const ParserFlag always_flags[] = {kAllowStrongMode}; + RunParserSyncTest(context_data, strict_statement_data, kError, NULL, 0, + always_flags, arraysize(always_flags)); + RunParserSyncTest(context_data, non_strict_statement_data, kSuccess, NULL, 0, + always_flags, arraysize(always_flags)); } @@ -2831,6 +2863,7 @@ TEST(StrictDelete) { // "delete " is not allowed in strict mode. const char* strict_context_data[][2] = { {"\"use strict\"; ", ""}, + {"\"use strong\"; ", ""}, { NULL, NULL } }; @@ -2870,14 +2903,21 @@ TEST(StrictDelete) { NULL }; - RunParserSyncTest(strict_context_data, sloppy_statement_data, kError); - RunParserSyncTest(sloppy_context_data, sloppy_statement_data, kSuccess); + static const ParserFlag always_flags[] = {kAllowStrongMode}; + RunParserSyncTest(strict_context_data, sloppy_statement_data, kError, NULL, 0, + always_flags, arraysize(always_flags)); + RunParserSyncTest(sloppy_context_data, sloppy_statement_data, kSuccess, NULL, + 0, always_flags, arraysize(always_flags)); - RunParserSyncTest(strict_context_data, good_statement_data, kSuccess); - RunParserSyncTest(sloppy_context_data, good_statement_data, kSuccess); + RunParserSyncTest(strict_context_data, good_statement_data, kSuccess, NULL, 0, + always_flags, arraysize(always_flags)); + RunParserSyncTest(sloppy_context_data, good_statement_data, kSuccess, NULL, 0, + always_flags, arraysize(always_flags)); - RunParserSyncTest(strict_context_data, bad_statement_data, kError); - RunParserSyncTest(sloppy_context_data, bad_statement_data, kError); + RunParserSyncTest(strict_context_data, bad_statement_data, kError, NULL, 0, + always_flags, arraysize(always_flags)); + RunParserSyncTest(sloppy_context_data, bad_statement_data, kError, NULL, 0, + always_flags, arraysize(always_flags)); } @@ -4970,6 +5010,12 @@ TEST(DeclarationsError) { {"'use strict'; for (;;)", ""}, {"'use strict'; for (x in y)", ""}, {"'use strict'; do ", " while (false)"}, + {"'use strong'; if (true)", ""}, + {"'use strong'; if (false) {} else", ""}, + {"'use strong'; while (false)", ""}, + {"'use strong'; for (;;)", ""}, + {"'use strong'; for (x in y)", ""}, + {"'use strong'; do ", " while (false)"}, {NULL, NULL}}; const char* statement_data[] = { @@ -4979,8 +5025,50 @@ TEST(DeclarationsError) { NULL}; static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, kAllowHarmonyScoping - }; + kAllowHarmonyClasses, kAllowHarmonyScoping, kAllowStrongMode}; RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags, arraysize(always_flags)); } + + +void TestLanguageMode(const char* source, + i::LanguageMode expected_language_mode) { + i::Isolate* isolate = CcTest::i_isolate(); + i::Factory* factory = isolate->factory(); + v8::HandleScope handles(CcTest::isolate()); + v8::Handle context = v8::Context::New(CcTest::isolate()); + v8::Context::Scope context_scope(context); + isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() - + 128 * 1024); + + i::Handle script = + factory->NewScript(factory->NewStringFromAsciiChecked(source)); + i::CompilationInfoWithZone info(script); + i::Parser::ParseInfo parse_info = {isolate->stack_guard()->real_climit(), + isolate->heap()->HashSeed(), + isolate->unicode_cache()}; + i::Parser parser(&info, &parse_info); + parser.set_allow_strong_mode(true); + info.MarkAsGlobal(); + parser.Parse(); + CHECK(info.function() != NULL); + CHECK_EQ(expected_language_mode, info.function()->language_mode()); +} + + +TEST(LanguageModeDirectives) { + TestLanguageMode("\"use nothing\"", i::SLOPPY); + TestLanguageMode("\"use strict\"", i::STRICT); + TestLanguageMode("\"use strong\"", i::STRONG); + + TestLanguageMode("var x = 1; \"use strict\"", i::SLOPPY); + TestLanguageMode("var x = 1; \"use strong\"", i::SLOPPY); + + // Test that multiple directives ("use strict" / "use strong") put the parser + // into the correct mode. + TestLanguageMode("\"use strict\"; \"use strong\";", i::STRONG); + TestLanguageMode("\"use strong\"; \"use strict\";", i::STRONG); + + TestLanguageMode("\"use some future directive\"; \"use strict\";", i::STRICT); + TestLanguageMode("\"use some future directive\"; \"use strong\";", i::STRONG); +} diff --git a/test/unittests/compiler/js-typed-lowering-unittest.cc b/test/unittests/compiler/js-typed-lowering-unittest.cc index d8dc725..d61a181 100644 --- a/test/unittests/compiler/js-typed-lowering-unittest.cc +++ b/test/unittests/compiler/js-typed-lowering-unittest.cc @@ -62,8 +62,8 @@ Type* const kJSTypes[] = {Type::Undefined(), Type::Null(), Type::Boolean(), Type::Number(), Type::String(), Type::Object()}; -STATIC_ASSERT(LANGUAGE_END == 2); -const LanguageMode kLanguageModes[] = {SLOPPY, STRICT}; +STATIC_ASSERT(LANGUAGE_END == 3); +const LanguageMode kLanguageModes[] = {SLOPPY, STRICT, STRONG}; } // namespace -- 2.7.4