2021-09-09 18:03:01 +02:00
/*
2024-10-04 13:19:50 +02:00
* Copyright ( c ) 2021 - 2023 , Andreas Kling < andreas @ ladybird . org >
2021-09-09 18:03:01 +02:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2022-02-05 16:18:22 +01:00
# include <AK/Debug.h>
2021-09-12 21:56:44 +02:00
# include <LibCore/ElapsedTimer.h>
2023-06-17 13:16:35 +02:00
# include <LibJS/Bytecode/Interpreter.h>
2021-10-14 16:12:53 +01:00
# include <LibWeb/Bindings/ExceptionOrUtils.h>
2021-09-09 18:03:01 +02:00
# include <LibWeb/HTML/Scripting/ClassicScript.h>
2021-10-14 16:12:53 +01:00
# include <LibWeb/HTML/Scripting/Environments.h>
2022-02-07 15:12:41 +01:00
# include <LibWeb/HTML/Scripting/ExceptionReporter.h>
2024-09-26 15:40:23 +01:00
# include <LibWeb/HTML/WindowOrWorkerGlobalScope.h>
2022-09-25 17:28:46 +01:00
# include <LibWeb/WebIDL/DOMException.h>
2021-09-09 18:03:01 +02:00
namespace Web : : HTML {
2024-11-15 04:01:23 +13:00
GC_DEFINE_ALLOCATOR ( ClassicScript ) ;
2023-11-19 19:47:52 +01:00
2021-09-09 19:03:50 +02:00
// https://html.spec.whatwg.org/multipage/webappapis.html#creating-a-classic-script
2024-10-21 14:24:06 +13:00
// https://whatpr.org/html/9893/webappapis.html#creating-a-classic-script
2024-11-15 04:01:23 +13:00
GC : : Ref < ClassicScript > ClassicScript : : create ( ByteString filename , StringView source , JS : : Realm & realm , URL : : URL base_url , size_t source_line_number , MutedErrors muted_errors )
2021-09-09 18:03:01 +02:00
{
2024-10-21 14:24:06 +13:00
auto & vm = realm . vm ( ) ;
2022-09-05 14:32:33 +02:00
2024-10-21 14:29:39 +13:00
// 1. If muted errors is true, then set baseURL to about:blank.
2021-09-09 19:03:50 +02:00
if ( muted_errors = = MutedErrors : : Yes )
2025-02-15 23:51:45 +13:00
base_url = URL : : about_blank ( ) ;
2021-09-09 19:03:50 +02:00
2024-10-21 14:24:06 +13:00
// 2. If scripting is disabled for realm, then set source to the empty string.
if ( is_scripting_disabled ( realm ) )
2022-07-11 17:32:29 +00:00
source = " " sv ;
2021-09-09 19:03:50 +02:00
2024-10-21 14:29:39 +13:00
// 3. Let script be a new classic script that this algorithm will subsequently initialize.
2024-10-25 16:27:26 +13:00
// 4. Set script's realm to realm.
// 5. Set script's base URL to baseURL.
2024-11-14 06:13:46 +13:00
auto script = vm . heap ( ) . allocate < ClassicScript > ( move ( base_url ) , move ( filename ) , realm ) ;
2021-09-09 19:03:50 +02:00
2024-10-21 14:29:39 +13:00
// FIXME: 6. Set script's fetch options to options.
2021-09-09 19:03:50 +02:00
2024-10-21 14:29:39 +13:00
// 7. Set script's muted errors to muted errors.
2021-09-09 19:03:50 +02:00
script - > m_muted_errors = muted_errors ;
2024-10-21 14:29:39 +13:00
// 8. Set script's parse error and error to rethrow to null.
2023-05-18 19:05:56 +02:00
script - > set_parse_error ( JS : : js_null ( ) ) ;
script - > set_error_to_rethrow ( JS : : js_null ( ) ) ;
2021-09-09 19:03:50 +02:00
2024-10-21 14:29:39 +13:00
// FIXME: 9. Record classic script creation time given script and sourceURLForWindowScripts .
2024-10-21 14:24:06 +13:00
// 10. Let result be ParseScript(source, realm, script).
2021-09-14 21:00:41 +02:00
auto parse_timer = Core : : ElapsedTimer : : start_new ( ) ;
2024-10-21 14:24:06 +13:00
auto result = JS : : Script : : parse ( source , realm , script - > filename ( ) , script , source_line_number ) ;
2024-11-23 19:22:31 +04:00
dbgln_if ( HTML_SCRIPT_DEBUG , " ClassicScript: Parsed {} in {}ms " , script - > filename ( ) , parse_timer . elapsed_milliseconds ( ) ) ;
2021-09-09 19:03:50 +02:00
2021-09-14 20:56:57 +02:00
// 11. If result is a list of errors, then:
if ( result . is_error ( ) ) {
2021-10-14 16:12:53 +01:00
auto & parse_error = result . error ( ) . first ( ) ;
2024-04-05 09:26:03 +02:00
dbgln_if ( HTML_SCRIPT_DEBUG , " ClassicScript: Failed to parse: {} " , parse_error . to_string ( ) ) ;
2021-10-14 16:12:53 +01:00
2023-05-18 19:05:56 +02:00
// 1. Set script's parse error and its error to rethrow to result[0].
2024-10-21 14:24:06 +13:00
script - > set_parse_error ( JS : : SyntaxError : : create ( realm , parse_error . to_string ( ) ) ) ;
2023-05-18 19:05:56 +02:00
script - > set_error_to_rethrow ( script - > parse_error ( ) ) ;
2021-09-14 20:56:57 +02:00
// 2. Return script.
2022-12-14 17:40:33 +00:00
return script ;
2021-09-14 20:56:57 +02:00
}
2021-09-09 19:03:50 +02:00
// 12. Set script's record to result.
2022-09-05 14:32:33 +02:00
script - > m_script_record = * result . release_value ( ) ;
2021-09-09 19:03:50 +02:00
// 13. Return script.
2022-12-14 17:40:33 +00:00
return script ;
2021-09-09 19:03:50 +02:00
}
// https://html.spec.whatwg.org/multipage/webappapis.html#run-a-classic-script
2024-10-21 14:24:06 +13:00
// https://whatpr.org/html/9893/webappapis.html#run-a-classic-script
2024-11-15 04:01:23 +13:00
JS : : Completion ClassicScript : : run ( RethrowErrors rethrow_errors , GC : : Ptr < JS : : Environment > lexical_environment_override )
2021-09-09 19:03:50 +02:00
{
2024-10-25 16:27:26 +13:00
// 1. Let realm be the realm of script.
auto & realm = this - > realm ( ) ;
2021-10-14 16:12:53 +01:00
2025-04-09 12:45:18 +01:00
// 2. Check if we can run script with realm. If this returns "do not run", then return NormalCompletion(empty).
2024-10-21 14:24:06 +13:00
if ( can_run_script ( realm ) = = RunScriptDecision : : DoNotRun )
2025-04-04 18:11:45 +02:00
return JS : : normal_completion ( JS : : js_undefined ( ) ) ;
2021-10-14 16:12:53 +01:00
2024-10-21 20:09:02 +13:00
// 3. Prepare to run script given realm.
prepare_to_run_script ( realm ) ;
2021-10-14 16:12:53 +01:00
// 4. Let evaluationStatus be null.
JS : : Completion evaluation_status ;
// 5. If script's error to rethrow is not null, then set evaluationStatus to Completion { [[Type]]: throw, [[Value]]: script's error to rethrow, [[Target]]: empty }.
2023-05-18 19:05:56 +02:00
if ( ! error_to_rethrow ( ) . is_null ( ) ) {
2024-05-10 09:28:48 +02:00
evaluation_status = JS : : Completion { JS : : Completion : : Type : : Throw , error_to_rethrow ( ) } ;
2021-10-14 16:12:53 +01:00
} else {
auto timer = Core : : ElapsedTimer : : start_new ( ) ;
// 6. Otherwise, set evaluationStatus to ScriptEvaluation(script's record).
2024-10-31 08:03:09 -04:00
evaluation_status = vm ( ) . bytecode_interpreter ( ) . run ( * m_script_record , lexical_environment_override ) ;
2021-10-14 16:12:53 +01:00
// FIXME: If ScriptEvaluation does not complete because the user agent has aborted the running script, leave evaluationStatus as null.
2024-11-23 19:22:31 +04:00
dbgln_if ( HTML_SCRIPT_DEBUG , " ClassicScript: Finished running script {}, Duration: {}ms " , filename ( ) , timer . elapsed_milliseconds ( ) ) ;
2021-09-18 01:38:40 +02:00
}
2021-10-14 16:12:53 +01:00
// 7. If evaluationStatus is an abrupt completion, then:
if ( evaluation_status . is_abrupt ( ) ) {
// 1. If rethrow errors is true and script's muted errors is false, then:
if ( rethrow_errors = = RethrowErrors : : Yes & & m_muted_errors = = MutedErrors : : No ) {
2024-10-21 16:18:25 +13:00
// 1. Clean up after running script with realm.
clean_up_after_running_script ( realm ) ;
2021-09-09 19:03:50 +02:00
2021-10-14 16:12:53 +01:00
// 2. Rethrow evaluationStatus.[[Value]].
2025-04-04 18:11:45 +02:00
return JS : : throw_completion ( evaluation_status . value ( ) ) ;
2021-10-14 16:12:53 +01:00
}
2022-01-16 13:16:04 +01:00
2021-10-14 16:12:53 +01:00
// 2. If rethrow errors is true and script's muted errors is true, then:
if ( rethrow_errors = = RethrowErrors : : Yes & & m_muted_errors = = MutedErrors : : Yes ) {
2024-10-21 16:18:25 +13:00
// 1. Clean up after running script with realm.
clean_up_after_running_script ( realm ) ;
2022-01-08 21:28:27 +01:00
2021-10-14 16:12:53 +01:00
// 2. Throw a "NetworkError" DOMException.
2024-10-21 14:24:06 +13:00
return throw_completion ( WebIDL : : NetworkError : : create ( realm , " Script error. " _string ) ) ;
2021-10-14 16:12:53 +01:00
}
2022-01-16 13:16:04 +01:00
2021-10-14 16:12:53 +01:00
// 3. Otherwise, rethrow errors is false. Perform the following steps:
VERIFY ( rethrow_errors = = RethrowErrors : : No ) ;
2022-01-16 13:16:04 +01:00
2024-10-25 16:27:26 +13:00
// 1. Report an exception given by evaluationStatus.[[Value]] for realms's global object.
2025-02-02 15:42:57 +00:00
auto & window_or_worker = as < WindowOrWorkerGlobalScopeMixin > ( realm . global_object ( ) ) ;
2025-04-04 18:11:45 +02:00
window_or_worker . report_an_exception ( evaluation_status . value ( ) ) ;
2021-10-14 16:12:53 +01:00
2024-10-21 16:18:25 +13:00
// 2. Clean up after running script with realm.
clean_up_after_running_script ( realm ) ;
2021-10-14 16:12:53 +01:00
// 3. Return evaluationStatus.
return evaluation_status ;
2022-01-08 21:28:27 +01:00
}
2021-10-14 16:12:53 +01:00
2024-10-21 16:18:25 +13:00
// 8. Clean up after running script with realm.
clean_up_after_running_script ( realm ) ;
2021-10-14 16:12:53 +01:00
// 9. If evaluationStatus is a normal completion, then return evaluationStatus.
VERIFY ( ! evaluation_status . is_abrupt ( ) ) ;
return evaluation_status ;
// FIXME: 10. If we've reached this point, evaluationStatus was left as null because the script was aborted prematurely during evaluation.
// Return Completion { [[Type]]: throw, [[Value]]: a new "QuotaExceededError" DOMException, [[Target]]: empty }.
2021-09-09 18:03:01 +02:00
}
2024-10-25 16:27:26 +13:00
ClassicScript : : ClassicScript ( URL : : URL base_url , ByteString filename , JS : : Realm & realm )
: Script ( move ( base_url ) , move ( filename ) , realm )
2021-09-09 18:03:01 +02:00
{
}
2022-03-14 13:21:51 -06:00
ClassicScript : : ~ ClassicScript ( ) = default ;
2021-09-09 18:03:01 +02:00
2022-09-05 14:32:33 +02:00
void ClassicScript : : visit_edges ( Cell : : Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
visitor . visit ( m_script_record ) ;
}
2021-09-09 18:03:01 +02:00
}