Ignore:
Timestamp:
Dec 25, 2016, 10:35:07 PM (8 years ago)
Author:
Yusuke Suzuki
Message:

Propagate the source origin as much as possible
https://bugs.webkit.org/show_bug.cgi?id=166348

Reviewed by Darin Adler.

JSTests:

  • stress/source-origin.js: Added.

(shouldBe):

Source/JavaScriptCore:

This patch introduces CallFrame::callerSourceOrigin, SourceOrigin class
and SourceProvider::m_sourceOrigin. CallFrame::callerSourceOrigin returns
an appropriate SourceOrigin if possible. If we cannot find the appropriate
one, we just return null SourceOrigin.

This paves the way for implementing the module dynamic-import[1].
When the import operator is evaluated, it will resolve the module
specifier with this propagated source origin of the caller function.

To support import operator inside the dynamic code generation
functions (like eval, new Function, indirect call to eval),
we need to propagate the caller's source origin to the generated
source code.

We do not use sourceURL for that purpose. This is because we
would like to keep sourceURL for eval / new Function null.
This sourceURL will be used for the stack dump for errors with line/column
numbers. Dumping the caller's sourceURL with line/column numbers are
meaningless. So we would like to keep it null while we would like
to propagate SourceOrigin for dynamic imports.

[1]: https://github.com/tc39/proposal-dynamic-import

  • API/JSBase.cpp:

(JSEvaluateScript):
(JSCheckScriptSyntax):

  • API/JSObjectRef.cpp:

(JSObjectMakeFunction):

  • API/JSScriptRef.cpp:

(OpaqueJSScript::create):
(OpaqueJSScript::vm):
(OpaqueJSScript::OpaqueJSScript):
(parseScript):

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Scripts/builtins/builtins_templates.py:
  • Scripts/tests/builtins/expected/WebCore-AnotherGuardedInternalBuiltin-Separate.js-result:
  • Scripts/tests/builtins/expected/WebCore-ArbitraryConditionalGuard-Separate.js-result:
  • Scripts/tests/builtins/expected/WebCore-GuardedBuiltin-Separate.js-result:
  • Scripts/tests/builtins/expected/WebCore-GuardedInternalBuiltin-Separate.js-result:
  • Scripts/tests/builtins/expected/WebCore-UnguardedBuiltin-Separate.js-result:
  • Scripts/tests/builtins/expected/WebCore-xmlCasingTest-Separate.js-result:
  • builtins/BuiltinExecutables.cpp:

(JSC::BuiltinExecutables::BuiltinExecutables):
(JSC::BuiltinExecutables::createDefaultConstructor):

  • debugger/DebuggerCallFrame.cpp:

(JSC::DebuggerCallFrame::evaluateWithScopeExtension):

  • inspector/InjectedScriptManager.cpp:

(Inspector::InjectedScriptManager::createInjectedScript):

  • inspector/JSInjectedScriptHost.cpp:

(Inspector::JSInjectedScriptHost::evaluateWithScopeExtension):

  • inspector/agents/InspectorRuntimeAgent.cpp:

(Inspector::InspectorRuntimeAgent::parse):

  • interpreter/CallFrame.cpp:

(JSC::CallFrame::callerSourceOrigin):

  • interpreter/CallFrame.h:
  • interpreter/Interpreter.cpp:

(JSC::eval):

  • jsc.cpp:

(jscSource):
(GlobalObject::finishCreation):
(extractDirectoryName):
(currentWorkingDirectory):
(GlobalObject::moduleLoaderResolve):
(functionRunString):
(functionLoadString):
(functionCallerSourceOrigin):
(functionCreateBuiltin):
(functionCheckModuleSyntax):
(runInteractive):

  • parser/SourceCode.h:

(JSC::makeSource):

  • parser/SourceProvider.cpp:

(JSC::SourceProvider::SourceProvider):

  • parser/SourceProvider.h:

