mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 00:42:44 +00:00 
			
		
		
		
	LibWeb: Make more JS modules actually run
First, we had a logic typo where we were checking parse errors for non-empty instead of non-null. Fixing this caused more modules to actually start executing. As usual, this tripped on some "empty backup incumbent settings object stack" bugs, so this patch also pushes a module execution context in two places where it makes sense. Co-Authored-By: networkException <networkexception@serenityos.org>
This commit is contained in:
		
							parent
							
								
									a2c3db8367
								
							
						
					
					
						commit
						2d69a009fb
					
				
					 2 changed files with 29 additions and 6 deletions
				
			
		|  | @ -480,18 +480,22 @@ ErrorOr<void> initialize_main_thread_vm() | ||||||
|             // 1. Let completion be null.
 |             // 1. Let completion be null.
 | ||||||
|             // NOTE: Our JS::Completion does not support non JS::Value types for its [[Value]], a such we
 |             // NOTE: Our JS::Completion does not support non JS::Value types for its [[Value]], a such we
 | ||||||
|             //       use JS::ThrowCompletionOr here.
 |             //       use JS::ThrowCompletionOr here.
 | ||||||
|  | 
 | ||||||
|  |             auto& vm = realm.vm(); | ||||||
|  |             JS::GCPtr<JS::Module> module = nullptr; | ||||||
|  | 
 | ||||||
