aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/corelib/buildgraph/artifactsscriptvalue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/corelib/buildgraph/artifactsscriptvalue.cpp')
-rw-r--r--src/lib/corelib/buildgraph/artifactsscriptvalue.cpp257
1 files changed, 132 insertions, 125 deletions
diff --git a/src/lib/corelib/buildgraph/artifactsscriptvalue.cpp b/src/lib/corelib/buildgraph/artifactsscriptvalue.cpp
index 2adb77d47..6d0ea738f 100644
--- a/src/lib/corelib/buildgraph/artifactsscriptvalue.cpp
+++ b/src/lib/corelib/buildgraph/artifactsscriptvalue.cpp
@@ -45,171 +45,178 @@
#include <language/language.h>
#include <language/scriptengine.h>
-#include <QtScript/qscriptclass.h>
-#include <QtScript/qscriptcontext.h>
+#include <tools/stlutils.h>
+#include <tools/stringconstants.h>
namespace qbs {
namespace Internal {
-enum BuildGraphScriptValueCommonPropertyKeys : quint32 {
- CachedValueKey,
- FileTagKey,
- ProductPtrKey,
-};
-
-class ArtifactsScriptClass : public QScriptClass
+template<class ProductOrModule>
+static bool isRelevantArtifact(const ProductOrModule *productOrModule, const Artifact *artifact)
{
-public:
- ArtifactsScriptClass(QScriptEngine *engine) : QScriptClass(engine) { }
-
-private:
- QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name,
- QueryFlags flags, uint *id) override
- {
- getProduct(object);
- qbsEngine()->setNonExistingArtifactSetRequested(m_product, name.toString());
- return QScriptClass::queryProperty(object, name, flags, id);
- }
-
- QScriptClassPropertyIterator *newIterator(const QScriptValue &object) override
- {
- getProduct(object);
- qbsEngine()->setArtifactsEnumerated(m_product);
- return QScriptClass::newIterator(object);
+ if constexpr (std::is_same_v<ProductOrModule, ResolvedProduct>) {
+ Q_UNUSED(productOrModule)
+ return !artifact->isTargetOfModule();
+ } else {
+ return artifact->targetOfModule == productOrModule->name;
}
-
- void getProduct(const QScriptValue &object)
- {
- if (m_lastObjectId != object.objectId()) {
- m_lastObjectId = object.objectId();
- m_product = reinterpret_cast<const ResolvedProduct *>(
- object.data().property(ProductPtrKey).toVariant().value<quintptr>());
- }
- }
-
- ScriptEngine *qbsEngine() const { return static_cast<ScriptEngine *>(engine()); }
-
- qint64 m_lastObjectId = 0;
- const ResolvedProduct *m_product = nullptr;
-};
-
-static bool isRelevantArtifact(const ResolvedProduct *, const Artifact *artifact)
-{
- return !artifact->isTargetOfModule();
-}
-static bool isRelevantArtifact(const ResolvedModule *module, const Artifact *artifact)
-{
- return artifact->targetOfModule == module->name;
}
-static ArtifactSetByFileTag artifactsMap(const ResolvedProduct *product)
+template<class ProductOrModule>
+static ArtifactSetByFileTag artifactsMap(const ProductOrModule *productOrModule)
{
- return product->buildData->artifactsByFileTag();
+ if constexpr (std::is_same_v<ProductOrModule, ResolvedProduct>)
+ return productOrModule->buildData->artifactsByFileTag();
+ else
+ return artifactsMap(productOrModule->product);
}
-static ArtifactSetByFileTag artifactsMap(const ResolvedModule *module)
+template<class ProductOrModule> static int scriptClassIndex()
{
- return artifactsMap(module->product);
+ if constexpr (std::is_same_v<ProductOrModule, ResolvedProduct>)
+ return 0;
+ return 1;
}
-static QScriptValue createArtifactsObject(const ResolvedProduct *product, ScriptEngine *engine)
+template<class ProductOrModule>
+std::unique_lock<std::mutex> getArtifactsMapLock(ProductOrModule *productOrModule)
{
- QScriptClass *scriptClass = engine->artifactsScriptClass();
- if (!scriptClass) {
- scriptClass = new ArtifactsScriptClass(engine);
- engine->setArtifactsScriptClass(scriptClass);
- }
- QScriptValue artifactsObj = engine->newObject(scriptClass);
- QScriptValue data = engine->newObject();
- QVariant v;
- v.setValue<quintptr>(reinterpret_cast<quintptr>(product));
- data.setProperty(ProductPtrKey, engine->newVariant(v));
- artifactsObj.setData(data);
- return artifactsObj;
+ if constexpr (std::is_same_v<ProductOrModule, ResolvedProduct>)
+ return productOrModule->buildData->getArtifactsMapLock();
+ else
+ return getArtifactsMapLock(productOrModule->product);
}
-static QScriptValue createArtifactsObject(const ResolvedModule *, ScriptEngine *engine)
+template<class ProductOrModule>
+static bool checkAndSetArtifactsMapUpToDateFlag(const ProductOrModule *productOrModule)
{
- return engine->newObject();
+ if constexpr (std::is_same_v<ProductOrModule, ResolvedProduct>)
+ return productOrModule->buildData->checkAndSetJsArtifactsMapUpToDateFlag();
+ else
+ return checkAndSetArtifactsMapUpToDateFlag(productOrModule->product);
}
-static bool checkAndSetArtifactsMapUpToDateFlag(const ResolvedProduct *p)
+// Must be called with artifacts map lock held!
+template<class ProductOrModule>
+void registerArtifactsMapAccess(ScriptEngine *engine, ProductOrModule *productOrModule)
{
- return p->buildData->checkAndSetJsArtifactsMapUpToDateFlag();
+ if constexpr (std::is_same_v<ProductOrModule, ResolvedProduct>) {
+ if (!checkAndSetArtifactsMapUpToDateFlag(productOrModule))
+ engine->setArtifactsMapRequested(productOrModule, true);
+ else
+ engine->setArtifactsMapRequested(productOrModule, false);
+ } else {
+ registerArtifactsMapAccess(engine, productOrModule->product);
+ }
}
-static bool checkAndSetArtifactsMapUpToDateFlag(const ResolvedModule *) { return true; }
-static void registerArtifactsMapAccess(const ResolvedProduct *p, ScriptEngine *e, bool forceUpdate)
-{
- e->setArtifactsMapRequested(p, forceUpdate);
-}
-static void registerArtifactsMapAccess(const ResolvedModule *, ScriptEngine *, bool) {}
-static void registerArtifactsSetAccess(const ResolvedProduct *p, const FileTag &t, ScriptEngine *e)
+template<class ProductOrModule>
+static int getArtifactsPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, uint32_t *plen,
+ JSValueConst obj)
{
- e->setArtifactSetRequestedForTag(p, t);
+ ScriptEngine * const engine = ScriptEngine::engineForContext(ctx);
+ const auto productOrModule = attachedPointer<ProductOrModule>(
+ obj, engine->artifactsScriptClass(scriptClassIndex<ProductOrModule>()));
+ const std::unique_lock lock = getArtifactsMapLock(productOrModule);
+ registerArtifactsMapAccess(engine, productOrModule);
+ if constexpr (std::is_same_v<ProductOrModule, ResolvedProduct>)
+ engine->setArtifactsEnumerated(productOrModule);
+ const auto &map = artifactsMap(productOrModule);
+ const auto filter = [productOrModule](const Artifact *a) {
+ return isRelevantArtifact(productOrModule, a);
+ };
+ QStringList tags;
+ for (auto it = map.cbegin(); it != map.cend(); ++it) {
+ if (any_of(it.value(), filter)) {
+ tags << it.key().toString();
+ }
+ }
+ *plen = tags.size();
+ if (!tags.isEmpty()) {
+ *ptab = reinterpret_cast<JSPropertyEnum *>(js_malloc(ctx, *plen * sizeof **ptab));
+ JSPropertyEnum *entry = *ptab;
+ for (const QString &tag : std::as_const(tags)) {
+ entry->atom = JS_NewAtom(ctx, tag.toUtf8().constData());
+ entry->is_enumerable = 1;
+ ++entry;
+ }
+ } else {
+ *ptab = nullptr;
+ }
+ return 0;
}
-static void registerArtifactsSetAccess(const ResolvedModule *, const FileTag &, ScriptEngine *) {}
-template<class ProductOrModule> static QScriptValue js_artifactsForFileTag(
- QScriptContext *ctx, ScriptEngine *engine, const ProductOrModule *productOrModule)
+template<class ProductOrModule>
+static int getArtifactsProperty(JSContext *ctx, JSPropertyDescriptor *desc,
+ JSValueConst obj, JSAtom prop)
{
- const FileTag fileTag = FileTag(ctx->callee().property(FileTagKey).toString().toUtf8());
- registerArtifactsSetAccess(productOrModule, fileTag, engine);
- QScriptValue result = ctx->callee().property(CachedValueKey);
- if (result.isArray())
- return result;
- auto artifacts = artifactsMap(productOrModule).value(fileTag);
- const auto filter = [productOrModule](const Artifact *a) {
+ if (!desc)
+ return 1;
+
+ desc->flags = JS_PROP_ENUMERABLE;
+ desc->value = desc->getter = desc->setter = JS_UNDEFINED;
+ ScriptEngine * const engine = ScriptEngine::engineForContext(ctx);
+ const auto productOrModule = attachedPointer<ProductOrModule>(
+ obj, engine->artifactsScriptClass(scriptClassIndex<ProductOrModule>()));
+ const std::unique_lock lock = getArtifactsMapLock(productOrModule);
+ registerArtifactsMapAccess(engine, productOrModule);
+ const QString tagString = getJsString(ctx, prop);
+ const FileTag fileTag(tagString.toUtf8());
+ const auto &map = artifactsMap(productOrModule);
+ const auto it = map.constFind(fileTag);
+ if (it == map.constEnd()) {
+ if constexpr (std::is_same_v<ProductOrModule, ResolvedProduct>)
+ engine->setNonExistingArtifactSetRequested(productOrModule, tagString);
+ return 1;
+ }
+ if constexpr (std::is_same_v<ProductOrModule, ResolvedProduct>)
+ engine->setArtifactSetRequestedForTag(productOrModule, fileTag);
+ ArtifactSet artifacts = it.value();
+ removeIf(artifacts, [productOrModule](const Artifact *a) {
return !isRelevantArtifact(productOrModule, a);
- };
- artifacts.erase(std::remove_if(artifacts.begin(), artifacts.end(), filter), artifacts.end());
- result = engine->newArray(uint(artifacts.size()));
- ctx->callee().setProperty(CachedValueKey, result);
- int k = 0;
- for (const Artifact * const artifact : artifacts)
- result.setProperty(k++, Transformer::translateFileConfig(engine, artifact, QString()));
- return result;
+ });
+ if (!artifacts.empty()) {
+ desc->value = JS_NewArray(ctx); // TODO: Also cache this list?
+ int k = 0;
+ for (Artifact * const artifact : artifacts) {
+ JS_SetPropertyUint32(ctx, desc->value, k++,
+ Transformer::translateFileConfig(engine, artifact, QString()));
+ }
+ }
+ return 1;
}
-template<class ProductOrModule> static QScriptValue js_artifacts(
- QScriptContext *ctx, ScriptEngine *engine, const ProductOrModule *productOrModule)
+template<class ProductOrModule> static JSValue js_artifacts(JSContext *ctx,
+ JSValue jsProductOrModule)
{
- QScriptValue artifactsObj = ctx->callee().property(CachedValueKey);
- if (artifactsObj.isObject() && checkAndSetArtifactsMapUpToDateFlag(productOrModule)) {
- registerArtifactsMapAccess(productOrModule, engine, false);
+ ScriptEngine * const engine = ScriptEngine::engineForContext(ctx);
+ const auto productOrModule = attachedPointer<ProductOrModule>(jsProductOrModule,
+ engine->dataWithPtrClass());
+ JSValue artifactsObj = engine->artifactsMapScriptValue(productOrModule);
+ if (!JS_IsUndefined(artifactsObj))
return artifactsObj;
+ const int classIndex = scriptClassIndex<ProductOrModule>();
+ JSClassID scriptClass = engine->artifactsScriptClass(classIndex);
+ if (scriptClass == 0) {
+ const QByteArray className = "ArtifactsScriptClass" + QByteArray::number(classIndex);
+ scriptClass = engine->registerClass(className.constData(), nullptr, nullptr, JS_UNDEFINED,
+ &getArtifactsPropertyNames<ProductOrModule>,
+ &getArtifactsProperty<ProductOrModule>);
+ engine->setArtifactsScriptClass(classIndex, scriptClass);
}
- registerArtifactsMapAccess(productOrModule, engine, true);
- artifactsObj = createArtifactsObject(productOrModule, engine);
- ctx->callee().setProperty(CachedValueKey, artifactsObj);
- const auto &map = artifactsMap(productOrModule);
- for (auto it = map.cbegin(); it != map.cend(); ++it) {
- const auto filter = [productOrModule](const Artifact *a) {
- return isRelevantArtifact(productOrModule, a);
- };
- if (std::none_of(it.value().cbegin(), it.value().cend(), filter))
- continue;
- QScriptValue fileTagFunc = engine->newFunction(&js_artifactsForFileTag<ProductOrModule>,
- productOrModule);
- const QString fileTag = it.key().toString();
- fileTagFunc.setProperty(FileTagKey, fileTag);
- artifactsObj.setProperty(fileTag, fileTagFunc,
- QScriptValue::ReadOnly | QScriptValue::Undeletable
- | QScriptValue::PropertyGetter);
- }
+ artifactsObj = JS_NewObjectClass(engine->context(), scriptClass);
+ attachPointerTo(artifactsObj, productOrModule);
return artifactsObj;
}
-QScriptValue artifactsScriptValueForProduct(QScriptContext *ctx, ScriptEngine *engine,
- const ResolvedProduct *product)
+JSValue artifactsScriptValueForProduct(JSContext *ctx, JSValue this_val, int, JSValue *)
{
- return js_artifacts(ctx, engine, product);
+ return js_artifacts<ResolvedProduct>(ctx, this_val);
}
-QScriptValue artifactsScriptValueForModule(QScriptContext *ctx, ScriptEngine *engine,
- const ResolvedModule *module)
+JSValue artifactsScriptValueForModule(JSContext *ctx, JSValueConst this_val, int, JSValueConst *)
{
- return js_artifacts(ctx, engine, module);
+ return js_artifacts<ResolvedModule>(ctx, this_val);
}
} // namespace Internal