From cb32b98f584cb8a7c550119bc8bb7a21984546ba Mon Sep 17 00:00:00 2001 From: Tyler Rockwood Date: Thu, 6 Aug 2026 11:38:58 -0500 Subject: [PATCH] firestore: only pay `.stack` cost in error paths `.stack` is relatively expensive to compute and currently every RPC in Firestore captures the stack, although it's only used in the error cases. We can improve the performance in V8 by deferring source map resolution to only error cases. --- handwritten/firestore/dev/src/bulk-writer.ts | 4 ++-- handwritten/firestore/dev/src/index.ts | 4 ++-- handwritten/firestore/dev/src/pipelines/pipeline-util.ts | 4 ++-- handwritten/firestore/dev/src/reference/aggregate-query.ts | 4 ++-- handwritten/firestore/dev/src/reference/query-util.ts | 4 ++-- handwritten/firestore/dev/src/write-batch.ts | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/handwritten/firestore/dev/src/bulk-writer.ts b/handwritten/firestore/dev/src/bulk-writer.ts index 251baefb49b7..f5697bb628c0 100644 --- a/handwritten/firestore/dev/src/bulk-writer.ts +++ b/handwritten/firestore/dev/src/bulk-writer.ts @@ -253,7 +253,7 @@ class BulkCommitBatch extends WriteBatch { const tag = options?.requestTag ?? requestTag(); // Capture the error stack to preserve stack tracing across async calls. - const stack = Error().stack!; + const callsiteError = Error(); let response: api.IBatchWriteResponse; try { @@ -295,7 +295,7 @@ class BulkCommitBatch extends WriteBatch { status.message || undefined, ); error.code = status.code as number; - this.pendingOps[i].onError(wrapError(error, stack)); + this.pendingOps[i].onError(wrapError(error, callsiteError.stack!)); } } }, diff --git a/handwritten/firestore/dev/src/index.ts b/handwritten/firestore/dev/src/index.ts index 5218efaf939e..4379c1835f68 100644 --- a/handwritten/firestore/dev/src/index.ts +++ b/handwritten/firestore/dev/src/index.ts @@ -1374,7 +1374,7 @@ export class Firestore implements firestore.Firestore { const tag = requestTag(); // Capture the error stack to preserve stack tracing across async calls. - const stack = Error().stack!; + const callsiteError = Error(); return this.initializeIfNeeded(tag) .then(() => { @@ -1382,7 +1382,7 @@ export class Firestore implements firestore.Firestore { return reader.get(tag); }) .catch(err => { - throw wrapError(err, stack); + throw wrapError(err, callsiteError.stack!); }); }, ); diff --git a/handwritten/firestore/dev/src/pipelines/pipeline-util.ts b/handwritten/firestore/dev/src/pipelines/pipeline-util.ts index 17961b4da1e1..bac75f1d3460 100644 --- a/handwritten/firestore/dev/src/pipelines/pipeline-util.ts +++ b/handwritten/firestore/dev/src/pipelines/pipeline-util.ts @@ -92,7 +92,7 @@ export class ExecutionUtil { transactionOrReadTime?: Uint8Array | Timestamp | api.ITransactionOptions, ): Promise { // Capture the error stack to preserve stack tracing across async calls. - const stack = Error().stack!; + const callsiteError = Error(); return new Promise((resolve, reject): void => { const result: Array = []; @@ -103,7 +103,7 @@ export class ExecutionUtil { transactionOrReadTime, ); stream.on('error', err => { - reject(wrapError(err, stack)); + reject(wrapError(err, callsiteError.stack!)); }); stream.on('data', (data: PipelineStreamElement[]) => { for (const element of data) { diff --git a/handwritten/firestore/dev/src/reference/aggregate-query.ts b/handwritten/firestore/dev/src/reference/aggregate-query.ts index f4934c44d7bc..f58664687922 100644 --- a/handwritten/firestore/dev/src/reference/aggregate-query.ts +++ b/handwritten/firestore/dev/src/reference/aggregate-query.ts @@ -139,7 +139,7 @@ export class AggregateQuery< > > { // Capture the error stack to preserve stack tracing across async calls. - const stack = Error().stack!; + const callsiteError = Error(); return new Promise((resolve, reject) => { const output: QueryResponse< @@ -148,7 +148,7 @@ export class AggregateQuery< const stream = this._stream(transactionOrReadTime, explainOptions); stream.on('error', err => { - reject(wrapError(err, stack)); + reject(wrapError(err, callsiteError.stack!)); }); stream.on( 'data', diff --git a/handwritten/firestore/dev/src/reference/query-util.ts b/handwritten/firestore/dev/src/reference/query-util.ts index a5aa0c24f5a3..9f68d427c58a 100644 --- a/handwritten/firestore/dev/src/reference/query-util.ts +++ b/handwritten/firestore/dev/src/reference/query-util.ts @@ -69,7 +69,7 @@ export class QueryUtil< explainOptions?: firestore.ExplainOptions, ): Promise>> { // Capture the error stack to preserve stack tracing across async calls. - const stack = Error().stack!; + const callsiteError = Error(); return new Promise((resolve, reject) => { const docs: Array> = []; @@ -84,7 +84,7 @@ export class QueryUtil< explainOptions, ) .on('error', err => { - reject(wrapError(err, stack)); + reject(wrapError(err, callsiteError.stack!)); }) .on('data', (data: QueryStreamElement) => { if (data.transaction) { diff --git a/handwritten/firestore/dev/src/write-batch.ts b/handwritten/firestore/dev/src/write-batch.ts index 0b9492011d34..276b7a34908c 100644 --- a/handwritten/firestore/dev/src/write-batch.ts +++ b/handwritten/firestore/dev/src/write-batch.ts @@ -580,7 +580,7 @@ export class WriteBatch implements firestore.WriteBatch { SPAN_NAME_BATCH_COMMIT, async () => { // Capture the error stack to preserve stack tracing across async calls. - const stack = Error().stack!; + const callsiteError = Error(); // Commits should also be retried when they fail with status code ABORTED. const retryCodes = [StatusCode.ABORTED, ...getRetryCodes('commit')]; @@ -597,7 +597,7 @@ export class WriteBatch implements firestore.WriteBatch { ); }) .catch(err => { - throw wrapError(err, stack); + throw wrapError(err, callsiteError.stack!); }); }, {