|             auto completion = [&]() -> JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Module>> { |             auto completion = [&]() -> JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Module>> { | ||||||
|                 // 2. If moduleScript is null, then set completion to Completion Record { [[Type]]: throw, [[Value]]: a new TypeError, [[Target]]: empty }.
 |                 // 2. If moduleScript is null, then set completion to Completion Record { [[Type]]: throw, [[Value]]: a new TypeError, [[Target]]: empty }.
 | ||||||
|                 if (!module_script) { |                 if (!module_script) { | ||||||
|                     return JS::throw_completion(JS::TypeError::create(realm, DeprecatedString::formatted("Loading imported module '{}' failed.", module_request.module_specifier))); |                     return JS::throw_completion(JS::TypeError::create(realm, DeprecatedString::formatted("Loading imported module '{}' failed.", module_request.module_specifier))); | ||||||
|                 } |                 } | ||||||
|                 // 3. Otherwise, if moduleScript's parse error is not null, then:
 |                 // 3. Otherwise, if moduleScript's parse error is not null, then:
 | ||||||
|                 else if (!module_script->parse_error().is_empty()) { |                 else if (!module_script->parse_error().is_null()) { | ||||||
|                     // 1. Let parseError be moduleScript's parse error.
 |                     // 1. Let parseError be moduleScript's parse error.
 | ||||||
|                     auto parse_error = module_script->parse_error(); |                     auto parse_error = module_script->parse_error(); | ||||||
| 
 | 
 | ||||||
|                     // 2. Set completion to Completion Record { [[Type]]: throw, [[Value]]: parseError, [[Target]]: empty }.
 |                     // 2. Set completion to Completion Record { [[Type]]: throw, [[Value]]: parseError, [[Target]]: empty }.
 | ||||||
|                     return JS::throw_completion(parse_error); |                     auto completion = JS::throw_completion(parse_error); | ||||||
| 
 | 
 | ||||||
|                     // 3. If loadState is not undefined and loadState.[[ParseError]] is null, set loadState.[[ParseError]] to parseError.
 |                     // 3. If loadState is not undefined and loadState.[[ParseError]] is null, set loadState.[[ParseError]] to parseError.
 | ||||||
|                     if (load_state) { |                     if (load_state) { | ||||||
|  | @ -500,18 +504,28 @@ ErrorOr<void> initialize_main_thread_vm() | ||||||
|                             load_state_as_fetch_context.parse_error = parse_error; |                             load_state_as_fetch_context.parse_error = parse_error; | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|  | 
 | ||||||
|  |                     return completion; | ||||||
|                 } |                 } | ||||||
|                 // 4. Otherwise, set completion to Completion Record { [[Type]]: normal, [[Value]]: result's record, [[Target]]: empty }.
 |                 // 4. Otherwise, set completion to Completion Record { [[Type]]: normal, [[Value]]: result's record, [[Target]]: empty }.
 | ||||||
|                 else { |                 else { | ||||||
|                     auto* record = static_cast<HTML::JavaScriptModuleScript&>(*module_script).record(); |                     module = static_cast<HTML::JavaScriptModuleScript&>(*module_script).record(); | ||||||
| 
 |                     return JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Module>>(*module); | ||||||
|                     return JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Module>>(*record); |  | ||||||
|                 } |                 } | ||||||
|             }(); |             }(); | ||||||
| 
 | 
 | ||||||
|             // 5. Perform FinishLoadingImportedModule(referrer, moduleRequest, payload, completion).
 |             // 5. Perform FinishLoadingImportedModule(referrer, moduleRequest, payload, completion).
 | ||||||
|             HTML::TemporaryExecutionContext context { host_defined_environment_settings_object(realm) }; |             // NON-STANDARD: To ensure that LibJS can find the module on the stack, we push a new execution context.
 | ||||||
|  | 
 | ||||||
|  |             auto module_execution_context = JS::ExecutionContext::create(realm.heap()); | ||||||
|  |             module_execution_context->realm = realm; | ||||||
|  |             if (module) | ||||||
|  |                 module_execution_context->script_or_module = JS::NonnullGCPtr { *module }; | ||||||
|  |             vm.push_execution_context(*module_execution_context); | ||||||
|  | 
 | ||||||
|             JS::finish_loading_imported_module(referrer, module_request, payload, completion); |             JS::finish_loading_imported_module(referrer, module_request, payload, completion); | ||||||
|  | 
 | ||||||
|  |             vm.pop_execution_context(); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         // 13. Fetch a single imported module script given url, fetchClient, destination, fetchOptions, settingsObject, fetchReferrer,
 |         // 13. Fetch a single imported module script given url, fetchClient, destination, fetchOptions, settingsObject, fetchReferrer,
 | ||||||
|  |  | ||||||
|  | @ -147,6 +147,12 @@ JS::Promise* JavaScriptModuleScript::run(PreventErrorReporting) | ||||||
|         auto record = m_record; |         auto record = m_record; | ||||||
|         VERIFY(record); |         VERIFY(record); | ||||||
| 
 | 
 | ||||||
|  |         // NON-STANDARD: To ensure that LibJS can find the module on the stack, we push a new execution context.
 | ||||||
|  |         auto module_execution_context = JS::ExecutionContext::create(heap()); | ||||||
|  |         module_execution_context->realm = &settings.realm(); | ||||||
|  |         module_execution_context->script_or_module = JS::NonnullGCPtr<JS::Module> { *record }; | ||||||
|  |         vm().push_execution_context(*module_execution_context); | ||||||
|  | 
 | ||||||
|         // 2. Set evaluationPromise to record.Evaluate().
 |         // 2. Set evaluationPromise to record.Evaluate().
 | ||||||
|         auto elevation_promise_or_error = record->evaluate(vm()); |         auto elevation_promise_or_error = record->evaluate(vm()); | ||||||
| 
 | 
 | ||||||
|  | @ -161,6 +167,9 @@ JS::Promise* JavaScriptModuleScript::run(PreventErrorReporting) | ||||||
|         } else { |         } else { | ||||||
|             evaluation_promise = elevation_promise_or_error.value(); |             evaluation_promise = elevation_promise_or_error.value(); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         // NON-STANDARD: Pop the execution context mentioned above.
 | ||||||
|  |         vm().pop_execution_context(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // FIXME: 7. If preventErrorReporting is false, then upon rejection of evaluationPromise with reason, report the exception given by reason for script.
 |     // FIXME: 7. If preventErrorReporting is false, then upon rejection of evaluationPromise with reason, report the exception given by reason for script.
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling