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:
parent
f184ff0650
commit
d21b9a1422
@ -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")
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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); }
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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_;
|
||||
|
10
src/ic/ic.h
10
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<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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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> {};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user