Skip to content

Commit 19caf5d

Browse files
committed
esm: improve getFormatOfExtensionlessFile perf.
1 parent 7b624c3 commit 19caf5d

File tree

6 files changed

+76
-18
lines changed

6 files changed

+76
-18
lines changed

lib/internal/modules/esm/formats.js

+11-18
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
'use strict';
22

3-
const {
4-
RegExpPrototypeExec,
5-
Uint8Array,
6-
} = primordials;
3+
const { RegExpPrototypeExec } = primordials;
74
const { getOptionValue } = require('internal/options');
8-
9-
const { closeSync, openSync, readSync } = require('fs');
5+
const { getValidatedPath } = require('internal/fs/utils');
6+
const pathModule = require('path');
7+
const fsBindings = internalBinding('fs');
8+
const { fs: fsConstants } = internalBinding('constants');
109

1110
const experimentalWasmModules = getOptionValue('--experimental-wasm-modules');
1211

@@ -47,20 +46,14 @@ function mimeToFormat(mime) {
4746
function getFormatOfExtensionlessFile(url) {
4847
if (!experimentalWasmModules) { return 'module'; }
4948

50-
const magic = new Uint8Array(4);
51-
let fd;
52-
try {
53-
// TODO(@anonrig): Optimize the following by having a single C++ call
54-
fd = openSync(url);
55-
readSync(fd, magic, 0, 4); // Only read the first four bytes
56-
if (magic[0] === 0x00 && magic[1] === 0x61 && magic[2] === 0x73 && magic[3] === 0x6d) {
49+
const path = pathModule.toNamespacedPath(getValidatedPath(url));
50+
51+
switch (fsBindings.getFormatOfExtensionlessFile(path)) {
52+
case fsConstants.EXTENSIONLESS_FORMAT_WASM:
5753
return 'wasm';
58-
}
59-
} finally {
60-
if (fd !== undefined) { closeSync(fd); }
54+
default:
55+
return 'module';
6156
}
62-
63-
return 'module';
6457
}
6558

6659
module.exports = {

src/node_constants.cc

+4
Original file line numberDiff line numberDiff line change
@@ -1058,6 +1058,10 @@ void DefineSystemConstants(Local<Object> target) {
10581058
NODE_DEFINE_CONSTANT(target, UV_DIRENT_CHAR);
10591059
NODE_DEFINE_CONSTANT(target, UV_DIRENT_BLOCK);
10601060

1061+
// Define module specific constants
1062+
NODE_DEFINE_CONSTANT(target, EXTENSIONLESS_FORMAT_JAVASCRIPT);
1063+
NODE_DEFINE_CONSTANT(target, EXTENSIONLESS_FORMAT_WASM);
1064+
10611065
NODE_DEFINE_CONSTANT(target, S_IFMT);
10621066
NODE_DEFINE_CONSTANT(target, S_IFREG);
10631067
NODE_DEFINE_CONSTANT(target, S_IFDIR);

src/node_constants.h

+3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
#include "node.h"
2828
#include "v8.h"
2929

30+
#define EXTENSIONLESS_FORMAT_JAVASCRIPT (0)
31+
#define EXTENSIONLESS_FORMAT_WASM (1)
32+
3033
#if HAVE_OPENSSL
3134

3235
#ifndef RSA_PSS_SALTLEN_DIGEST

src/node_file.cc

+50
Original file line numberDiff line numberDiff line change
@@ -2978,6 +2978,51 @@ static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
29782978
}
29792979
}
29802980

2981+
static void GetFormatOfExtensionlessFile(
2982+
const FunctionCallbackInfo<Value>& args) {
2983+
CHECK_EQ(args.Length(), 1);
2984+
CHECK(args[0]->IsString());
2985+
2986+
Environment* env = Environment::GetCurrent(args);
2987+
node::Utf8Value input(args.GetIsolate(), args[0]);
2988+
2989+
THROW_IF_INSUFFICIENT_PERMISSIONS(
2990+
env, permission::PermissionScope::kFileSystemRead, input.ToStringView());
2991+
2992+
uv_fs_t req;
2993+
FS_SYNC_TRACE_BEGIN(open)
2994+
uv_file file = uv_fs_open(nullptr, &req, input.out(), O_RDONLY, 0, nullptr);
2995+
FS_SYNC_TRACE_END(open);
2996+
2997+
if (req.result < 0) {
2998+
return args.GetReturnValue().Set(EXTENSIONLESS_FORMAT_JAVASCRIPT);
2999+
}
3000+
3001+
auto cleanup = OnScopeLeave([&req, &file]() {
3002+
FS_SYNC_TRACE_BEGIN(close);
3003+
CHECK_EQ(0, uv_fs_close(nullptr, &req, file, nullptr));
3004+
FS_SYNC_TRACE_END(close);
3005+
uv_fs_req_cleanup(&req);
3006+
});
3007+
3008+
char buffer[4];
3009+
uv_buf_t buf = uv_buf_init(buffer, sizeof(buffer));
3010+
int err = uv_fs_read(nullptr, &req, file, &buf, 1, 0, nullptr);
3011+
3012+
if (err < 0) {
3013+
return args.GetReturnValue().Set(EXTENSIONLESS_FORMAT_JAVASCRIPT);
3014+
}
3015+
3016+
// We do this by taking advantage of the fact that all Wasm files start with
3017+
// the header `0x00 0x61 0x73 0x6d`
3018+
if (buffer[0] == 0x00 && buffer[1] == 0x61 && buffer[2] == 0x73 &&
3019+
buffer[3] == 0x6d) {
3020+
return args.GetReturnValue().Set(EXTENSIONLESS_FORMAT_WASM);
3021+
}
3022+
3023+
return args.GetReturnValue().Set(EXTENSIONLESS_FORMAT_JAVASCRIPT);
3024+
}
3025+
29813026
static bool FileURLToPath(
29823027
Environment* env,
29833028
const ada::url_aggregator& file_url,
@@ -3390,6 +3435,10 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data,
33903435
Local<ObjectTemplate> target) {
33913436
Isolate* isolate = isolate_data->isolate();
33923437

3438+
SetMethod(isolate,
3439+
target,
3440+
"getFormatOfExtensionlessFile",
3441+
GetFormatOfExtensionlessFile);
33933442
SetMethod(isolate, target, "access", Access);
33943443
SetMethod(isolate, target, "accessSync", AccessSync);
33953444
SetMethod(isolate, target, "close", Close);
@@ -3518,6 +3567,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
35183567
StatWatcher::RegisterExternalReferences(registry);
35193568
BindingData::RegisterExternalReferences(registry);
35203569

3570+
registry->Register(GetFormatOfExtensionlessFile);
35213571
registry->Register(Close);
35223572
registry->Register(CloseSync);
35233573
registry->Register(ExistsSync);

typings/internalBinding/constants.d.ts

+2
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ export interface ConstantsBinding {
186186
COPYFILE_FICLONE: 2;
187187
UV_FS_COPYFILE_FICLONE_FORCE: 4;
188188
COPYFILE_FICLONE_FORCE: 4;
189+
EXTENSIONLESS_FORMAT_JAVASCRIPT: 0,
190+
EXTENSIONLESS_FORMAT_WASM: 1,
189191
};
190192
crypto: {
191193
OPENSSL_VERSION_NUMBER: 269488319;

typings/internalBinding/fs.d.ts

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { ConstantsBinding } from './constants';
2+
13
declare namespace InternalFSBinding {
24
class FSReqCallback<ResultType = unknown> {
35
constructor(bigint?: boolean);
@@ -218,6 +220,8 @@ declare namespace InternalFSBinding {
218220
function writeString(fd: number, value: string, pos: unknown, encoding: unknown, req: FSReqCallback<number>): void;
219221
function writeString(fd: number, value: string, pos: unknown, encoding: unknown, req: undefined, ctx: FSSyncContext): number;
220222
function writeString(fd: number, value: string, pos: unknown, encoding: unknown, usePromises: typeof kUsePromises): Promise<number>;
223+
224+
function getFormatOfExtensionlessFile(url: string): ConstantsBinding['fs'];
221225
}
222226

223227
export interface FsBinding {
@@ -269,4 +273,6 @@ export interface FsBinding {
269273
writeBuffer: typeof InternalFSBinding.writeBuffer;
270274
writeBuffers: typeof InternalFSBinding.writeBuffers;
271275
writeString: typeof InternalFSBinding.writeString;
276+
277+
getFormatOfExtensionlessFile: typeof InternalFSBinding.getFormatOfExtensionlessFile;
272278
}

0 commit comments

Comments
 (0)