(JSC::SourceProvider::sourceOrigin):
(JSC::StringSourceProvider::create):
(JSC::StringSourceProvider::StringSourceProvider):
(JSC::WebAssemblySourceProvider::create):
(JSC::WebAssemblySourceProvider::WebAssemblySourceProvider):

  • runtime/FunctionConstructor.cpp:

(JSC::constructFunction):
(JSC::constructFunctionSkippingEvalEnabledCheck):

  • runtime/FunctionConstructor.h:
  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::globalFuncEval):

  • runtime/ModuleLoaderPrototype.cpp:

(JSC::moduleLoaderPrototypeParseModule):

  • runtime/ScriptExecutable.h:

(JSC::ScriptExecutable::sourceOrigin):

  • runtime/SourceOrigin.h: Added.

(JSC::SourceOrigin::SourceOrigin):
(JSC::SourceOrigin::string):
(JSC::SourceOrigin::isNull):

  • tools/FunctionOverrides.cpp:

(JSC::initializeOverrideInfo):

Source/WebCore:

  • bindings/js/CachedScriptSourceProvider.h:

(WebCore::CachedScriptSourceProvider::CachedScriptSourceProvider):

  • bindings/js/JSLazyEventListener.cpp:

(WebCore::JSLazyEventListener::initializeJSFunction):

  • bindings/js/ScriptSourceCode.h:

(WebCore::ScriptSourceCode::ScriptSourceCode):

  • bridge/NP_jsobject.cpp:

(_NPN_Evaluate):

  • bridge/objc/WebScriptObject.mm:

(-[WebScriptObject evaluateWebScript:]):

Source/WebKit/mac:

  • Plugins/Hosted/NetscapePluginInstanceProxy.mm:

(WebKit::NetscapePluginInstanceProxy::evaluate):

Source/WebKit/win:

  • Plugins/PluginPackage.cpp:

(WebCore::NPN_Evaluate):
(WebCore::makeSource): Deleted.

Source/WebKit2:

  • WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp:

