Skip to content

Commit fef6ca7

Browse files
committed
adopt new loader for microsoft#78542
1 parent 54c6639 commit fef6ca7

1 file changed

Lines changed: 54 additions & 14 deletions

File tree

src/vs/loader.js

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -709,8 +709,11 @@ var AMDLoader;
709709
var recorder = moduleManager.getRecorder();
710710
var cachedDataPath = that._getCachedDataPath(nodeCachedData, filename);
711711
var options = { filename: filename };
712+
var hashData;
712713
try {
713-
options.cachedData = that._fs.readFileSync(cachedDataPath);
714+
var data = that._fs.readFileSync(cachedDataPath);
715+
hashData = data.slice(0, 16);
716+
options.cachedData = data.slice(16);
714717
recorder.record(60 /* CachedDataFound */, cachedDataPath);
715718
}
716719
catch (_e) {
@@ -724,7 +727,8 @@ var AMDLoader;
724727
var args = [this.exports, require, this, filename, dirname, process, _commonjsGlobal, Buffer];
725728
var result = compileWrapper.apply(this.exports, args);
726729
// cached data aftermath
727-
setTimeout(function () { return that._handleCachedData(script, cachedDataPath, !options.cachedData, moduleManager); }, Math.ceil(moduleManager.getConfig().getOptionsLiteral().nodeCachedData.writeDelay * Math.random()));
730+
that._handleCachedData(script, scriptSource, cachedDataPath, !options.cachedData, moduleManager);
731+
that._verifyCachedData(script, scriptSource, cachedDataPath, hashData);
728732
return result;
729733
};
730734
};
@@ -755,7 +759,7 @@ var AMDLoader;
755759
var vmScriptPathOrUri_1 = this._getElectronRendererScriptPathOrUri(normalizedScriptSrc_1);
756760
var wantsCachedData_1 = Boolean(opts.nodeCachedData);
757761
var cachedDataPath_1 = wantsCachedData_1 ? this._getCachedDataPath(opts.nodeCachedData, scriptSrc) : undefined;
758-
this._readSourceAndCachedData(normalizedScriptSrc_1, cachedDataPath_1, recorder, function (err, data, cachedData) {
762+
this._readSourceAndCachedData(normalizedScriptSrc_1, cachedDataPath_1, recorder, function (err, data, cachedData, hashData) {
759763
if (err) {
760764
errorback(err);
761765
return;
@@ -770,7 +774,8 @@ var AMDLoader;
770774
scriptSource = nodeInstrumenter(scriptSource, normalizedScriptSrc_1);
771775
var scriptOpts = { filename: vmScriptPathOrUri_1, cachedData: cachedData };
772776
var script = _this._createAndEvalScript(moduleManager, scriptSource, scriptOpts, callback, errorback);
773-
_this._handleCachedData(script, cachedDataPath_1, wantsCachedData_1 && !cachedData, moduleManager);
777+
_this._handleCachedData(script, scriptSource, cachedDataPath_1, wantsCachedData_1 && !cachedData, moduleManager);
778+
_this._verifyCachedData(script, scriptSource, cachedDataPath_1, hashData);
774779
});
775780
}
776781
};
@@ -815,36 +820,43 @@ var AMDLoader;
815820
var basename = this._path.basename(filename).replace(/\.js$/, '');
816821
return this._path.join(config.path, basename + "-" + hash + ".code");
817822
};
818-
NodeScriptLoader.prototype._handleCachedData = function (script, cachedDataPath, createCachedData, moduleManager) {
823+
NodeScriptLoader.prototype._handleCachedData = function (script, scriptSource, cachedDataPath, createCachedData, moduleManager) {
819824
var _this = this;
820825
if (script.cachedDataRejected) {
821826
// cached data got rejected -> delete and re-create
822827
this._fs.unlink(cachedDataPath, function (err) {
823828
moduleManager.getRecorder().record(62 /* CachedDataRejected */, cachedDataPath);
824-
_this._createAndWriteCachedData(script, cachedDataPath, moduleManager);
829+
_this._createAndWriteCachedData(script, scriptSource, cachedDataPath, moduleManager);
825830
if (err) {
826831
moduleManager.getConfig().onError(err);
827832
}
828833
});
829834
}
830835
else if (createCachedData) {
831836
// no cached data, but wanted
832-
this._createAndWriteCachedData(script, cachedDataPath, moduleManager);
837+
this._createAndWriteCachedData(script, scriptSource, cachedDataPath, moduleManager);
833838
}
834839
};
835-
NodeScriptLoader.prototype._createAndWriteCachedData = function (script, cachedDataPath, moduleManager) {
840+
// Cached data format: | SOURCE_HASH | V8_CACHED_DATA |
841+
// -SOURCE_HASH is the md5 hash of the JS source (always 16 bytes)
842+
// -V8_CACHED_DATA is what v8 produces
843+
NodeScriptLoader.prototype._createAndWriteCachedData = function (script, scriptSource, cachedDataPath, moduleManager) {
836844
var _this = this;
837845
var timeout = Math.ceil(moduleManager.getConfig().getOptionsLiteral().nodeCachedData.writeDelay * (1 + Math.random()));
838846
var lastSize = -1;
839847
var iteration = 0;
848+
var hashData = undefined;
840849
var createLoop = function () {
841850
setTimeout(function () {
851+
if (!hashData) {
852+
hashData = _this._crypto.createHash('md5').update(scriptSource, 'utf8').digest();
853+
}
842854
var cachedData = script.createCachedData();
843855
if (cachedData.length === 0 || cachedData.length === lastSize || iteration >= 5) {
844856
return;
845857
}
846858
lastSize = cachedData.length;
847-
_this._fs.writeFile(cachedDataPath, cachedData, function (err) {
859+
_this._fs.writeFile(cachedDataPath, Buffer.concat([hashData, cachedData]), function (err) {
848860
if (err) {
849861
moduleManager.getConfig().onError(err);
850862
}
@@ -865,28 +877,56 @@ var AMDLoader;
865877
}
866878
else {
867879
// cached data case: read both files in parallel
868-
var source_1;
869-
var cachedData_1;
880+
var source_1 = undefined;
881+
var cachedData_1 = undefined;
882+
var hashData_1 = undefined;
870883
var steps_1 = 2;
871884
var step_1 = function (err) {
872885
if (err) {
873886
callback(err);
874887
}
875888
else if (--steps_1 === 0) {
876-
callback(undefined, source_1, cachedData_1);
889+
callback(undefined, source_1, cachedData_1, hashData_1);
877890
}
878891
};
879892
this._fs.readFile(sourcePath, { encoding: 'utf8' }, function (err, data) {
880893
source_1 = data;
881894
step_1(err);
882895
});
883896
this._fs.readFile(cachedDataPath, function (err, data) {
884-
cachedData_1 = data && data.length > 0 ? data : undefined;
897+
if (!err && data && data.length > 0) {
898+
hashData_1 = data.slice(0, 16);
899+
cachedData_1 = data.slice(16);
900+
recorder.record(60 /* CachedDataFound */, cachedDataPath);
901+
}
902+
else {
903+
recorder.record(61 /* CachedDataMissed */, cachedDataPath);
904+
}
885905
step_1(); // ignored: cached data is optional
886-
recorder.record(err ? 61 /* CachedDataMissed */ : 60 /* CachedDataFound */, cachedDataPath);
887906
});
888907
}
889908
};
909+
NodeScriptLoader.prototype._verifyCachedData = function (script, scriptSource, cachedDataPath, hashData) {
910+
var _this = this;
911+
if (!hashData) {
912+
// nothing to do
913+
return;
914+
}
915+
if (script.cachedDataRejected) {
916+
// invalid anyways
917+
return;
918+
}
919+
setTimeout(function () {
920+
// check source hash - the contract is that file paths change when file content
921+
// change (e.g use the commit or version id as cache path). this check is
922+
// for violations of this contract.
923+
var hashDataNow = _this._crypto.createHash('md5').update(scriptSource, 'utf8').digest();
924+
if (!hashData.equals(hashDataNow)) {
925+
console.warn("FAILED TO VERIFY CACHED DATA. Deleting '" + cachedDataPath + "' now, but a RESTART IS REQUIRED");
926+
_this._fs.unlink(cachedDataPath, function (err) { return console.error("FAILED to unlink: '" + cachedDataPath + "'", err); });
927+
}
928+
}, Math.ceil(5000 * (1 + Math.random())));
929+
};
890930
NodeScriptLoader._BOM = 0xFEFF;
891931
NodeScriptLoader._PREFIX = '(function (require, define, __filename, __dirname) { ';
892932
NodeScriptLoader._SUFFIX = '\n});';

0 commit comments

Comments
 (0)