2010-10-01 Oliver Hunt <oliver@apple.com>
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 Oct 2010 19:12:29 +0000 (19:12 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 Oct 2010 19:12:29 +0000 (19:12 +0000)
        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  <oliver@apple.com>

        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  <oliver@apple.com>

        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:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@69516 268f45cc-cd09-0410-ab3c-d52691b4dbfc

65 files changed:
JavaScriptCore/CMakeLists.txt
JavaScriptCore/ChangeLog
JavaScriptCore/GNUmakefile.am
JavaScriptCore/JavaScriptCore.exp
JavaScriptCore/JavaScriptCore.pro
JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
JavaScriptCore/bytecode/CodeBlock.cpp
JavaScriptCore/bytecode/CodeBlock.h
JavaScriptCore/bytecode/EvalCodeCache.h
JavaScriptCore/bytecode/Opcode.h
JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
JavaScriptCore/bytecompiler/BytecodeGenerator.h
JavaScriptCore/debugger/Debugger.cpp
JavaScriptCore/debugger/DebuggerCallFrame.cpp
JavaScriptCore/interpreter/Interpreter.cpp
JavaScriptCore/jit/JIT.cpp
JavaScriptCore/jit/JIT.h
JavaScriptCore/jit/JITOpcodes.cpp
JavaScriptCore/jit/JITOpcodes32_64.cpp
JavaScriptCore/jit/JITStubs.cpp
JavaScriptCore/jit/JITStubs.h
JavaScriptCore/parser/ASTBuilder.h
JavaScriptCore/parser/JSParser.cpp
JavaScriptCore/parser/JSParser.h
JavaScriptCore/parser/Lexer.cpp
JavaScriptCore/parser/Lexer.h
JavaScriptCore/parser/Nodes.cpp
JavaScriptCore/parser/Nodes.h
JavaScriptCore/parser/Parser.cpp
JavaScriptCore/parser/Parser.h
JavaScriptCore/parser/SyntaxChecker.h
JavaScriptCore/runtime/Arguments.cpp
JavaScriptCore/runtime/Arguments.h
JavaScriptCore/runtime/CommonIdentifiers.cpp
JavaScriptCore/runtime/CommonIdentifiers.h
JavaScriptCore/runtime/Error.cpp
JavaScriptCore/runtime/Error.h
JavaScriptCore/runtime/Executable.cpp
JavaScriptCore/runtime/Executable.h
JavaScriptCore/runtime/JSActivation.cpp
JavaScriptCore/runtime/JSActivation.h
JavaScriptCore/runtime/JSFunction.cpp
JavaScriptCore/runtime/JSGlobalData.cpp
JavaScriptCore/runtime/JSGlobalData.h
JavaScriptCore/runtime/JSGlobalObject.cpp
JavaScriptCore/runtime/JSGlobalObject.h
JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
JavaScriptCore/runtime/JSObject.cpp
JavaScriptCore/runtime/JSObject.h
JavaScriptCore/runtime/JSStaticScopeObject.cpp
JavaScriptCore/runtime/JSStaticScopeObject.h
JavaScriptCore/runtime/JSValue.h
JavaScriptCore/runtime/JSZombie.h
JavaScriptCore/runtime/PutPropertySlot.h
JavaScriptCore/runtime/StrictEvalActivation.cpp [new file with mode: 0644]
JavaScriptCore/runtime/StrictEvalActivation.h [new file with mode: 0644]
LayoutTests/ChangeLog
LayoutTests/fast/js/basic-strict-mode-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/basic-strict-mode.html [new file with mode: 0644]
LayoutTests/fast/js/script-tests/basic-strict-mode.js [new file with mode: 0644]
WebCore/ChangeLog
WebCore/WebCore.xcodeproj/project.pbxproj
WebCore/bindings/js/JSDOMWindowBase.cpp
WebCore/bindings/js/JSDOMWindowBase.h

index 3db1d09..90067a4 100644 (file)
@@ -157,6 +157,7 @@ SET(JavaScriptCore_SOURCES
     runtime/RopeImpl.cpp
     runtime/ScopeChain.cpp
     runtime/SmallStrings.cpp
+    runtime/StrictEvalActivation.cpp
     runtime/StringConstructor.cpp
     runtime/StringObject.cpp
     runtime/StringPrototype.cpp
index c5ae2c1..ee94c07 100644 (file)
@@ -1,3 +1,301 @@
+2010-10-01  Oliver Hunt  <oliver@apple.com>
+
+        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-10  Patrick Gansterer  <paroga@webkit.org>
 
         Unreviewed.
index 88d1761..7d637b3 100644 (file)
@@ -388,6 +388,8 @@ javascriptcore_sources += \
        JavaScriptCore/runtime/ScopeChainMark.h \
        JavaScriptCore/runtime/SmallStrings.cpp \
        JavaScriptCore/runtime/SmallStrings.h \
+       JavaScriptCore/runtime/StrictEvalActivation.cpp\
+       JavaScriptCore/runtime/StrictEvalActivation.h\
        JavaScriptCore/runtime/StringBuilder.h \
        JavaScriptCore/runtime/StringConcatenate.h \
        JavaScriptCore/runtime/StringConstructor.cpp \
index f773f0b..9ae5108 100644 (file)
@@ -531,6 +531,7 @@ __ZNK3JSC8JSObject11hasPropertyEPNS_9ExecStateERKNS_10IdentifierE
 __ZNK3JSC8JSObject11hasPropertyEPNS_9ExecStateEj
 __ZNK3JSC8JSObject12defaultValueEPNS_9ExecStateENS_22PreferredPrimitiveTypeE
 __ZNK3JSC8JSObject12toThisObjectEPNS_9ExecStateE
+__ZNK3JSC8JSObject18toStrictThisObjectEPNS_9ExecStateE
 __ZNK3JSC8JSObject8toNumberEPNS_9ExecStateE
 __ZNK3JSC8JSObject8toObjectEPNS_9ExecStateE
 __ZNK3JSC8JSObject8toStringEPNS_9ExecStateE
index f463f41..f83bf4c 100644 (file)
@@ -197,6 +197,7 @@ SOURCES += \
     runtime/RopeImpl.cpp \
     runtime/ScopeChain.cpp \
     runtime/SmallStrings.cpp \
+    runtime/StrictEvalActivation.cpp \
     runtime/StringConstructor.cpp \
     runtime/StringObject.cpp \
     runtime/StringPrototype.cpp \
index 83d34e3..479b3dd 100644 (file)
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath="..\..\runtime\StrictEvalActivation.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\runtime\StrictEvalActivation.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath="..\..\runtime\StringConstructor.cpp"\r
                                >\r
                        </File>\r
index 8e78bbc..a45f982 100644 (file)
                A72701B90DADE94900E548D7 /* ExceptionHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = A72701B30DADE94900E548D7 /* ExceptionHelpers.h */; };
                A727FF6B0DA3092200E548D7 /* JSPropertyNameIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A727FF660DA3053B00E548D7 /* JSPropertyNameIterator.cpp */; };
                A7280A2811557E3000D56957 /* JSObjectRefPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = A79EDB0811531CD60019E912 /* JSObjectRefPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               A730B6121250068F009D25B1 /* StrictEvalActivation.h in Headers */ = {isa = PBXBuildFile; fileRef = A730B6101250068F009D25B1 /* StrictEvalActivation.h */; };
+               A730B6131250068F009D25B1 /* StrictEvalActivation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A730B6111250068F009D25B1 /* StrictEvalActivation.cpp */; };
                A7386554118697B400540279 /* SpecializedThunkJIT.h in Headers */ = {isa = PBXBuildFile; fileRef = A7386551118697B400540279 /* SpecializedThunkJIT.h */; };
                A7386555118697B400540279 /* ThunkGenerators.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7386552118697B400540279 /* ThunkGenerators.cpp */; };
                A7386556118697B400540279 /* ThunkGenerators.h in Headers */ = {isa = PBXBuildFile; fileRef = A7386553118697B400540279 /* ThunkGenerators.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A72701B30DADE94900E548D7 /* ExceptionHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExceptionHelpers.h; sourceTree = "<group>"; };
                A727FF650DA3053B00E548D7 /* JSPropertyNameIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPropertyNameIterator.h; sourceTree = "<group>"; };
                A727FF660DA3053B00E548D7 /* JSPropertyNameIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPropertyNameIterator.cpp; sourceTree = "<group>"; };
+               A730B6101250068F009D25B1 /* StrictEvalActivation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StrictEvalActivation.h; sourceTree = "<group>"; };
+               A730B6111250068F009D25B1 /* StrictEvalActivation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StrictEvalActivation.cpp; sourceTree = "<group>"; };
                A7386551118697B400540279 /* SpecializedThunkJIT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpecializedThunkJIT.h; sourceTree = "<group>"; };
                A7386552118697B400540279 /* ThunkGenerators.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThunkGenerators.cpp; sourceTree = "<group>"; };
                A7386553118697B400540279 /* ThunkGenerators.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThunkGenerators.h; sourceTree = "<group>"; };
                                14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */,
                                14035DB010DBFB2A00FFFFE7 /* WeakGCPtr.h */,
                                1420BE7A10AA6DDB00F455D2 /* WeakRandom.h */,
+                               A730B6101250068F009D25B1 /* StrictEvalActivation.h */,
+                               A730B6111250068F009D25B1 /* StrictEvalActivation.cpp */,
                        );
                        path = runtime;
                        sourceTree = "<group>";
                                9714AF5F122F32070092D9F5 /* ParsedURL.h in Headers */,
                                9714AF60122F32070092D9F5 /* URLString.h in Headers */,
                                90213E3E123A40C200D422F3 /* MemoryStatistics.h in Headers */,
+                               A730B6121250068F009D25B1 /* StrictEvalActivation.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXProject;
                        buildConfigurationList = 149C277108902AFE008A9EFC /* Build configuration list for PBXProject "JavaScriptCore" */;
                        compatibilityVersion = "Xcode 2.4";