(WebKit::NPRuntimeObjectMap::evaluate):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/jsc.cpp

    r209906 r210149  
    10101010static EncodedJSValue JSC_HOST_CALL functionSetRandomSeed(ExecState*);
    10111011static EncodedJSValue JSC_HOST_CALL functionIsRope(ExecState*);
     1012static EncodedJSValue JSC_HOST_CALL functionCallerSourceOrigin(ExecState*);
    10121013
    10131014struct Script {
     
    11041105{
    11051106    String str = stringFromUTF(utf8);
    1106     return makeSource(str, filename);
     1107    return makeSource(str, SourceOrigin { filename }, filename);
    11071108}
    11081109
     
    12331234        addFunction(vm, "setRandomSeed", functionSetRandomSeed, 1);
    12341235        addFunction(vm, "isRope", functionIsRope, 1);
     1236        addFunction(vm, "callerSourceOrigin", functionCallerSourceOrigin, 0);
    12351237
    12361238        addFunction(vm, "is32BitPlatform", functionIs32BitPlatform, 0);
     
    13331335}
    13341336
    1335 static bool extractDirectoryName(const String& absolutePathToFile, DirectoryName& directoryName)
     1337static std::optional<DirectoryName> extractDirectoryName(const String& absolutePathToFile)
    13361338{
    13371339    size_t firstSeparatorPosition = absolutePathToFile.find(pathSeparator());
    13381340    if (firstSeparatorPosition == notFound)
    1339         return false;
     1341        return std::nullopt;
     1342    DirectoryName directoryName;
    13401343    directoryName.rootName = absolutePathToFile.substring(0, firstSeparatorPosition + 1); // Include the separator.
    13411344    size_t lastSeparatorPosition = absolutePathToFile.reverseFind(pathSeparator());
     
    13481351        directoryName.queryName = absolutePathToFile.substring(queryStartPosition, queryLength);
    13491352    }
    1350     return true;
    1351 }
    1352 
    1353 static bool currentWorkingDirectory(DirectoryName& directoryName)
     1353    return directoryName;
     1354}
     1355
     1356static std::optional<DirectoryName> currentWorkingDirectory()
    13541357{
    13551358#if OS(WINDOWS)
     
    13651368    DWORD bufferLength = ::GetCurrentDirectoryW(0, nullptr);
    13661369    if (!bufferLength)
    1367         return false;
     1370        return std::nullopt;
    13681371    // In Windows, wchar_t is the UTF-16LE.
    13691372    // https://msdn.microsoft.com/en-us/library/dd374081.aspx
     
    13751378    // We don't support network path like \\host\share\<path name>.
    13761379    if (directoryString.startsWith("\\\\"))
    1377         return false;
     1380        return std::nullopt;
    13781381#else
    13791382    auto buffer = std::make_unique<char[]>(PATH_MAX);
    13801383    if (!getcwd(buffer.get(), PATH_MAX))
    1381         return false;
     1384        return std::nullopt;
    13821385    String directoryString = String::fromUTF8(buffer.get());
    13831386#endif
    13841387    if (directoryString.isEmpty())
    1385         return false;
     1388        return std::nullopt;
    13861389
    13871390    if (directoryString[directoryString.length() - 1] == pathSeparator())
    1388         return extractDirectoryName(directoryString, directoryName);
     1391        return extractDirectoryName(directoryString);
    13891392    // Append the seperator to represents the file name. extractDirectoryName only accepts the absolute file name.
    1390     return extractDirectoryName(makeString(directoryString, pathSeparator()), directoryName);
     1393    return extractDirectoryName(makeString(directoryString, pathSeparator()));
    13911394}
    13921395
     
    14341437        return deferred->resolve(exec, keyValue);
    14351438
    1436     DirectoryName directoryName;
    14371439    if (referrerValue.isUndefined()) {
    1438         if (!currentWorkingDirectory(directoryName))
     1440        auto directoryName = currentWorkingDirectory();
     1441        if (!directoryName)
    14391442            return deferred->reject(exec, createError(exec, ASCIILiteral("Could not resolve the current working directory.")));
    1440     } else {
    1441         const Identifier referrer = referrerValue.toPropertyKey(exec);
    1442         if (UNLIKELY(scope.exception())) {
    1443             JSValue exception = scope.exception();
    1444             scope.clearException();
    1445             return deferred->reject(exec, exception);
    1446         }
    1447         if (referrer.isSymbol()) {
    1448             if (!currentWorkingDirectory(directoryName))
    1449                 return deferred->reject(exec, createError(exec, ASCIILiteral("Could not resolve the current working directory.")));
    1450         } else {
    1451             // If the referrer exists, we assume that the referrer is the correct absolute path.
    1452             if (!extractDirectoryName(referrer.impl(), directoryName))
    1453                 return deferred->reject(exec, createError(exec, makeString("Could not resolve the referrer name '", String(referrer.impl()), "'.")));
    1454         }
    1455     }
    1456 
    1457     return deferred->resolve(exec, jsString(exec, resolvePath(directoryName, ModuleName(key.impl()))));
     1443        return deferred->resolve(exec, jsString(exec, resolvePath(directoryName.value(), ModuleName(key.impl()))));
     1444    }
     1445
     1446    const Identifier referrer = referrerValue.toPropertyKey(exec);
     1447    if (UNLIKELY(scope.exception())) {
     1448        JSValue exception = scope.exception();
     1449        scope.clearException();
     1450        return deferred->reject(exec, exception);
     1451    }
     1452
     1453    if (referrer.isSymbol()) {
     1454        auto directoryName = currentWorkingDirectory();
     1455        if (!directoryName)
     1456            return deferred->reject(exec, createError(exec, ASCIILiteral("Could not resolve the current working directory.")));
     1457        return deferred->resolve(exec, jsString(exec, resolvePath(directoryName.value(), ModuleName(key.impl()))));
     1458    }
     1459
     1460    // If the referrer exists, we assume that the referrer is the correct absolute path.
     1461    auto directoryName = extractDirectoryName(referrer.impl());
     1462    if (!directoryName)
     1463        return deferred->reject(exec, createError(exec, makeString("Could not resolve the referrer name '", String(referrer.impl()), "'.")));
     1464    return deferred->resolve(exec, jsString(exec, resolvePath(directoryName.value(), ModuleName(key.impl()))));
    14581465}
    14591466
     
    19461953
    19471954    NakedPtr<Exception> exception;
    1948     evaluate(globalObject->globalExec(), makeSource(source), JSValue(), exception);
     1955    evaluate(globalObject->globalExec(), makeSource(source, exec->callerSourceOrigin()), JSValue(), exception);
    19491956
    19501957    if (exception) {
     
    19861993
    19871994    NakedPtr<Exception> evaluationException;
    1988     JSValue result = evaluate(globalObject->globalExec(), makeSource(sourceCode), JSValue(), evaluationException);
     1995    JSValue result = evaluate(globalObject->globalExec(), makeSource(sourceCode, exec->callerSourceOrigin()), JSValue(), evaluationException);
    19891996    if (evaluationException)
    19901997        throwException(exec, scope, evaluationException);
     
    21052112    const StringImpl* impl = asString(argument)->tryGetValueImpl();
    21062113    return JSValue::encode(jsBoolean(!impl));
     2114}
     2115
     2116EncodedJSValue JSC_HOST_CALL functionCallerSourceOrigin(ExecState* state)
     2117{
     2118    SourceOrigin sourceOrigin = state->callerSourceOrigin();
     2119    if (sourceOrigin.isNull())
     2120        return JSValue::encode(jsNull());
     2121    return JSValue::encode(jsString(state, sourceOrigin.string()));
    21072122}
    21082123
     
    24052420    RETURN_IF_EXCEPTION(scope, encodedJSValue());
    24062421
    2407     const SourceCode& source = makeSource(functionText);
     2422    const SourceCode& source = makeSource(functionText, { });
    24082423    JSFunction* func = JSFunction::createBuiltinFunction(vm, createBuiltinExecutable(vm, source, Identifier::fromString(&vm, "foo"), ConstructorKind::None, ConstructAbility::CannotConstruct)->link(vm, source), exec->lexicalGlobalObject());
    24092424
     
    24292444
    24302445    ParserError error;
    2431     bool validSyntax = checkModuleSyntax(exec, makeSource(source, String(), TextPosition(), SourceProviderSourceType::Module), error);
     2446    bool validSyntax = checkModuleSyntax(exec, makeSource(source, { }, String(), TextPosition(), SourceProviderSourceType::Module), error);
    24322447    stopWatch.stop();
    24332448
     
    29482963    auto scope = DECLARE_CATCH_SCOPE(vm);
    29492964
    2950     String interpreterName(ASCIILiteral("Interpreter"));
     2965    std::optional<DirectoryName> directoryName = currentWorkingDirectory();
     2966    if (!directoryName)
     2967        return;
     2968    SourceOrigin sourceOrigin(resolvePath(directoryName.value(), ModuleName("interpreter")));
    29512969   
    29522970    bool shouldQuit = false;
     
    29632981            source = source + line;
    29642982            source = source + '\n';
    2965             checkSyntax(globalObject->vm(), makeSource(source, interpreterName), error);
     2983            checkSyntax(globalObject->vm(), makeSource(source, sourceOrigin), error);
    29662984            if (!line[0]) {
    29672985                free(line);
     
    29792997       
    29802998        NakedPtr<Exception> evaluationException;
    2981         JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, interpreterName), JSValue(), evaluationException);
     2999        JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, sourceOrigin), JSValue(), evaluationException);
    29823000#else
    29833001        printf("%s", interactivePrompt);
     
    29943012
    29953013        NakedPtr<Exception> evaluationException;
    2996         JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line, interpreterName), JSValue(), evaluationException);
     3014        JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line, sourceOrigin.string()), JSValue(), evaluationException);
    29973015#endif
    29983016        if (evaluationException)
Note: See TracChangeset for help on using the changeset viewer.