From 6ea922cd8edf3c44bf49a5b4fd5e58bfc5985640 Mon Sep 17 00:00:00 2001
From: Tooru Fujisawa <arai_a@mac.com>
Date: Wed, 31 May 2023 01:26:44 +0000
Subject: [PATCH] Bug 1834483 - Part 1: Add NativeStackLimit field to
 FrontendContext. r=bthrall

Differential Revision: https://phabricator.services.mozilla.com/D179002
---
 js/public/Stack.h                   |  7 +++++++
 js/src/frontend/FrontendContext.cpp | 14 ++++++++++++++
 js/src/frontend/FrontendContext.h   | 13 ++++++++++---
 js/src/jsapi.cpp                    |  5 +----
 4 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/js/public/Stack.h b/js/public/Stack.h
index 061b28396cd0c..6f01b2b7289eb 100644
--- a/js/public/Stack.h
+++ b/js/public/Stack.h
@@ -36,6 +36,13 @@ constexpr NativeStackLimit NativeStackLimitMin = UINTPTR_MAX;
 constexpr NativeStackLimit NativeStackLimitMax = 0;
 #endif
 
+#ifdef __wasi__
+// We build with the "stack-first" wasm-ld option, so the stack grows downward
+// toward zero. Let's set a limit just a bit above this so that we catch an
+// overflow before a Wasm trap occurs.
+constexpr NativeStackLimit WASINativeStackLimit = 1024;
+#endif  // __wasi__
+
 inline NativeStackLimit GetNativeStackLimit(NativeStackBase base,
                                             NativeStackSize size) {
 #if JS_STACK_GROWTH_DIRECTION > 0
diff --git a/js/src/frontend/FrontendContext.cpp b/js/src/frontend/FrontendContext.cpp
index 979b7e95c6a12..312d265ae01cf 100644
--- a/js/src/frontend/FrontendContext.cpp
+++ b/js/src/frontend/FrontendContext.cpp
@@ -11,6 +11,7 @@
 #include "js/friend/StackLimits.h"  // js::ReportOverRecursed
 #include "js/Modules.h"
 #include "util/DifferentialTesting.h"
+#include "util/NativeStack.h"  // GetNativeStackBase
 #include "vm/JSContext.h"
 
 using namespace js;
@@ -42,6 +43,18 @@ bool FrontendContext::setSupportedImportAssertions(
   return true;
 }
 
+void FrontendContext::setStackQuota(JS::NativeStackSize stackSize) {
+#ifdef __wasi__
+  stackLimit_ = JS::WASINativeStackLimit;
+#else   // __wasi__
+  if (stackSize == 0) {
+    stackLimit_ = JS::NativeStackLimitMax;
+  } else {
+    stackLimit_ = JS::GetNativeStackLimit(GetNativeStackBase(), stackSize - 1);
+  }
+#endif  // !__wasi__
+}
+
 bool FrontendContext::allocateOwnedPool() {
   MOZ_ASSERT(!nameCollectionPool_);
 
@@ -137,6 +150,7 @@ void FrontendContext::setCurrentJSContext(JSContext* cx) {
   maybeCx_ = cx;
   nameCollectionPool_ = &cx->frontendCollectionPool();
   scriptDataTableHolder_ = &cx->runtime()->scriptDataTableHolder();
+  stackLimit_ = cx->stackLimitForCurrentPrincipal();
 }
 
 void FrontendContext::convertToRuntimeError(
diff --git a/js/src/frontend/FrontendContext.h b/js/src/frontend/FrontendContext.h
index 247864465badb..d9db91fabfb81 100644
--- a/js/src/frontend/FrontendContext.h
+++ b/js/src/frontend/FrontendContext.h
@@ -13,9 +13,10 @@
 
 #include <stddef.h>  // size_t
 
-#include "js/AllocPolicy.h"     // SystemAllocPolicy, AllocFunction
-#include "js/ErrorReport.h"     // JSErrorCallback, JSErrorFormatString
-#include "js/Modules.h"         // JS::ImportAssertionVector
+#include "js/AllocPolicy.h"  // SystemAllocPolicy, AllocFunction
+#include "js/ErrorReport.h"  // JSErrorCallback, JSErrorFormatString
+#include "js/Modules.h"      // JS::ImportAssertionVector
+#include "js/Stack.h"  // JS::NativeStackSize, JS::NativeStackLimit, JS::NativeStackLimitMax
 #include "js/Vector.h"          // Vector
 #include "vm/ErrorReporting.h"  // CompileError
 #include "vm/MallocProvider.h"  // MallocProvider
@@ -73,6 +74,8 @@ class FrontendContext {
 
   JS::ImportAssertionVector supportedImportAssertions_;
 
+  JS::NativeStackLimit stackLimit_ = JS::NativeStackLimitMax;
+
  protected:
   // (optional) Current JSContext to support main-thread-specific
   // handling for error reporting, GC, and memory allocation.
@@ -89,6 +92,9 @@ class FrontendContext {
         supportedImportAssertions_() {}
   ~FrontendContext();
 
+  void setStackQuota(JS::NativeStackSize stackSize);
+  JS::NativeStackLimit stackLimit() const { return stackLimit_; }
+
   bool allocateOwnedPool();
 
   frontend::NameCollectionPool& nameCollectionPool() {
@@ -109,6 +115,7 @@ class FrontendContext {
   //   * js::frontend::NameCollectionPool for reusing allocation
   //   * js::SharedScriptDataTableHolder for de-duplicating bytecode
   //     within given runtime
+  //   * Copy the native stack limit from the JSContext
   //
   // And also this JSContext can be retrieved by maybeCurrentJSContext below.
   void setCurrentJSContext(JSContext* cx);
diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
index 1fc92856427a4..90ba9bcf0857c 100644
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1471,10 +1471,7 @@ JS_GetExternalStringCallbacks(JSString* str) {
 static void SetNativeStackSize(JSContext* cx, JS::StackKind kind,
                                JS::NativeStackSize stackSize) {
 #ifdef __wasi__
-  // WASI makes this easy: we build with the "stack-first" wasm-ld option, so
-  // the stack grows downward toward zero. Let's set a limit just a bit above
-  // this so that we catch an overflow before a Wasm trap occurs.
-  cx->nativeStackLimit[kind] = 1024;
+  cx->nativeStackLimit[kind] = JS::WASINativeStackLimit;
 #else   // __wasi__
   if (stackSize == 0) {
     cx->nativeStackLimit[kind] = JS::NativeStackLimitMax;
-- 
GitLab