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}
This commit is contained in:
marja 2015-02-05 06:11:34 -08:00 committed by Commit bot
parent f184ff0650
commit d21b9a1422
17 changed files with 291 additions and 129 deletions

View File

@ -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")

View File

@ -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<LanguageMode, 0, 1> {};
class FunctionKindBits : public BitField<FunctionKind, 1, 4> {};
STATIC_ASSERT(LANGUAGE_END == 3);
class LanguageModeBits : public BitField<LanguageMode, 0, 2> {};
class FunctionKindBits : public BitField<FunctionKind, 2, 4> {};
DEFINE_CALL_INTERFACE_DESCRIPTOR(FastNewClosure);
DEFINE_HYDROGEN_CODE_STUB(FastNewClosure, HydrogenCodeStub);

View File

@ -1355,7 +1355,7 @@ Handle<SharedFunctionInfo> Compiler::CompileScript(
}
if (FLAG_use_strict) {
info.SetLanguageMode(
static_cast<LanguageMode>(info.language_mode() | STRICT));
static_cast<LanguageMode>(info.language_mode() | STRICT_BIT));
}
result = CompileToplevel(&info);
@ -1389,7 +1389,7 @@ Handle<SharedFunctionInfo> Compiler::CompileStreamedScript(
if (FLAG_use_strict) {
info->SetLanguageMode(
static_cast<LanguageMode>(info->language_mode() | STRICT));
static_cast<LanguageMode>(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.

View File

@ -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<JSFunction> 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); }

View File

@ -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)

View File

@ -227,25 +227,47 @@ template <typename T, class P = FreeStoreAllocationPolicy> 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_strict(LanguageMode language_mode) {
return language_mode & STRICT;
}
inline bool is_sloppy(LanguageMode language_mode) {
return (language_mode & STRICT) == 0;
return (language_mode & STRICT_BIT) == 0;
}
inline bool is_valid_language_mode(int language_mode) {
return language_mode == SLOPPY || language_mode == STRICT;
inline bool is_strict(LanguageMode language_mode) {
return language_mode & STRICT_BIT;
}
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 ||
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<LanguageMode>(language_mode);
}
// Mask for the sign bit in a smi.
const intptr_t kSmiSignMask = kIntptrSignBit;

View File