-                       developmentRegion = English;
                        hasScannedForEncodings = 1;
                        knownRegions = (
                                English,
                                9714AF46122F28850092D9F5 /* URLSegments.cpp in Sources */,
                                9714AF5E122F32070092D9F5 /* ParsedURL.cpp in Sources */,
                                90213E3D123A40C200D422F3 /* MemoryStatistics.cpp in Sources */,
+                               A730B6131250068F009D25B1 /* StrictEvalActivation.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index a2b863d..91f1d36 100644 (file)
@@ -517,6 +517,11 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             printf("[%4d] convert_this %s\n", location, registerName(exec, r0).data());
             break;
         }
+        case op_convert_this_strict: {
+            int r0 = (++it)->u.operand;
+            printf("[%4d] convert_this_strict %s\n", location, registerName(exec, r0).data());
+            break;
+        }
         case op_new_object: {
             int r0 = (++it)->u.operand;
             printf("[%4d] new_object\t %s\n", location, registerName(exec, r0).data());
@@ -1371,6 +1376,7 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlo
     , m_needsFullScopeChain(ownerExecutable->needsActivation())
     , m_usesEval(ownerExecutable->usesEval())
     , m_isNumericCompareFunction(false)
+    , m_isStrictMode(ownerExecutable->isStrictMode())
     , m_codeType(codeType)
     , m_source(sourceProvider)
     , m_sourceOffset(sourceOffset)
@@ -1557,7 +1563,7 @@ bool CodeBlock::reparseForExceptionInfoIfNecessary(CallFrame* callFrame)
             scopeChain = scopeChain->next;
     }
 
-    m_exceptionInfo = m_ownerExecutable->reparseExceptionInfo(m_globalData, scopeChain, this);
+    m_exceptionInfo = m_ownerExecutable->reparseExceptionInfo(scopeChain, this);
     return m_exceptionInfo;
 }
 
index 86971cb..a5f7d28 100644 (file)
@@ -297,6 +297,8 @@ namespace JSC {
         void printStructure(const char* name, const Instruction*, int operand) const;
 #endif
 
+        bool isStrictMode() const { return m_isStrictMode; }
+
         inline bool isKnownNotImmediate(int index)
         {
             if (index == m_thisRegister)
@@ -564,6 +566,7 @@ namespace JSC {
         bool m_needsFullScopeChain;
         bool m_usesEval;
         bool m_isNumericCompareFunction;
+        bool m_isStrictMode;
 
         CodeType m_codeType;
 
index 7c4cb33..edd575f 100644 (file)
@@ -43,20 +43,20 @@ namespace JSC {
 
     class EvalCodeCache {
     public:
-        PassRefPtr<EvalExecutable> get(ExecState* exec, const UString& evalSource, ScopeChainNode* scopeChain, JSValue& exceptionValue)
+        PassRefPtr<EvalExecutable> get(ExecState* exec, bool inStrictContext, const UString& evalSource, ScopeChainNode* scopeChain, JSValue& exceptionValue)
         {
             RefPtr<EvalExecutable> evalExecutable;
 
-            if (evalSource.length() < maxCacheableSourceLength && (*scopeChain->begin())->isVariableObject())
+            if (!inStrictContext && evalSource.length() < maxCacheableSourceLength && (*scopeChain->begin())->isVariableObject())
                 evalExecutable = m_cacheMap.get(evalSource.impl());
 
             if (!evalExecutable) {
-                evalExecutable = EvalExecutable::create(exec, makeSource(evalSource));
+                evalExecutable = EvalExecutable::create(exec, makeSource(evalSource), inStrictContext);
                 exceptionValue = evalExecutable->compile(exec, scopeChain);
                 if (exceptionValue)
                     return 0;
 
-                if (evalSource.length() < maxCacheableSourceLength && (*scopeChain->begin())->isVariableObject() && m_cacheMap.size() < maxCacheEntries)
+                if (!inStrictContext && evalSource.length() < maxCacheableSourceLength && (*scopeChain->begin())->isVariableObject() && m_cacheMap.size() < maxCacheEntries)
                     m_cacheMap.set(evalSource.impl(), evalExecutable);
             }
 
index 3f6b213..884bea5 100644 (file)
@@ -45,6 +45,7 @@ namespace JSC {
         macro(op_create_this, 3) \
         macro(op_get_callee, 2) \
         macro(op_convert_this, 2) \
+        macro(op_convert_this_strict, 2) \
         \
         macro(op_new_object, 2) \
         macro(op_new_array, 4) \
index 4c6e1f3..d58fd55 100644 (file)
@@ -343,6 +343,11 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debug
 
         emitInitLazyRegister(argumentsRegister);
         emitInitLazyRegister(unmodifiedArgumentsRegister);
+        
+        if (m_codeBlock->isStrictMode()) {
+            emitOpcode(op_create_arguments);
+            instructions().append(argumentsRegister->index());
+        }
 
         // The debugger currently retrieves the arguments object from an activation rather than pulling
         // it from a call frame.  In the long-term it should stop doing that (<rdar://problem/6911886>),
@@ -442,7 +447,10 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debug
         instructions().append(m_thisRegister.index());
         instructions().append(funcProto->index());
     } else if (functionBody->usesThis() || m_shouldEmitDebugHooks) {
-        emitOpcode(op_convert_this);
+        if (codeBlock->isStrictMode())
+            emitOpcode(op_convert_this_strict);
+        else
+            emitOpcode(op_convert_this);
         instructions().append(m_thisRegister.index());
     }
 }
@@ -1557,6 +1565,12 @@ void BytecodeGenerator::createArgumentsIfNecessary()
         return;
     ASSERT(m_codeBlock->usesArguments());
 
+    // If we're in strict mode we tear off the arguments on function
+    // entry, so there's no need to check if we need to create them
+    // now
+    if (m_codeBlock->isStrictMode())
+        return;
+
     emitOpcode(op_create_arguments);
     instructions().append(m_codeBlock->argumentsRegister());
 }
@@ -1674,7 +1688,8 @@ RegisterID* BytecodeGenerator::emitReturn(RegisterID* src)
         emitOpcode(op_tear_off_activation);
         instructions().append(m_activationRegister->index());
         instructions().append(m_codeBlock->argumentsRegister());
-    } else if (m_codeBlock->usesArguments() && m_codeBlock->m_numParameters > 1) { // If there are no named parameters, there's nothing to tear off, since extra / unnamed parameters get copied to the arguments object at construct time.
+    } else if (m_codeBlock->usesArguments() && m_codeBlock->m_numParameters > 1
+               && !m_codeBlock->isStrictMode()) { // If there are no named parameters, there's nothing to tear off, since extra / unnamed parameters get copied to the arguments object at construct time.
         emitOpcode(op_tear_off_arguments);
         instructions().append(m_codeBlock->argumentsRegister());
     }
index b6047ae..bd5c803 100644 (file)
@@ -419,6 +419,8 @@ namespace JSC {
         }
 
         bool shouldEmitProfileHooks() { return m_shouldEmitProfileHooks; }
+        
+        bool isStrictMode() const { return m_codeBlock->isStrictMode(); }
 
     private:
         void emitOpcode(OpcodeID);
@@ -499,12 +501,12 @@ namespace JSC {
 
         PassRefPtr<FunctionExecutable> makeFunction(ExecState* exec, FunctionBodyNode* body)
         {
-            return FunctionExecutable::create(exec, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine());
+            return FunctionExecutable::create(exec, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
         }
 
         PassRefPtr<FunctionExecutable> makeFunction(JSGlobalData* globalData, FunctionBodyNode* body)
         {
-            return FunctionExecutable::create(globalData, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine());
+            return FunctionExecutable::create(globalData, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
         }
 
         RegisterID* emitInitLazyRegister(RegisterID*);
index cbcbd21..17dfdf7 100644 (file)
@@ -101,7 +101,7 @@ JSValue evaluateInGlobalCallFrame(const UString& script, JSValue& exception, JSG
 {
     CallFrame* globalCallFrame = globalObject->globalExec();
 
-    RefPtr<EvalExecutable> eval = EvalExecutable::create(globalCallFrame, makeSource(script));
+    RefPtr<EvalExecutable> eval = EvalExecutable::create(globalCallFrame, makeSource(script), false);
     JSObject* error = eval->compile(globalCallFrame, globalCallFrame->scopeChain());
     if (error)
         return error;
index 32f65dd..c98c7cc 100644 (file)
@@ -88,7 +88,7 @@ JSValue DebuggerCallFrame::evaluate(const UString& script, JSValue& exception) c
     if (!m_callFrame->codeBlock())
         return JSValue();
 
-    RefPtr<EvalExecutable> eval = EvalExecutable::create(m_callFrame, makeSource(script));
+    RefPtr<EvalExecutable> eval = EvalExecutable::create(m_callFrame, makeSource(script), m_callFrame->codeBlock()->isStrictMode());
     JSObject* error = eval->compile(m_callFrame, m_callFrame->scopeChain());
     if (error)
         return error;
index ecff7d6..9689d1a 100644 (file)
@@ -59,6 +59,7 @@
 #include "RegExpPrototype.h"
 #include "Register.h"
 #include "SamplingTool.h"
+#include "StrictEvalActivation.h"
 #include <limits.h>
 #include <stdio.h>
 #include <wtf/Threading.h>
@@ -389,14 +390,18 @@ NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* r
     UString programSource = asString(program)->value(callFrame);
     if (callFrame->hadException())
         return JSValue();
-
-    LiteralParser preparser(callFrame, programSource, LiteralParser::NonStrictJSON);
-    if (JSValue parsedObject = preparser.tryLiteralParse())
-        return parsedObject;
+    
+    CodeBlock* codeBlock = callFrame->codeBlock();
+    if (!codeBlock->isStrictMode()) {
+        // FIXME: We can use the preparser in strict mode, we just need additional logic
+        // to prevent duplicates.
+        LiteralParser preparser(callFrame, programSource, LiteralParser::NonStrictJSON);
+        if (JSValue parsedObject = preparser.tryLiteralParse())
+            return parsedObject;
+    }
 
     ScopeChainNode* scopeChain = callFrame->scopeChain();
-    CodeBlock* codeBlock = callFrame->codeBlock();
-    RefPtr<EvalExecutable> eval = codeBlock->evalCodeCache().get(callFrame, programSource, scopeChain, exceptionValue);
+    RefPtr<EvalExecutable> eval = codeBlock->evalCodeCache().get(callFrame, codeBlock->isStrictMode(), programSource, scopeChain, exceptionValue);
 
     JSValue result = jsUndefined();
     if (eval)
@@ -561,9 +566,11 @@ NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue ex
             scopeChain = scopeChain->pop();
         JSActivation* activation = asActivation(scopeChain->object);
         activation->copyRegisters();
-        if (JSValue arguments = callFrame->r(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue())
-            asArguments(arguments)->setActivation(activation);
-    } else if (oldCodeBlock->usesArguments()) {
+        if (JSValue arguments = callFrame->r(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue()) {
+            if (!oldCodeBlock->isStrictMode())
+                asArguments(arguments)->setActivation(activation);
+        }
+    } else if (oldCodeBlock->usesArguments() && !oldCodeBlock->isStrictMode()) {
         if (JSValue arguments = callFrame->r(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue())
             asArguments(arguments)->copyRegisters();
     }
@@ -1061,7 +1068,7 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObjec
     }
     EvalCodeBlock* codeBlock = &eval->generatedBytecode();
 
-    JSVariableObject* variableObject;
+    JSObject* variableObject;
     for (ScopeChainNode* node = scopeChain; ; node = node->next) {
         ASSERT(node);
         if (node->object->isVariableObject()) {
@@ -1072,7 +1079,13 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObjec
 
     unsigned numVariables = codeBlock->numVariables();
     int numFunctions = codeBlock->numberOfFunctionDecls();
+    bool pushedScope = false;
     if (numVariables || numFunctions) {
+        if (codeBlock->isStrictMode()) {
+            variableObject = new (callFrame) StrictEvalActivation(callFrame);
+            scopeChain = scopeChain->push(variableObject);
+            pushedScope = true;
+        }
         // Scope for BatchedTransitionOptimizer
         BatchedTransitionOptimizer optimizer(variableObject);
 
@@ -1095,6 +1108,8 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObjec
     Register* newEnd = m_registerFile.start() + globalRegisterOffset + codeBlock->m_numCalleeRegisters;
     if (!m_registerFile.grow(newEnd)) {
         *exception = createStackOverflowError(callFrame);
+        if (pushedScope)
+            scopeChain->pop();
         return jsNull();
     }
 
@@ -1137,6 +1152,8 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObjec
         (*profiler)->didExecute(callFrame, eval->sourceURL(), eval->lineNo());
 
     m_registerFile.shrink(oldEnd);
+    if (pushedScope)
+        scopeChain->pop();
     return result;
 }
 
@@ -2964,7 +2981,7 @@ skip_id_custom_self:
 
         JSValue baseValue = callFrame->r(base).jsValue();
         Identifier& ident = codeBlock->identifier(property);
-        PutPropertySlot slot;
+        PutPropertySlot slot(codeBlock->isStrictMode());
         if (direct) {
             baseValue.putDirect(callFrame, ident, callFrame->r(value).jsValue(), slot);
             ASSERT(slot.base() == baseValue);
@@ -3080,7 +3097,7 @@ skip_id_custom_self:
 
         JSValue baseValue = callFrame->r(base).jsValue();
         Identifier& ident = codeBlock->identifier(property);
-        PutPropertySlot slot;
+        PutPropertySlot slot(codeBlock->isStrictMode());
         if (direct) {
             baseValue.putDirect(callFrame, ident, callFrame->r(value).jsValue(), slot);
             ASSERT(slot.base() == baseValue);
@@ -3105,9 +3122,13 @@ skip_id_custom_self:
 
         JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame);
         Identifier& ident = codeBlock->identifier(property);
-        JSValue result = jsBoolean(baseObj->deleteProperty(callFrame, ident));
+        bool result = baseObj->deleteProperty(callFrame, ident);
+        if (!result && codeBlock->isStrictMode()) {
+            exceptionValue = createTypeError(callFrame, "Unable to delete property.");
+            goto vm_throw;
+        }
         CHECK_FOR_EXCEPTION();
-        callFrame->r(dst) = result;
+        callFrame->r(dst) = jsBoolean(result);
         vPC += OPCODE_LENGTH(op_del_by_id);
         NEXT_INSTRUCTION();
     }
@@ -3260,7 +3281,7 @@ skip_id_custom_self:
         } else {
             Identifier property(callFrame, subscript.toString(callFrame));
             if (!globalData->exception) { // Don't put to an object if toString threw an exception.
-                PutPropertySlot slot;
+                PutPropertySlot slot(codeBlock->isStrictMode());
                 baseValue.put(callFrame, property, callFrame->r(value).jsValue(), slot);
             }
         }
@@ -3284,19 +3305,22 @@ skip_id_custom_self:
         JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame); // may throw
 
         JSValue subscript = callFrame->r(property).jsValue();
-        JSValue result;
+        bool result;
         uint32_t i;
         if (subscript.getUInt32(i))
-            result = jsBoolean(baseObj->deleteProperty(callFrame, i));
+            result = baseObj->deleteProperty(callFrame, i);
         else {
             CHECK_FOR_EXCEPTION();
             Identifier property(callFrame, subscript.toString(callFrame));
             CHECK_FOR_EXCEPTION();
-            result = jsBoolean(baseObj->deleteProperty(callFrame, property));
+            result = baseObj->deleteProperty(callFrame, property);
+        }
+        if (!result && codeBlock->isStrictMode()) {
+            exceptionValue = createTypeError(callFrame, "Unable to delete property.");
+            goto vm_throw;
         }
-
         CHECK_FOR_EXCEPTION();
-        callFrame->r(dst) = result;
+        callFrame->r(dst) = jsBoolean(result);
         vPC += OPCODE_LENGTH(op_del_by_val);
         NEXT_INSTRUCTION();
     }
@@ -4036,6 +4060,11 @@ skip_id_custom_self:
         } else if (JSValue argumentsValue = callFrame->r(unmodifiedArgumentsRegister(arguments)).jsValue())
             asArguments(argumentsValue)->copyRegisters();
 
+        if (JSValue arguments = callFrame->r(unmodifiedArgumentsRegister(src2)).jsValue()) {
+            if (!codeBlock->isStrictMode())
+                asArguments(arguments)->setActivation(activation);
+        }
+
         vPC += OPCODE_LENGTH(op_tear_off_activation);
         NEXT_INSTRUCTION();
     }
@@ -4225,6 +4254,25 @@ skip_id_custom_self:
         vPC += OPCODE_LENGTH(op_convert_this);
         NEXT_INSTRUCTION();
     }
+    DEFINE_OPCODE(op_convert_this_strict) {
+        /* convert_this_strict this(r)
+         
+         Takes the value in the 'this' register, and converts it to
+         its "this" form if (and only if) "this" is an object with a
+         custom this conversion
+         
+         This opcode should only be used at the beginning of a code
+         block.
+         */
+        
+        int thisRegister = vPC[1].u.operand;
+        JSValue thisVal = callFrame->r(thisRegister).jsValue();
+        if (thisVal.isObject() && thisVal.needsThisConversion())
+            callFrame->r(thisRegister) = JSValue(thisVal.toStrictThisObject(callFrame));
+        
+        vPC += OPCODE_LENGTH(op_convert_this_strict);
+        NEXT_INSTRUCTION();
+    }
     DEFINE_OPCODE(op_init_lazy_reg) {
         /* init_lazy_reg dst(r)
 
index f3e9e62..7910827 100644 (file)
@@ -225,6 +225,7 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_get_callee)
         DEFINE_OP(op_create_this)
         DEFINE_OP(op_convert_this)
+        DEFINE_OP(op_convert_this_strict)
         DEFINE_OP(op_init_lazy_reg)
         DEFINE_OP(op_create_arguments)
         DEFINE_OP(op_debug)
@@ -396,6 +397,7 @@ void JIT::privateCompileSlowCases()
         DEFINE_SLOWCASE_OP(op_call_varargs)
         DEFINE_SLOWCASE_OP(op_construct)
         DEFINE_SLOWCASE_OP(op_convert_this)
+        DEFINE_SLOWCASE_OP(op_convert_this_strict)
 #if !USE(JSVALUE32)
         DEFINE_SLOWCASE_OP(op_div)
 #endif
index 8cb2055..89deac6 100644 (file)
@@ -738,6 +738,7 @@ namespace JSC {
         void emit_op_get_callee(Instruction*);
         void emit_op_create_this(Instruction*);
         void emit_op_convert_this(Instruction*);
+        void emit_op_convert_this_strict(Instruction*);
         void emit_op_create_arguments(Instruction*);
         void emit_op_debug(Instruction*);
         void emit_op_del_by_id(Instruction*);
@@ -845,6 +846,7 @@ namespace JSC {
         void emitSlow_op_call_varargs(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_construct(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_convert_this(Instruction*, Vector<SlowCaseEntry>::iterator&);
+        void emitSlow_op_convert_this_strict(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_div(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_eq(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_get_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&);
index 718548a..3e70578 100644 (file)
@@ -895,7 +895,7 @@ void JIT::emit_op_get_pnames(Instruction* currentInstruction)
     emitGetVirtualRegister(base, regT0);
     if (!m_codeBlock->isKnownNotImmediate(base))
         isNotObject.append(emitJumpIfNotJSCell(regT0));
-    if (base != m_codeBlock->thisRegister()) {
+    if (base != m_codeBlock->thisRegister() || m_codeBlock->isStrictMode()) {
         loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
         isNotObject.append(branch8(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType)));
     }
@@ -1255,6 +1255,23 @@ void JIT::emit_op_convert_this(Instruction* currentInstruction)
     addSlowCase(branchTest8(NonZero, Address(regT1, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(NeedsThisConversion)));
 }
 
+void JIT::emit_op_convert_this_strict(Instruction* currentInstruction)
+{
+    emitGetVirtualRegister(currentInstruction[1].u.operand, regT0);
+    Jump notNull = branchTestPtr(NonZero, regT0);
+    move(ImmPtr(JSValue::encode(jsNull())), regT0);
+    emitPutVirtualRegister(currentInstruction[1].u.operand, regT0);
+    Jump setThis = jump();
+    notNull.link(this);
+    Jump isImmediate = emitJumpIfNotJSCell(regT0);
+    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT1);
+    Jump notAnObject = branch8(NotEqual, Address(regT3, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType));
+    addSlowCase(branchTest8(NonZero, Address(regT1, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(NeedsThisConversion)));
+    isImmediate.link(this);
+    notAnObject.link(this);
+    setThis.link(this);
+}
+
 void JIT::emit_op_get_callee(Instruction* currentInstruction)
 {
     unsigned result = currentInstruction[1].u.operand;
@@ -1304,6 +1321,14 @@ void JIT::emitSlow_op_convert_this(Instruction* currentInstruction, Vector<SlowC
     stubCall.call(currentInstruction[1].u.operand);
 }
 
+void JIT::emitSlow_op_convert_this_strict(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    linkSlowCase(iter);
+    JITStubCall stubCall(this, cti_op_convert_this_strict);
+    stubCall.addArgument(regT0);
+    stubCall.call(currentInstruction[1].u.operand);
+}
+
 void JIT::emitSlow_op_to_primitive(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
     linkSlowCase(iter);
index fad85e4..326704d 100644 (file)
@@ -1239,7 +1239,7 @@ void JIT::emit_op_get_pnames(Instruction* currentInstruction)
     emitLoad(base, regT1, regT0);
     if (!m_codeBlock->isKnownNotImmediate(base))
         isNotObject.append(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
-    if (base != m_codeBlock->thisRegister()) {
+    if (base != m_codeBlock->thisRegister() || m_codeBlock->isStrictMode()) {
         loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
         isNotObject.append(branch8(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType)));
     }
@@ -1554,6 +1554,26 @@ void JIT::emit_op_convert_this(Instruction* currentInstruction)
     map(m_bytecodeOffset + OPCODE_LENGTH(op_convert_this), thisRegister, regT1, regT0);
 }
 
+void JIT::emit_op_convert_this_strict(Instruction* currentInstruction)
+{
+    unsigned thisRegister = currentInstruction[1].u.operand;
+    
+    emitLoad(thisRegister, regT1, regT0);
+    
+    Jump notNull = branch32(NotEqual, regT1, Imm32(JSValue::EmptyValueTag));
+    emitStore(thisRegister, jsNull());
+    Jump setThis = jump();
+    notNull.link(this);
+    Jump isImmediate = branch32(NotEqual, regT1, Imm32(JSValue::CellTag));
+    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT1);
+    Jump notAnObject = branch8(NotEqual, Address(regT3, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType));
+    addSlowCase(branchTest8(NonZero, Address(regT1, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(NeedsThisConversion)));
+    isImmediate.link(this);
+    notAnObject.link(this);
+    setThis.link(this);
+    map(m_bytecodeOffset + OPCODE_LENGTH(op_convert_this), thisRegister, regT1, regT0);
+}
+
 void JIT::emitSlow_op_convert_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
     unsigned thisRegister = currentInstruction[1].u.operand;
@@ -1566,6 +1586,17 @@ void JIT::emitSlow_op_convert_this(Instruction* currentInstruction, Vector<SlowC
     stubCall.call(thisRegister);
 }
 
+void JIT::emitSlow_op_convert_this_strict(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    unsigned thisRegister = currentInstruction[1].u.operand;
+    
+    linkSlowCase(iter);
+    
+    JITStubCall stubCall(this, cti_op_convert_this_strict);
+    stubCall.addArgument(regT1, regT0);
+    stubCall.call(thisRegister);
+}
+
 void JIT::emit_op_profile_will_call(Instruction* currentInstruction)
 {
     peek(regT2, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof(void*));
index 07adc68..ed2ad7e 100644 (file)
@@ -1065,7 +1065,9 @@ static NEVER_INLINE void throwStackOverflowError(CallFrame* callFrame, JSGlobalD
         return 0; \
     } while (0)
 #define VM_THROW_EXCEPTION_AT_END() \
-    returnToThrowTrampoline(stackFrame.globalData, STUB_RETURN_ADDRESS, STUB_RETURN_ADDRESS)
+    do {\
+        returnToThrowTrampoline(stackFrame.globalData, STUB_RETURN_ADDRESS, STUB_RETURN_ADDRESS);\
+    } while (0)
 
 #define CHECK_FOR_EXCEPTION() \
     do { \
@@ -1301,6 +1303,18 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_convert_this)
     return JSValue::encode(result);
 }
 
+DEFINE_STUB_FUNCTION(EncodedJSValue, op_convert_this_strict)
+{
+    STUB_INIT_STACK_FRAME(stackFrame);
+    
+    JSValue v1 = stackFrame.args[0].jsValue();
+    CallFrame* callFrame = stackFrame.callFrame;
+
+    JSValue result = v1.toStrictThisObject(callFrame);
+    CHECK_FOR_EXCEPTION_AT_END();
+    return JSValue::encode(result);
+}
+
 DEFINE_STUB_FUNCTION(void, op_end)
 {
     STUB_INIT_STACK_FRAME(stackFrame);
@@ -1404,7 +1418,7 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id_generic)
 {
     STUB_INIT_STACK_FRAME(stackFrame);
 
-    PutPropertySlot slot;
+    PutPropertySlot slot(stackFrame.callFrame->codeBlock()->isStrictMode());
     stackFrame.args[0].jsValue().put(stackFrame.callFrame, stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot);
     CHECK_FOR_EXCEPTION_AT_END();
 }
@@ -1413,7 +1427,7 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id_direct_generic)
 {
     STUB_INIT_STACK_FRAME(stackFrame);
     
-    PutPropertySlot slot;
+    PutPropertySlot slot(stackFrame.callFrame->codeBlock()->isStrictMode());
     stackFrame.args[0].jsValue().putDirect(stackFrame.callFrame, stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot);
     CHECK_FOR_EXCEPTION_AT_END();
 }
@@ -1441,7 +1455,7 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id)
     CallFrame* callFrame = stackFrame.callFrame;
     Identifier& ident = stackFrame.args[1].identifier();
     
-    PutPropertySlot slot;
+    PutPropertySlot slot(callFrame->codeBlock()->isStrictMode());
     stackFrame.args[0].jsValue().put(callFrame, ident, stackFrame.args[2].jsValue(), slot);
     
     CodeBlock* codeBlock = stackFrame.callFrame->codeBlock();
@@ -1460,7 +1474,7 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id_direct)
     CallFrame* callFrame = stackFrame.callFrame;
     Identifier& ident = stackFrame.args[1].identifier();
     
-    PutPropertySlot slot;
+    PutPropertySlot slot(callFrame->codeBlock()->isStrictMode());
     stackFrame.args[0].jsValue().putDirect(callFrame, ident, stackFrame.args[2].jsValue(), slot);
     
     CodeBlock* codeBlock = stackFrame.callFrame->codeBlock();
@@ -1479,8 +1493,8 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id_fail)
 
     CallFrame* callFrame = stackFrame.callFrame;
     Identifier& ident = stackFrame.args[1].identifier();
-
-    PutPropertySlot slot;
+    
+    PutPropertySlot slot(callFrame->codeBlock()->isStrictMode());
     stackFrame.args[0].jsValue().put(callFrame, ident, stackFrame.args[2].jsValue(), slot);
 
     CHECK_FOR_EXCEPTION_AT_END();
@@ -1493,7 +1507,7 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id_direct_fail)
     CallFrame* callFrame = stackFrame.callFrame;
     Identifier& ident = stackFrame.args[1].identifier();
     
-    PutPropertySlot slot;
+    PutPropertySlot slot(callFrame->codeBlock()->isStrictMode());
     stackFrame.args[0].jsValue().putDirect(callFrame, ident, stackFrame.args[2].jsValue(), slot);
     
     CHECK_FOR_EXCEPTION_AT_END();
@@ -1880,7 +1894,11 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_id)
     
     JSObject* baseObj = stackFrame.args[0].jsValue().toObject(callFrame);
 
-    JSValue result = jsBoolean(baseObj->deleteProperty(callFrame, stackFrame.args[1].identifier()));
+    bool couldDelete = baseObj->deleteProperty(callFrame, stackFrame.args[1].identifier());
+    JSValue result = jsBoolean(couldDelete);
+    if (!couldDelete && callFrame->codeBlock()->isStrictMode())
+        stackFrame.globalData->exception = createTypeError(stackFrame.callFrame, "Unable to delete property.");
+
     CHECK_FOR_EXCEPTION_AT_END();
     return JSValue::encode(result);
 }
@@ -2222,8 +2240,10 @@ DEFINE_STUB_FUNCTION(void, op_tear_off_activation)
     }
     JSActivation* activation = asActivation(stackFrame.args[0].jsValue());
     activation->copyRegisters();
-    if (JSValue v = stackFrame.args[1].jsValue())
-        asArguments(v)->setActivation(activation);
+    if (JSValue v = stackFrame.args[1].jsValue()) {
+        if (!stackFrame.callFrame->codeBlock()->isStrictMode())
+            asArguments(v)->setActivation(activation);
+    }
 }
 
 DEFINE_STUB_FUNCTION(void, op_tear_off_arguments)
@@ -2503,7 +2523,7 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val)
     } else {
         Identifier property(callFrame, subscript.toString(callFrame));
         if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception.
-            PutPropertySlot slot;
+            PutPropertySlot slot(callFrame->codeBlock()->isStrictMode());
             baseValue.put(callFrame, property, value, slot);
         }
     }
@@ -2546,7 +2566,7 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val_byte_array)
     } else {
         Identifier property(callFrame, subscript.toString(callFrame));
         if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception.
-            PutPropertySlot slot;
+            PutPropertySlot slot(callFrame->codeBlock()->isStrictMode());
             baseValue.put(callFrame, property, value, slot);
         }
     }
@@ -3501,19 +3521,22 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_val)
     JSObject* baseObj = baseValue.toObject(callFrame); // may throw
 
     JSValue subscript = stackFrame.args[1].jsValue();
-    JSValue result;
+    bool result;
     uint32_t i;
     if (subscript.getUInt32(i))
-        result = jsBoolean(baseObj->deleteProperty(callFrame, i));
+        result = baseObj->deleteProperty(callFrame, i);
     else {
         CHECK_FOR_EXCEPTION();
         Identifier property(callFrame, subscript.toString(callFrame));
         CHECK_FOR_EXCEPTION();
-        result = jsBoolean(baseObj->deleteProperty(callFrame, property));
+        result = baseObj->deleteProperty(callFrame, property);
     }
 
+    if (!result && callFrame->codeBlock()->isStrictMode())
+        stackFrame.globalData->exception = createTypeError(stackFrame.callFrame, "Unable to delete property.");
+
     CHECK_FOR_EXCEPTION_AT_END();
-    return JSValue::encode(result);
+    return JSValue::encode(jsBoolean(result));
 }
 
 DEFINE_STUB_FUNCTION(void, op_put_getter)
index 2b22e6d..bd7d19c 100644 (file)
@@ -296,6 +296,7 @@ extern "C" {
     EncodedJSValue JIT_STUB cti_op_construct_NotJSConstruct(STUB_ARGS_DECLARATION);
     EncodedJSValue JIT_STUB cti_op_create_this(STUB_ARGS_DECLARATION);
     EncodedJSValue JIT_STUB cti_op_convert_this(STUB_ARGS_DECLARATION);
+    EncodedJSValue JIT_STUB cti_op_convert_this_strict(STUB_ARGS_DECLARATION);
     EncodedJSValue JIT_STUB cti_op_create_arguments(STUB_ARGS_DECLARATION);
     EncodedJSValue JIT_STUB cti_op_create_arguments_no_params(STUB_ARGS_DECLARATION);
     EncodedJSValue JIT_STUB cti_op_del_by_id(STUB_ARGS_DECLARATION);
index 40023f8..9a68144 100644 (file)
@@ -249,10 +249,10 @@ public:
         return result;
     }
 
-    FunctionBodyNode* createFunctionBody()
+    FunctionBodyNode* createFunctionBody(bool inStrictContext)
     {
         usesClosures();
-        return FunctionBodyNode::create(m_globalData);
+        return FunctionBodyNode::create(m_globalData, inStrictContext);
     }
     
     template <bool> PropertyNode* createGetterOrSetterProperty(PropertyNode::Type type, const Identifier* name, ParameterNode* params, FunctionBodyNode* body, int openBracePos, int closeBracePos, int bodyStartLine, int bodyEndLine)
@@ -578,6 +578,9 @@ public:
     
     const Identifier& getName(Property property) { return property->name(); }
     PropertyNode::Type getType(Property property) { return property->type(); }
+
+    bool isResolve(ExpressionNode* expr) { return expr->isResolveNode(); }
+
 private:
     struct Scope {
         Scope(JSGlobalData* globalData)
index 0e526ac..5ba2a0a 100644 (file)
@@ -29,6 +29,7 @@
 
 using namespace JSC;
 
+#include "CodeBlock.h"
 #include "JSGlobalData.h"
 #include "NodeInfo.h"
 #include "ASTBuilder.h"
@@ -42,6 +43,8 @@ namespace JSC {
 #define fail() do { m_error = true; return 0; } while (0)
 #define failIfFalse(cond) do { if (!(cond)) fail(); } while (0)
 #define failIfTrue(cond) do { if ((cond)) fail(); } while (0)
+#define failIfTrueIfStrict(cond) do { if ((cond) && strictMode()) fail(); } while (0)
+#define failIfFalseIfStrict(cond) do { if ((!(cond)) && strictMode()) fail(); } while (0)
 #define consumeOrFail(tokenType) do { if (!consume(tokenType)) fail(); } while (0)
 #define matchOrFail(tokenType) do { if (!match(tokenType)) fail(); } while (0)
 #define failIfStackOverflow() do { failIfFalse(canRecurse()); } while (0)
@@ -67,8 +70,8 @@ static const ptrdiff_t kMaxParserStackUsage = 128 * sizeof(void*) * 1024;
 
 class JSParser {
 public:
-    JSParser(Lexer*, JSGlobalData*, FunctionParameters*, SourceProvider*);
-    bool parseProgram();
+    JSParser(Lexer*, JSGlobalData*, FunctionParameters*, bool isStrictContext, bool isFunction, SourceProvider*);
+    bool parseProgram(JSGlobalObject*);
 private:
     struct AllowInOverride {
         AllowInOverride(JSParser* parser)
@@ -90,7 +93,7 @@ private:
         m_lastLine = m_token.m_info.line;
         m_lastTokenEnd = m_token.m_info.endOffset;
         m_lexer->setLastLineNumber(m_lastLine);
-        m_token.m_type = m_lexer->lex(&m_token.m_data, &m_token.m_info, lexType);
+        m_token.m_type = m_lexer->lex(&m_token.m_data, &m_token.m_info, lexType, strictMode());
         m_tokenCount++;
     }
 
@@ -121,9 +124,23 @@ private:
     {
         return m_token.m_info.endOffset;
     }
-
-    template <class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&);
-    template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&);
+    
+    void startLoop() { currentScope()->startLoop(); }
+    void endLoop() { currentScope()->endLoop(); }
+    void startSwitch() { currentScope()->startSwitch(); }
+    void endSwitch() { currentScope()->endSwitch(); }
+    void setStrictMode() { currentScope()->setStrictMode(); }
+    bool strictMode() { return currentScope()->strictMode(); }
+    bool isValidStrictMode() { return currentScope()->isValidStrictMode(); }
+    bool declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); }
+    bool breakIsValid() { return currentScope()->breakIsValid(); }
+    void pushLabel(const Identifier* label) { currentScope()->pushLabel(label); }
+    void popLabel() { currentScope()->popLabel(); }
+    bool hasLabel(const Identifier* label) { return currentScope()->hasLabel(label); }
+
+    enum SourceElementsMode { CheckForStrictMode, DontCheckForStrictMode };
+    template <SourceElementsMode mode, class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&);
+    template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive);
     template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&);
     template <class TreeBuilder> TreeStatement parseVarDeclaration(TreeBuilder&);
     template <class TreeBuilder> TreeStatement parseConstDeclaration(TreeBuilder&);
@@ -199,32 +216,118 @@ private:
     int m_assignmentCount;
     int m_nonLHSCount;
     bool m_syntaxAlreadyValidated;
+    int m_statementDepth;
+    int m_nonTrivialExpressionCount;
+    const Identifier* m_lastIdentifier;
+
+    struct DepthManager {
+        DepthManager(int* depth)
+            : m_originalDepth(*depth)
+            , m_depth(depth)
+        {
+        }
+        
+        ~DepthManager()
+        {
+            *m_depth = m_originalDepth;
+        }
+        
+    private:
+        int m_originalDepth;
+        int* m_depth;
+    };
 
     struct Scope {
-        Scope()
-            : m_usesEval(false)
+        Scope(JSGlobalData* globalData, bool isFunction, bool strictMode)
+            : m_globalData(globalData)
+            , m_usesEval(false)
             , m_needsFullActivation(false)
             , m_allowsNewDecls(true)
+            , m_strictMode(strictMode)
+            , m_isFunction(isFunction)
+            , m_isValidStrictMode(true)
+            , m_loopDepth(0)
+            , m_switchDepth(0)
+            , m_labels(0)
         {
         }
         
-        void declareVariable(const Identifier* ident)
+        void startSwitch() { m_switchDepth++; }
+        void endSwitch() { m_switchDepth--; }
+        void startLoop() { m_loopDepth++; }
+        void endLoop() { ASSERT(m_loopDepth); m_loopDepth--; }
+        bool inLoop() { return !!m_loopDepth; }
+        bool breakIsValid() { return m_loopDepth || m_switchDepth; }
+
+        void pushLabel(const Identifier* label)
+        {
+            if (!m_labels)
+                m_labels = new LabelStack;
+            m_labels->append(label->impl());
+        }
+
+        void popLabel()
+        {
+            ASSERT(m_labels);
+            ASSERT(m_labels->size());
+            m_labels->removeLast();
+        }
+
+        bool hasLabel(const Identifier* label)
+        {
+            if (!m_labels)
+                return false;
+            for (int i = m_labels->size(); i > 0; i--) {
+                if (m_labels->at(i - 1) == label->impl())
+                    return true;
+            }
+            return false;
+        }
+
+        void setIsFunction() { m_isFunction = true; }
+        bool isFunction() { return m_isFunction; }
+        
+        bool declareVariable(const Identifier* ident)
         {
+            bool isValidStrictMode = m_globalData->propertyNames->eval != *ident && m_globalData->propertyNames->arguments != *ident;
+            m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
             m_declaredVariables.add(ident->ustring().impl());
+            return isValidStrictMode;
+        }
+        
+        void declareWrite(const Identifier* ident)
+        {
+            ASSERT(m_strictMode);
+            m_writtenVariables.add(ident->impl());
+        }
+        
+        bool deleteProperty(const Identifier* ident)
+        {
+            if (m_declaredVariables.contains(ident->impl()))
+                return false;
+            m_deletedVariables.add(ident->impl());
+            return true;
         }
         
         void preventNewDecls() { m_allowsNewDecls = false; }
         bool allowsNewDecls() const { return m_allowsNewDecls; }
 
+        bool declareParameter(const Identifier* ident)
+        {
+            bool isValidStrictMode = m_declaredVariables.add(ident->ustring().impl()).second && m_globalData->propertyNames->eval != *ident && m_globalData->propertyNames->arguments != *ident;
+            m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
+            return isValidStrictMode;
+        }
+        
         void useVariable(const Identifier* ident, bool isEval)
         {
             m_usesEval |= isEval;
             m_usedVariables.add(ident->ustring().impl());
         }
         
-        void needsFullActivation() { m_needsFullActivation = true; }
+        void setNeedsFullActivation() { m_needsFullActivation = true; }
         
-        void collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables)
+        bool collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables)
         {
             if (nestedScope->m_usesEval)
                 m_usesEval = true;
@@ -236,6 +339,45 @@ private:
                 if (shouldTrackClosedVariables)
                     m_closedVariables.add(*ptr);
             }
+            if (nestedScope->m_writtenVariables.size()) {
+                IdentifierSet::iterator end = nestedScope->m_writtenVariables.end();
+                for (IdentifierSet::iterator ptr = nestedScope->m_writtenVariables.begin(); ptr != end; ++ptr) {
+                    if (nestedScope->m_declaredVariables.contains(*ptr))
+                        continue;
+                    m_writtenVariables.add(*ptr);
+                }
+            }
+            if (nestedScope->m_deletedVariables.size()) {
+                IdentifierSet::iterator end = nestedScope->m_deletedVariables.end();
+                for (IdentifierSet::iterator ptr = nestedScope->m_deletedVariables.begin(); ptr != end; ++ptr) {
+                    if (nestedScope->m_declaredVariables.contains(*ptr))
+                        return false;
+                    if (m_declaredVariables.contains(*ptr))
+                        return false;
+                    m_deletedVariables.add(*ptr);
+                }
+            }
+            return true;
+        }
+
+        void getUncapturedWrittenVariables(IdentifierSet& writtenVariables)
+        {
+            IdentifierSet::iterator end = m_writtenVariables.end();
+            for (IdentifierSet::iterator ptr = m_writtenVariables.begin(); ptr != end; ++ptr) {
+                if (!m_declaredVariables.contains(*ptr))
+                    writtenVariables.add(*ptr);
+            }
+        }
+
+        bool getDeletedVariables(IdentifierSet& deletedVariables)
+        {
+            IdentifierSet::iterator end = m_deletedVariables.end();
+            for (IdentifierSet::iterator ptr = m_deletedVariables.begin(); ptr != end; ++ptr) {
+                if (m_declaredVariables.contains(*ptr))
+                    return false;
+            }
+            deletedVariables.swap(m_deletedVariables);
+            return true;
         }
 
         void getCapturedVariables(IdentifierSet& capturedVariables)
@@ -250,13 +392,27 @@ private:
                 capturedVariables.add(*ptr);
             }
         }
+        void setStrictMode() { m_strictMode = true; }
+        bool strictMode() const { return m_strictMode; }
+        bool isValidStrictMode() const { return m_isValidStrictMode; }
+
     private:
-        bool m_usesEval;
-        bool m_needsFullActivation;
-        bool m_allowsNewDecls;
+        JSGlobalData* m_globalData;
+        bool m_usesEval : 1;
+        bool m_needsFullActivation : 1;
+        bool m_allowsNewDecls : 1;
+        bool m_strictMode : 1;
+        bool m_isFunction : 1;
+        bool m_isValidStrictMode : 1;
+        int m_loopDepth;
+        int m_switchDepth;
+        typedef Vector<StringImpl*, 2> LabelStack;
+        LabelStack* m_labels;
         IdentifierSet m_declaredVariables;
         IdentifierSet m_usedVariables;
         IdentifierSet m_closedVariables;
+        IdentifierSet m_writtenVariables;
+        IdentifierSet m_deletedVariables;
     };
     
     typedef Vector<Scope, 10> ScopeStack;
@@ -281,19 +437,26 @@ private:
     
     ScopeRef pushScope()
     {
-        m_scopeStack.append(Scope());
+        bool isFunction = false;
+        bool isStrict = false;
+        if (!m_scopeStack.isEmpty()) {
+            isStrict = m_scopeStack.last().strictMode();
+            isFunction = m_scopeStack.last().isFunction();
+        }
+        m_scopeStack.append(Scope(m_globalData, isFunction, isStrict));
         return currentScope();
     }
 
-    void popScope(ScopeRef scope, bool shouldTrackClosedVariables)
+    bool popScope(ScopeRef scope, bool shouldTrackClosedVariables)
     {
         ASSERT_UNUSED(scope, scope.index() == m_scopeStack.size() - 1);
         ASSERT(m_scopeStack.size() > 1);
-        m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables);
+        bool result = m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables);
         m_scopeStack.removeLast();
+        return result;
     }
     
-    void declareVariable(const Identifier* ident)
+    bool declareVariable(const Identifier* ident)
     {
         unsigned i = m_scopeStack.size() - 1;
         ASSERT(i < m_scopeStack.size());
@@ -301,19 +464,32 @@ private:
             i--;
             ASSERT(i < m_scopeStack.size());
         }
-        m_scopeStack[i].declareVariable(ident);
+        return m_scopeStack[i].declareVariable(ident);
+    }
+    
+    void declareWrite(const Identifier* ident)
+    {
+        if (!m_syntaxAlreadyValidated)
+            m_scopeStack.last().declareWrite(ident);
     }
 
+    bool deleteProperty(const Identifier* ident)
+    {
+        if (!m_syntaxAlreadyValidated)
+            return m_scopeStack.last().deleteProperty(ident);
+        return true;
+    }
+    
     ScopeStack m_scopeStack;
 };
 
-int jsParse(JSGlobalData* globalData, FunctionParameters* parameters, const SourceCode* source)
+int jsParse(JSGlobalObject* lexicalGlobalObject, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode, const SourceCode* source)
 {
-    JSParser parser(globalData->lexer, globalData, parameters, source->provider());
-    return parser.parseProgram();
+    JSParser parser(lexicalGlobalObject->globalData()->lexer, lexicalGlobalObject->globalData(), parameters, strictness == JSParseStrict, parserMode == JSParseFunctionCode, source->provider());
+    return parser.parseProgram(lexicalGlobalObject);
 }
 
-JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, FunctionParameters* parameters, SourceProvider* provider)
+JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, FunctionParameters* parameters, bool inStrictContext, bool isFunction, SourceProvider* provider)
     : m_lexer(lexer)
     , m_endAddress(0)
     , m_error(false)
@@ -325,28 +501,56 @@ JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, FunctionParameters* p
     , m_assignmentCount(0)
     , m_nonLHSCount(0)
     , m_syntaxAlreadyValidated(provider->isValid())
+    , m_statementDepth(0)
+    , m_nonTrivialExpressionCount(0)
+    , m_lastIdentifier(0)
 {
     m_endAddress = wtfThreadData().approximatedStackStart() - kMaxParserStackUsage;
-    next();
-    m_lexer->setLastLineNumber(tokenLine());
     ScopeRef scope = pushScope();
+    if (isFunction)
+        scope->setIsFunction();
+    if (inStrictContext)
+        scope->setStrictMode();
     if (parameters) {
         for (unsigned i = 0; i < parameters->size(); i++)
-            scope->declareVariable(&parameters->at(i));
+            scope->declareParameter(&parameters->at(i));
     }
+    next();
+    m_lexer->setLastLineNumber(tokenLine());
 }
 
-bool JSParser::parseProgram()
+bool JSParser::parseProgram(JSGlobalObject* lexicalGlobalObject)
 {
     ASTBuilder context(m_globalData, m_lexer);
+    if (m_lexer->isReparsing())
+        m_statementDepth--;
     ScopeRef scope = currentScope();
-    SourceElements* sourceElements = parseSourceElements<ASTBuilder>(context);
+    SourceElements* sourceElements = parseSourceElements<CheckForStrictMode>(context);
     if (!sourceElements || !consume(EOFTOK))
         return true;
+    if (!m_syntaxAlreadyValidated) {
+        IdentifierSet writtenVariables;
+        scope->getUncapturedWrittenVariables(writtenVariables);
+        IdentifierSet::const_iterator end = writtenVariables.end();
+        for (IdentifierSet::const_iterator ptr = writtenVariables.begin(); ptr != end; ++ptr) {
+            PropertySlot slot(lexicalGlobalObject);
+            if (!lexicalGlobalObject->getPropertySlot(lexicalGlobalObject->globalExec(), Identifier(m_globalData, *ptr), slot))
+                return true;
+        }
+        IdentifierSet deletedVariables;
+        if (!scope->getDeletedVariables(deletedVariables))
+            return true;
+        end = deletedVariables.end();
+        SymbolTable& globalEnvRecord = lexicalGlobalObject->symbolTable();
+        for (IdentifierSet::const_iterator ptr = deletedVariables.begin(); ptr != end; ++ptr) {
+            if (!globalEnvRecord.get(*ptr).isNull())
+                return true;
+        }
+    }
     IdentifierSet capturedVariables;
     scope->getCapturedVariables(capturedVariables);
-    m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), context.features(),
-                                          m_lastLine, context.numConstants(), capturedVariables);
+    m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), context.features() | (scope->strictMode() ? StrictModeFeature : 0),
+                                           m_lastLine, context.numConstants(), capturedVariables);
     return false;
 }
 
@@ -355,11 +559,30 @@ bool JSParser::allowAutomaticSemicolon()
     return match(CLOSEBRACE) || match(EOFTOK) || m_lexer->prevTerminator();
 }
 
-template <class TreeBuilder> TreeSourceElements JSParser::parseSourceElements(TreeBuilder& context)
+template <JSParser::SourceElementsMode mode, class TreeBuilder> TreeSourceElements JSParser::parseSourceElements(TreeBuilder& context)
 {
     TreeSourceElements sourceElements = context.createSourceElements();
-    while (TreeStatement statement = parseStatement(context))
+    bool seenNonDirective = false;
+    const Identifier* directive = 0;
+    unsigned startOffset = m_token.m_info.startOffset;
+    bool hasSetStrict = false;
+    while (TreeStatement statement = parseStatement(context, directive)) {
+        if (mode == CheckForStrictMode && !seenNonDirective) {
+            if (directive) {
+                if (!hasSetStrict && m_globalData->propertyNames->useStrictIdentifier == *directive) {
+                    setStrictMode();
+                    hasSetStrict = true;
+                    failIfFalse(isValidStrictMode());
+                    m_lexer->setOffset(startOffset);
+                    next();
+                    failIfTrue(m_error);
+                    continue;
+                }
+            } else
+                seenNonDirective = true;
+        }
         context.appendStatement(sourceElements, statement);
+    }
 
     if (m_error)
         fail();
@@ -399,7 +622,10 @@ template <class TreeBuilder> TreeStatement JSParser::parseDoWhileStatement(TreeB
     ASSERT(match(DO));
     int startLine = tokenLine();
     next();
-    TreeStatement statement = parseStatement(context);
+    const Identifier* unused = 0;
+    startLoop();
+    TreeStatement statement = parseStatement(context, unused);
+    endLoop();
     failIfFalse(statement);
     int endLine = tokenLine();
     consumeOrFail(WHILE);
@@ -422,7 +648,10 @@ template <class TreeBuilder> TreeStatement JSParser::parseWhileStatement(TreeBui
     failIfFalse(expr);
     int endLine = tokenLine();
     consumeOrFail(CLOSEPAREN);
-    TreeStatement statement = parseStatement(context);
+    const Identifier* unused = 0;
+    startLoop();
+    TreeStatement statement = parseStatement(context, unused);
+    endLoop();
     failIfFalse(statement);
     return context.createWhileStatement(expr, statement, startLine, endLine);
 }
@@ -441,7 +670,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseVarDeclarationList(Tr
         lastIdent = name;
         next();
         bool hasInitializer = match(EQUAL);
-        declareVariable(name);
+        failIfFalseIfStrict(declareVariable(name));
         context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0);
         if (hasInitializer) {
             int varDivot = tokenStart() + 1;
@@ -465,6 +694,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseVarDeclarationList(Tr
 
 template <class TreeBuilder> TreeConstDeclList JSParser::parseConstDeclarationList(TreeBuilder& context)
 {
+    failIfTrue(strictMode());
     TreeConstDeclList constDecls = 0;
     TreeConstDeclList tail = 0;
     do {
@@ -532,7 +762,10 @@ template <class TreeBuilder> TreeStatement JSParser::parseForStatement(TreeBuild
         int endLine = tokenLine();
         consumeOrFail(CLOSEPAREN);
 
-        TreeStatement statement = parseStatement(context);
+        const Identifier* unused = 0;
+        startLoop();
+        TreeStatement statement = parseStatement(context, unused);
+        endLoop();
         failIfFalse(statement);
 
         return context.createForInLoop(forInTarget, forInInitializer, expr, statement, declsStart, inLocation, exprEnd, initStart, initEnd, startLine, endLine);
@@ -566,7 +799,10 @@ template <class TreeBuilder> TreeStatement JSParser::parseForStatement(TreeBuild
         }
         int endLine = tokenLine();
         consumeOrFail(CLOSEPAREN);
-        TreeStatement statement = parseStatement(context);
+        const Identifier* unused = 0;
+        startLoop();
+        TreeStatement statement = parseStatement(context, unused);
+        endLoop();
         failIfFalse(statement);
         return context.createForLoop(decls, condition, increment, statement, hasDeclaration, startLine, endLine);
     }
@@ -579,7 +815,10 @@ template <class TreeBuilder> TreeStatement JSParser::parseForStatement(TreeBuild
     int exprEnd = lastTokenEnd();
     int endLine = tokenLine();
     consumeOrFail(CLOSEPAREN);
-    TreeStatement statement = parseStatement(context);
+    const Identifier* unused = 0;
+    startLoop();
+    TreeStatement statement = parseStatement(context, unused);
+    endLoop();
     failIfFalse(statement);
     
     return context.createForInLoop(decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine);
@@ -594,10 +833,13 @@ template <class TreeBuilder> TreeStatement JSParser::parseBreakStatement(TreeBui
     int endLine = tokenLine();
     next();
 
-    if (autoSemiColon())
+    if (autoSemiColon()) {
+        failIfFalseIfStrict(breakIsValid());
         return context.createBreakStatement(startCol, endCol, startLine, endLine);
+    }
     matchOrFail(IDENT);
     const Identifier* ident = m_token.m_data.ident;
+    failIfFalseIfStrict(hasLabel(ident));
     endCol = tokenEnd();
     endLine = tokenLine();
     next();
@@ -614,10 +856,13 @@ template <class TreeBuilder> TreeStatement JSParser::parseContinueStatement(Tree
     int endLine = tokenLine();
     next();
 
-    if (autoSemiColon())
+    if (autoSemiColon()) {
+        failIfFalseIfStrict(breakIsValid());
         return context.createContinueStatement(startCol, endCol, startLine, endLine);
+    }
     matchOrFail(IDENT);
     const Identifier* ident = m_token.m_data.ident;
+    failIfFalseIfStrict(hasLabel(ident));
     endCol = tokenEnd();
     endLine = tokenLine();
     next();
@@ -628,6 +873,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseContinueStatement(Tree
 template <class TreeBuilder> TreeStatement JSParser::parseReturnStatement(TreeBuilder& context)
 {
     ASSERT(match(RETURN));
+    failIfFalseIfStrict(currentScope()->isFunction());
     int startLine = tokenLine();
     int endLine = startLine;
     int start = tokenStart();
@@ -668,7 +914,8 @@ template <class TreeBuilder> TreeStatement JSParser::parseThrowStatement(TreeBui
 template <class TreeBuilder> TreeStatement JSParser::parseWithStatement(TreeBuilder& context)
 {
     ASSERT(match(WITH));
-    currentScope()->needsFullActivation();
+    failIfTrue(strictMode());
+    currentScope()->setNeedsFullActivation();
     int startLine = tokenLine();
     next();
     consumeOrFail(OPENPAREN);
@@ -679,8 +926,8 @@ template <class TreeBuilder> TreeStatement JSParser::parseWithStatement(TreeBuil
 
     int endLine = tokenLine();
     consumeOrFail(CLOSEPAREN);
-    
-    TreeStatement statement = parseStatement(context);
+    const Identifier* unused = 0;
+    TreeStatement statement = parseStatement(context, unused);
     failIfFalse(statement);
 
     return context.createWithStatement(expr, statement, start, end, startLine, endLine);
@@ -697,7 +944,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseSwitchStatement(TreeBu
     int endLine = tokenLine();
     consumeOrFail(CLOSEPAREN);
     consumeOrFail(OPENBRACE);
-
+    startSwitch();
     TreeClauseList firstClauses = parseSwitchClauses(context);
     failIfTrue(m_error);
 
@@ -706,6 +953,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseSwitchStatement(TreeBu
 
     TreeClauseList secondClauses = parseSwitchClauses(context);
     failIfTrue(m_error);
+    endSwitch();
     consumeOrFail(CLOSEBRACE);
 
     return context.createSwitchStatement(expr, firstClauses, defaultClause, secondClauses, startLine, endLine);
@@ -720,7 +968,7 @@ template <class TreeBuilder> TreeClauseList JSParser::parseSwitchClauses(TreeBui
     TreeExpression condition = parseExpression(context);
     failIfFalse(condition);
     consumeOrFail(COLON);
-    TreeSourceElements statements = parseSourceElements(context);
+    TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
     failIfFalse(statements);
     TreeClause clause = context.createClause(condition, statements);
     TreeClauseList clauseList = context.createClauseList(clause);
@@ -731,7 +979,7 @@ template <class TreeBuilder> TreeClauseList JSParser::parseSwitchClauses(TreeBui
         TreeExpression condition = parseExpression(context);
         failIfFalse(condition);
         consumeOrFail(COLON);
-        TreeSourceElements statements = parseSourceElements(context);
+        TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
         failIfFalse(statements);
         clause = context.createClause(condition, statements);
         tail = context.createClauseList(tail, clause);
@@ -745,7 +993,7 @@ template <class TreeBuilder> TreeClause JSParser::parseSwitchDefaultClause(TreeB
         return 0;
     next();
     consumeOrFail(COLON);
-    TreeSourceElements statements = parseSourceElements(context);
+    TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
     failIfFalse(statements);
     return context.createClause(0, statements);
 }
@@ -767,14 +1015,14 @@ template <class TreeBuilder> TreeStatement JSParser::parseTryStatement(TreeBuild
     int lastLine = m_lastLine;
 
     if (match(CATCH)) {
-        currentScope()->needsFullActivation();
+        currentScope()->setNeedsFullActivation();
         next();
         consumeOrFail(OPENPAREN);
         matchOrFail(IDENT);
         ident = m_token.m_data.ident;
         next();
         ScopeRef catchScope = pushScope();
-        catchScope->declareVariable(ident);
+        failIfFalseIfStrict(catchScope->declareVariable(ident));
         catchScope->preventNewDecls();
         consumeOrFail(CLOSEPAREN);
         matchOrFail(OPENBRACE);
@@ -782,7 +1030,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseTryStatement(TreeBuild
         catchBlock = parseBlockStatement(context);
         failIfFalse(catchBlock);
         catchHasEval = initialEvalCount != context.evalCount();
-        popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo);
+        failIfFalse(popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo));
     }
 
     if (match(FINALLY)) {
@@ -816,15 +1064,19 @@ template <class TreeBuilder> TreeStatement JSParser::parseBlockStatement(TreeBui
         next();
         return context.createBlockStatement(0, start, m_lastLine);
     }
-    TreeSourceElements subtree = parseSourceElements(context);
+    TreeSourceElements subtree = parseSourceElements<DontCheckForStrictMode>(context);
     failIfFalse(subtree);
     matchOrFail(CLOSEBRACE);
     next();
     return context.createBlockStatement(subtree, start, m_lastLine);
 }
 
-template <class TreeBuilder> TreeStatement JSParser::parseStatement(TreeBuilder& context)
+template <class TreeBuilder> TreeStatement JSParser::parseStatement(TreeBuilder& context, const Identifier*& directive)
 {
+    DepthManager statementDepth(&m_statementDepth);
+    m_statementDepth++;
+    directive = 0;
+    int nonTrivialExpressionCount = 0;
     failIfStackOverflow();
     switch (m_token.m_type) {
     case OPENBRACE:
@@ -834,6 +1086,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseStatement(TreeBuilder&
     case CONSTTOKEN:
         return parseConstDeclaration(context);
     case FUNCTION:
+        failIfFalseIfStrict(m_statementDepth == 1);
         return parseFunctionDeclaration(context);
     case SEMICOLON:
         next();
@@ -870,8 +1123,14 @@ template <class TreeBuilder> TreeStatement JSParser::parseStatement(TreeBuilder&
         return 0;
     case IDENT:
         return parseExpressionOrLabelStatement(context);
+    case STRING:
+        directive = m_token.m_data.ident;
+        nonTrivialExpressionCount = m_nonTrivialExpressionCount;
     default:
-        return parseExpressionStatement(context);
+        TreeStatement exprStatement = parseExpressionStatement(context);
+        if (directive && nonTrivialExpressionCount != m_nonTrivialExpressionCount)
+            directive = 0;
+        return exprStatement;
     }
 }
 
@@ -879,7 +1138,7 @@ template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParame
 {
     matchOrFail(IDENT);
     usesArguments = m_globalData->propertyNames->arguments == *m_token.m_data.ident;
-    declareVariable(m_token.m_data.ident);
+    failIfFalseIfStrict(declareParameter(m_token.m_data.ident));
     TreeFormalParameterList list = context.createFormalParameterList(*m_token.m_data.ident);
     TreeFormalParameterList tail = list;
     next();
@@ -887,7 +1146,8 @@ template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParame
         next();
         matchOrFail(IDENT);
         const Identifier* ident = m_token.m_data.ident;
-        declareVariable(ident);
+        usesArguments |= m_globalData->propertyNames->arguments == *m_token.m_data.ident;
+        failIfFalseIfStrict(declareParameter(ident));
         next();
         usesArguments = usesArguments || m_globalData->propertyNames->arguments == *ident;
         tail = context.createFormalParameterList(tail, *ident);
@@ -898,20 +1158,23 @@ template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParame
 template <class TreeBuilder> TreeFunctionBody JSParser::parseFunctionBody(TreeBuilder& context)
 {
     if (match(CLOSEBRACE))
-        return context.createFunctionBody();
+        return context.createFunctionBody(strictMode());
+    DepthManager statementDepth(&m_statementDepth);
+    m_statementDepth = 0;
     typename TreeBuilder::FunctionBodyBuilder bodyBuilder(m_globalData, m_lexer);
-    failIfFalse(parseSourceElements(bodyBuilder));
-    return context.createFunctionBody();
+    failIfFalse(parseSourceElements<CheckForStrictMode>(bodyBuilder));
+    return context.createFunctionBody(strictMode());
 }
 
 template <JSParser::FunctionRequirements requirements, bool nameIsInContainingScope, class TreeBuilder> bool JSParser::parseFunctionInfo(TreeBuilder& context, const Identifier*& name, TreeFormalParameterList& parameters, TreeFunctionBody& body, int& openBracePos, int& closeBracePos, int& bodyStartLine)
 {
     ScopeRef functionScope = pushScope();
+    functionScope->setIsFunction();
     if (match(IDENT)) {
         name = m_token.m_data.ident;
         next();
         if (!nameIsInContainingScope)
-            functionScope->declareVariable(name);
+            failIfFalseIfStrict(functionScope->declareVariable(name));
     } else if (requirements == FunctionNeedsName)
         return false;
     consumeOrFail(OPENPAREN);
@@ -931,7 +1194,11 @@ template <JSParser::FunctionRequirements requirements, bool nameIsInContainingSc
     failIfFalse(body);
     if (usesArguments)
         context.setUsesArguments(body);
-    popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo);
+    if (functionScope->strictMode() && name) {
+        failIfTrue(m_globalData->propertyNames->arguments == *name);
+        failIfTrue(m_globalData->propertyNames->eval == *name);
+    }
+    failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo));
     matchOrFail(CLOSEBRACE);
     closeBracePos = m_token.m_data.intValue;
     next();
@@ -950,7 +1217,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseFunctionDeclaration(Tr
     int bodyStartLine = 0;
     failIfFalse((parseFunctionInfo<FunctionNeedsName, true>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
     failIfFalse(name);
-    declareVariable(name);
+    failIfFalseIfStrict(declareVariable(name));
     return context.createFuncDeclStatement(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
 }
 
@@ -973,7 +1240,12 @@ template <class TreeBuilder> TreeStatement JSParser::parseExpressionOrLabelState
     failIfFalse(currentToken + 1 == m_tokenCount);
     int end = tokenEnd();
     consumeOrFail(COLON);
-    TreeStatement statement = parseStatement(context);
+    const Identifier* unused = 0;
+    if (strictMode() && !m_syntaxAlreadyValidated)
+        pushLabel(ident);
+    TreeStatement statement = parseStatement(context, unused);
+    if (strictMode() && !m_syntaxAlreadyValidated)
+        popLabel();
     failIfFalse(statement);
     return context.createLabelStatement(ident, statement, start, end);
 }
@@ -1001,7 +1273,8 @@ template <class TreeBuilder> TreeStatement JSParser::parseIfStatement(TreeBuilde
     int end = tokenLine();
     consumeOrFail(CLOSEPAREN);
 
-    TreeStatement trueBlock = parseStatement(context);
+    const Identifier* unused = 0;
+    TreeStatement trueBlock = parseStatement(context, unused);
     failIfFalse(trueBlock);
 
     if (!match(ELSE))
@@ -1014,7 +1287,8 @@ template <class TreeBuilder> TreeStatement JSParser::parseIfStatement(TreeBuilde
     do {
         next();
         if (!match(IF)) {
-            TreeStatement block = parseStatement(context);
+            const Identifier* unused = 0;
+            TreeStatement block = parseStatement(context, unused);
             failIfFalse(block);
             statementStack.append(block);
             trailingElse = true;
@@ -1029,8 +1303,8 @@ template <class TreeBuilder> TreeStatement JSParser::parseIfStatement(TreeBuilde
         failIfFalse(innerCondition);
         int innerEnd = tokenLine();
         consumeOrFail(CLOSEPAREN);
-        
-        TreeStatement innerTrueBlock = parseStatement(context);
+        const Identifier* unused = 0;
+        TreeStatement innerTrueBlock = parseStatement(context, unused);
         failIfFalse(innerTrueBlock);     
         exprStack.append(innerCondition);
         posStack.append(make_pair(innerStart, innerEnd));
@@ -1070,6 +1344,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseExpression(TreeBuilde
     if (!match(COMMA))
         return node;
     next();
+    m_nonTrivialExpressionCount++;
     m_nonLHSCount++;
     TreeExpression right = parseAssignmentExpression(context);
     failIfFalse(right);
@@ -1115,11 +1390,17 @@ template <typename TreeBuilder> TreeExpression JSParser::parseAssignmentExpressi
         default:
             goto end;
         }
+        m_nonTrivialExpressionCount++;
         hadAssignment = true;
         context.assignmentStackAppend(assignmentStack, lhs, start, tokenStart(), m_assignmentCount, op);
         start = tokenStart();
         m_assignmentCount++;
         next();
+        if (strictMode() && m_lastIdentifier && context.isResolve(lhs)) {
+            failIfTrueIfStrict(m_globalData->propertyNames->eval == *m_lastIdentifier);
+            declareWrite(m_lastIdentifier);
+            m_lastIdentifier = 0;
+        }
         lhs = parseConditionalExpression(context);
         failIfFalse(lhs);
         if (initialNonLHSCount != m_nonLHSCount)
@@ -1144,6 +1425,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseConditionalExpression
     failIfFalse(cond);
     if (!match(QUESTION))
         return cond;
+    m_nonTrivialExpressionCount++;
     m_nonLHSCount++;
     next();
     TreeExpression lhs = parseAssignmentExpression(context);
@@ -1181,6 +1463,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseBinaryExpression(Tree
         int precedence = isBinaryOperator(m_token.m_type);
         if (!precedence)
             break;
+        m_nonTrivialExpressionCount++;
         m_nonLHSCount++;
         int operatorToken = m_token.m_type;
         next();
@@ -1196,7 +1479,6 @@ template <class TreeBuilder> TreeExpression JSParser::parseBinaryExpression(Tree
         }
         context.operatorStackAppend(operatorStackDepth, operatorToken, precedence);
     }
-
     while (operatorStackDepth) {
         ASSERT(operandStackDepth > 1);
 
@@ -1327,6 +1609,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseStrictObjectLiteral(T
         if (!m_syntaxAlreadyValidated) {
             std::pair<ObjectValidationMap::iterator, bool> propertyEntryIter = objectValidator.add(context.getName(property).impl(), context.getType(property));
             if (!propertyEntryIter.second) {
+                failIfTrue(strictMode());
                 if ((context.getType(property) & propertyEntryIter.first->second) != PropertyNode::Constant) {
                     // Can't have multiple getters or setters with the same name, nor can we define 
                     // a property as both an accessor and a constant value
@@ -1389,6 +1672,8 @@ template <class TreeBuilder> TreeExpression JSParser::parsePrimaryExpression(Tre
 {
     switch (m_token.m_type) {
     case OPENBRACE:
+        if (strictMode())
+            return parseStrictObjectLiteral(context);
         return parseObjectLiteral(context);
     case OPENBRACKET:
         return parseArrayLiteral(context);
@@ -1410,6 +1695,7 @@ template <class TreeBuilder> TreeExpression JSParser::parsePrimaryExpression(Tre
         const Identifier* ident = m_token.m_data.ident;
         next();
         currentScope()->useVariable(ident, m_globalData->propertyNames->eval == *ident);
+        m_lastIdentifier = ident;
         return context.createResolve(ident, start);
     }
     case STRING: {
@@ -1485,6 +1771,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseMemberExpression(Tree
         next();
         newCount++;
     }
+
     if (match(FUNCTION)) {
         const Identifier* name = &m_globalData->propertyNames->nullIdentifier;
         TreeFormalParameterList parameters = 0;
@@ -1502,6 +1789,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseMemberExpression(Tree
     while (true) {
         switch (m_token.m_type) {
         case OPENBRACKET: {
+            m_nonTrivialExpressionCount++;
             int expressionEnd = lastTokenEnd();
             next();
             int nonLHSCount = m_nonLHSCount;
@@ -1515,6 +1803,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseMemberExpression(Tree
             break;
         }
         case OPENPAREN: {
+            m_nonTrivialExpressionCount++;
             if (newCount) {
                 newCount--;
                 if (match(OPENPAREN)) {
@@ -1535,6 +1824,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseMemberExpression(Tree
             break;
         }
         case DOT: {
+            m_nonTrivialExpressionCount++;
             int expressionEnd = lastTokenEnd();
             next(Lexer::IgnoreReservedWords);
             matchOrFail(IDENT);
@@ -1556,25 +1846,59 @@ template <class TreeBuilder> TreeExpression JSParser::parseUnaryExpression(TreeB
 {
     AllowInOverride allowInOverride(this);
     int tokenStackDepth = 0;
+    bool modifiesExpr = false;
+    bool requiresLExpr = false;
     while (isUnaryOp(m_token.m_type)) {
+        if (strictMode()) {
+            switch (m_token.m_type) {
+            case PLUSPLUS:
+            case MINUSMINUS:
+            case AUTOPLUSPLUS:
+            case AUTOMINUSMINUS:
+                failIfTrue(requiresLExpr);
+                modifiesExpr = true;
+                requiresLExpr = true;
+                break;
+            case DELETETOKEN:
+                failIfTrue(requiresLExpr);
+                requiresLExpr = true;
+                break;
+            default:
+                failIfTrue(requiresLExpr);
+                break;
+            }
+        }
         m_nonLHSCount++;
         context.appendUnaryToken(tokenStackDepth, m_token.m_type, tokenStart());
         next();
+        m_nonTrivialExpressionCount++;
     }
     int subExprStart = tokenStart();
     TreeExpression expr = parseMemberExpression(context);
     failIfFalse(expr);
+    bool isEval = false;
+    if (strictMode() && !m_syntaxAlreadyValidated) {
+        if (context.isResolve(expr))
+            isEval = m_globalData->propertyNames->eval == *m_lastIdentifier;
+    }
+    failIfTrueIfStrict(isEval && modifiesExpr);
     switch (m_token.m_type) {
     case PLUSPLUS:
+        m_nonTrivialExpressionCount++;
         m_nonLHSCount++;
         expr = context.makePostfixNode(expr, OpPlusPlus, subExprStart, lastTokenEnd(), tokenEnd());
         m_assignmentCount++;
+        failIfTrueIfStrict(isEval);
+        failIfTrueIfStrict(requiresLExpr);
         next();
         break;
     case MINUSMINUS:
+        m_nonTrivialExpressionCount++;
         m_nonLHSCount++;
         expr = context.makePostfixNode(expr, OpMinusMinus, subExprStart, lastTokenEnd(), tokenEnd());
         m_assignmentCount++;
+        failIfTrueIfStrict(isEval);
+        failIfTrueIfStrict(requiresLExpr);
         next();
         break;
     default:
@@ -1583,7 +1907,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseUnaryExpression(TreeB
 
     int end = lastTokenEnd();
 
-    if (!TreeBuilder::CreatesAST)
+    if (!TreeBuilder::CreatesAST && (m_syntaxAlreadyValidated || !strictMode()))
         return expr;
 
     while (tokenStackDepth) {
@@ -1617,6 +1941,8 @@ template <class TreeBuilder> TreeExpression JSParser::parseUnaryExpression(TreeB
             expr = context.createVoid(expr);
             break;
         case DELETETOKEN:
+            if (strictMode() && context.isResolve(expr))
+                failIfFalse(deleteProperty(m_lastIdentifier));
             expr = context.makeDeleteNode(expr, context.unaryTokenStackLastStart(tokenStackDepth), end, end);
             break;
         default:
index ab18fab..64b18e7 100644 (file)
 
 namespace JSC {
 
+class ExecState;
 class FunctionParameters;
 class Identifier;
-class JSGlobalData;
+class JSGlobalObject;
 class SourceCode;
 
 enum {
@@ -155,6 +156,9 @@ struct JSToken {
     JSTokenInfo m_info;
 };
 
-int jsParse(JSGlobalData*, FunctionParameters*, const SourceCode*);
+enum JSParserStrictness { JSParseNormal, JSParseStrict };
+enum JSParserMode { JSParseProgramCode, JSParseFunctionCode };
+
+int jsParse(JSGlobalObject*, FunctionParameters*, JSParserStrictness, JSParserMode, const SourceCode*);
 }
 #endif // JSParser_h
index cc4321d..239729e 100644 (file)
@@ -453,7 +453,7 @@ ALWAYS_INLINE JSTokenType Lexer::parseIdentifier(JSTokenData* lvalp, LexType lex
     return IDENT;
 }
 
-ALWAYS_INLINE bool Lexer::parseString(JSTokenData* lvalp)
+ALWAYS_INLINE bool Lexer::parseString(JSTokenData* lvalp, bool strictMode)
 {
     int stringQuoteCharacter = m_current;
     shift();
@@ -494,6 +494,8 @@ ALWAYS_INLINE bool Lexer::parseString(JSTokenData* lvalp)
                     return false;
             } else if (isASCIIOctalDigit(m_current)) {
                 // Octal character sequences
+                if (strictMode)
+                    return false;
                 int character1 = m_current;
                 shift();
                 if (isASCIIOctalDigit(m_current)) {
@@ -696,7 +698,7 @@ ALWAYS_INLINE bool Lexer::parseMultilineComment()
     }
 }
 
-JSTokenType Lexer::lex(JSTokenData* lvalp, JSTokenInfo* llocp, LexType lexType)
+JSTokenType Lexer::lex(JSTokenData* lvalp, JSTokenInfo* llocp, LexType lexType, bool strictMode)
 {
     ASSERT(!m_error);
     ASSERT(m_buffer8.isEmpty());
@@ -976,8 +978,11 @@ start:
         } else {
             record8('0');
             if (isASCIIOctalDigit(m_current)) {
-                if (parseOctal(lvalp->doubleValue))
+                if (parseOctal(lvalp->doubleValue)) {
+                    if (strictMode)
+                        goto returnError;
                     token = NUMBER;
+                }
             }
         }
         // Fall through into CharacterNumber
@@ -1006,7 +1011,7 @@ inNumberAfterDecimalPoint:
         m_delimited = false;
         break;
     case CharacterQuote:
-        if (UNLIKELY(!parseString(lvalp)))
+        if (UNLIKELY(!parseString(lvalp, strictMode)))
             goto returnError;
         shift();
         m_delimited = false;
index e6c1efd..4d2513d 100644 (file)
@@ -48,10 +48,11 @@ namespace JSC {
         // Functions to set up parsing.
         void setCode(const SourceCode&, ParserArena&);
         void setIsReparsing() { m_isReparsing = true; }
+        bool isReparsing() const { return m_isReparsing; }
 
         // Functions for the parser itself.
         enum LexType { IdentifyReservedWords, IgnoreReservedWords };
-        JSTokenType lex(JSTokenData* lvalp, JSTokenInfo* llocp, LexType);
+        JSTokenType lex(JSTokenData* lvalp, JSTokenInfo* llocp, LexType, bool strictMode);
         int lineNumber() const { return m_lineNumber; }
         void setLastLineNumber(int lastLineNumber) { m_lastLineNumber = lastLineNumber; }
         int lastLineNumber() const { return m_lastLineNumber; }
@@ -95,7 +96,7 @@ namespace JSC {
         ALWAYS_INLINE bool lastTokenWasRestrKeyword() const;
 
         ALWAYS_INLINE JSTokenType parseIdentifier(JSTokenData*, LexType);
-        ALWAYS_INLINE bool parseString(JSTokenData* lvalp);
+        ALWAYS_INLINE bool parseString(JSTokenData* lvalp, bool strictMode);
         ALWAYS_INLINE void parseHex(double& returnValue);
         ALWAYS_INLINE bool parseOctal(double& returnValue);
         ALWAYS_INLINE bool parseDecimal(double& returnValue);
index 534e28a..34aa674 100644 (file)
@@ -89,10 +89,10 @@ ScopeNodeData::ScopeNodeData(ParserArena& arena, SourceElements* statements, Var
 
 // ------------------------------ ScopeNode -----------------------------
 
-ScopeNode::ScopeNode(JSGlobalData* globalData)
+ScopeNode::ScopeNode(JSGlobalData* globalData, bool inStrictContext)
     : StatementNode(globalData)
     , ParserArenaRefCounted(globalData)
-    , m_features(NoFeatures)
+    , m_features(inStrictContext ? StrictModeFeature : NoFeatures)
 {
 }
 
@@ -154,8 +154,8 @@ FunctionParameters::FunctionParameters(ParameterNode* firstParameter)
         append(parameter->ident());
 }
 
-inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData)
-    : ScopeNode(globalData)
+inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, bool inStrictContext)
+    : ScopeNode(globalData, inStrictContext)
 {
 }
 
@@ -177,9 +177,9 @@ void FunctionBodyNode::finishParsing(PassRefPtr<FunctionParameters> parameters,
     m_ident = ident;
 }
 
-FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData)
+FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData, bool inStrictContext)
 {
-    return new FunctionBodyNode(globalData);
+    return new FunctionBodyNode(globalData, inStrictContext);
 }
 
 PassRefPtr<FunctionBodyNode> FunctionBodyNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
index fa61cdc..f2a7c1e 100644 (file)
@@ -57,6 +57,7 @@ namespace JSC {
     const CodeFeatures WithFeature = 1 << 4;
     const CodeFeatures CatchFeature = 1 << 5;
     const CodeFeatures ThisFeature = 1 << 6;
+    const CodeFeatures StrictModeFeature = 1 << 7;
     const CodeFeatures AllFeatures = EvalFeature | ClosureFeature | AssignFeature | ArgumentsFeature | WithFeature | CatchFeature | ThisFeature;
 
     enum Operator {
@@ -1393,7 +1394,7 @@ namespace JSC {
         typedef DeclarationStacks::VarStack VarStack;
         typedef DeclarationStacks::FunctionStack FunctionStack;
 
-        ScopeNode(JSGlobalData*);
+        ScopeNode(JSGlobalData*, bool inStrictContext);
         ScopeNode(JSGlobalData*, const SourceCode&, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, CodeFeatures, int numConstants);
 
         using ParserArenaRefCounted::operator new;
@@ -1410,6 +1411,7 @@ namespace JSC {
 
         bool usesEval() const { return m_features & EvalFeature; }
         bool usesArguments() const { return m_features & ArgumentsFeature; }
+        bool isStrictMode() const { return m_features & StrictModeFeature; }
         void setUsesArguments() { m_features |= ArgumentsFeature; }
         bool usesThis() const { return m_features & ThisFeature; }
         bool needsActivationForMoreThanVariables() const { ASSERT(m_data); return m_features & (EvalFeature | WithFeature | CatchFeature); }
@@ -1444,6 +1446,7 @@ namespace JSC {
 
     class ProgramNode : public ScopeNode {
     public:
+        static const bool isFunctionNode = false;
         static PassRefPtr<ProgramNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
 
         static const bool scopeIsFunction = false;
@@ -1456,6 +1459,7 @@ namespace JSC {
 
     class EvalNode : public ScopeNode {
     public:
+        static const bool isFunctionNode = false;
         static PassRefPtr<EvalNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
 
         static const bool scopeIsFunction = false;
@@ -1476,7 +1480,8 @@ namespace JSC {
 
     class FunctionBodyNode : public ScopeNode {
     public:
-        static FunctionBodyNode* create(JSGlobalData*);
+        static const bool isFunctionNode = true;
+        static FunctionBodyNode* create(JSGlobalData*, bool isStrictMode);
         static PassRefPtr<FunctionBodyNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
 
         FunctionParameters* parameters() const { return m_parameters.get(); }
@@ -1492,7 +1497,7 @@ namespace JSC {
         static const bool scopeIsFunction = true;
 
     private:
-        FunctionBodyNode(JSGlobalData*);
+        FunctionBodyNode(JSGlobalData*, bool inStrictContext);
         FunctionBodyNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
 
         Identifier m_ident;
index 0c0b2d7..dc2cbe4 100644 (file)
@@ -35,8 +35,9 @@ extern int jscyyparse(void*);
 
 namespace JSC {
 
-void Parser::parse(JSGlobalData* globalData, FunctionParameters* parameters, int* errLine, UString* errMsg)
+void Parser::parse(JSGlobalObject* lexicalGlobalObject, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode mode, int* errLine, UString* errMsg)
 {
+    ASSERT(lexicalGlobalObject);
     m_sourceElements = 0;
 
     int defaultErrLine;
@@ -50,10 +51,10 @@ void Parser::parse(JSGlobalData* globalData, FunctionParameters* parameters, int
     *errLine = -1;
     *errMsg = UString();
 
-    Lexer& lexer = *globalData->lexer;
+    Lexer& lexer = *lexicalGlobalObject->globalData()->lexer;
     lexer.setCode(*m_source, m_arena);
 
-    int parseError = jsParse(globalData, parameters, m_source);
+    int parseError = jsParse(lexicalGlobalObject, parameters, strictness, mode, m_source);
     int lineNumber = lexer.lineNumber();
     bool lexError = lexer.sawError();
     lexer.clear();
index 9134de1..f5bbcb8 100644 (file)
@@ -48,7 +48,7 @@ namespace JSC {
     class Parser : public Noncopyable {
     public:
         template <class ParsedNode>
-        PassRefPtr<ParsedNode> parse(JSGlobalData* globalData, JSGlobalObject* lexicalGlobalObject, Debugger*, ExecState*, const SourceCode& source, FunctionParameters*, JSObject** exception);
+        PassRefPtr<ParsedNode> parse(JSGlobalObject* lexicalGlobalObject, Debugger*, ExecState*, const SourceCode& source, FunctionParameters*, JSParserStrictness strictness, JSObject** exception);
 
         void didFinishParsing(SourceElements*, ParserArenaData<DeclarationStacks::VarStack>*, 
                               ParserArenaData<DeclarationStacks::FunctionStack>*, CodeFeatures features,
@@ -57,7 +57,7 @@ namespace JSC {
         ParserArena& arena() { return m_arena; }
 
     private:
-        void parse(JSGlobalData*, FunctionParameters*, int* errLine, UString* errMsg);
+        void parse(JSGlobalObject* lexicalGlobalObject, FunctionParameters*, JSParserStrictness strictness, JSParserMode mode, int* errLine, UString* errMsg);
 
         // Used to determine type of error to report.
         bool isFunctionBodyNode(ScopeNode*) { return false; }
@@ -75,20 +75,21 @@ namespace JSC {
     };
 
     template <class ParsedNode>
-    PassRefPtr<ParsedNode> Parser::parse(JSGlobalData* globalData, JSGlobalObject* lexicalGlobalObject, Debugger* debugger, ExecState* debuggerExecState, const SourceCode& source, FunctionParameters* parameters, JSObject** exception)
+    PassRefPtr<ParsedNode> Parser::parse(JSGlobalObject* lexicalGlobalObject, Debugger* debugger, ExecState* debuggerExecState, const SourceCode& source, FunctionParameters* parameters, JSParserStrictness strictness, JSObject** exception)
     {
+        ASSERT(lexicalGlobalObject);
         ASSERT(exception && !*exception);
         int errLine;
         UString errMsg;
 
         m_source = &source;
         if (ParsedNode::scopeIsFunction)
-            globalData->lexer->setIsReparsing();
-        parse(globalData, parameters, &errLine, &errMsg);
+            lexicalGlobalObject->globalData()->lexer->setIsReparsing();
+        parse(lexicalGlobalObject, parameters, strictness, ParsedNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, &errLine, &errMsg);
 
         RefPtr<ParsedNode> result;
         if (m_sourceElements) {
-            result = ParsedNode::create(globalData,
+            result = ParsedNode::create(lexicalGlobalObject->globalData(),
                 m_sourceElements,
                 m_varDeclarations ? &m_varDeclarations->data : 0,
                 m_funcDeclarations ? &m_funcDeclarations->data : 0,
@@ -107,7 +108,7 @@ namespace JSC {
             if (isFunctionBodyNode(static_cast<ParsedNode*>(0)))
                 *exception = createStackOverflowError(lexicalGlobalObject);
             else
-                *exception = addErrorInfo(globalData, createSyntaxError(lexicalGlobalObject, errMsg), errLine, source);
+                *exception = addErrorInfo(lexicalGlobalObject->globalData(), createSyntaxError(lexicalGlobalObject, errMsg), errLine, source);
         }
 
         m_arena.reset();
index ce3ab61..f9093a7 100644 (file)
@@ -30,15 +30,24 @@ namespace JSC {
 class SyntaxChecker {
 public:
     SyntaxChecker(JSGlobalData* , Lexer*)
+        : m_topBinaryExpr(0)
     {
     }
 
     typedef SyntaxChecker FunctionBodyBuilder;
+    enum { NoneExpr = 0,
+        ResolveEvalExpr, ResolveExpr, NumberExpr, StringExpr,
+        ThisExpr, NullExpr, BoolExpr, RegExpExpr, ObjectLiteralExpr,
+        FunctionExpr, BracketExpr, DotExpr, CallExpr,
+        NewExpr, PreExpr, PostExpr, UnaryExpr, BinaryExpr,
+        ConditionalExpr, AssignmentExpr, TypeofExpr,
+        DeleteExpr, ArrayLiteralExpr };
+    typedef int ExpressionType;
 
-    typedef int Expression;
+    typedef ExpressionType Expression;
     typedef int SourceElements;
     typedef int Arguments;
-    typedef int Comma;
+    typedef ExpressionType Comma;
     struct Property {
         ALWAYS_INLINE Property(void* = 0)
             : type((PropertyNode::Type)0)
@@ -73,38 +82,38 @@ public:
     static const bool NeedsFreeVariableInfo = false;
 
     int createSourceElements() { return 1; }
-    int makeFunctionCallNode(int, int, int, int, int) { return 1; }
-    void appendToComma(int, int) { }
-    int createCommaExpr(int, int) { return 1; }
-    int makeAssignNode(int, Operator, int, bool, bool, int, int, int) { return 1; }
-    int makePrefixNode(int, Operator, int, int, int) { return 1; }
-    int makePostfixNode(int, Operator, int, int, int) { return 1; }
-    int makeTypeOfNode(int) { return 1; }
-    int makeDeleteNode(int, int, int, int) { return 1; }
-    int makeNegateNode(int) { return 1; }
-    int makeBitwiseNotNode(int) { return 1; }
-    int createLogicalNot(int) { return 1; }
-    int createUnaryPlus(int) { return 1; }
-    int createVoid(int) { return 1; }
-    int thisExpr() { return 1; }
-    int createResolve(const Identifier*, int) { return 1; }
-    int createObjectLiteral() { return 1; }
-    int createObjectLiteral(int) { return 1; }
-    int createArray(int) { return 1; }
-    int createArray(int, int) { return 1; }
-    int createNumberExpr(double) { return 1; }
-    int createString(const Identifier*) { return 1; }
-    int createBoolean(bool) { return 1; }
-    int createNull() { return 1; }
-    int createBracketAccess(int, int, bool, int, int, int) { return 1; }
-    int createDotAccess(int, const Identifier&, int, int, int) { return 1; }
-    int createRegex(const Identifier&, const Identifier&, int) { return 1; }
-    int createNewExpr(int, int, int, int, int) { return 1; }
-    int createNewExpr(int, int, int) { return 1; }
-    int createConditionalExpr(int, int, int) { return 1; }
-    int createAssignResolve(const Identifier&, int, bool, int, int, int) { return 1; }
-    int createFunctionExpr(const Identifier*, int, int, int, int, int, int) { return 1; }
-    int createFunctionBody() { return 1; }
+    ExpressionType makeFunctionCallNode(int, int, int, int, int) { return CallExpr; }
+    void appendToComma(ExpressionType& base, ExpressionType right) { base = right; }
+    ExpressionType createCommaExpr(ExpressionType, ExpressionType right) { return right; }
+    ExpressionType makeAssignNode(ExpressionType, Operator, ExpressionType, bool, bool, int, int, int) { return AssignmentExpr; }
+    ExpressionType makePrefixNode(ExpressionType, Operator, int, int, int) { return PreExpr; }
+    ExpressionType makePostfixNode(ExpressionType, Operator, int, int, int) { return PostExpr; }
+    ExpressionType makeTypeOfNode(ExpressionType) { return TypeofExpr; }
+    ExpressionType makeDeleteNode(ExpressionType, int, int, int) { return DeleteExpr; }
+    ExpressionType makeNegateNode(ExpressionType) { return UnaryExpr; }
+    ExpressionType makeBitwiseNotNode(ExpressionType) { return UnaryExpr; }
+    ExpressionType createLogicalNot(ExpressionType) { return UnaryExpr; }
+    ExpressionType createUnaryPlus(ExpressionType) { return UnaryExpr; }
+    ExpressionType createVoid(ExpressionType) { return UnaryExpr; }
+    ExpressionType thisExpr() { return ThisExpr; }
+    ExpressionType createResolve(const Identifier*, int) { return ResolveExpr; }
+    ExpressionType createObjectLiteral() { return ObjectLiteralExpr; }
+    ExpressionType createObjectLiteral(int) { return ObjectLiteralExpr; }
+    ExpressionType createArray(int) { return ArrayLiteralExpr; }
+    ExpressionType createArray(int, int) { return ArrayLiteralExpr; }
+    ExpressionType createNumberExpr(double) { return NumberExpr; }
+    ExpressionType createString(const Identifier*) { return StringExpr; }
+    ExpressionType createBoolean(bool) { return BoolExpr; }
+    ExpressionType createNull() { return NullExpr; }
+    ExpressionType createBracketAccess(ExpressionType, ExpressionType, bool, int, int, int) { return BracketExpr; }
+    ExpressionType createDotAccess(ExpressionType, const Identifier&, int, int, int) { return DotExpr; }
+    ExpressionType createRegex(const Identifier&, const Identifier&, int) { return RegExpExpr; }
+    ExpressionType createNewExpr(ExpressionType, int, int, int, int) { return NewExpr; }
+    ExpressionType createNewExpr(ExpressionType, int, int) { return NewExpr; }
+    ExpressionType createConditionalExpr(ExpressionType, ExpressionType, ExpressionType) { return ConditionalExpr; }
+    ExpressionType createAssignResolve(const Identifier&, ExpressionType, bool, int, int, int) { return AssignmentExpr; }
+    ExpressionType createFunctionExpr(const Identifier*, int, int, int, int, int, int) { return FunctionExpr; }
+    int createFunctionBody(bool) { return 1; }
     int createArguments() { return 1; }
     int createArguments(int) { return 1; }
     int createArgumentsList(int) { return 1; }
@@ -169,26 +178,38 @@ public:
     void addVar(const Identifier*, bool) { }
     int combineCommaNodes(int, int) { return 1; }
     int evalCount() const { return 0; }
-    void appendBinaryExpressionInfo(int& operandStackDepth, int, int, int, int, bool) { operandStackDepth++; }
+    void appendBinaryExpressionInfo(int& operandStackDepth, int expr, int, int, int, bool)
+    {
+        if (!m_topBinaryExpr)
+            m_topBinaryExpr = expr;
+        else
+            m_topBinaryExpr = BinaryExpr;
+        operandStackDepth++;
+    }
     
     // Logic to handle datastructures used during parsing of binary expressions
     void operatorStackPop(int& operatorStackDepth) { operatorStackDepth--; }
     bool operatorStackHasHigherPrecedence(int&, int) { return true; }
-    BinaryOperand getFromOperandStack(int) { return 1; }
+    BinaryOperand getFromOperandStack(int) { return m_topBinaryExpr; }
     void shrinkOperandStackBy(int& operandStackDepth, int amount) { operandStackDepth -= amount; }
     void appendBinaryOperation(int& operandStackDepth, int&, BinaryOperand, BinaryOperand) { operandStackDepth++; }
     void operatorStackAppend(int& operatorStackDepth, int, int) { operatorStackDepth++; }
-    int popOperandStack(int&) { return 1; }
+    int popOperandStack(int&) { int res = m_topBinaryExpr; m_topBinaryExpr = 0; return res; }
     
-    void appendUnaryToken(int&, int, int) { }
-    int unaryTokenStackLastType(int&) { ASSERT_NOT_REACHED(); return 1; }
-    int unaryTokenStackLastStart(int&) { ASSERT_NOT_REACHED(); return 1; }
-    void unaryTokenStackRemoveLast(int&) { }
+    void appendUnaryToken(int& stackDepth, int tok, int) { stackDepth = 1; m_topUnaryToken = tok; }
+    int unaryTokenStackLastType(int&) { return m_topUnaryToken; }
+    int unaryTokenStackLastStart(int&) { return 0; }
+    void unaryTokenStackRemoveLast(int& stackDepth) { stackDepth = 0; }
     
     void assignmentStackAppend(int, int, int, int, int, Operator) { }
     int createAssignment(int, int, int, int, int) { ASSERT_NOT_REACHED(); return 1; }
     const Identifier& getName(const Property& property) { ASSERT(property.name); return *property.name; }
     PropertyNode::Type getType(const Property& property) { return property.type; }
+    bool isResolve(ExpressionType expr) { return expr == ResolveExpr || expr == ResolveEvalExpr; }
+    
+private:
+    int m_topBinaryExpr;
+    int m_topUnaryToken;
 };
 
 }
index 450dc7d..5c5e522 100644 (file)
@@ -153,6 +153,30 @@ bool Arguments::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& sl
 
     return JSObject::getOwnPropertySlot(exec, Identifier(exec, UString::number(i)), slot);
 }
+    
+void Arguments::createStrictModeCallerIfNecessary(ExecState* exec)
+{
+    if (d->overrodeCaller)
+        return;
+
+    d->overrodeCaller = true;
+    PropertyDescriptor descriptor;
+    JSValue thrower = createTypeErrorFunction(exec, "Unable to access caller of strict mode function");
+    descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
+    defineOwnProperty(exec, exec->propertyNames().caller, descriptor, false);
+}
+
+void Arguments::createStrictModeCalleeIfNecessary(ExecState* exec)
+{
+    if (d->overrodeCallee)
+        return;
+    
+    d->overrodeCallee = true;
+    PropertyDescriptor descriptor;
+    JSValue thrower = createTypeErrorFunction(exec, "Unable to access callee of strict mode function");
+    descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
+    defineOwnProperty(exec, exec->propertyNames().callee, descriptor, false);
+}
 
 bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
 {
@@ -172,10 +196,16 @@ bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyNa
     }
 
     if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
-        slot.setValue(d->callee);
-        return true;
+        if (!d->isStrictMode) {
+            slot.setValue(d->callee);
+            return true;
+        }
+        createStrictModeCalleeIfNecessary(exec);
     }
 
+    if (propertyName == exec->propertyNames().caller && d->isStrictMode)
+        createStrictModeCallerIfNecessary(exec);
+
     return JSObject::getOwnPropertySlot(exec, propertyName, slot);
 }
 
@@ -197,9 +227,15 @@ bool Arguments::getOwnPropertyDescriptor(ExecState* exec, const Identifier& prop
     }
     
     if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
-        descriptor.setDescriptor(d->callee, DontEnum);
-        return true;
+        if (!d->isStrictMode) {
+            descriptor.setDescriptor(d->callee, DontEnum);
+            return true;
+        }
+        createStrictModeCalleeIfNecessary(exec);
     }
+
+    if (propertyName == exec->propertyNames().caller && d->isStrictMode)
+        createStrictModeCallerIfNecessary(exec);
     
     return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
 }
@@ -249,11 +285,17 @@ void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue val
     }
 
     if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
-        d->overrodeCallee = true;
-        putDirect(propertyName, value, DontEnum);
-        return;
+        if (!d->isStrictMode) {
+            d->overrodeCallee = true;
+            putDirect(propertyName, value, DontEnum);
+            return;
+        }
+        createStrictModeCalleeIfNecessary(exec);
     }
 
+    if (propertyName == exec->propertyNames().caller && d->isStrictMode)
+        createStrictModeCallerIfNecessary(exec);
+
     JSObject::put(exec, propertyName, value, slot);
 }
 
@@ -294,9 +336,15 @@ bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName)
     }
 
     if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
-        d->overrodeCallee = true;
-        return true;
+        if (!d->isStrictMode) {
+            d->overrodeCallee = true;
+            return true;
+        }
+        createStrictModeCalleeIfNecessary(exec);
     }
+    
+    if (propertyName == exec->propertyNames().caller && !d->isStrictMode)
+        createStrictModeCallerIfNecessary(exec);
 
     return JSObject::deleteProperty(exec, propertyName);
 }
index 49c8b3b..715a2ac 100644 (file)
@@ -50,6 +50,8 @@ namespace JSC {
         JSFunction* callee;
         bool overrodeLength : 1;
         bool overrodeCallee : 1;
+        bool overrodeCaller : 1;
+        bool isStrictMode : 1;
     };
 
 
@@ -105,6 +107,8 @@ namespace JSC {
         virtual void put(ExecState*, unsigned propertyName, JSValue, PutPropertySlot&);
         virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
         virtual bool deleteProperty(ExecState*, unsigned propertyName);
+        void createStrictModeCallerIfNecessary(ExecState*);
+        void createStrictModeCalleeIfNecessary(ExecState*);
 
         virtual const ClassInfo* classInfo() const { return &info; }
 
@@ -172,6 +176,10 @@ namespace JSC {
         d->callee = callee;
         d->overrodeLength = false;
         d->overrodeCallee = false;
+        d->overrodeCaller = false;
+        d->isStrictMode = callFrame->codeBlock()->isStrictMode();
+        if (d->isStrictMode)
+            copyRegisters();
     }
 
     inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
@@ -201,6 +209,10 @@ namespace JSC {
         d->callee = asFunction(callFrame->callee());
         d->overrodeLength = false;
         d->overrodeCallee = false;
+        d->overrodeCaller = false;
+        d->isStrictMode = callFrame->codeBlock()->isStrictMode();
+        if (d->isStrictMode)
+            copyRegisters();
     }
 
     inline void Arguments::copyRegisters()
index 3837817..1561102 100644 (file)
@@ -32,6 +32,7 @@ CommonIdentifiers::CommonIdentifiers(JSGlobalData* globalData)
     , emptyIdentifier(globalData, "")
     , underscoreProto(globalData, "__proto__")
     , thisIdentifier(globalData, "this")
+    , useStrictIdentifier(globalData, "use strict")
     JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PROPERTY_NAME)
 {
 }
index de24f4a..1e22b6a 100644 (file)
@@ -94,6 +94,7 @@ namespace JSC {
         const Identifier emptyIdentifier;
         const Identifier underscoreProto;
         const Identifier thisIdentifier;
+        const Identifier useStrictIdentifier;
 
 #define JSC_IDENTIFIER_DECLARE_PROPERTY_NAME_GLOBAL(name) const Identifier name;
         JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(JSC_IDENTIFIER_DECLARE_PROPERTY_NAME_GLOBAL)
index a2be473..e35424b 100644 (file)
@@ -195,4 +195,47 @@ JSObject* throwSyntaxError(ExecState* exec)
     return throwError(exec, createSyntaxError(exec, "Syntax error"));
 }
 
+class StrictModeTypeErrorFunction : public InternalFunction {
+public:
+    StrictModeTypeErrorFunction(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, const UString& message)
+        : InternalFunction(&exec->globalData(), globalObject, structure, exec->globalData().propertyNames->emptyIdentifier)
+        , m_message(message)
+    {
+    }
+    
+    static EncodedJSValue JSC_HOST_CALL constructThrowTypeError(ExecState* exec)
+    {
+        throwTypeError(exec, static_cast<StrictModeTypeErrorFunction*>(exec->callee())->m_message);
+        return JSValue::encode(jsNull());
+    }
+    
+    ConstructType getConstructData(ConstructData& constructData)
+    {
+        constructData.native.function = constructThrowTypeError;
+        return ConstructTypeHost;
+    }
+    
+    static EncodedJSValue JSC_HOST_CALL callThrowTypeError(ExecState* exec)
+    {
+        throwTypeError(exec, static_cast<StrictModeTypeErrorFunction*>(exec->callee())->m_message);
+        return JSValue::encode(jsNull());
+    }
+
+    CallType getCallData(CallData& callData)
+    {
+        callData.native.function = callThrowTypeError;
+        return CallTypeHost;
+    }
+
+private:
+    UString m_message;
+};
+
+COMPILE_ASSERT(sizeof(StrictModeTypeErrorFunction) <= sizeof(CollectorCell), sizeof_StrictModeTypeErrorFunction_must_be_less_than_CollectorCell);
+
+JSValue createTypeErrorFunction(ExecState* exec, const UString& message)
+{
+    return new (exec) StrictModeTypeErrorFunction(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->internalFunctionStructure(), message);
+}
+
 } // namespace JSC
index 1a0ece5..bfde7dc 100644 (file)
@@ -73,6 +73,8 @@ namespace JSC {
     inline EncodedJSValue throwVMError(ExecState* exec, JSValue error) { return JSValue::encode(throwError(exec, error)); }
     inline EncodedJSValue throwVMTypeError(ExecState* exec) { return JSValue::encode(throwTypeError(exec)); }
 
+    JSValue createTypeErrorFunction(ExecState* exec, const UString& message);
+    
 } // namespace JSC
 
 #endif // Error_h
index 871f3e2..56e509a 100644 (file)
@@ -45,8 +45,8 @@ VPtrHackExecutable::~VPtrHackExecutable()
 {
 }
 
-EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source)
-    : ScriptExecutable(exec, source)
+EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext)
+    : ScriptExecutable(exec, source, inStrictContext)
 {
 }
 
@@ -55,7 +55,7 @@ EvalExecutable::~EvalExecutable()
 }
 
 ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source)
-    : ScriptExecutable(exec, source)
+    : ScriptExecutable(exec, source, false)
 {
 }
 
@@ -63,8 +63,8 @@ ProgramExecutable::~ProgramExecutable()
 {
 }
 
-FunctionExecutable::FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
-    : ScriptExecutable(globalData, source)
+FunctionExecutable::FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext, int firstLine, int lastLine)
+    : ScriptExecutable(globalData, source, inStrictContext)
     , m_numCapturedVariables(0)
     , m_forceUsesArguments(forceUsesArguments)
     , m_parameters(parameters)
@@ -75,8 +75,8 @@ FunctionExecutable::FunctionExecutable(JSGlobalData* globalData, const Identifie
     m_lastLine = lastLine;
 }
 
-FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
-    : ScriptExecutable(exec, source)
+FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext, int firstLine, int lastLine)
+    : ScriptExecutable(exec, source, inStrictContext)
     , m_numCapturedVariables(0)
     , m_forceUsesArguments(forceUsesArguments)
     , m_parameters(parameters)
@@ -96,7 +96,7 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scope
     JSObject* exception = 0;
     JSGlobalData* globalData = &exec->globalData();
     JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
-    RefPtr<EvalNode> evalNode = globalData->parser->parse<EvalNode>(globalData, lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, &exception);
+    RefPtr<EvalNode> evalNode = globalData->parser->parse<EvalNode>(lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, &exception);
     if (!evalNode) {
         ASSERT(exception);
         return exception;
@@ -131,7 +131,7 @@ JSObject* ProgramExecutable::checkSyntax(ExecState* exec)
     JSObject* exception = 0;
     JSGlobalData* globalData = &exec->globalData();
     JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
-    RefPtr<ProgramNode> programNode = globalData->parser->parse<ProgramNode>(globalData, lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, &exception);
+    RefPtr<ProgramNode> programNode = globalData->parser->parse<ProgramNode>(lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, JSParseNormal, &exception);
     if (programNode)
         return 0;
     ASSERT(exception);
@@ -145,7 +145,7 @@ JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* sc
     JSObject* exception = 0;
     JSGlobalData* globalData = &exec->globalData();
     JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
-    RefPtr<ProgramNode> programNode = globalData->parser->parse<ProgramNode>(globalData, lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, &exception);
+    RefPtr<ProgramNode> programNode = globalData->parser->parse<ProgramNode>(lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, &exception);
     if (!programNode) {
         ASSERT(exception);
         return exception;
@@ -178,7 +178,7 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChain
 {
     JSObject* exception = 0;
     JSGlobalData* globalData = scopeChainNode->globalData;
-    RefPtr<FunctionBodyNode> body = globalData->parser->parse<FunctionBodyNode>(globalData, exec->lexicalGlobalObject(), 0, 0, m_source, m_parameters.get(), &exception);
+    RefPtr<FunctionBodyNode> body = globalData->parser->parse<FunctionBodyNode>(exec->lexicalGlobalObject(), 0, 0, m_source, m_parameters.get(), isStrictMode() ? JSParseStrict : JSParseNormal, &exception);
     if (!body) {
         ASSERT(exception);
         return exception;
@@ -219,7 +219,7 @@ JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, Scope
 {
     JSObject* exception = 0;
     JSGlobalData* globalData = scopeChainNode->globalData;
-    RefPtr<FunctionBodyNode> body = globalData->parser->parse<FunctionBodyNode>(globalData, exec->lexicalGlobalObject(), 0, 0, m_source, m_parameters.get(), &exception);
+    RefPtr<FunctionBodyNode> body = globalData->parser->parse<FunctionBodyNode>(exec->lexicalGlobalObject(), 0, 0, m_source, m_parameters.get(), isStrictMode() ? JSParseStrict : JSParseNormal, &exception);
     if (!body) {
         ASSERT(exception);
         return exception;
@@ -264,12 +264,14 @@ void FunctionExecutable::markAggregate(MarkStack& markStack)
         m_codeBlockForConstruct->markAggregate(markStack);
 }
 
-PassOwnPtr<ExceptionInfo> FunctionExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock)
+PassOwnPtr<ExceptionInfo> FunctionExecutable::reparseExceptionInfo(ScopeChainNode* scopeChainNode, CodeBlock* codeBlock)
 {
     JSObject* exception = 0;
-    RefPtr<FunctionBodyNode> newFunctionBody = globalData->parser->parse<FunctionBodyNode>(globalData, 0, 0, 0, m_source, m_parameters.get(), &exception);
+    JSGlobalData* globalData = scopeChainNode->globalData;
+    RefPtr<FunctionBodyNode> newFunctionBody = globalData->parser->parse<FunctionBodyNode>(scopeChainNode->globalObject, 0, 0, m_source, m_parameters.get(), isStrictMode() ? JSParseStrict : JSParseNormal, &exception);
     if (!newFunctionBody)
         return PassOwnPtr<ExceptionInfo>();
+    ASSERT(newFunctionBody->isStrictMode() == isStrictMode());
     if (m_forceUsesArguments)
         newFunctionBody->setUsesArguments();
     newFunctionBody->finishParsing(m_parameters, m_name);
@@ -298,10 +300,12 @@ PassOwnPtr<ExceptionInfo> FunctionExecutable::reparseExceptionInfo(JSGlobalData*
     return newCodeBlock->extractExceptionInfo();
 }
 
-PassOwnPtr<ExceptionInfo> EvalExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock)
+PassOwnPtr<ExceptionInfo> EvalExecutable::reparseExceptionInfo(ScopeChainNode* scopeChainNode, CodeBlock* codeBlock)
 {
     JSObject* exception = 0;
-    RefPtr<EvalNode> newEvalBody = globalData->parser->parse<EvalNode>(globalData, 0, 0, 0, m_source, 0, &exception);
+    JSGlobalData* globalData = scopeChainNode->globalData;
+    RefPtr<EvalNode> newEvalBody = globalData->parser->parse<EvalNode>(scopeChainNode->globalObject, 0, 0, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, &exception);
+    ASSERT(newEvalBody->isStrictMode() == isStrictMode());
     if (!newEvalBody)
         return PassOwnPtr<ExceptionInfo>();
 
@@ -341,7 +345,7 @@ void FunctionExecutable::recompile(ExecState*)
 PassRefPtr<FunctionExecutable> FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception)
 {
     JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
-    RefPtr<ProgramNode> program = exec->globalData().parser->parse<ProgramNode>(&exec->globalData(), lexicalGlobalObject, debugger, exec, source, 0, exception);
+    RefPtr<ProgramNode> program = exec->globalData().parser->parse<ProgramNode>(lexicalGlobalObject, debugger, exec, source, 0, JSParseNormal, exception);
     if (!program) {
         ASSERT(*exception);
         return 0;
@@ -357,7 +361,7 @@ PassRefPtr<FunctionExecutable> FunctionExecutable::fromGlobalCode(const Identifi
     FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body();
     ASSERT(body);
 
-    return FunctionExecutable::create(&exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine());
+    return FunctionExecutable::create(&exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), false, body->lineNo(), body->lastLine());
 }
 
 UString FunctionExecutable::paramString() const
@@ -372,7 +376,7 @@ UString FunctionExecutable::paramString() const
     return builder.build();
 }
 
-PassOwnPtr<ExceptionInfo> ProgramExecutable::reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*)
+PassOwnPtr<ExceptionInfo> ProgramExecutable::reparseExceptionInfo(ScopeChainNode*, CodeBlock*)
 {
     // CodeBlocks for program code are transient and therefore do not gain from from throwing out their exception information.
     return PassOwnPtr<ExceptionInfo>();
index feab7ef..4c4ca56 100644 (file)
@@ -138,10 +138,10 @@ namespace JSC {
 
     class ScriptExecutable : public ExecutableBase {
     public:
-        ScriptExecutable(JSGlobalData* globalData, const SourceCode& source)
+        ScriptExecutable(JSGlobalData* globalData, const SourceCode& source, bool isInStrictContext)
             : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED)
             , m_source(source)
-            , m_features(0)
+            , m_features(isInStrictContext ? StrictModeFeature : 0)
         {
 #if ENABLE(CODEBLOCK_SAMPLING)
             relaxAdoptionRequirement();
@@ -152,10 +152,10 @@ namespace JSC {
 #endif
         }
 
-        ScriptExecutable(ExecState* exec, const SourceCode& source)
+        ScriptExecutable(ExecState* exec, const SourceCode& source, bool isInStrictContext)
             : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED)
             , m_source(source)
-            , m_features(0)
+            , m_features(isInStrictContext ? StrictModeFeature : 0)
         {
 #if ENABLE(CODEBLOCK_SAMPLING)
             relaxAdoptionRequirement();
@@ -175,8 +175,9 @@ namespace JSC {
         bool usesEval() const { return m_features & EvalFeature; }
         bool usesArguments() const { return m_features & ArgumentsFeature; }
         bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); }
+        bool isStrictMode() const { return m_features & StrictModeFeature; }
 
-        virtual PassOwnPtr<ExceptionInfo> reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) = 0;
+        virtual PassOwnPtr<ExceptionInfo> reparseExceptionInfo(ScopeChainNode*, CodeBlock*) = 0;
 
     protected:
         void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine)
@@ -214,7 +215,7 @@ namespace JSC {
             return *m_evalCodeBlock;
         }
 
-        static PassRefPtr<EvalExecutable> create(ExecState* exec, const SourceCode& source) { return adoptRef(new EvalExecutable(exec, source)); }
+        static PassRefPtr<EvalExecutable> create(ExecState* exec, const SourceCode& source, bool isInStrictContext) { return adoptRef(new EvalExecutable(exec, source, isInStrictContext)); }
 
 #if ENABLE(JIT)
         JITCode& generatedJITCode()
@@ -224,11 +225,11 @@ namespace JSC {
 #endif
 
     private:
-        EvalExecutable(ExecState*, const SourceCode&);
+        EvalExecutable(ExecState*, const SourceCode&, bool);
 
         JSObject* compileInternal(ExecState*, ScopeChainNode*);
 
-        virtual PassOwnPtr<ExceptionInfo> reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*);
+        virtual PassOwnPtr<ExceptionInfo> reparseExceptionInfo(ScopeChainNode*, CodeBlock*);
 
         OwnPtr<EvalCodeBlock> m_evalCodeBlock;
     };
@@ -271,7 +272,7 @@ namespace JSC {
 
         JSObject* compileInternal(ExecState*, ScopeChainNode*);
 
-        virtual PassOwnPtr<ExceptionInfo> reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*);
+        virtual PassOwnPtr<ExceptionInfo> reparseExceptionInfo(ScopeChainNode*, CodeBlock*);
 
         OwnPtr<ProgramCodeBlock> m_programCodeBlock;
     };
@@ -279,14 +280,14 @@ namespace JSC {
     class FunctionExecutable : public ScriptExecutable {
         friend class JIT;
     public:
-        static PassRefPtr<FunctionExecutable> create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
+        static PassRefPtr<FunctionExecutable> create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
         {
-            return adoptRef(new FunctionExecutable(exec, name, source, forceUsesArguments, parameters, firstLine, lastLine));
+            return adoptRef(new FunctionExecutable(exec, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine));
         }
 
-        static PassRefPtr<FunctionExecutable> create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
+        static PassRefPtr<FunctionExecutable> create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
         {
-            return adoptRef(new FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, firstLine, lastLine));
+            return adoptRef(new FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine));
         }
 
         ~FunctionExecutable();
@@ -358,13 +359,13 @@ namespace JSC {
         static PassRefPtr<FunctionExecutable> fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
 
     private:
-        FunctionExecutable(JSGlobalData*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, int firstLine, int lastLine);
-        FunctionExecutable(ExecState*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, int firstLine, int lastLine);
+        FunctionExecutable(JSGlobalData*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool, int firstLine, int lastLine);
+        FunctionExecutable(ExecState*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool, int firstLine, int lastLine);
 
         JSObject* compileForCallInternal(ExecState*, ScopeChainNode*);
         JSObject* compileForConstructInternal(ExecState*, ScopeChainNode*);
 
-        virtual PassOwnPtr<ExceptionInfo> reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*);
+        virtual PassOwnPtr<ExceptionInfo> reparseExceptionInfo(ScopeChainNode*, CodeBlock*);
 
         unsigned m_numCapturedVariables : 31;
         bool m_forceUsesArguments : 1;
index d121518..795ad1f 100644 (file)
@@ -186,6 +186,11 @@ JSObject* JSActivation::toThisObject(ExecState* exec) const
     return exec->globalThisValue();
 }
 
+JSValue JSActivation::toStrictThisObject(ExecState*) const
+{
+    return jsNull();
+}
+    
 bool JSActivation::isDynamicScope(bool& requiresDynamicChecks) const
 {
     requiresDynamicChecks = d()->functionExecutable->usesEval();
index 9ff9168..6dd6d70 100644 (file)
@@ -60,6 +60,7 @@ namespace JSC {
         virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
 
         virtual JSObject* toThisObject(ExecState*) const;
+        virtual JSValue toStrictThisObject(ExecState*) const;
 
         void copyRegisters();
         
index 7eb9ba5..fdaa509 100644 (file)
@@ -122,6 +122,15 @@ JSFunction::~JSFunction()
     }
 }
 
+static const char* StrictModeCallerAccessError = "Cannot access caller property of a strict mode function";
+static const char* StrictModeArgumentsAccessError = "Cannot access arguments property of a strict mode function";
+
+static void createDescriptorForThrowingProperty(ExecState* exec, PropertyDescriptor& descriptor, const char* message)
+{
+    JSValue thrower = createTypeErrorFunction(exec, message);
+    descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
+}
+
 const UString& JSFunction::name(ExecState* exec)
 {
     return asString(getDirect(exec->globalData().propertyNames->name))->tryGetValue();
@@ -209,6 +218,12 @@ bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyN
     }
 
     if (propertyName == exec->propertyNames().arguments) {
+        if (jsExecutable()->isStrictMode()) {
+            throwTypeError(exec, "Can't access arguments object of a strict mode function");
+            slot.setValue(jsNull());
+            return true;
+        }
+   
         slot.setCacheableCustom(this, argumentsGetter);
         return true;
     }
@@ -219,6 +234,11 @@ bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyN
     }
 
     if (propertyName == exec->propertyNames().caller) {
+        if (jsExecutable()->isStrictMode()) {
+            throwTypeError(exec, StrictModeCallerAccessError);
+            slot.setValue(jsNull());
+            return true;
+        }
         slot.setCacheableCustom(this, callerGetter);
         return true;
     }
@@ -226,35 +246,41 @@ bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyN
     return Base::getOwnPropertySlot(exec, propertyName, slot);
 }
 
-    bool JSFunction::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
-    {
-        if (isHostFunction())
-            return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
-        
-        if (propertyName == exec->propertyNames().prototype) {
-            PropertySlot slot;
-            getOwnPropertySlot(exec, propertyName, slot);
-            return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
-        }
-        
-        if (propertyName == exec->propertyNames().arguments) {
+bool JSFunction::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+    if (isHostFunction())
+        return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
+    
+    if (propertyName == exec->propertyNames().prototype) {
+        PropertySlot slot;
+        getOwnPropertySlot(exec, propertyName, slot);
+        return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
+    }
+    
+    if (propertyName == exec->propertyNames().arguments) {
+        if (jsExecutable()->isStrictMode())
+            createDescriptorForThrowingProperty(exec, descriptor, StrictModeArgumentsAccessError);
+        else
             descriptor.setDescriptor(exec->interpreter()->retrieveArguments(exec, this), ReadOnly | DontEnum | DontDelete);
-            return true;
-        }
-        
-        if (propertyName == exec->propertyNames().length) {
-            descriptor.setDescriptor(jsNumber(exec, jsExecutable()->parameterCount()), ReadOnly | DontEnum | DontDelete);
-            return true;
-        }
-        
-        if (propertyName == exec->propertyNames().caller) {
+        return true;
+    }
+    
+    if (propertyName == exec->propertyNames().length) {
+        descriptor.setDescriptor(jsNumber(exec, jsExecutable()->parameterCount()), ReadOnly | DontEnum | DontDelete);
+        return true;
+    }
+    
+    if (propertyName == exec->propertyNames().caller) {
+        if (jsExecutable()->isStrictMode())
+            createDescriptorForThrowingProperty(exec, descriptor, StrictModeCallerAccessError);
+        else
             descriptor.setDescriptor(exec->interpreter()->retrieveCaller(exec, this), ReadOnly | DontEnum | DontDelete);
-            return true;
-        }
-        
-        return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
+        return true;
     }
     
+    return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
+}
+
 void JSFunction::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
 {
     if (!isHostFunction() && (mode == IncludeDontEnumProperties)) {
@@ -272,6 +298,16 @@ void JSFunction::put(ExecState* exec, const Identifier& propertyName, JSValue va
         Base::put(exec, propertyName, value, slot);
         return;
     }
+    if (jsExecutable()->isStrictMode()) {
+        if (propertyName == exec->propertyNames().arguments) {
+            throwTypeError(exec, StrictModeArgumentsAccessError);
+            return;
+        }
+        if (propertyName == exec->propertyNames().caller) {
+            throwTypeError(exec, StrictModeCallerAccessError);
+            return;
+        }
+    }
     if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
         return;
     Base::put(exec, propertyName, value, slot);
index 5eaa59b..073b54c 100644 (file)
@@ -50,6 +50,7 @@
 #include "Nodes.h"
 #include "Parser.h"
 #include "RegExpCache.h"
+#include "StrictEvalActivation.h"
 #include <wtf/WTFThreadData.h>
 #if ENABLE(REGEXP_TRACING)
 #include "RegExp.h"
@@ -124,6 +125,7 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread
     , interruptedExecutionErrorStructure(JSObject::createStructure(jsNull()))
     , terminatedExecutionErrorStructure(JSObject::createStructure(jsNull()))
     , staticScopeStructure(JSStaticScopeObject::createStructure(jsNull()))
+    , strictEvalActivationStructure(StrictEvalActivation::createStructure(jsNull()))
     , stringStructure(JSString::createStructure(jsNull()))
     , notAnObjectErrorStubStructure(JSNotAnObjectErrorStub::createStructure(jsNull()))
     , notAnObjectStructure(JSNotAnObject::createStructure(jsNull()))
index 8e2ed61..67f2ed4 100644 (file)
@@ -145,6 +145,7 @@ namespace JSC {
         RefPtr<Structure> interruptedExecutionErrorStructure;
         RefPtr<Structure> terminatedExecutionErrorStructure;
         RefPtr<Structure> staticScopeStructure;
+        RefPtr<Structure> strictEvalActivationStructure;
         RefPtr<Structure> stringStructure;
         RefPtr<Structure> notAnObjectErrorStubStructure;
         RefPtr<Structure> notAnObjectStructure;
index 89c042a..903e573 100644 (file)
@@ -204,6 +204,7 @@ void JSGlobalObject::reset(JSValue prototype)
 
     d()->functionPrototype = new (exec) FunctionPrototype(exec, this, FunctionPrototype::createStructure(jsNull())); // The real prototype will be set once ObjectPrototype is created.
     d()->prototypeFunctionStructure = PrototypeFunction::createStructure(d()->functionPrototype);
+    d()->internalFunctionStructure = InternalFunction::createStructure(d()->functionPrototype);
     NativeFunctionWrapper* callFunction = 0;
     NativeFunctionWrapper* applyFunction = 0;
     d()->functionPrototype->addFunctionProperties(exec, this, d()->prototypeFunctionStructure.get(), &callFunction, &applyFunction);
index f5d2fb0..3b99439 100644 (file)
@@ -148,6 +148,7 @@ namespace JSC {
             RefPtr<Structure> regExpMatchesArrayStructure;
             RefPtr<Structure> regExpStructure;
             RefPtr<Structure> stringObjectStructure;
+            RefPtr<Structure> internalFunctionStructure;
 
             SymbolTable symbolTable;
             unsigned profileGroup;
@@ -243,6 +244,7 @@ namespace JSC {
         Structure* functionStructure() const { return d()->functionStructure.get(); }
         Structure* numberObjectStructure() const { return d()->numberObjectStructure.get(); }
         Structure* prototypeFunctionStructure() const { return d()->prototypeFunctionStructure.get(); }
+        Structure* internalFunctionStructure() const { return d()->internalFunctionStructure.get(); }
         Structure* regExpMatchesArrayStructure() const { return d()->regExpMatchesArrayStructure.get(); }
         Structure* regExpStructure() const { return d()->regExpStructure.get(); }
         Structure* stringObjectStructure() const { return d()->stringObjectStructure.get(); }
index 1e20f7f..cd89dd2 100644 (file)
@@ -450,7 +450,7 @@ EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec)
     if (JSValue parsedObject = preparser.tryLiteralParse())
         return JSValue::encode(parsedObject);
 
-    RefPtr<EvalExecutable> eval = EvalExecutable::create(exec, makeSource(s));
+    RefPtr<EvalExecutable> eval = EvalExecutable::create(exec, makeSource(s), false);
     JSObject* error = eval->compile(exec, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain().node());
     if (error)
         return throwVMError(exec, error);
index cabc428..30e40e4 100644 (file)
@@ -43,6 +43,8 @@ namespace JSC {
 
 ASSERT_CLASS_FITS_IN_CELL(JSObject);
 
+const char* StrictModeReadonlyPropertyWriteError = "Attempted to assign to readonly property.";
+
 static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode)
 {
     // Add properties from the static hashtables of properties
@@ -114,15 +116,19 @@ void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue valu
     for (JSObject* obj = this; !obj->structure()->hasGetterSetterProperties(); obj = asObject(prototype)) {
         prototype = obj->prototype();
         if (prototype.isNull()) {
-            putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot);
+            if (!putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot) && slot.isStrictMode())
+                throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
             return;
         }
     }
     
     unsigned attributes;
     JSCell* specificValue;
-    if ((m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) && attributes & ReadOnly)
+    if ((m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) && attributes & ReadOnly) {
+        if (slot.isStrictMode())
+            throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
         return;
+    }
 
     for (JSObject* obj = this; ; obj = asObject(prototype)) {
         if (JSValue gs = obj->getDirect(propertyName)) {
@@ -151,7 +157,8 @@ void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue valu
             break;
     }
 
-    putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot);
+    if (!putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot) && slot.isStrictMode())
+        throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
     return;
 }
 
@@ -489,6 +496,11 @@ JSObject* JSObject::toThisObject(ExecState*) const
     return const_cast<JSObject*>(this);
 }
 
+JSValue JSObject::toStrictThisObject(ExecState*) const
+{
+    return const_cast<JSObject*>(this);
+}
+
 JSObject* JSObject::unwrappedObject()
 {
     return this;
@@ -702,4 +714,9 @@ bool JSObject::defineOwnProperty(ExecState* exec, const Identifier& propertyName
     return true;
 }
 
+JSObject* throwTypeError(ExecState* exec, const UString& message)
+{
+    return throwError(exec, createTypeError(exec, message));
+}
+
 } // namespace JSC
index 4201703..da95f07 100644 (file)
@@ -55,6 +55,9 @@ namespace JSC {
     class Structure;
     struct HashTable;
 
+    JSObject* throwTypeError(ExecState*, const UString&);
+    extern const char* StrictModeReadonlyPropertyWriteError;
+
     // ECMA 262-3 8.6.1
     // Property attributes
     enum Attribute {
@@ -140,6 +143,7 @@ namespace JSC {
         virtual JSObject* toObject(ExecState*) const;
 
         virtual JSObject* toThisObject(ExecState*) const;
+        virtual JSValue toStrictThisObject(ExecState*) const;
         virtual JSObject* unwrappedObject();
 
         bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const;
@@ -175,9 +179,9 @@ namespace JSC {
         bool hasCustomProperties() { return !m_structure->isEmpty(); }
         bool hasGetterSetterProperties() { return m_structure->hasGetterSetterProperties(); }
 
-        void putDirect(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
+        bool putDirect(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
         void putDirect(const Identifier& propertyName, JSValue value, unsigned attr = 0);
-        void putDirect(const Identifier& propertyName, JSValue value, PutPropertySlot&);
+        bool putDirect(const Identifier& propertyName, JSValue value, PutPropertySlot&);
 
         void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr = 0);
         void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
@@ -205,6 +209,7 @@ namespace JSC {
         virtual bool isVariableObject() const { return false; }
         virtual bool isActivationObject() const { return false; }
         virtual bool isNotAnObjectErrorStub() const { return false; }
+        virtual bool isStrictModeFunction() const { return false; }
 
         virtual ComplType exceptionType() const { return Throw; }
 
@@ -265,8 +270,8 @@ namespace JSC {
             return reinterpret_cast<JSValue*>(&propertyStorage()[offset]);
         }
 
-        void putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot, JSCell*);
-        void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
+        bool putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot, JSCell*);
+        bool putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
         void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr = 0);
 
         bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
@@ -450,7 +455,7 @@ inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const
     return jsUndefined();
 }
 
-inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction)
+inline bool JSObject::putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction)
 {
     ASSERT(value);
     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
@@ -465,7 +470,8 @@ inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue
             if (currentSpecificFunction && (specificFunction != currentSpecificFunction))
                 m_structure->despecifyDictionaryFunction(propertyName);
             if (checkReadOnly && currentAttributes & ReadOnly)
-                return;
+                return false;
+
             putDirectOffset(offset, value);
             // At this point, the objects structure only has a specific value set if previously there
             // had been one set, and if the new value being specified is the same (otherwise we would
@@ -475,7 +481,7 @@ inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue
             // If there was previously a value, and the new value is the same, then we cannot cache.
             if (!currentSpecificFunction || (specificFunction != currentSpecificFunction))
                 slot.setExistingProperty(this, offset);
-            return;
+            return true;
         }
 
         size_t currentCapacity = m_structure->propertyStorageCapacity();
@@ -488,7 +494,7 @@ inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue
         // See comment on setNewProperty call below.
         if (!specificFunction)
             slot.setNewProperty(this, offset);
-        return;
+        return true;
     }
 
     size_t offset;
@@ -504,7 +510,7 @@ inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue
         // so leave the slot in an uncachable state.
         if (!specificFunction)
             slot.setNewProperty(this, offset);
-        return;
+        return true;
     }
 
     unsigned currentAttributes;
@@ -512,7 +518,7 @@ inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue
     offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction);
     if (offset != WTF::notFound) {
         if (checkReadOnly && currentAttributes & ReadOnly)
-            return;
+            return false;
 
         // There are three possibilities here:
         //  (1) There is an existing specific value set, and we're overwriting with *the same value*.
@@ -527,7 +533,7 @@ inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue
             // case (1) Do the put, then return leaving the slot uncachable.
             if (specificFunction == currentSpecificFunction) {
                 putDirectOffset(offset, value);
-                return;
+                return true;
             }
             // case (2) Despecify, fall through to (3).
             setStructure(Structure::despecifyFunctionTransition(m_structure, propertyName));
@@ -536,7 +542,7 @@ inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue
         // case (3) set the slot, do the put, return.
         slot.setExistingProperty(this, offset);
         putDirectOffset(offset, value);
-        return;
+        return true;
     }
 
     // If we have a specific function, we may have got to this point if there is
@@ -561,14 +567,15 @@ inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue
     // so leave the slot in an uncachable state.
     if (!specificFunction)
         slot.setNewProperty(this, offset);
+    return true;
 }
 
-inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
+inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
 {
     ASSERT(value);
     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
 
-    putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value));
+    return putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value));
 }
 
 inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
@@ -577,12 +584,12 @@ inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi
     putDirectInternal(propertyName, value, attributes, false, slot, getJSFunction(globalData, value));
 }
 
-inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
+inline bool JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
 {
     ASSERT(value);
     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
 
-    putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, 0);
+    return putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, 0);
 }
 
 inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes)
@@ -591,9 +598,9 @@ inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, u
     putDirectInternal(propertyName, value, attributes, false, slot, 0);
 }
 
-inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+inline bool JSObject::putDirect(const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
 {
-    putDirectInternal(propertyName, value, 0, false, slot, 0);
+    return putDirectInternal(propertyName, value, 0, false, slot, 0);
 }
 
 inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
@@ -698,10 +705,11 @@ inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValu
     asCell()->put(exec, propertyName, value, slot);
 }
 
-inline void JSValue::putDirect(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+inline void JSValue::putDirect(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
 {
     ASSERT(isCell() && isObject());
-    asObject(asCell())->putDirect(propertyName, value, slot);
+    if (!asObject(asCell())->putDirect(propertyName, value, slot) && slot.isStrictMode())
+        throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
 }
 
 inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue value)
@@ -756,6 +764,13 @@ inline JSString* JSValue::toThisJSString(ExecState* exec) const
     return isString() ? static_cast<JSString*>(asCell()) : jsString(exec, toThisObject(exec)->toString(exec));
 }
 
+inline JSValue JSValue::toStrictThisObject(ExecState* exec) const
+{
+    if (!isObject())
+        return *this;
+    return asObject(asCell())->toStrictThisObject(exec);
+}
+
 } // namespace JSC
 
 #endif // JSObject_h
index ad10218..7ab1d1c 100644 (file)
@@ -42,6 +42,11 @@ JSObject* JSStaticScopeObject::toThisObject(ExecState* exec) const
     return exec->globalThisValue();
 }
 
+JSValue JSStaticScopeObject::toStrictThisObject(ExecState*) const
+{
+    return jsNull();
+}
+
 void JSStaticScopeObject::put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot&)
 {
     if (symbolTablePut(propertyName, value))
index c0519c1..e69356a 100644 (file)
@@ -53,6 +53,7 @@ namespace JSC{
         virtual void markChildren(MarkStack&);
         bool isDynamicScope(bool& requiresDynamicChecks) const;
         virtual JSObject* toThisObject(ExecState*) const;
+        virtual JSValue toStrictThisObject(ExecState*) const;
         virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
         virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&);
         void putWithAttributes(ExecState*, const Identifier&, JSValue, unsigned attributes);
index b5834c1..f776157 100644 (file)
@@ -193,6 +193,7 @@ namespace JSC {
 
         bool needsThisConversion() const;
         JSObject* toThisObject(ExecState*) const;
+        JSValue toStrictThisObject(ExecState*) const;
         UString toThisString(ExecState*) const;
         JSString* toThisJSString(ExecState*) const;
 
index 711f673..da45699 100644 (file)
@@ -60,6 +60,7 @@ public:
     virtual bool deleteProperty(ExecState*, const Identifier&) { ASSERT_NOT_REACHED(); return false; }
     virtual bool deleteProperty(ExecState*, unsigned) { ASSERT_NOT_REACHED(); return false; }
     virtual JSObject* toThisObject(ExecState*) const { ASSERT_NOT_REACHED(); return 0; }
+    virtual JSValue toStrictThisObject(ExecState*) const { ASSERT_NOT_REACHED(); return JSValue(); }
     virtual JSValue getJSNumber() { ASSERT_NOT_REACHED(); return jsNull(); }
     virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&) { ASSERT_NOT_REACHED(); return false; }
     virtual bool getOwnPropertySlot(ExecState*, unsigned, PropertySlot&) { ASSERT_NOT_REACHED(); return false; }
index eb8ea8a..4b0b394 100644 (file)
@@ -38,9 +38,10 @@ namespace JSC {
     public:
         enum Type { Uncachable, ExistingProperty, NewProperty };
 
-        PutPropertySlot()
+        PutPropertySlot(bool isStrictMode = false)
             : m_type(Uncachable)
             , m_base(0)
+            , m_isStrictMode(isStrictMode)
         {
         }
 
@@ -61,6 +62,7 @@ namespace JSC {
         Type type() const { return m_type; }
         JSObject* base() const { return m_base; }
 
+        bool isStrictMode() const { return m_isStrictMode; }
         bool isCacheable() const { return m_type != Uncachable; }
         size_t cachedOffset() const {
             ASSERT(isCacheable());
@@ -70,6 +72,7 @@ namespace JSC {
         Type m_type;
         JSObject* m_base;
         size_t m_offset;
+        bool m_isStrictMode;
     };
 
 } // namespace JSC
diff --git a/JavaScriptCore/runtime/StrictEvalActivation.cpp b/JavaScriptCore/runtime/StrictEvalActivation.cpp
new file mode 100644 (file)
index 0000000..5bb013b
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "StrictEvalActivation.h"
+
+namespace JSC {
+
+StrictEvalActivation::StrictEvalActivation(ExecState* exec)
+    : JSObject(exec->globalData().strictEvalActivationStructure)
+{
+}
+
+bool StrictEvalActivation::deleteProperty(ExecState*, const Identifier&)
+{
+    return false;
+}
+
+JSObject* StrictEvalActivation::toThisObject(ExecState* exec) const
+{
+    return exec->globalThisValue();
+}
+
+JSValue StrictEvalActivation::toStrictThisObject(ExecState*) const
+{
+    return jsNull();
+}
+
+}
diff --git a/JavaScriptCore/runtime/StrictEvalActivation.h b/JavaScriptCore/runtime/StrictEvalActivation.h
new file mode 100644 (file)
index 0000000..1385eec
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StrictEvalActivation_h
+#define StrictEvalActivation_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class StrictEvalActivation : public JSObject {
+public:
+    StrictEvalActivation(ExecState*);
+    virtual bool deleteProperty(ExecState*, const Identifier&);
+    virtual JSObject* toThisObject(ExecState*) const;
+    virtual JSValue toStrictThisObject(ExecState*) const;
+};
+
+} // namespace JSC
+
+#endif // StrictEvalActivation_h
index fec086d..31b20b1 100644 (file)
@@ -1,3 +1,18 @@
+2010-10-01  Oliver Hunt  <oliver@apple.com>
+
+        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-10  Antonio Gomes  <agomes@rim.com>
 
         Reviewed by Andreas Kling.
diff --git a/LayoutTests/fast/js/basic-strict-mode-expected.txt b/LayoutTests/fast/js/basic-strict-mode-expected.txt
new file mode 100644 (file)
index 0000000..ac3de83
--- /dev/null
@@ -0,0 +1,100 @@
+Test behaviour of strict mode
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS testThis.call(null) is null
+PASS testThis.call(1) is 1
+PASS testThis.call(true) is true
+PASS testThis.call(false) is false
+PASS testThis.call(undefined) is undefined
+PASS testThis.call('a string') is 'a string'
+PASS testGlobalAccess() is null
+PASS (function eval(){'use strict';}) threw exception SyntaxError: Parse error.
+PASS (function (eval){'use strict';}) threw exception SyntaxError: Parse error.
+PASS (function arguments(){'use strict';}) threw exception SyntaxError: Parse error.
+PASS (function (arguments){'use strict';}) threw exception SyntaxError: Parse error.
+PASS (function (){'use strict'; var eval;}) threw exception SyntaxError: Parse error.
+PASS (function (){'use strict'; var arguments;}) threw exception SyntaxError: Parse error.
+PASS (function (){'use strict'; try{}catch(eval){}}) threw exception SyntaxError: Parse error.
+PASS (function (){'use strict'; try{}catch(arguments){}}) threw exception SyntaxError: Parse error.
+PASS (function (a, a){'use strict';}) threw exception SyntaxError: Parse error.
+PASS (function (a){'use strict'; delete a;})() threw exception SyntaxError: Parse error.
+PASS (function (){'use strict'; var a; delete a;})() threw exception SyntaxError: Parse error.
+PASS (function (){var a; function f() {'use strict'; delete a;} })() threw exception SyntaxError: Parse error.
+PASS (function (){'use strict'; with(1){};}) threw exception SyntaxError: Parse error.
+PASS (function (){'use strict'; arguments.callee; })() threw exception TypeError: Unable to access callee of strict mode function.
+PASS (function (){'use strict'; arguments.caller; })() threw exception TypeError: Unable to access caller of strict mode function.
+PASS (function f(){'use strict'; f.arguments; })() threw exception TypeError: Can't access arguments object of a strict mode function.
+PASS (function f(){'use strict'; f.caller; })() threw exception TypeError: Cannot access caller property of a strict mode function.
+PASS (function f(){'use strict'; f.arguments=5; })() threw exception TypeError: Cannot access arguments property of a strict mode function.
+PASS (function f(){'use strict'; f.caller=5; })() threw exception TypeError: Cannot access caller property of a strict mode function.
+PASS (function (arg){'use strict'; arguments.callee; })() threw exception TypeError: Unable to access callee of strict mode function.
+PASS (function (arg){'use strict'; arguments.caller; })() threw exception TypeError: Unable to access caller of strict mode function.
+PASS (function f(arg){'use strict'; f.arguments; })() threw exception TypeError: Can't access arguments object of a strict mode function.
+PASS (function f(arg){'use strict'; f.caller; })() threw exception TypeError: Cannot access caller property of a strict mode function.
+PASS (function f(arg){'use strict'; f.arguments=5; })() threw exception TypeError: Cannot access arguments property of a strict mode function.
+PASS (function f(arg){'use strict'; f.caller=5; })() threw exception TypeError: Cannot access caller property of a strict mode function.
+PASS 'use strict'; (function (){with(1){};}) threw exception SyntaxError: Parse error.
+PASS 'use strict'; (function (){var a; delete a;}) threw exception SyntaxError: Parse error.
+PASS 'use strict'; var a; (function (){ delete a;}) threw exception SyntaxError: Parse error.
+PASS var a; (function (){ 'use strict'; delete a;}) threw exception SyntaxError: Parse error.
+PASS 'misc directive'; 'use strict'; with({}){} threw exception SyntaxError: Parse error.
+PASS 'use strict'; return threw exception SyntaxError: Parse error.
+PASS 'use strict'; break threw exception SyntaxError: Parse error.
+PASS 'use strict'; continue threw exception SyntaxError: Parse error.
+PASS 'use strict'; for(;;)return threw exception SyntaxError: Parse error.
+PASS 'use strict'; for(;;)break missingLabel threw exception SyntaxError: Parse error.
+PASS 'use strict'; for(;;)continue missingLabel threw exception SyntaxError: Parse error.
+PASS 'use strict'; 007; threw exception SyntaxError: Parse error.
+PASS 'use strict'; '\007'; threw exception SyntaxError: Parse error.
+PASS '\007'; 'use strict'; threw exception SyntaxError: Parse error.
+PASS 'use strict'; (function (){ delete someDeclaredGlobal;}) threw exception SyntaxError: Parse error.
+PASS (function (){ 'use strict'; delete someDeclaredGlobal;}) threw exception SyntaxError: Parse error.
+PASS 'use strict'; someGlobal = 'Shouldn\'t be able to assign this.'; someGlobal; threw exception SyntaxError: Parse error.
+PASS 'use strict'; eval('var introducedVariable = "FAIL: variable introduced into containing scope";'); introducedVariable threw exception ReferenceError: Can't find variable: introducedVariable.
+PASS 'use strict'; objectWithReadonlyProperty.prop = 'fail' threw exception TypeError: Attempted to assign to readonly property..
+PASS 'use strict'; delete objectWithReadonlyProperty.prop threw exception TypeError: Unable to delete property..
+PASS 'use strict'; delete objectWithReadonlyProperty[readonlyPropName] threw exception TypeError: Unable to delete property..
+PASS 'use strict'; ++eval threw exception SyntaxError: Parse error.
+PASS 'use strict'; eval++ threw exception SyntaxError: Parse error.
+PASS 'use strict'; --eval threw exception SyntaxError: Parse error.
+PASS 'use strict'; eval-- threw exception SyntaxError: Parse error.
+PASS 'use strict'; if (0) delete +a.b threw exception SyntaxError: Parse error.
+PASS 'use strict'; if (0) delete ++a.b threw exception SyntaxError: Parse error.
+PASS 'use strict'; if (0) delete void a.b threw exception SyntaxError: Parse error.
+PASS (function (a){'use strict'; a = false; return a !== arguments[0]; })(true) is true
+PASS (function (a){'use strict'; arguments[0] = false; return a !== arguments[0]; })(true) is true
+PASS (function (a){'use strict'; a=false; return arguments; })(true)[0] is true
+PASS (function (a){'use strict'; arguments[0]=false; return a; })(true) is true
+PASS (function (a){'use strict'; arguments[0]=true; return arguments; })(false)[0] is true
+PASS (function (){'use strict';  arguments[0]=true; return arguments; })(false)[0] is true
+PASS (function (a){'use strict'; arguments[0]=true; a=false; return arguments; })()[0] is true
+PASS (function (a){'use strict'; arguments[0]=false; a=true; return a; })() is true
+PASS (function (a){'use strict'; arguments[0]=true; return arguments; })()[0] is true
+PASS (function (){'use strict';  arguments[0]=true; return arguments; })()[0] is true
+PASS (function (a){'use strict'; var local; (function (){local;})(); a = false; return a !== arguments[0]; })(true) is true
+PASS (function (a){'use strict'; var local; (function (){local;})(); arguments[0] = false; return a !== arguments[0]; })(true) is true
+PASS (function (a){'use strict'; var local; (function (){local;})(); a=false; return arguments; })(true)[0] is true
+PASS (function (a){'use strict'; var local; (function (){local;})(); arguments[0]=false; return a; })(true) is true
+PASS (function (a){'use strict'; var local; (function (){local;})(); arguments[0]=true; return arguments; })(false)[0] is true
+PASS (function (){'use strict';  var local; (function (){local;})(); arguments[0]=true; return arguments; })(false)[0] is true
+PASS (function (a){'use strict'; var local; (function (){local;})(); arguments[0]=true; a=false; return arguments; })()[0] is true
+PASS (function (a){'use strict'; var local; (function (){local;})(); arguments[0]=true; return arguments; })()[0] is true
+PASS (function (a){'use strict'; var local; (function (){local;})(); arguments[0]=false; a=true; return a; })() is true
+PASS (function (){'use strict';  var local; (function (){local;})(); arguments[0]=true; return arguments; })()[0] is true
+PASS 'use strict'; (function (){var a = true; eval('var a = false'); return a; })() is true
+PASS (function (){var a = true; eval('"use strict"; var a = false'); return a; })() is true
+PASS (function f(arg){'use strict'; return Object.getOwnPropertyDescriptor(f, 'arguments').value; })() is undefined.
+PASS (function f(arg){'use strict'; return Object.getOwnPropertyDescriptor(f, 'caller').value; })() is undefined.
+PASS (function f(arg){'use strict'; return Object.getOwnPropertyDescriptor(arguments, 'callee').value; })() is undefined.
+PASS (function f(arg){'use strict'; return Object.getOwnPropertyDescriptor(arguments, 'caller').value; })() is undefined.
+PASS (function f(arg){'use strict'; var descriptor = Object.getOwnPropertyDescriptor(arguments, 'caller'); return descriptor.get === descriptor.set; })() is true
+PASS (function f(arg){'use strict'; var descriptor = Object.getOwnPropertyDescriptor(arguments, 'callee'); return descriptor.get === descriptor.set; })() is true
+PASS (function f(arg){'use strict'; var descriptor = Object.getOwnPropertyDescriptor(f, 'caller'); return descriptor.get === descriptor.set; })() is true
+PASS (function f(arg){'use strict'; var descriptor = Object.getOwnPropertyDescriptor(f, 'arguments'); return descriptor.get === descriptor.set; })() is true
+PASS 'use strict'; (function f() { for(var i in this); })(); true; is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/basic-strict-mode.html b/LayoutTests/fast/js/basic-strict-mode.html
new file mode 100644 (file)
index 0000000..9e771df
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="resources/js-test-style.css">
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="script-tests/basic-strict-mode.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/script-tests/basic-strict-mode.js b/LayoutTests/fast/js/script-tests/basic-strict-mode.js
new file mode 100644 (file)
index 0000000..5592be4
--- /dev/null
@@ -0,0 +1,115 @@
+description("Test behaviour of strict mode");
+
+var globalThisTest;
+function testThis() {
+    "use strict";
+    return this;
+}
+function testGlobalAccess() {
+    return testThis();
+}
+shouldBe("testThis.call(null)", "null");
+shouldBe("testThis.call(1)", "1");
+shouldBe("testThis.call(true)", "true");
+shouldBe("testThis.call(false)", "false");
+shouldBe("testThis.call(undefined)", "undefined");
+shouldBe("testThis.call('a string')", "'a string'");
+
+shouldBe("testGlobalAccess()", "null");
+
+shouldThrow("(function eval(){'use strict';})");
+shouldThrow("(function (eval){'use strict';})");
+shouldThrow("(function arguments(){'use strict';})");
+shouldThrow("(function (arguments){'use strict';})");
+shouldThrow("(function (){'use strict'; var eval;})");
+shouldThrow("(function (){'use strict'; var arguments;})");
+shouldThrow("(function (){'use strict'; try{}catch(eval){}})");
+shouldThrow("(function (){'use strict'; try{}catch(arguments){}})");
+shouldThrow("(function (a, a){'use strict';})");
+shouldThrow("(function (a){'use strict'; delete a;})()");
+shouldThrow("(function (){'use strict'; var a; delete a;})()");
+shouldThrow("(function (){var a; function f() {'use strict'; delete a;} })()");
+shouldThrow("(function (){'use strict'; with(1){};})");
+shouldThrow("(function (){'use strict'; arguments.callee; })()");
+shouldThrow("(function (){'use strict'; arguments.caller; })()");
+shouldThrow("(function f(){'use strict'; f.arguments; })()");
+shouldThrow("(function f(){'use strict'; f.caller; })()");
+shouldThrow("(function f(){'use strict'; f.arguments=5; })()");
+shouldThrow("(function f(){'use strict'; f.caller=5; })()");
+shouldThrow("(function (arg){'use strict'; arguments.callee; })()");
+shouldThrow("(function (arg){'use strict'; arguments.caller; })()");
+shouldThrow("(function f(arg){'use strict'; f.arguments; })()");
+shouldThrow("(function f(arg){'use strict'; f.caller; })()");
+shouldThrow("(function f(arg){'use strict'; f.arguments=5; })()");
+shouldThrow("(function f(arg){'use strict'; f.caller=5; })()");
+shouldThrow("'use strict'; (function (){with(1){};})");
+shouldThrow("'use strict'; (function (){var a; delete a;})");
+shouldThrow("'use strict'; var a; (function (){ delete a;})");
+shouldThrow("var a; (function (){ 'use strict'; delete a;})");
+shouldThrow("'misc directive'; 'use strict'; with({}){}");
+shouldThrow("'use strict'; return");
+shouldThrow("'use strict'; break");
+shouldThrow("'use strict'; continue");
+shouldThrow("'use strict'; for(;;)return");
+shouldThrow("'use strict'; for(;;)break missingLabel");
+shouldThrow("'use strict'; for(;;)continue missingLabel");
+shouldThrow("'use strict'; 007;");
+shouldThrow("'use strict'; '\\007';");
+shouldThrow("'\\007'; 'use strict';");
+
+var someDeclaredGlobal;
+shouldThrow("'use strict'; (function (){ delete someDeclaredGlobal;})");
+shouldThrow("(function (){ 'use strict'; delete someDeclaredGlobal;})");
+shouldThrow("'use strict'; someGlobal = 'Shouldn\\'t be able to assign this.'; someGlobal;");
+shouldThrow("'use strict'; eval('var introducedVariable = \"FAIL: variable introduced into containing scope\";'); introducedVariable");
+var objectWithReadonlyProperty = {};
+Object.defineProperty(objectWithReadonlyProperty, "prop", {value: "value", writable:false});
+shouldThrow("'use strict'; objectWithReadonlyProperty.prop = 'fail'");
+shouldThrow("'use strict'; delete objectWithReadonlyProperty.prop");
+readonlyPropName = "prop";
+shouldThrow("'use strict'; delete objectWithReadonlyProperty[readonlyPropName]");
+shouldThrow("'use strict'; ++eval");
+shouldThrow("'use strict'; eval++");
+shouldThrow("'use strict'; --eval");
+shouldThrow("'use strict'; eval--");
+shouldThrow("'use strict'; if (0) delete +a.b");
+shouldThrow("'use strict'; if (0) delete ++a.b");
+shouldThrow("'use strict'; if (0) delete void a.b");
+
+shouldBeTrue("(function (a){'use strict'; a = false; return a !== arguments[0]; })(true)");
+shouldBeTrue("(function (a){'use strict'; arguments[0] = false; return a !== arguments[0]; })(true)");
+shouldBeTrue("(function (a){'use strict'; a=false; return arguments; })(true)[0]");
+shouldBeTrue("(function (a){'use strict'; arguments[0]=false; return a; })(true)");
+shouldBeTrue("(function (a){'use strict'; arguments[0]=true; return arguments; })(false)[0]");
+shouldBeTrue("(function (){'use strict';  arguments[0]=true; return arguments; })(false)[0]");
+shouldBeTrue("(function (a){'use strict'; arguments[0]=true; a=false; return arguments; })()[0]");
+shouldBeTrue("(function (a){'use strict'; arguments[0]=false; a=true; return a; })()");
+shouldBeTrue("(function (a){'use strict'; arguments[0]=true; return arguments; })()[0]");
+shouldBeTrue("(function (){'use strict';  arguments[0]=true; return arguments; })()[0]");
+
+// Same tests again, this time forcing an activation to be created as well
+shouldBeTrue("(function (a){'use strict'; var local; (function (){local;})(); a = false; return a !== arguments[0]; })(true)");
+shouldBeTrue("(function (a){'use strict'; var local; (function (){local;})(); arguments[0] = false; return a !== arguments[0]; })(true)");
+shouldBeTrue("(function (a){'use strict'; var local; (function (){local;})(); a=false; return arguments; })(true)[0]");
+shouldBeTrue("(function (a){'use strict'; var local; (function (){local;})(); arguments[0]=false; return a; })(true)");
+shouldBeTrue("(function (a){'use strict'; var local; (function (){local;})(); arguments[0]=true; return arguments; })(false)[0]");
+shouldBeTrue("(function (){'use strict';  var local; (function (){local;})(); arguments[0]=true; return arguments; })(false)[0]");
+shouldBeTrue("(function (a){'use strict'; var local; (function (){local;})(); arguments[0]=true; a=false; return arguments; })()[0]");
+shouldBeTrue("(function (a){'use strict'; var local; (function (){local;})(); arguments[0]=true; return arguments; })()[0]");
+shouldBeTrue("(function (a){'use strict'; var local; (function (){local;})(); arguments[0]=false; a=true; return a; })()");
+shouldBeTrue("(function (){'use strict';  var local; (function (){local;})(); arguments[0]=true; return arguments; })()[0]");
+
+shouldBeTrue("'use strict'; (function (){var a = true; eval('var a = false'); return a; })()");
+shouldBeTrue("(function (){var a = true; eval('\"use strict\"; var a = false'); return a; })()");
+
+shouldBeUndefined("(function f(arg){'use strict'; return Object.getOwnPropertyDescriptor(f, 'arguments').value; })()");
+shouldBeUndefined("(function f(arg){'use strict'; return Object.getOwnPropertyDescriptor(f, 'caller').value; })()");
+shouldBeUndefined("(function f(arg){'use strict'; return Object.getOwnPropertyDescriptor(arguments, 'callee').value; })()");
+shouldBeUndefined("(function f(arg){'use strict'; return Object.getOwnPropertyDescriptor(arguments, 'caller').value; })()");
+shouldBeTrue("(function f(arg){'use strict'; var descriptor = Object.getOwnPropertyDescriptor(arguments, 'caller'); return descriptor.get === descriptor.set; })()");
+shouldBeTrue("(function f(arg){'use strict'; var descriptor = Object.getOwnPropertyDescriptor(arguments, 'callee'); return descriptor.get === descriptor.set; })()");
+shouldBeTrue("(function f(arg){'use strict'; var descriptor = Object.getOwnPropertyDescriptor(f, 'caller'); return descriptor.get === descriptor.set; })()");
+shouldBeTrue("(function f(arg){'use strict'; var descriptor = Object.getOwnPropertyDescriptor(f, 'arguments'); return descriptor.get === descriptor.set; })()");
+shouldBeTrue("'use strict'; (function f() { for(var i in this); })(); true;")
+
+var successfullyParsed = true;
index 07f2a65..89fdaab 100644 (file)
@@ -1,3 +1,20 @@
+2010-10-01  Oliver Hunt  <oliver@apple.com>
+
+        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:
+
 2010-10-11  Joseph Pecoraro  <joepeck@webkit.org>
 
         Reviewed by Eric Carlson.
index 94b3ca2..df51401 100644 (file)
                        isa = PBXProject;
                        buildConfigurationList = 149C284308902B11008A9EFC /* Build configuration list for PBXProject "WebCore" */;
                        compatibilityVersion = "Xcode 2.4";
-                       developmentRegion = English;
                        hasScannedForEncodings = 1;
                        knownRegions = (
                                English,
index 82ac1ce..2872a54 100644 (file)
@@ -146,6 +146,11 @@ JSObject* JSDOMWindowBase::toThisObject(ExecState*) const
     return shell();
 }
 
+JSValue JSDOMWindowBase::toStrictThisObject(ExecState*) const
+{
+    return shell();
+}
+
 JSDOMWindowShell* JSDOMWindowBase::shell() const
 {
     return d()->shell;
index f4f1ef9..cafca73 100644 (file)
@@ -69,8 +69,9 @@ namespace WebCore {
 
         // Don't call this version of allowsAccessFrom -- it's a slightly incorrect implementation used only by WebScriptObject
         virtual bool allowsAccessFrom(const JSC::JSGlobalObject*) const;
-
+        
         virtual JSC::JSObject* toThisObject(JSC::ExecState*) const;
+        virtual JSC::JSValue toStrictThisObject(JSC::ExecState*) const;
         JSDOMWindowShell* shell() const;
 
         static JSC::JSGlobalData* commonJSGlobalData();