History

Fixed incorrect Script.require behavior

Karol Suprynowicz committed 3 years ago

Commit 209f1d51 parent 1f2a9871 file · +68 −0Browse files

Showing the changes to libraries/script-engine/src/v8/ScriptEngineV8.cpp (1 of 1 file). Show all

Unified · Split

libraries/script-engine/src/v8/ScriptEngineV8.cpp+68−0
@@ -625,6 +625,9 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure, · 624 unmodified lines
625 qCDebug(shared) << QString("[%1] evaluateInClosure %2").arg(isEvaluating()).arg(shortName);625 qCDebug(shared) << QString("[%1] evaluateInClosure %2").arg(isEvaluating()).arg(shortName);
626#endif626#endif
627 {627 {
628 ScriptContextV8Wrapper scriptContext(this, getContext(), currentContext()->parentContext());
629 ScriptContextGuard scriptContextGuard(&scriptContext);
630
628 v8::TryCatch tryCatch(getIsolate());631 v8::TryCatch tryCatch(getIsolate());
629 // Since V8 cannot use arbitrary object as global object, objects from main global need to be copied to closure's global object632 // Since V8 cannot use arbitrary object as global object, objects from main global need to be copied to closure's global object
630 auto globalObjectContents = _globalObjectContents.Get(_v8Isolate);633 auto globalObjectContents = _globalObjectContents.Get(_v8Isolate);
@@ -649,12 +652,77 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure, · 18 unmodified lines
649 // "Script" API is context-dependent, so it needs to be recreated for each new context652 // "Script" API is context-dependent, so it needs to be recreated for each new context
650 registerGlobalObject("Script", new ScriptManagerScriptingInterface(_manager), ScriptEngine::ScriptOwnership);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 auto maybeResult = program.constGet()->GetUnboundScript()->BindToCurrentContext()->Run(closureContext);719 auto maybeResult = program.constGet()->GetUnboundScript()->BindToCurrentContext()->Run(closureContext);
653 v8::Local<v8::Value> v8Result;720 v8::Local<v8::Value> v8Result;
654 if (!maybeResult.ToLocal(&v8Result)) {721 if (!maybeResult.ToLocal(&v8Result)) {
655 v8::String::Utf8Value utf8Value(getIsolate(), tryCatch.Exception());722 v8::String::Utf8Value utf8Value(getIsolate(), tryCatch.Exception());
656 QString errorMessage = QString(__FUNCTION__) + " hasCaught:" + QString(*utf8Value) + "\n"723 QString errorMessage = QString(__FUNCTION__) + " hasCaught:" + QString(*utf8Value) + "\n"
657 + "tryCatch details:" + formatErrorMessageFromTryCatch(tryCatch);724 + "tryCatch details:" + formatErrorMessageFromTryCatch(tryCatch);
725 v8Result = v8::Null(_v8Isolate);
658 if (_manager) {726 if (_manager) {
659 _manager->scriptErrorMessage(errorMessage);727 _manager->scriptErrorMessage(errorMessage);
660 } else {728 } else {