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

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

Reviewed by Gavin Barraclough.

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

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

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

Summary of major changes to the parser:

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

Runtime changes:

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

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

Reviewed by Gavin Barraclough.

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

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

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

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

Reviewed by Gavin Barraclough.

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

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

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

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

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/runtime/Arguments.cpp

    r65588 r69516  
    154154    return JSObject::getOwnPropertySlot(exec, Identifier(exec, UString::number(i)), slot);
    155155}
     156   
     157void Arguments::createStrictModeCallerIfNecessary(ExecState* exec)
     158{
     159    if (d->overrodeCaller)
     160        return;
     161
     162    d->overrodeCaller = true;
     163    PropertyDescriptor descriptor;
     164    JSValue thrower = createTypeErrorFunction(exec, "Unable to access caller of strict mode function");
     165    descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
     166    defineOwnProperty(exec, exec->propertyNames().caller, descriptor, false);
     167}
     168
     169void Arguments::createStrictModeCalleeIfNecessary(ExecState* exec)
     170{
     171    if (d->overrodeCallee)
     172        return;
     173   
     174    d->overrodeCallee = true;
     175    PropertyDescriptor descriptor;
     176    JSValue thrower = createTypeErrorFunction(exec, "Unable to access callee of strict mode function");
     177    descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
     178    defineOwnProperty(exec, exec->propertyNames().callee, descriptor, false);
     179}
    156180
    157181bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
     
    173197
    174198    if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
    175         slot.setValue(d->callee);
    176         return true;
    177     }
     199        if (!d->isStrictMode) {
     200            slot.setValue(d->callee);
     201            return true;
     202        }
     203        createStrictModeCalleeIfNecessary(exec);
     204    }
     205
     206    if (propertyName == exec->propertyNames().caller && d->isStrictMode)
     207        createStrictModeCallerIfNecessary(exec);
    178208
    179209    return JSObject::getOwnPropertySlot(exec, propertyName, slot);
     
    198228   
    199229    if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
    200         descriptor.setDescriptor(d->callee, DontEnum);
    201         return true;
    202     }
     230        if (!d->isStrictMode) {
     231            descriptor.setDescriptor(d->callee, DontEnum);
     232            return true;
     233        }
     234        createStrictModeCalleeIfNecessary(exec);
     235    }
     236
     237    if (propertyName == exec->propertyNames().caller && d->isStrictMode)
     238        createStrictModeCallerIfNecessary(exec);
    203239   
    204240    return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
     
    250286
    251287    if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
    252         d->overrodeCallee = true;
    253         putDirect(propertyName, value, DontEnum);
    254         return;
    255     }
     288        if (!d->isStrictMode) {
     289            d->overrodeCallee = true;
     290            putDirect(propertyName, value, DontEnum);
     291            return;
     292        }
     293        createStrictModeCalleeIfNecessary(exec);
     294    }
     295
     296    if (propertyName == exec->propertyNames().caller && d->isStrictMode)
     297        createStrictModeCallerIfNecessary(exec);
    256298
    257299    JSObject::put(exec, propertyName, value, slot);
     
    295337
    296338    if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
    297         d->overrodeCallee = true;
    298         return true;
    299     }
     339        if (!d->isStrictMode) {
     340            d->overrodeCallee = true;
     341            return true;
     342        }
     343        createStrictModeCalleeIfNecessary(exec);
     344    }
     345   
     346    if (propertyName == exec->propertyNames().caller && !d->isStrictMode)
     347        createStrictModeCallerIfNecessary(exec);
    300348
    301349    return JSObject::deleteProperty(exec, propertyName);
Note: See TracChangeset for help on using the changeset viewer.