Showing the changes to libraries/script-engine/src/v8/ScriptEngineV8.cpp (1 of 1 file). Show all
Unified · Split
| @@ -625,6 +625,9 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure, · 624 unmodified lines | ||
| 625 | 625 | qCDebug(shared) << QString("[%1] evaluateInClosure %2").arg(isEvaluating()).arg(shortName); |
| 626 | 626 | #endif |
| 627 | 627 | { |
| 628 | + ScriptContextV8Wrapper scriptContext(this, getContext(), currentContext()->parentContext()); | |
| 629 | + ScriptContextGuard scriptContextGuard(&scriptContext); | |
| 630 | + | |
| 628 | 631 | v8::TryCatch tryCatch(getIsolate()); |
| 629 | 632 | // Since V8 cannot use arbitrary object as global object, objects from main global need to be copied to closure's global object |
| 630 | 633 | auto globalObjectContents = _globalObjectContents.Get(_v8Isolate); |
| @@ -649,12 +652,77 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure, · 18 unmodified lines | ||
| 649 | 652 | // "Script" API is context-dependent, so it needs to be recreated for each new context |
| 650 | 653 | registerGlobalObject("Script", new ScriptManagerScriptingInterface(_manager), ScriptEngine::ScriptOwnership); |
| 651 | 654 | |
| 655 | + // Script.require properties need to be copied, since that's where the Script.require cache is | |
| 656 | + // Get source and destination Script.require objects | |
| 657 | + try { | |
| 658 | + v8::Local<v8::Value> oldScriptObjectValue; | |
| 659 | + if (!globalObjectContents | |
| 660 | + ->Get(closureContext, v8::String::NewFromUtf8(_v8Isolate, "Script").ToLocalChecked()) | |
| 661 | + .ToLocal(&oldScriptObjectValue)) { | |
| 662 | + throw(QString("evaluateInClosure: Script API object does not exist in calling script")); | |
| 663 | + } | |
| 664 | + if (!oldScriptObjectValue->IsObject()) { | |
| 665 | + throw(QString("evaluateInClosure: Script API object invalid in calling script")); | |
| 666 | + } | |
| 667 | + v8::Local<v8::Object> oldScriptObject = v8::Local<v8::Object>::Cast(oldScriptObjectValue); | |
| 668 | + | |
| 669 | + v8::Local<v8::Value> oldRequireObjectValue; | |
| 670 | + if (!oldScriptObject->Get(closureContext, v8::String::NewFromUtf8(_v8Isolate, "require").ToLocalChecked()) | |
| 671 | + .ToLocal(&oldRequireObjectValue)) { | |
| 672 | + throw(QString("evaluateInClosure: Script.require API object does not exist in calling script")); | |
| 673 | + } | |
| 674 | + if (!oldRequireObjectValue->IsObject()) { | |
| 675 | + throw(QString("evaluateInClosure: Script.require API object invalid in calling script")); | |
| 676 | + } | |
| 677 | + v8::Local<v8::Object> oldRequireObject = v8::Local<v8::Object>::Cast(oldRequireObjectValue); | |
| 678 | + | |
| 679 | + v8::Local<v8::Value> newScriptObjectValue; | |
| 680 | + if (!closureContext->Global() | |
| 681 | + ->Get(closureContext, v8::String::NewFromUtf8(_v8Isolate, "Script").ToLocalChecked()) | |
| 682 | + .ToLocal(&newScriptObjectValue)) { | |
| 683 | + Q_ASSERT(false); // This should never happen | |
| 684 | + } | |
| 685 | + if (!newScriptObjectValue->IsObject()) { | |
| 686 | + Q_ASSERT(false); // This should never happen | |
| 687 | + } | |
| 688 | + v8::Local<v8::Object> newScriptObject = v8::Local<v8::Object>::Cast(newScriptObjectValue); | |
| 689 | + | |
| 690 | + v8::Local<v8::Value> newRequireObjectValue; | |
| 691 | + if (!newScriptObject->Get(closureContext, v8::String::NewFromUtf8(_v8Isolate, "require").ToLocalChecked()) | |
| 692 | + .ToLocal(&newRequireObjectValue)) { | |
| 693 | + Q_ASSERT(false); // This should never happen | |
| 694 | + } | |
| 695 | + if (!newRequireObjectValue->IsObject()) { | |
| 696 | + Q_ASSERT(false); // This should never happen | |
| 697 | + } | |
| 698 | + v8::Local<v8::Object> newRequireObject = v8::Local<v8::Object>::Cast(newRequireObjectValue); | |
| 699 | + | |
| 700 | + auto requireMemberNames = | |
| 701 | + oldRequireObject->GetPropertyNames(oldRequireObject->CreationContext()).ToLocalChecked(); | |
| 702 | + for (size_t i = 0; i < requireMemberNames->Length(); i++) { | |
| 703 | + auto name = requireMemberNames->Get(closureContext, i).ToLocalChecked(); | |
| 704 | + v8::Local<v8::Value> oldObject; | |
| 705 | + if (!oldRequireObject->Get(oldRequireObject->CreationContext(), name).ToLocal(&oldObject)) { | |
| 706 | + Q_ASSERT(false); // This should never happen, the property has been reported as existing | |
| 707 | + } | |
| 708 | + if (!newRequireObject->Set(closureContext, name,oldObject).FromMaybe(false)) { | |
| 709 | + Q_ASSERT(false); | |
| 710 | + } | |
| 711 | + } | |
| 712 | + } catch (QString exception) { | |
| 713 | + raiseException(exception); | |
| 714 | + popContext(); | |
| 715 | + _evaluatingCounter--; | |
| 716 | + return nullValue(); | |
| 717 | + } | |
| 718 | + | |
| 652 | 719 | auto maybeResult = program.constGet()->GetUnboundScript()->BindToCurrentContext()->Run(closureContext); |
| 653 | 720 | v8::Local<v8::Value> v8Result; |
| 654 | 721 | if (!maybeResult.ToLocal(&v8Result)) { |
| 655 | 722 | v8::String::Utf8Value utf8Value(getIsolate(), tryCatch.Exception()); |
| 656 | 723 | QString errorMessage = QString(__FUNCTION__) + " hasCaught:" + QString(*utf8Value) + "\n" |
| 657 | 724 | + "tryCatch details:" + formatErrorMessageFromTryCatch(tryCatch); |
| 725 | + v8Result = v8::Null(_v8Isolate); | |
| 658 | 726 | if (_manager) { |
| 659 | 727 | _manager->scriptErrorMessage(errorMessage); |
| 660 | 728 | } else { |