Ignore:
Timestamp:
Oct 11, 2010, 12:12:29 PM (15 years ago)
Author:
[email protected]
Message:

2010-10-01 Oliver Hunt <[email protected]>

Reviewed by Gavin Barraclough.

[ES5] Implement strict mode
https://bugs.webkit.org/show_bug.cgi?id=10701

Initial strict mode implementation. This is the simplest
implementation that could possibly work and adds (hopefully)
all of the restrictions required by strict mode. There are
a number of inefficiencies, especially in the handling of
arguments and eval as smart implementations would make this
patch more complicated.

The SyntaxChecker AST builder has become somewhat more complex
as strict mode does require more parse tree information to
validate the syntax.

Summary of major changes to the parser:

  • We track when we enter strict mode (this may come as a surprise)
  • Strict mode actually requires a degree of AST knowledge to validate so the SyntaxChecker now produces values that can be used to distinguish "node" types.
  • We now track variables that are written to. We do this to statically identify writes to global properties that don't exist and abort at that point. This should actually make it possible to optimise some other cases in the future but for now it's purely for validity checking. Currently writes are only tracked in strict mode code.
  • Labels are now tracked as it is now a syntax error to jump to a label that does not exist (or to use break, continue, or return in a context where they would be invalid).

Runtime changes:

  • In order to get correct hanlding of the Arguments object all strict mode functions that reference arguments create and tearoff the arguments object on entry. This is not strictly necessary but was the least work necessary to get the correct behaviour.
  • PutPropertySlot now tracks whether it is being used for a strict mode write, and if so Object::put will throw when a write can't be completed.
  • StrictEvalActivation was added as an "activation" object for strict mode eval (so that strict eval does not introduce new variables into the containing scope).
  • CMakeLists.txt:
  • GNUmakefile.am:
  • JavaScriptCore.exp:
  • JavaScriptCore.pro:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::dump): (JSC::CodeBlock::CodeBlock): (JSC::CodeBlock::reparseForExceptionInfoIfNecessary):
  • bytecode/CodeBlock.h: (JSC::CodeBlock::isStrictMode):
  • bytecode/EvalCodeCache.h: (JSC::EvalCodeCache::get):
  • bytecode/Opcode.h:
  • bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::BytecodeGenerator): (JSC::BytecodeGenerator::createArgumentsIfNecessary): (JSC::BytecodeGenerator::emitReturn):
  • bytecompiler/BytecodeGenerator.h: (JSC::BytecodeGenerator::isStrictMode): (JSC::BytecodeGenerator::makeFunction):
  • debugger/Debugger.cpp: (JSC::evaluateInGlobalCallFrame):
  • debugger/DebuggerCallFrame.cpp: (JSC::DebuggerCallFrame::evaluate):
  • interpreter/Interpreter.cpp: (JSC::Interpreter::callEval): (JSC::Interpreter::unwindCallFrame): (JSC::Interpreter::execute): (JSC::Interpreter::privateExecute):
  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): (JSC::JIT::privateCompileSlowCases):
  • jit/JIT.h:
  • jit/JITOpcodes.cpp: (JSC::JIT::emit_op_get_pnames): (JSC::JIT::emit_op_convert_this_strict): (JSC::JIT::emitSlow_op_convert_this_strict):
  • jit/JITOpcodes32_64.cpp: (JSC::JIT::emit_op_get_pnames):
  • jit/JITStubs.cpp: (JSC::DEFINE_STUB_FUNCTION):
  • jit/JITStubs.h:
  • parser/ASTBuilder.h: (JSC::ASTBuilder::createFunctionBody): (JSC::ASTBuilder::isResolve):
  • parser/JSParser.cpp: (JSC::JSParser::next): (JSC::JSParser::startLoop): (JSC::JSParser::endLoop): (JSC::JSParser::startSwitch): (JSC::JSParser::endSwitch): (JSC::JSParser::setStrictMode): (JSC::JSParser::strictMode): (JSC::JSParser::isValidStrictMode): (JSC::JSParser::declareParameter): (JSC::JSParser::breakIsValid): (JSC::JSParser::pushLabel): (JSC::JSParser::popLabel): (JSC::JSParser::hasLabel): (JSC::JSParser::DepthManager::DepthManager): (JSC::JSParser::DepthManager::~DepthManager): (JSC::JSParser::Scope::Scope): (JSC::JSParser::Scope::startSwitch): (JSC::JSParser::Scope::endSwitch): (JSC::JSParser::Scope::startLoop): (JSC::JSParser::Scope::endLoop): (JSC::JSParser::Scope::inLoop): (JSC::JSParser::Scope::breakIsValid): (JSC::JSParser::Scope::pushLabel): (JSC::JSParser::Scope::popLabel): (JSC::JSParser::Scope::hasLabel): (JSC::JSParser::Scope::isFunction): (JSC::JSParser::Scope::declareVariable): (JSC::JSParser::Scope::declareWrite): (JSC::JSParser::Scope::deleteProperty): (JSC::JSParser::Scope::declareParameter): (JSC::JSParser::Scope::setNeedsFullActivation): (JSC::JSParser::Scope::collectFreeVariables): (JSC::JSParser::Scope::getUncapturedWrittenVariables): (JSC::JSParser::Scope::getDeletedVariables): (JSC::JSParser::Scope::setStrictMode): (JSC::JSParser::Scope::strictMode): (JSC::JSParser::Scope::isValidStrictMode): (JSC::JSParser::pushScope): (JSC::JSParser::popScope): (JSC::JSParser::declareVariable): (JSC::JSParser::declareWrite): (JSC::JSParser::deleteProperty): (JSC::jsParse): (JSC::JSParser::JSParser): (JSC::JSParser::parseProgram): (JSC::JSParser::parseSourceElements): (JSC::JSParser::parseDoWhileStatement): (JSC::JSParser::parseWhileStatement): (JSC::JSParser::parseVarDeclarationList): (JSC::JSParser::parseConstDeclarationList): (JSC::JSParser::parseForStatement): (JSC::JSParser::parseBreakStatement): (JSC::JSParser::parseContinueStatement): (JSC::JSParser::parseReturnStatement): (JSC::JSParser::parseWithStatement): (JSC::JSParser::parseSwitchStatement): (JSC::JSParser::parseSwitchClauses): (JSC::JSParser::parseSwitchDefaultClause): (JSC::JSParser::parseTryStatement): (JSC::JSParser::parseBlockStatement): (JSC::JSParser::parseStatement): (JSC::JSParser::parseFormalParameters): (JSC::JSParser::parseFunctionBody): (JSC::JSParser::parseFunctionInfo): (JSC::JSParser::parseFunctionDeclaration): (JSC::JSParser::parseExpressionOrLabelStatement): (JSC::JSParser::parseIfStatement): (JSC::JSParser::parseExpression): (JSC::JSParser::parseAssignmentExpression): (JSC::JSParser::parseConditionalExpression): (JSC::JSParser::parseBinaryExpression): (JSC::JSParser::parseStrictObjectLiteral): (JSC::JSParser::parsePrimaryExpression): (JSC::JSParser::parseMemberExpression): (JSC::JSParser::parseUnaryExpression):
  • parser/JSParser.h:
  • parser/Lexer.cpp: (JSC::Lexer::parseString): (JSC::Lexer::lex):
  • parser/Lexer.h: (JSC::Lexer::isReparsing):
  • parser/Nodes.cpp: (JSC::ScopeNode::ScopeNode): (JSC::FunctionBodyNode::FunctionBodyNode): (JSC::FunctionBodyNode::create):
  • parser/Nodes.h: (JSC::ScopeNode::isStrictMode):
  • parser/Parser.cpp: (JSC::Parser::parse):
  • parser/Parser.h: (JSC::Parser::parse):
  • parser/SyntaxChecker.h: (JSC::SyntaxChecker::SyntaxChecker): (JSC::SyntaxChecker::makeFunctionCallNode): (JSC::SyntaxChecker::appendToComma): (JSC::SyntaxChecker::createCommaExpr): (JSC::SyntaxChecker::makeAssignNode): (JSC::SyntaxChecker::makePrefixNode): (JSC::SyntaxChecker::makePostfixNode): (JSC::SyntaxChecker::makeTypeOfNode): (JSC::SyntaxChecker::makeDeleteNode): (JSC::SyntaxChecker::makeNegateNode): (JSC::SyntaxChecker::makeBitwiseNotNode): (JSC::SyntaxChecker::createLogicalNot): (JSC::SyntaxChecker::createUnaryPlus): (JSC::SyntaxChecker::createVoid): (JSC::SyntaxChecker::thisExpr): (JSC::SyntaxChecker::createResolve): (JSC::SyntaxChecker::createObjectLiteral): (JSC::SyntaxChecker::createArray): (JSC::SyntaxChecker::createNumberExpr): (JSC::SyntaxChecker::createString): (JSC::SyntaxChecker::createBoolean): (JSC::SyntaxChecker::createNull): (JSC::SyntaxChecker::createBracketAccess): (JSC::SyntaxChecker::createDotAccess): (JSC::SyntaxChecker::createRegex): (JSC::SyntaxChecker::createNewExpr): (JSC::SyntaxChecker::createConditionalExpr): (JSC::SyntaxChecker::createAssignResolve): (JSC::SyntaxChecker::createFunctionExpr): (JSC::SyntaxChecker::createFunctionBody): (JSC::SyntaxChecker::appendBinaryExpressionInfo): (JSC::SyntaxChecker::operatorStackPop):
  • runtime/Arguments.cpp: (JSC::Arguments::createStrictModeCallerIfNecessary): (JSC::Arguments::createStrictModeCalleeIfNecessary): (JSC::Arguments::getOwnPropertySlot): (JSC::Arguments::getOwnPropertyDescriptor): (JSC::Arguments::put): (JSC::Arguments::deleteProperty):
  • runtime/Arguments.h: (JSC::Arguments::Arguments):
  • runtime/CommonIdentifiers.cpp: (JSC::CommonIdentifiers::CommonIdentifiers):
  • runtime/CommonIdentifiers.h:
  • runtime/Error.cpp: (JSC::StrictModeTypeErrorFunction::StrictModeTypeErrorFunction): (JSC::StrictModeTypeErrorFunction::constructThrowTypeError): (JSC::StrictModeTypeErrorFunction::getConstructData): (JSC::StrictModeTypeErrorFunction::callThrowTypeError): (JSC::StrictModeTypeErrorFunction::getCallData): (JSC::createTypeErrorFunction):
  • runtime/Error.h:
  • runtime/Executable.cpp: (JSC::EvalExecutable::EvalExecutable): (JSC::ProgramExecutable::ProgramExecutable): (JSC::FunctionExecutable::FunctionExecutable): (JSC::EvalExecutable::compileInternal): (JSC::ProgramExecutable::checkSyntax): (JSC::ProgramExecutable::compileInternal): (JSC::FunctionExecutable::compileForCallInternal): (JSC::FunctionExecutable::compileForConstructInternal): (JSC::FunctionExecutable::reparseExceptionInfo): (JSC::EvalExecutable::reparseExceptionInfo): (JSC::FunctionExecutable::fromGlobalCode): (JSC::ProgramExecutable::reparseExceptionInfo):
  • runtime/Executable.h: (JSC::ScriptExecutable::ScriptExecutable): (JSC::ScriptExecutable::isStrictMode): (JSC::EvalExecutable::create): (JSC::FunctionExecutable::create):
  • runtime/JSActivation.cpp: (JSC::JSActivation::toStrictThisObject):
  • runtime/JSActivation.h:
  • runtime/JSFunction.cpp: (JSC::createDescriptorForThrowingProperty): (JSC::JSFunction::getOwnPropertySlot): (JSC::JSFunction::getOwnPropertyDescriptor): (JSC::JSFunction::put):
  • runtime/JSGlobalData.cpp: (JSC::JSGlobalData::JSGlobalData):
  • runtime/JSGlobalData.h:
  • runtime/JSGlobalObject.cpp: (JSC::JSGlobalObject::reset):
  • runtime/JSGlobalObject.h: (JSC::JSGlobalObject::internalFunctionStructure):
  • runtime/JSGlobalObjectFunctions.cpp: (JSC::globalFuncEval):
  • runtime/JSObject.cpp: (JSC::JSObject::put): (JSC::JSObject::toStrictThisObject): (JSC::throwTypeError):
  • runtime/JSObject.h: (JSC::JSObject::isStrictModeFunction): (JSC::JSObject::putDirectInternal): (JSC::JSObject::putDirect): (JSC::JSValue::putDirect): (JSC::JSValue::toStrictThisObject):
  • runtime/JSStaticScopeObject.cpp: (JSC::JSStaticScopeObject::toStrictThisObject):
  • runtime/JSStaticScopeObject.h:
  • runtime/JSValue.h:
  • runtime/JSZombie.h: (JSC::JSZombie::toStrictThisObject):
  • runtime/PutPropertySlot.h: (JSC::PutPropertySlot::PutPropertySlot): (JSC::PutPropertySlot::isStrictMode):
  • runtime/StrictEvalActivation.cpp: Added. (JSC::StrictEvalActivation::StrictEvalActivation): (JSC::StrictEvalActivation::deleteProperty): (JSC::StrictEvalActivation::toThisObject): (JSC::StrictEvalActivation::toStrictThisObject):
  • runtime/StrictEvalActivation.h: Added.

2010-10-01 Oliver Hunt <[email protected]>

Reviewed by Gavin Barraclough.

[ES5] Implement strict mode
https://bugs.webkit.org/show_bug.cgi?id=10701

Tests for the many different behaviours we get in strict mode.

  • fast/js/basic-strict-mode-expected.txt: Added.
  • fast/js/basic-strict-mode.html: Added.
  • fast/js/script-tests/basic-strict-mode.js: Added. (testThis): (testGlobalAccess):

2010-10-01 Oliver Hunt <[email protected]>

Reviewed by Gavin Barraclough.

[ES5] Implement strict mode
https://bugs.webkit.org/show_bug.cgi?id=10701

Test: fast/js/basic-strict-mode.html

Override toStrictThisObject on the domwindow so that
it correctly provides the shell object when used as this
in a strict mode function.

  • bindings/js/JSDOMWindowBase.cpp: (WebCore::JSDOMWindowBase::toStrictThisObject):
  • bindings/js/JSDOMWindowBase.h:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/parser/JSParser.cpp

    r68288 r69516  
    3030using namespace JSC;
    3131
     32#include "CodeBlock.h"
    3233#include "JSGlobalData.h"
    3334#include "NodeInfo.h"
     
    4344#define failIfFalse(cond) do { if (!(cond)) fail(); } while (0)
    4445#define failIfTrue(cond) do { if ((cond)) fail(); } while (0)
     46#define failIfTrueIfStrict(cond) do { if ((cond) && strictMode()) fail(); } while (0)
     47#define failIfFalseIfStrict(cond) do { if ((!(cond)) && strictMode()) fail(); } while (0)
    4548#define consumeOrFail(tokenType) do { if (!consume(tokenType)) fail(); } while (0)
    4649#define matchOrFail(tokenType) do { if (!match(tokenType)) fail(); } while (0)
     
    6871class JSParser {
    6972public:
    70     JSParser(Lexer*, JSGlobalData*, FunctionParameters*, SourceProvider*);
    71     bool parseProgram();
     73    JSParser(Lexer*, JSGlobalData*, FunctionParameters*, bool isStrictContext, bool isFunction, SourceProvider*);
     74    bool parseProgram(JSGlobalObject*);
    7275private:
    7376    struct AllowInOverride {
     
    9194        m_lastTokenEnd = m_token.m_info.endOffset;
    9295        m_lexer->setLastLineNumber(m_lastLine);
    93         m_token.m_type = m_lexer->lex(&m_token.m_data, &m_token.m_info, lexType);
     96        m_token.m_type = m_lexer->lex(&m_token.m_data, &m_token.m_info, lexType, strictMode());
    9497        m_tokenCount++;
    9598    }
     
    122125        return m_token.m_info.endOffset;
    123126    }
    124 
    125     template <class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&);
    126     template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&);
     127   
     128    void startLoop() { currentScope()->startLoop(); }
     129    void endLoop() { currentScope()->endLoop(); }
     130    void startSwitch() { currentScope()->startSwitch(); }
     131    void endSwitch() { currentScope()->endSwitch(); }
     132    void setStrictMode() { currentScope()->setStrictMode(); }
     133    bool strictMode() { return currentScope()->strictMode(); }
     134    bool isValidStrictMode() { return currentScope()->isValidStrictMode(); }
     135    bool declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); }
     136    bool breakIsValid() { return currentScope()->breakIsValid(); }
     137    void pushLabel(const Identifier* label) { currentScope()->pushLabel(label); }
     138    void popLabel() { currentScope()->popLabel(); }
     139    bool hasLabel(const Identifier* label) { return currentScope()->hasLabel(label); }
     140
     141    enum SourceElementsMode { CheckForStrictMode, DontCheckForStrictMode };
     142    template <SourceElementsMode mode, class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&);
     143    template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive);
    127144    template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&);
    128145    template <class TreeBuilder> TreeStatement parseVarDeclaration(TreeBuilder&);
     
    200217    int m_nonLHSCount;
    201218    bool m_syntaxAlreadyValidated;
     219    int m_statementDepth;
     220    int m_nonTrivialExpressionCount;
     221    const Identifier* m_lastIdentifier;
     222
     223    struct DepthManager {
     224        DepthManager(int* depth)
     225            : m_originalDepth(*depth)
     226            , m_depth(depth)
     227        {
     228        }
     229       
     230        ~DepthManager()
     231        {
     232            *m_depth = m_originalDepth;
     233        }
     234       
     235    private:
     236        int m_originalDepth;
     237        int* m_depth;
     238    };
    202239
    203240    struct Scope {
    204         Scope()
    205             : m_usesEval(false)
     241        Scope(JSGlobalData* globalData, bool isFunction, bool strictMode)
     242            : m_globalData(globalData)
     243            , m_usesEval(false)
    206244            , m_needsFullActivation(false)
    207245            , m_allowsNewDecls(true)
     246            , m_strictMode(strictMode)
     247            , m_isFunction(isFunction)
     248            , m_isValidStrictMode(true)
     249            , m_loopDepth(0)
     250            , m_switchDepth(0)
     251            , m_labels(0)
    208252        {
    209253        }
    210254       
    211         void declareVariable(const Identifier* ident)
     255        void startSwitch() { m_switchDepth++; }
     256        void endSwitch() { m_switchDepth--; }
     257        void startLoop() { m_loopDepth++; }
     258        void endLoop() { ASSERT(m_loopDepth); m_loopDepth--; }
     259        bool inLoop() { return !!m_loopDepth; }
     260        bool breakIsValid() { return m_loopDepth || m_switchDepth; }
     261
     262        void pushLabel(const Identifier* label)
    212263        {
     264            if (!m_labels)
     265                m_labels = new LabelStack;
     266            m_labels->append(label->impl());
     267        }
     268
     269        void popLabel()
     270        {
     271            ASSERT(m_labels);
     272            ASSERT(m_labels->size());
     273            m_labels->removeLast();
     274        }
     275
     276        bool hasLabel(const Identifier* label)
     277        {
     278            if (!m_labels)
     279                return false;
     280            for (int i = m_labels->size(); i > 0; i--) {
     281                if (m_labels->at(i - 1) == label->impl())
     282                    return true;
     283            }
     284            return false;
     285        }
     286
     287        void setIsFunction() { m_isFunction = true; }
     288        bool isFunction() { return m_isFunction; }
     289       
     290        bool declareVariable(const Identifier* ident)
     291        {
     292            bool isValidStrictMode = m_globalData->propertyNames->eval != *ident && m_globalData->propertyNames->arguments != *ident;
     293            m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
    213294            m_declaredVariables.add(ident->ustring().impl());
     295            return isValidStrictMode;
     296        }
     297       
     298        void declareWrite(const Identifier* ident)
     299        {
     300            ASSERT(m_strictMode);
     301            m_writtenVariables.add(ident->impl());
     302        }
     303       
     304        bool deleteProperty(const Identifier* ident)
     305        {
     306            if (m_declaredVariables.contains(ident->impl()))
     307                return false;
     308            m_deletedVariables.add(ident->impl());
     309            return true;
    214310        }
    215311       
     
    217313        bool allowsNewDecls() const { return m_allowsNewDecls; }
    218314
     315        bool declareParameter(const Identifier* ident)
     316        {
     317            bool isValidStrictMode = m_declaredVariables.add(ident->ustring().impl()).second && m_globalData->propertyNames->eval != *ident && m_globalData->propertyNames->arguments != *ident;
     318            m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
     319            return isValidStrictMode;
     320        }
     321       
    219322        void useVariable(const Identifier* ident, bool isEval)
    220323        {
     
    223326        }
    224327       
    225         void needsFullActivation() { m_needsFullActivation = true; }
     328        void setNeedsFullActivation() { m_needsFullActivation = true; }
    226329       
    227         void collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables)
     330        bool collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables)
    228331        {
    229332            if (nestedScope->m_usesEval)
     
    237340                    m_closedVariables.add(*ptr);
    238341            }
     342            if (nestedScope->m_writtenVariables.size()) {
     343                IdentifierSet::iterator end = nestedScope->m_writtenVariables.end();
     344                for (IdentifierSet::iterator ptr = nestedScope->m_writtenVariables.begin(); ptr != end; ++ptr) {
     345                    if (nestedScope->m_declaredVariables.contains(*ptr))
     346                        continue;
     347                    m_writtenVariables.add(*ptr);
     348                }
     349            }
     350            if (nestedScope->m_deletedVariables.size()) {
     351                IdentifierSet::iterator end = nestedScope->m_deletedVariables.end();
     352                for (IdentifierSet::iterator ptr = nestedScope->m_deletedVariables.begin(); ptr != end; ++ptr) {
     353                    if (nestedScope->m_declaredVariables.contains(*ptr))
     354                        return false;
     355                    if (m_declaredVariables.contains(*ptr))
     356                        return false;
     357                    m_deletedVariables.add(*ptr);
     358                }
     359            }
     360            return true;
     361        }
     362
     363        void getUncapturedWrittenVariables(IdentifierSet& writtenVariables)
     364        {
     365            IdentifierSet::iterator end = m_writtenVariables.end();
     366            for (IdentifierSet::iterator ptr = m_writtenVariables.begin(); ptr != end; ++ptr) {
     367                if (!m_declaredVariables.contains(*ptr))
     368                    writtenVariables.add(*ptr);
     369            }
     370        }
     371
     372        bool getDeletedVariables(IdentifierSet& deletedVariables)
     373        {
     374            IdentifierSet::iterator end = m_deletedVariables.end();
     375            for (IdentifierSet::iterator ptr = m_deletedVariables.begin(); ptr != end; ++ptr) {
     376                if (m_declaredVariables.contains(*ptr))
     377                    return false;
     378            }
     379            deletedVariables.swap(m_deletedVariables);
     380            return true;
    239381        }
    240382
     
    251393            }
    252394        }
     395        void setStrictMode() { m_strictMode = true; }
     396        bool strictMode() const { return m_strictMode; }
     397        bool isValidStrictMode() const { return m_isValidStrictMode; }
     398
    253399    private:
    254         bool m_usesEval;
    255         bool m_needsFullActivation;
    256         bool m_allowsNewDecls;
     400        JSGlobalData* m_globalData;
     401        bool m_usesEval : 1;
     402        bool m_needsFullActivation : 1;
     403        bool m_allowsNewDecls : 1;
     404        bool m_strictMode : 1;
     405        bool m_isFunction : 1;
     406        bool m_isValidStrictMode : 1;
     407        int m_loopDepth;
     408        int m_switchDepth;
     409        typedef Vector<StringImpl*, 2> LabelStack;
     410        LabelStack* m_labels;
    257411        IdentifierSet m_declaredVariables;
    258412        IdentifierSet m_usedVariables;
    259413        IdentifierSet m_closedVariables;
     414        IdentifierSet m_writtenVariables;
     415        IdentifierSet m_deletedVariables;
    260416    };
    261417   
     
    282438    ScopeRef pushScope()
    283439    {
    284         m_scopeStack.append(Scope());
     440        bool isFunction = false;
     441        bool isStrict = false;
     442        if (!m_scopeStack.isEmpty()) {
     443            isStrict = m_scopeStack.last().strictMode();
     444            isFunction = m_scopeStack.last().isFunction();
     445        }
     446        m_scopeStack.append(Scope(m_globalData, isFunction, isStrict));
    285447        return currentScope();
    286448    }
    287449
    288     void popScope(ScopeRef scope, bool shouldTrackClosedVariables)
     450    bool popScope(ScopeRef scope, bool shouldTrackClosedVariables)
    289451    {
    290452        ASSERT_UNUSED(scope, scope.index() == m_scopeStack.size() - 1);
    291453        ASSERT(m_scopeStack.size() > 1);
    292         m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables);
     454        bool result = m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables);
    293455        m_scopeStack.removeLast();
     456        return result;
    294457    }
    295458   
    296     void declareVariable(const Identifier* ident)
     459    bool declareVariable(const Identifier* ident)
    297460    {
    298461        unsigned i = m_scopeStack.size() - 1;
     
    302465            ASSERT(i < m_scopeStack.size());
    303466        }
    304         m_scopeStack[i].declareVariable(ident);
    305     }
    306 
     467        return m_scopeStack[i].declareVariable(ident);
     468    }
     469   
     470    void declareWrite(const Identifier* ident)
     471    {
     472        if (!m_syntaxAlreadyValidated)
     473            m_scopeStack.last().declareWrite(ident);
     474    }
     475
     476    bool deleteProperty(const Identifier* ident)
     477    {
     478        if (!m_syntaxAlreadyValidated)
     479            return m_scopeStack.last().deleteProperty(ident);
     480        return true;
     481    }
     482   
    307483    ScopeStack m_scopeStack;
    308484};
    309485
    310 int jsParse(JSGlobalData* globalData, FunctionParameters* parameters, const SourceCode* source)
    311 {
    312     JSParser parser(globalData->lexer, globalData, parameters, source->provider());
    313     return parser.parseProgram();
    314 }
    315 
    316 JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, FunctionParameters* parameters, SourceProvider* provider)
     486int jsParse(JSGlobalObject* lexicalGlobalObject, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode, const SourceCode* source)
     487{
     488    JSParser parser(lexicalGlobalObject->globalData()->lexer, lexicalGlobalObject->globalData(), parameters, strictness == JSParseStrict, parserMode == JSParseFunctionCode, source->provider());
     489    return parser.parseProgram(lexicalGlobalObject);
     490}
     491
     492JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, FunctionParameters* parameters, bool inStrictContext, bool isFunction, SourceProvider* provider)
    317493    : m_lexer(lexer)
    318494    , m_endAddress(0)
     
    326502    , m_nonLHSCount(0)
    327503    , m_syntaxAlreadyValidated(provider->isValid())
     504    , m_statementDepth(0)
     505    , m_nonTrivialExpressionCount(0)
     506    , m_lastIdentifier(0)
    328507{
    329508    m_endAddress = wtfThreadData().approximatedStackStart() - kMaxParserStackUsage;
    330     next();
    331     m_lexer->setLastLineNumber(tokenLine());
    332509    ScopeRef scope = pushScope();
     510    if (isFunction)
     511        scope->setIsFunction();
     512    if (inStrictContext)
     513        scope->setStrictMode();
    333514    if (parameters) {
    334515        for (unsigned i = 0; i < parameters->size(); i++)
    335             scope->declareVariable(&parameters->at(i));
    336     }
    337 }
    338 
    339 bool JSParser::parseProgram()
     516            scope->declareParameter(&parameters->at(i));
     517    }
     518    next();
     519    m_lexer->setLastLineNumber(tokenLine());
     520}
     521
     522bool JSParser::parseProgram(JSGlobalObject* lexicalGlobalObject)
    340523{
    341524    ASTBuilder context(m_globalData, m_lexer);
     525    if (m_lexer->isReparsing())
     526        m_statementDepth--;
    342527    ScopeRef scope = currentScope();
    343     SourceElements* sourceElements = parseSourceElements<ASTBuilder>(context);
     528    SourceElements* sourceElements = parseSourceElements<CheckForStrictMode>(context);
    344529    if (!sourceElements || !consume(EOFTOK))
    345530        return true;
     531    if (!m_syntaxAlreadyValidated) {
     532        IdentifierSet writtenVariables;
     533        scope->getUncapturedWrittenVariables(writtenVariables);
     534        IdentifierSet::const_iterator end = writtenVariables.end();
     535        for (IdentifierSet::const_iterator ptr = writtenVariables.begin(); ptr != end; ++ptr) {
     536            PropertySlot slot(lexicalGlobalObject);
     537            if (!lexicalGlobalObject->getPropertySlot(lexicalGlobalObject->globalExec(), Identifier(m_globalData, *ptr), slot))
     538                return true;
     539        }
     540        IdentifierSet deletedVariables;
     541        if (!scope->getDeletedVariables(deletedVariables))
     542            return true;
     543        end = deletedVariables.end();
     544        SymbolTable& globalEnvRecord = lexicalGlobalObject->symbolTable();
     545        for (IdentifierSet::const_iterator ptr = deletedVariables.begin(); ptr != end; ++ptr) {
     546            if (!globalEnvRecord.get(*ptr).isNull())
     547                return true;
     548        }
     549    }
    346550    IdentifierSet capturedVariables;
    347551    scope->getCapturedVariables(capturedVariables);
    348     m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), context.features(),
    349                                           m_lastLine, context.numConstants(), capturedVariables);
     552    m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), context.features() | (scope->strictMode() ? StrictModeFeature : 0),
     553                                           m_lastLine, context.numConstants(), capturedVariables);
    350554    return false;
    351555}
     
    356560}
    357561
    358 template <class TreeBuilder> TreeSourceElements JSParser::parseSourceElements(TreeBuilder& context)
     562template <JSParser::SourceElementsMode mode, class TreeBuilder> TreeSourceElements JSParser::parseSourceElements(TreeBuilder& context)
    359563{
    360564    TreeSourceElements sourceElements = context.createSourceElements();
    361     while (TreeStatement statement = parseStatement(context))
     565    bool seenNonDirective = false;
     566    const Identifier* directive = 0;
     567    unsigned startOffset = m_token.m_info.startOffset;
     568    bool hasSetStrict = false;
     569    while (TreeStatement statement = parseStatement(context, directive)) {
     570        if (mode == CheckForStrictMode && !seenNonDirective) {
     571            if (directive) {
     572                if (!hasSetStrict && m_globalData->propertyNames->useStrictIdentifier == *directive) {
     573                    setStrictMode();
     574                    hasSetStrict = true;
     575                    failIfFalse(isValidStrictMode());
     576                    m_lexer->setOffset(startOffset);
     577                    next();
     578                    failIfTrue(m_error);
     579                    continue;
     580                }
     581            } else
     582                seenNonDirective = true;
     583        }
    362584        context.appendStatement(sourceElements, statement);
     585    }
    363586
    364587    if (m_error)
     
    400623    int startLine = tokenLine();
    401624    next();
    402     TreeStatement statement = parseStatement(context);
     625    const Identifier* unused = 0;
     626    startLoop();
     627    TreeStatement statement = parseStatement(context, unused);
     628    endLoop();
    403629    failIfFalse(statement);
    404630    int endLine = tokenLine();
     
    423649    int endLine = tokenLine();
    424650    consumeOrFail(CLOSEPAREN);
    425     TreeStatement statement = parseStatement(context);
     651    const Identifier* unused = 0;
     652    startLoop();
     653    TreeStatement statement = parseStatement(context, unused);
     654    endLoop();
    426655    failIfFalse(statement);
    427656    return context.createWhileStatement(expr, statement, startLine, endLine);
     
    442671        next();
    443672        bool hasInitializer = match(EQUAL);
    444         declareVariable(name);
     673        failIfFalseIfStrict(declareVariable(name));
    445674        context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0);
    446675        if (hasInitializer) {
     
    466695template <class TreeBuilder> TreeConstDeclList JSParser::parseConstDeclarationList(TreeBuilder& context)
    467696{
     697    failIfTrue(strictMode());
    468698    TreeConstDeclList constDecls = 0;
    469699    TreeConstDeclList tail = 0;
     
    533763        consumeOrFail(CLOSEPAREN);
    534764
    535         TreeStatement statement = parseStatement(context);
     765        const Identifier* unused = 0;
     766        startLoop();
     767        TreeStatement statement = parseStatement(context, unused);
     768        endLoop();
    536769        failIfFalse(statement);
    537770
     
    567800        int endLine = tokenLine();
    568801        consumeOrFail(CLOSEPAREN);
    569         TreeStatement statement = parseStatement(context);
     802        const Identifier* unused = 0;
     803        startLoop();
     804        TreeStatement statement = parseStatement(context, unused);
     805        endLoop();
    570806        failIfFalse(statement);
    571807        return context.createForLoop(decls, condition, increment, statement, hasDeclaration, startLine, endLine);
     
    580816    int endLine = tokenLine();
    581817    consumeOrFail(CLOSEPAREN);
    582     TreeStatement statement = parseStatement(context);
     818    const Identifier* unused = 0;
     819    startLoop();
     820    TreeStatement statement = parseStatement(context, unused);
     821    endLoop();
    583822    failIfFalse(statement);
    584823   
     
    595834    next();
    596835
    597     if (autoSemiColon())
     836    if (autoSemiColon()) {
     837        failIfFalseIfStrict(breakIsValid());
    598838        return context.createBreakStatement(startCol, endCol, startLine, endLine);
     839    }
    599840    matchOrFail(IDENT);
    600841    const Identifier* ident = m_token.m_data.ident;
     842    failIfFalseIfStrict(hasLabel(ident));
    601843    endCol = tokenEnd();
    602844    endLine = tokenLine();
     
    615857    next();
    616858
    617     if (autoSemiColon())
     859    if (autoSemiColon()) {
     860        failIfFalseIfStrict(breakIsValid());
    618861        return context.createContinueStatement(startCol, endCol, startLine, endLine);
     862    }
    619863    matchOrFail(IDENT);
    620864    const Identifier* ident = m_token.m_data.ident;
     865    failIfFalseIfStrict(hasLabel(ident));
    621866    endCol = tokenEnd();
    622867    endLine = tokenLine();
     
    629874{
    630875    ASSERT(match(RETURN));
     876    failIfFalseIfStrict(currentScope()->isFunction());
    631877    int startLine = tokenLine();
    632878    int endLine = startLine;
     
    669915{
    670916    ASSERT(match(WITH));
    671     currentScope()->needsFullActivation();
     917    failIfTrue(strictMode());
     918    currentScope()->setNeedsFullActivation();
    672919    int startLine = tokenLine();
    673920    next();
     
    680927    int endLine = tokenLine();
    681928    consumeOrFail(CLOSEPAREN);
    682    
    683     TreeStatement statement = parseStatement(context);
     929    const Identifier* unused = 0;
     930    TreeStatement statement = parseStatement(context, unused);
    684931    failIfFalse(statement);
    685932
     
    698945    consumeOrFail(CLOSEPAREN);
    699946    consumeOrFail(OPENBRACE);
    700 
     947    startSwitch();
    701948    TreeClauseList firstClauses = parseSwitchClauses(context);
    702949    failIfTrue(m_error);
     
    707954    TreeClauseList secondClauses = parseSwitchClauses(context);
    708955    failIfTrue(m_error);
     956    endSwitch();
    709957    consumeOrFail(CLOSEBRACE);
    710958
     
    721969    failIfFalse(condition);
    722970    consumeOrFail(COLON);
    723     TreeSourceElements statements = parseSourceElements(context);
     971    TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
    724972    failIfFalse(statements);
    725973    TreeClause clause = context.createClause(condition, statements);
     
    732980        failIfFalse(condition);
    733981        consumeOrFail(COLON);
    734         TreeSourceElements statements = parseSourceElements(context);
     982        TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
    735983        failIfFalse(statements);
    736984        clause = context.createClause(condition, statements);
     
    746994    next();
    747995    consumeOrFail(COLON);
    748     TreeSourceElements statements = parseSourceElements(context);
     996    TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
    749997    failIfFalse(statements);
    750998    return context.createClause(0, statements);
     
    7681016
    7691017    if (match(CATCH)) {
    770         currentScope()->needsFullActivation();
     1018        currentScope()->setNeedsFullActivation();
    7711019        next();
    7721020        consumeOrFail(OPENPAREN);
     
    7751023        next();
    7761024        ScopeRef catchScope = pushScope();
    777         catchScope->declareVariable(ident);
     1025        failIfFalseIfStrict(catchScope->declareVariable(ident));
    7781026        catchScope->preventNewDecls();
    7791027        consumeOrFail(CLOSEPAREN);
     
    7831031        failIfFalse(catchBlock);
    7841032        catchHasEval = initialEvalCount != context.evalCount();
    785         popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo);
     1033        failIfFalse(popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo));
    7861034    }
    7871035
     
    8171065        return context.createBlockStatement(0, start, m_lastLine);
    8181066    }
    819     TreeSourceElements subtree = parseSourceElements(context);
     1067    TreeSourceElements subtree = parseSourceElements<DontCheckForStrictMode>(context);
    8201068    failIfFalse(subtree);
    8211069    matchOrFail(CLOSEBRACE);
     
    8241072}
    8251073
    826 template <class TreeBuilder> TreeStatement JSParser::parseStatement(TreeBuilder& context)
    827 {
     1074template <class TreeBuilder> TreeStatement JSParser::parseStatement(TreeBuilder& context, const Identifier*& directive)
     1075{
     1076    DepthManager statementDepth(&m_statementDepth);
     1077    m_statementDepth++;
     1078    directive = 0;
     1079    int nonTrivialExpressionCount = 0;
    8281080    failIfStackOverflow();
    8291081    switch (m_token.m_type) {
     
    8351087        return parseConstDeclaration(context);
    8361088    case FUNCTION:
     1089        failIfFalseIfStrict(m_statementDepth == 1);
    8371090        return parseFunctionDeclaration(context);
    8381091    case SEMICOLON:
     
    8711124    case IDENT:
    8721125        return parseExpressionOrLabelStatement(context);
     1126    case STRING:
     1127        directive = m_token.m_data.ident;
     1128        nonTrivialExpressionCount = m_nonTrivialExpressionCount;
    8731129    default:
    874         return parseExpressionStatement(context);
     1130        TreeStatement exprStatement = parseExpressionStatement(context);
     1131        if (directive && nonTrivialExpressionCount != m_nonTrivialExpressionCount)
     1132            directive = 0;
     1133        return exprStatement;
    8751134    }
    8761135}
     
    8801139    matchOrFail(IDENT);
    8811140    usesArguments = m_globalData->propertyNames->arguments == *m_token.m_data.ident;
    882     declareVariable(m_token.m_data.ident);
     1141    failIfFalseIfStrict(declareParameter(m_token.m_data.ident));
    8831142    TreeFormalParameterList list = context.createFormalParameterList(*m_token.m_data.ident);
    8841143    TreeFormalParameterList tail = list;
     
    8881147        matchOrFail(IDENT);
    8891148        const Identifier* ident = m_token.m_data.ident;
    890         declareVariable(ident);
     1149        usesArguments |= m_globalData->propertyNames->arguments == *m_token.m_data.ident;
     1150        failIfFalseIfStrict(declareParameter(ident));
    8911151        next();
    8921152        usesArguments = usesArguments || m_globalData->propertyNames->arguments == *ident;
     
    8991159{
    9001160    if (match(CLOSEBRACE))
    901         return context.createFunctionBody();
     1161        return context.createFunctionBody(strictMode());
     1162    DepthManager statementDepth(&m_statementDepth);
     1163    m_statementDepth = 0;
    9021164    typename TreeBuilder::FunctionBodyBuilder bodyBuilder(m_globalData, m_lexer);
    903     failIfFalse(parseSourceElements(bodyBuilder));
    904     return context.createFunctionBody();
     1165    failIfFalse(parseSourceElements<CheckForStrictMode>(bodyBuilder));
     1166    return context.createFunctionBody(strictMode());
    9051167}
    9061168
     
    9081170{
    9091171    ScopeRef functionScope = pushScope();
     1172    functionScope->setIsFunction();
    9101173    if (match(IDENT)) {
    9111174        name = m_token.m_data.ident;
    9121175        next();
    9131176        if (!nameIsInContainingScope)
    914             functionScope->declareVariable(name);
     1177            failIfFalseIfStrict(functionScope->declareVariable(name));
    9151178    } else if (requirements == FunctionNeedsName)
    9161179        return false;
     
    9321195    if (usesArguments)
    9331196        context.setUsesArguments(body);
    934     popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo);
     1197    if (functionScope->strictMode() && name) {
     1198        failIfTrue(m_globalData->propertyNames->arguments == *name);
     1199        failIfTrue(m_globalData->propertyNames->eval == *name);
     1200    }
     1201    failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo));
    9351202    matchOrFail(CLOSEBRACE);
    9361203    closeBracePos = m_token.m_data.intValue;
     
    9511218    failIfFalse((parseFunctionInfo<FunctionNeedsName, true>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
    9521219    failIfFalse(name);
    953     declareVariable(name);
     1220    failIfFalseIfStrict(declareVariable(name));
    9541221    return context.createFuncDeclStatement(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
    9551222}
     
    9741241    int end = tokenEnd();
    9751242    consumeOrFail(COLON);
    976     TreeStatement statement = parseStatement(context);
     1243    const Identifier* unused = 0;
     1244    if (strictMode() && !m_syntaxAlreadyValidated)
     1245        pushLabel(ident);
     1246    TreeStatement statement = parseStatement(context, unused);
     1247    if (strictMode() && !m_syntaxAlreadyValidated)
     1248        popLabel();
    9771249    failIfFalse(statement);
    9781250    return context.createLabelStatement(ident, statement, start, end);
     
    10021274    consumeOrFail(CLOSEPAREN);
    10031275
    1004     TreeStatement trueBlock = parseStatement(context);
     1276    const Identifier* unused = 0;
     1277    TreeStatement trueBlock = parseStatement(context, unused);
    10051278    failIfFalse(trueBlock);
    10061279
     
    10151288        next();
    10161289        if (!match(IF)) {
    1017             TreeStatement block = parseStatement(context);
     1290            const Identifier* unused = 0;
     1291            TreeStatement block = parseStatement(context, unused);
    10181292            failIfFalse(block);
    10191293            statementStack.append(block);
     
    10301304        int innerEnd = tokenLine();
    10311305        consumeOrFail(CLOSEPAREN);
    1032        
    1033         TreeStatement innerTrueBlock = parseStatement(context);
     1306        const Identifier* unused = 0;
     1307        TreeStatement innerTrueBlock = parseStatement(context, unused);
    10341308        failIfFalse(innerTrueBlock);     
    10351309        exprStack.append(innerCondition);
     
    10711345        return node;
    10721346    next();
     1347    m_nonTrivialExpressionCount++;
    10731348    m_nonLHSCount++;
    10741349    TreeExpression right = parseAssignmentExpression(context);
     
    11161391            goto end;
    11171392        }
     1393        m_nonTrivialExpressionCount++;
    11181394        hadAssignment = true;
    11191395        context.assignmentStackAppend(assignmentStack, lhs, start, tokenStart(), m_assignmentCount, op);
     
    11211397        m_assignmentCount++;
    11221398        next();
     1399        if (strictMode() && m_lastIdentifier && context.isResolve(lhs)) {
     1400            failIfTrueIfStrict(m_globalData->propertyNames->eval == *m_lastIdentifier);
     1401            declareWrite(m_lastIdentifier);
     1402            m_lastIdentifier = 0;
     1403        }
    11231404        lhs = parseConditionalExpression(context);
    11241405        failIfFalse(lhs);
     
    11451426    if (!match(QUESTION))
    11461427        return cond;
     1428    m_nonTrivialExpressionCount++;
    11471429    m_nonLHSCount++;
    11481430    next();
     
    11821464        if (!precedence)
    11831465            break;
     1466        m_nonTrivialExpressionCount++;
    11841467        m_nonLHSCount++;
    11851468        int operatorToken = m_token.m_type;
     
    11971480        context.operatorStackAppend(operatorStackDepth, operatorToken, precedence);
    11981481    }
    1199 
    12001482    while (operatorStackDepth) {
    12011483        ASSERT(operandStackDepth > 1);
     
    13281610            std::pair<ObjectValidationMap::iterator, bool> propertyEntryIter = objectValidator.add(context.getName(property).impl(), context.getType(property));
    13291611            if (!propertyEntryIter.second) {
     1612                failIfTrue(strictMode());
    13301613                if ((context.getType(property) & propertyEntryIter.first->second) != PropertyNode::Constant) {
    13311614                    // Can't have multiple getters or setters with the same name, nor can we define
     
    13901673    switch (m_token.m_type) {
    13911674    case OPENBRACE:
     1675        if (strictMode())
     1676            return parseStrictObjectLiteral(context);
    13921677        return parseObjectLiteral(context);
    13931678    case OPENBRACKET:
     
    14111696        next();
    14121697        currentScope()->useVariable(ident, m_globalData->propertyNames->eval == *ident);
     1698        m_lastIdentifier = ident;
    14131699        return context.createResolve(ident, start);
    14141700    }
     
    14861772        newCount++;
    14871773    }
     1774
    14881775    if (match(FUNCTION)) {
    14891776        const Identifier* name = &m_globalData->propertyNames->nullIdentifier;
     
    15031790        switch (m_token.m_type) {
    15041791        case OPENBRACKET: {
     1792            m_nonTrivialExpressionCount++;
    15051793            int expressionEnd = lastTokenEnd();
    15061794            next();
     
    15161804        }
    15171805        case OPENPAREN: {
     1806            m_nonTrivialExpressionCount++;
    15181807            if (newCount) {
    15191808                newCount--;
     
    15361825        }
    15371826        case DOT: {
     1827            m_nonTrivialExpressionCount++;
    15381828            int expressionEnd = lastTokenEnd();
    15391829            next(Lexer::IgnoreReservedWords);
     
    15571847    AllowInOverride allowInOverride(this);
    15581848    int tokenStackDepth = 0;
     1849    bool modifiesExpr = false;
     1850    bool requiresLExpr = false;
    15591851    while (isUnaryOp(m_token.m_type)) {
     1852        if (strictMode()) {
     1853            switch (m_token.m_type) {
     1854            case PLUSPLUS:
     1855            case MINUSMINUS:
     1856            case AUTOPLUSPLUS:
     1857            case AUTOMINUSMINUS:
     1858                failIfTrue(requiresLExpr);
     1859                modifiesExpr = true;
     1860                requiresLExpr = true;
     1861                break;
     1862            case DELETETOKEN:
     1863                failIfTrue(requiresLExpr);
     1864                requiresLExpr = true;
     1865                break;
     1866            default:
     1867                failIfTrue(requiresLExpr);
     1868                break;
     1869            }
     1870        }
    15601871        m_nonLHSCount++;
    15611872        context.appendUnaryToken(tokenStackDepth, m_token.m_type, tokenStart());
    15621873        next();
     1874        m_nonTrivialExpressionCount++;
    15631875    }
    15641876    int subExprStart = tokenStart();
    15651877    TreeExpression expr = parseMemberExpression(context);
    15661878    failIfFalse(expr);
     1879    bool isEval = false;
     1880    if (strictMode() && !m_syntaxAlreadyValidated) {
     1881        if (context.isResolve(expr))
     1882            isEval = m_globalData->propertyNames->eval == *m_lastIdentifier;
     1883    }
     1884    failIfTrueIfStrict(isEval && modifiesExpr);
    15671885    switch (m_token.m_type) {
    15681886    case PLUSPLUS:
     1887        m_nonTrivialExpressionCount++;
    15691888        m_nonLHSCount++;
    15701889        expr = context.makePostfixNode(expr, OpPlusPlus, subExprStart, lastTokenEnd(), tokenEnd());
    15711890        m_assignmentCount++;
     1891        failIfTrueIfStrict(isEval);
     1892        failIfTrueIfStrict(requiresLExpr);
    15721893        next();
    15731894        break;
    15741895    case MINUSMINUS:
     1896        m_nonTrivialExpressionCount++;
    15751897        m_nonLHSCount++;
    15761898        expr = context.makePostfixNode(expr, OpMinusMinus, subExprStart, lastTokenEnd(), tokenEnd());
    15771899        m_assignmentCount++;
     1900        failIfTrueIfStrict(isEval);
     1901        failIfTrueIfStrict(requiresLExpr);
    15781902        next();
    15791903        break;
     
    15841908    int end = lastTokenEnd();
    15851909
    1586     if (!TreeBuilder::CreatesAST)
     1910    if (!TreeBuilder::CreatesAST && (m_syntaxAlreadyValidated || !strictMode()))
    15871911        return expr;
    15881912
     
    16181942            break;
    16191943        case DELETETOKEN:
     1944            if (strictMode() && context.isResolve(expr))
     1945                failIfFalse(deleteProperty(m_lastIdentifier));
    16201946            expr = context.makeDeleteNode(expr, context.unaryTokenStackLastStart(tokenStackDepth), end, end);
    16211947            break;
Note: See TracChangeset for help on using the changeset viewer.