@ -7618,8 +7618,8 @@ class HFunctionLiteral FINAL : public HTemplateInstruction<1> {
class FunctionKindField : public BitField<FunctionKind, 0, 4> {};
class PretenureField : public BitField<bool, 5, 1> {};
class HasNoLiteralsField : public BitField<bool, 6, 1> {};
STATIC_ASSERT(LANGUAGE_END == 2);
class LanguageModeField : public BitField<LanguageMode, 7, 1> {};
STATIC_ASSERT(LANGUAGE_END == 3);
class LanguageModeField : public BitField<LanguageMode, 7, 2> {};
Handle<SharedFunctionInfo> shared_info_;
uint32_t bit_field_;

View File

@ -520,8 +520,8 @@ class KeyedLoadIC : public LoadIC {
class StoreIC : public IC {
public:
STATIC_ASSERT(i::LANGUAGE_END == 2);
class LanguageModeState : public BitField<LanguageMode, 1, 1> {};
STATIC_ASSERT(i::LANGUAGE_END == 3);
class LanguageModeState : public BitField<LanguageMode, 1, 2> {};
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<KeyedAccessStoreMode, 2, 4> {}; // NOLINT
: public BitField<KeyedAccessStoreMode, 3, 4> {}; // NOLINT
class IcCheckTypeField : public BitField<IcCheckType, 6, 1> {};
class IcCheckTypeField : public BitField<IcCheckType, 7, 1> {};
static ExtraICState ComputeExtraICState(LanguageMode flag,
KeyedAccessStoreMode mode) {

View File

@ -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);
}

View File

@ -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;

View File

@ -4325,12 +4325,12 @@ class ScopeInfo : public FixedArray {
// Properties of scopes.
class ScopeTypeField : public BitField<ScopeType, 0, 4> {};
class CallsEvalField : public BitField<bool, 4, 1> {};
STATIC_ASSERT(LANGUAGE_END == 2);
class LanguageModeField : public BitField<LanguageMode, 5, 1> {};
class FunctionVariableField : public BitField<FunctionVariableInfo, 6, 2> {};
class FunctionVariableMode : public BitField<VariableMode, 8, 3> {};
class AsmModuleField : public BitField<bool, 11, 1> {};
class AsmFunctionField : public BitField<bool, 12, 1> {};
STATIC_ASSERT(LANGUAGE_END == 3);
class LanguageModeField : public BitField<LanguageMode, 5, 2> {};
class FunctionVariableField : public BitField<FunctionVariableInfo, 7, 2> {};
class FunctionVariableMode : public BitField<VariableMode, 9, 3> {};
class AsmModuleField : public BitField<bool, 12, 1> {};
class AsmFunctionField : public BitField<bool, 13, 1> {};
// 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<FunctionKind, kIsArrow, 5> {};

View File

@ -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<LanguageMode>(scope->language_mode() | STRICT));
static_cast<LanguageMode>(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<Statement*>* 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<LanguageMode>(
scope_->language_mode() | STRICT_BIT));
}
if (use_strong_found) {
scope_->SetLanguageMode(static_cast<LanguageMode>(
scope_->language_mode() | STRONG_BIT));
}
scope_->SetLanguageMode(
static_cast<LanguageMode>(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<LanguageMode>(scope->language_mode() | STRICT));
static_cast<LanguageMode>(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<LanguageMode>(scope_->language_mode() | STRICT));
static_cast<LanguageMode>(scope_->language_mode() | STRICT_BIT));
scope_->SetScopeName(name);
VariableProxy* proxy = NULL;

View File

@ -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<LanguageMode>(scope_->language_mode() | STRICT));
static_cast<LanguageMode>(scope_->language_mode() | STRICT_BIT));
} else if (statement.IsUseStrongLiteral() && allow_strong_mode()) {
scope_->SetLanguageMode(static_cast<LanguageMode>(
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<LanguageMode>(scope_->language_mode() | STRICT));
static_cast<LanguageMode>(scope_->language_mode() | STRICT_BIT));
scope_->SetScopeName(name);
bool has_extends = Check(Token::EXTENDS);

View File

@ -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<ExpressionType, ParenthesizationField::kNext, 3>
ExpressionTypeField;
typedef BitField<bool, ParenthesizationField::kNext, 1> IsUseStrictField;
typedef BitField<bool, IsUseStrictField::kNext, 1> IsUseStrongField;
typedef BitField<bool, ParenthesizationField::kNext, 1>
IsValidArrowParamListField;
typedef BitField<PreParserIdentifier::Type, ParenthesizationField::kNext, 10>
@ -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
};

View File

@ -894,8 +894,8 @@ class AllocateTargetSpace : public BitField<AllocationSpace, 1, 3> {};
class DeclareGlobalsEvalFlag : public BitField<bool, 0, 1> {};
class DeclareGlobalsNativeFlag : public BitField<bool, 1, 1> {};
STATIC_ASSERT(LANGUAGE_END == 2);
class DeclareGlobalsLanguageMode : public BitField<LanguageMode, 2, 1> {};
STATIC_ASSERT(LANGUAGE_END == 3);
class DeclareGlobalsLanguageMode : public BitField<LanguageMode, 2, 2> {};
} // namespace internal
} // namespace v8

View File

@ -1360,7 +1360,8 @@ enum ParserFlag {
kAllowHarmonyTemplates,
kAllowHarmonySloppy,
kAllowHarmonyUnicode,
kAllowHarmonyComputedPropertyNames
kAllowHarmonyComputedPropertyNames,
kAllowStrongMode
};
@ -1391,6 +1392,7 @@ void SetParserFlags(i::ParserBase<Traits>* 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 <Identifier>" 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<v8::Context> context = v8::Context::New(CcTest::isolate());
v8::Context::Scope context_scope(context);
isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
128 * 1024);
i::Handle<i::Script> 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);
}

View File

@ -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