Merge tracemonkey to mozilla-central.
authorChris Leary <cdleary@mozilla.com>
Thu, 31 Mar 2011 15:47:46 -0700
changeset 64562 6da508f706722da3e15f935eb9caa30d3110aca8
parent 64548 839c87b7e4bb175488843abfcbf1470ad82c6c7b (current diff)
parent 64561 ebb7eb076e899dc7975bed4124062ce6caa22451 (diff)
child 64563 12ea0bd80e2e4cd66baad854973768bd0e7e18ca
push idunknown
push userunknown
push dateunknown
milestone2.2a1pre
Merge tracemonkey to mozilla-central.
new file mode 100755
--- /dev/null
+++ b/config/check_source_count.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# Usage: check_source_count.py SEARCH_TERM COUNT ERROR_LOCATION REPLACEMENT [FILES...]
+#   Checks that FILES contains exactly COUNT matches of SEARCH_TERM. If it does
+#   not, an error message is printed, quoting ERROR_LOCATION, which should
+#   probably be the filename and line number of the erroneous call to
+#   check_source_count.py.
+
+import sys
+import os
+import re
+
+search_string = sys.argv[1]
+expected_count = int(sys.argv[2])
+error_location = sys.argv[3]
+replacement = sys.argv[4]
+files = sys.argv[5:]
+
+details = {}
+
+count = 0
+for f in files:
+    text = file(f).read()
+    match = re.findall(search_string, text)
+    if match:
+        num = len(match)
+        count += num
+        details[f] = num
+
+if count == expected_count:
+    print "TEST-PASS | check_source_count.py %s | %d" % (search_string, expected_count)
+
+else:
+    print "TEST-UNEXPECTED-FAIL | check_source_count.py %s | " % (search_string),
+    if count < expected_count:
+        print "There are less occurences of /%s/ than expected. This may mean that you have removed some, but forgotten to account for it %s." % (search_string, error_location)
+    else:
+        print "There are more occurences of /%s/ than expected. We're trying to prevent an increase in the number of %s's, using %s if possible. If it in unavoidable, you should update the expected count %s." % (search_string, search_string, replacement, error_location)
+
+    print "Expected: %d; found: %d" % (expected_count, count)
+    for k in sorted(details):
+        print "Found %d occurences in %s" % (details[k],k)
+    sys.exit(-1)
+
--- a/config/find_vanilla_new_calls
+++ b/config/find_vanilla_new_calls
@@ -14,17 +14,17 @@
 #   alloc/free checking.
 # - Doesn't detect the 'nothrow' variants, which are ok but probably still
 #   best avoided.
 # - Is designed to only run on Linux (though it may also work on Mac);  one
 #   platform will be enough to catch any violations.
 #
 # If this script fails:
 # - You need to find the uses of vanilla new/delete and replace them with
-#   js_new()/js_delete().
+#   {js::OffTheBooks,JSContext,JSRuntime}::{new_,/array_new}.
 # - Run this script on each of the .o files, that should narrow it down.
 # - After that, one way to find them is to run 'objdump -r -C' on the
 #   relevant .o files.  For example, you might search for 'operator new' and
 #   find a record like this:
 #
 #  RELOCATION RECORDS FOR [.text._ZN3JSC14ExecutablePool6createEj]:
 #  OFFSET   TYPE              VALUE
 #  00000009 R_386_PC32        __i686.get_pc_thunk.bx
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -83,17 +83,17 @@ ifdef INTEL_CXX
 # icc gets special optimize flags
 ifdef MOZ_PROFILE_GENERATE
 MODULE_OPTIMIZE_FLAGS = -O0
 else
 MODULE_OPTIMIZE_FLAGS = -O2 -ip
 endif
 else # not INTEL_CXX
 
-FAIL_ON_WARNINGS = 1
+#FAIL_ON_WARNINGS = 1
 MODULE_OPTIMIZE_FLAGS = -O3 -fstrict-aliasing -fno-stack-protector
 
 # We normally want -fomit-frame-pointer, but we want an explicit
 # -fno-omit-frame-pointer if we're using a sampling profiler.
 ifndef MOZ_PROFILING
 MODULE_OPTIMIZE_FLAGS += -fomit-frame-pointer
 else
 MODULE_OPTIMIZE_FLAGS += -fno-omit-frame-pointer
@@ -587,21 +587,52 @@ check::
 	$(srcdir)/config/find_vanilla_new_calls $(LIBRARY)
 endif
 
 # Help ensure that the number of OOM errors in SpiderMonkey doesn't increase.
 # If the number of OOM errors changes, update the number below. We intend this
 # number to go down over time, by fixing OOMs.
 ifdef DEBUG
 check-ooms:
-	$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/config/find_OOM_errors.py --regression 129
+	$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/config/find_OOM_errors.py --regression 125
 
 check:: check-ooms
 endif
 
+## Prevent regressing in our deprecation of non-preferred memory management functions.
+# We use all the files in the distribution so that different configurations
+# don't give different results. We skip the contents of objdirs using |find|
+# (it can't be done with %-expansion, because the files we want to skip aren't
+# in the vpath).
+ifneq ($(OS_ARCH),WINNT) # FIXME: this should be made work on Windows too.
+ALL_FILES=$(shell find $(srcdir) \( -name "*.cpp" -o -name "*.h" \) -not -path "*/dist/*")
+check-malloc-function-usage: $(filter-out %jsutil.h %jscntxt.h, $(ALL_FILES))
+
+	# js_malloc and friends are only used by other memory managers, and should
+	# never be used elsewhere directly.
+	$(srcdir)/config/check_source_count.py "\bjs_malloc\b" 0 \
+		"in Makefile.in" "cx->malloc_ or rt->malloc_" $^
+	$(srcdir)/config/check_source_count.py "\bjs_calloc\b" 0 \
+		"in Makefile.in" "cx->calloc_ or rt->calloc_" $^
+	$(srcdir)/config/check_source_count.py "\bjs_realloc\b" 0 \
+		"in Makefile.in" "cx->realloc_ or rt->realloc_" $^
+	$(srcdir)/config/check_source_count.py "\bjs_free\b" 0 \
+		"in Makefile.in" "cx->free_" $^
+
+	# We desire these numbers to go down, not up. See "User guide to memory
+	# management within SpiderMonkey" in jsutil.h.
+	$(srcdir)/config/check_source_count.py OffTheBooks:: 54 \
+		"in Makefile.in" "{cx,rt}->{new_,new_array,malloc_,calloc_,realloc_}" $^
+	# This should go to zero, if possible.
+	$(srcdir)/config/check_source_count.py UnwantedForeground:: 36 \
+		"in Makefile.in" "{cx,rt}->{free_,delete_,array_delete}" $^
+
+check:: check-malloc-function-usage
+endif
+
 ifndef WINCE
 JITFLAGS = ,m,j,mj,mjp,am,amj,amjp,amd
 check::
 	$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \
 	        --no-slow --no-progress --tinderbox --jitflags=$(JITFLAGS) $(DIST)/bin/js$(BIN_SUFFIX)
 
 check-valgrind::
 	$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \
--- a/js/src/assembler/jit/ExecutableAllocator.h
+++ b/js/src/assembler/jit/ExecutableAllocator.h
@@ -65,16 +65,18 @@ extern "C" __declspec(dllimport) void Ca
 #if ENABLE_ASSEMBLER
 
 //#define DEBUG_STRESS_JSC_ALLOCATOR
 
 namespace JSC {
 
   // These are reference-counted. A new one starts with a count of 1. 
   class ExecutablePool {
+
+    JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
     friend class ExecutableAllocator;
 private:
     struct Allocation {
         char* pages;
         size_t size;
 #if WTF_PLATFORM_SYMBIAN
         RChunk* chunk;
 #endif
@@ -95,19 +97,17 @@ public:
     // remember whether m_destroy was computed for the currently active GC.
     size_t m_gcNumber;
 
     void release(bool willDestroy = false)
     { 
         JS_ASSERT(m_refCount != 0);
         JS_ASSERT_IF(willDestroy, m_refCount = 1);
         if (--m_refCount == 0) {
-            /* We can't (easily) use js_delete() here because the destructor is private. */
-            this->~ExecutablePool();
-            js_free(this);
+            js::UnwantedForeground::delete_(this);
         }
     }
 
 private:
     // It should be impossible for us to roll over, because only small
     // pools have multiple holders, and they have one holder per chunk
     // of generated code, and they only hold 16KB or so of code.
     void addRef()
@@ -231,19 +231,17 @@ private:
 #ifdef DEBUG_STRESS_JSC_ALLOCATOR
         ExecutablePool::Allocation a = ExecutablePool::systemAlloc(size_t(4294967291));
 #else
         ExecutablePool::Allocation a = ExecutablePool::systemAlloc(allocSize);
 #endif
         if (!a.pages)
             return NULL;
 
-        /* We can't (easily) use js_new() here because the constructor is private. */
-        void *memory = js_malloc(sizeof(ExecutablePool));
-        return memory ? new(memory) ExecutablePool(a) : NULL;
+        return js::OffTheBooks::new_<ExecutablePool>(a);
     }
 
     ExecutablePool* poolForSize(size_t n)
     {
 #ifndef DEBUG_STRESS_JSC_ALLOCATOR
         // Try to fit in an existing small allocator.  Use the pool with the
         // least available space that is big enough (best-fit).  This is the
         // best strategy because (a) it maximizes the chance of the next
--- a/js/src/assembler/wtf/Assertions.cpp
+++ b/js/src/assembler/wtf/Assertions.cpp
@@ -69,53 +69,53 @@ static void printCallSite(const char* fi
 #else
     printf_stderr_common("(%s:%d %s)\n", file, line, function);
 #endif
 }
 
 void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion)
 {
     if (assertion)
-        printf_stderr_common("ASSERTION FAILED: %s\n", assertion);
+        printf_stderr_common("Assertion failure: %s\n", assertion);
     else
-        printf_stderr_common("SHOULD NEVER BE REACHED\n");
+        printf_stderr_common("Should never be reached\n");
     printCallSite(file, line, function);
 }
 
 void WTFReportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* assertion, const char* format, ...)
 {
-    printf_stderr_common("ASSERTION FAILED: ");
+    printf_stderr_common("Assertion failure: ");
     va_list args;
     va_start(args, format);
     vprintf_stderr_common(format, args);
     va_end(args);
     printf_stderr_common("\n%s\n", assertion);
     printCallSite(file, line, function);
 }
 
 void WTFReportArgumentAssertionFailure(const char* file, int line, const char* function, const char* argName, const char* assertion)
 {
-    printf_stderr_common("ARGUMENT BAD: %s, %s\n", argName, assertion);
+    printf_stderr_common("Argument bad: %s, %s\n", argName, assertion);
     printCallSite(file, line, function);
 }
 
 void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...)
 {
-    printf_stderr_common("FATAL ERROR: ");
+    printf_stderr_common("Fatal error: ");
     va_list args;
     va_start(args, format);
     vprintf_stderr_common(format, args);
     va_end(args);
     printf_stderr_common("\n");
     printCallSite(file, line, function);
 }
 
 void WTFReportError(const char* file, int line, const char* function, const char* format, ...)
 {
-    printf_stderr_common("ERROR: ");
+    printf_stderr_common("Error: ");
     va_list args;
     va_start(args, format);
     vprintf_stderr_common(format, args);
     va_end(args);
     printf_stderr_common("\n");
     printCallSite(file, line, function);
 }
 
new file mode 100755
--- /dev/null
+++ b/js/src/config/check_source_count.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# Usage: check_source_count.py SEARCH_TERM COUNT ERROR_LOCATION REPLACEMENT [FILES...]
+#   Checks that FILES contains exactly COUNT matches of SEARCH_TERM. If it does
+#   not, an error message is printed, quoting ERROR_LOCATION, which should
+#   probably be the filename and line number of the erroneous call to
+#   check_source_count.py.
+
+import sys
+import os
+import re
+
+search_string = sys.argv[1]
+expected_count = int(sys.argv[2])
+error_location = sys.argv[3]
+replacement = sys.argv[4]
+files = sys.argv[5:]
+
+details = {}
+
+count = 0
+for f in files:
+    text = file(f).read()
+    match = re.findall(search_string, text)
+    if match:
+        num = len(match)
+        count += num
+        details[f] = num
+
+if count == expected_count:
+    print "TEST-PASS | check_source_count.py %s | %d" % (search_string, expected_count)
+
+else:
+    print "TEST-UNEXPECTED-FAIL | check_source_count.py %s | " % (search_string),
+    if count < expected_count:
+        print "There are less occurences of /%s/ than expected. This may mean that you have removed some, but forgotten to account for it %s." % (search_string, error_location)
+    else:
+        print "There are more occurences of /%s/ than expected. We're trying to prevent an increase in the number of %s's, using %s if possible. If it in unavoidable, you should update the expected count %s." % (search_string, search_string, replacement, error_location)
+
+    print "Expected: %d; found: %d" % (expected_count, count)
+    for k in sorted(details):
+        print "Found %d occurences in %s" % (details[k],k)
+    sys.exit(-1)
+
--- a/js/src/config/find_vanilla_new_calls
+++ b/js/src/config/find_vanilla_new_calls
@@ -14,17 +14,17 @@
 #   alloc/free checking.
 # - Doesn't detect the 'nothrow' variants, which are ok but probably still
 #   best avoided.
 # - Is designed to only run on Linux (though it may also work on Mac);  one
 #   platform will be enough to catch any violations.
 #
 # If this script fails:
 # - You need to find the uses of vanilla new/delete and replace them with
-#   js_new()/js_delete().
+#   {js::OffTheBooks,JSContext,JSRuntime}::{new_,/array_new}.
 # - Run this script on each of the .o files, that should narrow it down.
 # - After that, one way to find them is to run 'objdump -r -C' on the
 #   relevant .o files.  For example, you might search for 'operator new' and
 #   find a record like this:
 #
 #  RELOCATION RECORDS FOR [.text._ZN3JSC14ExecutablePool6createEj]:
 #  OFFSET   TYPE              VALUE
 #  00000009 R_386_PC32        __i686.get_pc_thunk.bx
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -1839,34 +1839,34 @@ ImplicitConvert(JSContext* cx,
       case TYPE_unsigned_char: {
         // Convert from UTF-16 to UTF-8.
         size_t nbytes =
           js_GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength);
         if (nbytes == (size_t) -1)
           return false;
 
         char** charBuffer = static_cast<char**>(buffer);
-        *charBuffer = js_array_new<char>(nbytes + 1);
+        *charBuffer = cx->array_new<char>(nbytes + 1);
         if (!*charBuffer) {
           JS_ReportAllocationOverflow(cx);
           return false;
         }
 
         ASSERT_OK(js_DeflateStringToUTF8Buffer(cx, sourceChars, sourceLength,
                     *charBuffer, &nbytes));
         (*charBuffer)[nbytes] = 0;
         *freePointer = true;
         break;
       }
       case TYPE_jschar: {
         // Copy the jschar string data. (We could provide direct access to the
         // JSString's buffer, but this approach is safer if the caller happens
         // to modify the string.)
         jschar** jscharBuffer = static_cast<jschar**>(buffer);
-        *jscharBuffer = js_array_new<jschar>(sourceLength + 1);
+        *jscharBuffer = cx->array_new<jschar>(sourceLength + 1);
         if (!*jscharBuffer) {
           JS_ReportAllocationOverflow(cx);
           return false;
         }
 
         *freePointer = true;
         memcpy(*jscharBuffer, sourceChars, sourceLength * sizeof(jschar));
         (*jscharBuffer)[sourceLength] = 0;
@@ -1941,17 +1941,17 @@ ImplicitConvert(JSContext* cx,
           targetLength != size_t(sourceLength)) {
         JS_ReportError(cx, "ArrayType length does not match source array length");
         return false;
       }
 
       // Convert into an intermediate, in case of failure.
       size_t elementSize = CType::GetSize(cx, baseType);
       size_t arraySize = elementSize * targetLength;
-      AutoPtr<char>::Array intermediate(js_array_new<char>(arraySize));
+      AutoPtr<char>::Array intermediate(cx->array_new<char>(arraySize));
       if (!intermediate) {
         JS_ReportAllocationOverflow(cx);
         return false;
       }
 
       for (jsuint i = 0; i < sourceLength; ++i) {
         js::AutoValueRooter item(cx);
         if (!JS_GetElement(cx, sourceArray, i, item.jsval_addr()))
@@ -1978,17 +1978,17 @@ ImplicitConvert(JSContext* cx,
       JSObject* obj = JSVAL_TO_OBJECT(val);
       JSObject* iter = JS_NewPropertyIterator(cx, obj);
       if (!iter)
         return false;
       js::AutoObjectRooter iterroot(cx, iter);
 
       // Convert into an intermediate, in case of failure.
       size_t structSize = CType::GetSize(cx, targetType);
-      AutoPtr<char>::Array intermediate(js_array_new<char>(structSize));
+      AutoPtr<char>::Array intermediate(cx->array_new<char>(structSize));
       if (!intermediate) {
         JS_ReportAllocationOverflow(cx);
         return false;
       }
 
       jsid id;
       size_t i = 0;
       while (1) {
@@ -2697,37 +2697,37 @@ CType::Finalize(JSContext* cx, JSObject*
     return;
 
   // The contents of our slots depends on what kind of type we are.
   switch (TypeCode(JSVAL_TO_INT(slot))) {
   case TYPE_function: {
     // Free the FunctionInfo.
     ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FNINFO, &slot));
     if (!JSVAL_IS_VOID(slot))
-      js_delete(static_cast<FunctionInfo*>(JSVAL_TO_PRIVATE(slot)));
+      cx->delete_(static_cast<FunctionInfo*>(JSVAL_TO_PRIVATE(slot)));
     break;
   }
 
   case TYPE_struct: {
     // Free the FieldInfoHash table.
     ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FIELDINFO, &slot));
     if (!JSVAL_IS_VOID(slot)) {
       void* info = JSVAL_TO_PRIVATE(slot);
-      js_delete(static_cast<FieldInfoHash*>(info));
+      cx->delete_(static_cast<FieldInfoHash*>(info));
     }
   }
 
     // Fall through.
   case TYPE_array: {
     // Free the ffi_type info.
     ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FFITYPE, &slot));
     if (!JSVAL_IS_VOID(slot)) {
       ffi_type* ffiType = static_cast<ffi_type*>(JSVAL_TO_PRIVATE(slot));
-      js_array_delete(ffiType->elements);
-      js_delete(ffiType);
+      cx->array_delete(ffiType->elements);
+      cx->delete_(ffiType);
     }
 
     break;
   }
   default:
     // Nothing to do here.
     break;
   }
@@ -3696,26 +3696,26 @@ ArrayType::BuildFFIType(JSContext* cx, J
 
   // Create an ffi_type to represent the array. This is necessary for the case
   // where the array is part of a struct. Since libffi has no intrinsic
   // support for array types, we approximate it by creating a struct type
   // with elements of type 'baseType' and with appropriate size and alignment
   // values. It would be nice to not do all the work of setting up 'elements',
   // but some libffi platforms currently require that it be meaningful. I'm
   // looking at you, x86_64.
-  AutoPtr<ffi_type> ffiType(js_new<ffi_type>());
+  AutoPtr<ffi_type> ffiType(cx->new_<ffi_type>());
   if (!ffiType) {
     JS_ReportOutOfMemory(cx);
     return NULL;
   }
 
   ffiType->type = FFI_TYPE_STRUCT;
   ffiType->size = CType::GetSize(cx, obj);
   ffiType->alignment = CType::GetAlignment(cx, obj);
-  ffiType->elements = js_array_new<ffi_type*>(length + 1);
+  ffiType->elements = cx->array_new<ffi_type*>(length + 1);
   if (!ffiType->elements) {
     JS_ReportAllocationOverflow(cx);
     return NULL;
   }
 
   for (size_t i = 0; i < length; ++i)
     ffiType->elements[i] = ffiBaseType;
   ffiType->elements[length] = NULL;
@@ -4028,17 +4028,17 @@ StructType::DefineInternal(JSContext* cx
   if (!JS_DefineProperty(cx, prototype, "constructor", OBJECT_TO_JSVAL(typeObj),
          NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT))
     return JS_FALSE;
 
   // Create a FieldInfoHash to stash on the type object, and an array to root
   // its constituents. (We cannot simply stash the hash in a reserved slot now
   // to get GC safety for free, since if anything in this function fails we
   // do not want to mutate 'typeObj'.)
-  AutoPtr<FieldInfoHash> fields(js_new<FieldInfoHash>());
+  AutoPtr<FieldInfoHash> fields(cx->new_<FieldInfoHash>());
   Array<jsval, 16> fieldRootsArray;
   if (!fields || !fields->init(len) || !fieldRootsArray.appendN(JSVAL_VOID, len)) {
     JS_ReportOutOfMemory(cx);
     return JS_FALSE;
   }
   js::AutoArrayRooter fieldRoots(cx, fieldRootsArray.length(), 
     fieldRootsArray.begin());
 
@@ -4137,26 +4137,26 @@ StructType::BuildFFIType(JSContext* cx, 
   JS_ASSERT(CType::IsSizeDefined(cx, obj));
 
   const FieldInfoHash* fields = GetFieldInfo(cx, obj);
   size_t len = fields->count();
 
   size_t structSize = CType::GetSize(cx, obj);
   size_t structAlign = CType::GetAlignment(cx, obj);
 
-  AutoPtr<ffi_type> ffiType(js_new<ffi_type>());
+  AutoPtr<ffi_type> ffiType(cx->new_<ffi_type>());
   if (!ffiType) {
     JS_ReportOutOfMemory(cx);
     return NULL;
   }
   ffiType->type = FFI_TYPE_STRUCT;
 
   AutoPtr<ffi_type*>::Array elements;
   if (len != 0) {
-    elements = js_array_new<ffi_type*>(len + 1);
+    elements = cx->array_new<ffi_type*>(len + 1);
     if (!elements) {
       JS_ReportOutOfMemory(cx);
       return NULL;
     }
     elements[len] = NULL;
 
     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
       const FieldInfoHash::Entry& entry = r.front();
@@ -4165,17 +4165,17 @@ StructType::BuildFFIType(JSContext* cx, 
         return NULL;
       elements[entry.value.mIndex] = fieldType;
     }
 
   } else {
     // Represent an empty struct as having a size of 1 byte, just like C++.
     JS_ASSERT(structSize == 1);
     JS_ASSERT(structAlign == 1);
-    elements = js_array_new<ffi_type*>(2);
+    elements = cx->array_new<ffi_type*>(2);
     if (!elements) {
       JS_ReportOutOfMemory(cx);
       return NULL;
     }
     elements[0] = &ffi_type_uint8;
     elements[1] = NULL;
   }
 
@@ -4506,24 +4506,24 @@ StructType::AddressOfField(JSContext* cx
 
 // Helper class for handling allocation of function arguments.
 struct AutoValue
 {
   AutoValue() : mData(NULL) { }
 
   ~AutoValue()
   {
-    js_array_delete(static_cast<char*>(mData));
+    UnwantedForeground::array_delete(static_cast<char*>(mData));
   }
 
   bool SizeToType(JSContext* cx, JSObject* type)
   {
     // Allocate a minimum of sizeof(ffi_arg) to handle small integers.
     size_t size = Align(CType::GetSize(cx, type), sizeof(ffi_arg));
-    mData = js_array_new<char>(size);
+    mData = cx->array_new<char>(size);
     if (mData)
       memset(mData, 0, size);
     return mData != NULL;
   }
 
   void* mData;
 };
 
@@ -4718,17 +4718,17 @@ FunctionType::BuildSymbolName(JSContext*
 
 static FunctionInfo*
 NewFunctionInfo(JSContext* cx,
                 jsval abiType,
                 jsval returnType,
                 jsval* argTypes,
                 uintN argLength)
 {
-  AutoPtr<FunctionInfo> fninfo(js_new<FunctionInfo>());
+  AutoPtr<FunctionInfo> fninfo(cx->new_<FunctionInfo>());
   if (!fninfo) {
     JS_ReportOutOfMemory(cx);
     return NULL;
   }
 
   ffi_abi abi;
   if (!GetABI(cx, abiType, &abi)) {
     JS_ReportError(cx, "Invalid ABI specification");
@@ -5194,17 +5194,17 @@ CClosure::Create(JSContext* cx,
     return NULL;
   js::AutoObjectRooter root(cx, result);
 
   // Get the FunctionInfo from the FunctionType.
   FunctionInfo* fninfo = FunctionType::GetFunctionInfo(cx, typeObj);
   JS_ASSERT(!fninfo->mIsVariadic);
   JS_ASSERT(GetABICode(cx, fninfo->mABI) != ABI_WINAPI);
 
-  AutoPtr<ClosureInfo> cinfo(js_new<ClosureInfo>());
+  AutoPtr<ClosureInfo> cinfo(cx->new_<ClosureInfo>());
   if (!cinfo) {
     JS_ReportOutOfMemory(cx);
     return NULL;
   }
 
   // Get the prototype of the FunctionType object, of class CTypeProto,
   // which stores our JSContext for use with the closure.
   JSObject* proto = JS_GetPrototype(cx, typeObj);
@@ -5307,17 +5307,17 @@ CClosure::Finalize(JSContext* cx, JSObje
   if (!JS_GetReservedSlot(cx, obj, SLOT_CLOSUREINFO, &slot) ||
       JSVAL_IS_VOID(slot))
     return;
 
   ClosureInfo* cinfo = static_cast<ClosureInfo*>(JSVAL_TO_PRIVATE(slot));
   if (cinfo->closure)
     ffi_closure_free(cinfo->closure);
 
-  js_delete(cinfo);
+  cx->delete_(cinfo);
 }
 
 void
 CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
 {
   JS_ASSERT(cif);
   JS_ASSERT(result);
   JS_ASSERT(args);
@@ -5484,47 +5484,47 @@ CData::Create(JSContext* cx,
     return NULL;
 
   // Set our ownership flag.
   if (!JS_SetReservedSlot(cx, dataObj, SLOT_OWNS, BOOLEAN_TO_JSVAL(ownResult)))
     return NULL;
 
   // attach the buffer. since it might not be 2-byte aligned, we need to
   // allocate an aligned space for it and store it there. :(
-  char** buffer = js_new<char*>();
+  char** buffer = cx->new_<char*>();
   if (!buffer) {
     JS_ReportOutOfMemory(cx);
     return NULL;
   }
 
   char* data;
   if (!ownResult) {
     data = static_cast<char*>(source);
   } else {
     // Initialize our own buffer.
     size_t size = CType::GetSize(cx, typeObj);
-    data = js_array_new<char>(size);
+    data = cx->array_new<char>(size);
     if (!data) {
       // Report a catchable allocation error.
       JS_ReportAllocationOverflow(cx);
-      js_delete(buffer);
+      Foreground::delete_(buffer);
       return NULL;
     }
 
     if (!source)
       memset(data, 0, size);
     else
       memcpy(data, source, size);
   }
 
   *buffer = data;
   if (!JS_SetReservedSlot(cx, dataObj, SLOT_DATA, PRIVATE_TO_JSVAL(buffer))) {
     if (ownResult)
-      js_array_delete(data);
-    js_delete(buffer);
+      Foreground::array_delete(data);
+    Foreground::delete_(buffer);
     return NULL;
   }
 
   return dataObj;
 }
 
 void
 CData::Finalize(JSContext* cx, JSObject* obj)
@@ -5536,18 +5536,18 @@ CData::Finalize(JSContext* cx, JSObject*
 
   JSBool owns = JSVAL_TO_BOOLEAN(slot);
 
   if (!JS_GetReservedSlot(cx, obj, SLOT_DATA, &slot) || JSVAL_IS_VOID(slot))
     return;
   char** buffer = static_cast<char**>(JSVAL_TO_PRIVATE(slot));
 
   if (owns)
-    js_array_delete(*buffer);
-  js_delete(buffer);
+    cx->array_delete(*buffer);
+  cx->delete_(buffer);
 }
 
 JSObject*
 CData::GetCType(JSContext* cx, JSObject* dataObj)
 {
   JS_ASSERT(CData::IsCData(cx, dataObj));
 
   jsval slot;
@@ -5821,41 +5821,41 @@ Int64Base::Construct(JSContext* cx,
 {
   JSClass* clasp = isUnsigned ? &sUInt64Class : &sInt64Class;
   JSObject* result = JS_NewObject(cx, clasp, proto, JS_GetParent(cx, proto));
   if (!result)
     return NULL;
   js::AutoObjectRooter root(cx, result);
 
   // attach the Int64's data
-  JSUint64* buffer = js_new<JSUint64>(data);
+  JSUint64* buffer = cx->new_<JSUint64>(data);
   if (!buffer) {
     JS_ReportOutOfMemory(cx);
     return NULL;
   }
 
   if (!JS_SetReservedSlot(cx, result, SLOT_INT64, PRIVATE_TO_JSVAL(buffer))) {
-    js_delete(buffer);
+    Foreground::delete_(buffer);
     return NULL;
   }
 
   if (!JS_FreezeObject(cx, result))
     return NULL;
 
   return result;
 }
 
 void
 Int64Base::Finalize(JSContext* cx, JSObject* obj)
 {
   jsval slot;
   if (!JS_GetReservedSlot(cx, obj, SLOT_INT64, &slot) || JSVAL_IS_VOID(slot))
     return;
 
-  js_delete(static_cast<JSUint64*>(JSVAL_TO_PRIVATE(slot)));
+  cx->delete_(static_cast<JSUint64*>(JSVAL_TO_PRIVATE(slot)));
 }
 
 JSUint64
 Int64Base::GetInt(JSContext* cx, JSObject* obj) {
   JS_ASSERT(Int64::IsInt64(cx, obj) || UInt64::IsUInt64(cx, obj));
 
   jsval slot;
   ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_INT64, &slot));
--- a/js/src/ctypes/CTypes.h
+++ b/js/src/ctypes/CTypes.h
@@ -51,28 +51,28 @@ namespace ctypes {
 /*******************************************************************************
 ** Utility classes
 *******************************************************************************/
 
 template<class T>
 class OperatorDelete
 {
 public:
-  static void destroy(T* ptr) { js_delete(ptr); }
+  static void destroy(T* ptr) { UnwantedForeground::delete_(ptr); }
 };
 
 template<class T>
 class OperatorArrayDelete
 {
 public:
-  static void destroy(T* ptr) { js_array_delete(ptr); }
+  static void destroy(T* ptr) { UnwantedForeground::array_delete(ptr); }
 };
 
-// Class that takes ownership of a pointer T*, and calls js_delete() or
-// js_array_delete() upon destruction.
+// Class that takes ownership of a pointer T*, and calls cx->delete_() or
+// cx->array_delete() upon destruction.
 template<class T, class DeleteTraits = OperatorDelete<T> >
 class AutoPtr {
 private:
   typedef AutoPtr<T, DeleteTraits> self_type;
 
 public:
   // An AutoPtr variant that calls js_array_delete() instead.
   typedef AutoPtr<T, OperatorArrayDelete<T> > Array;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/pic/bug645184.js
@@ -0,0 +1,8 @@
+var obj = new Object();
+var passed = true;
+for (var i = 0; i < 100; i++) {
+if (obj['-1'] == null)
+    obj['-1'] = new Array();
+    assertEq(obj['-1'] == null, false);
+    obj = new Object();
+}
index 8da64fb6b61a5a047ac54c88020cf397fa7eaa25..14fb02a255f4cfa8300c9b73209116184f2fbf4f
GIT binary patch
literal 37
sc${;}%u6h)R7lIrNmbA&E=kNwNi0fH$jmD!EzwlSO)N>yNG;|90RKh}M*si-
--- a/js/src/jsapi-tests/Makefile.in
+++ b/js/src/jsapi-tests/Makefile.in
@@ -59,16 +59,17 @@ CPPSRCS = \
   testDefineGetterSetterNonEnumerable.cpp \
   testDefineProperty.cpp \
   testExtendedEq.cpp \
   testFuncCallback.cpp \
   testGCChunkAlloc.cpp \
   testGetPropertyDefault.cpp \
   testIntString.cpp \
   testLookup.cpp \
+  testLooselyEqual.cpp \
   testNewObject.cpp \
   testOps.cpp \
   testPropCache.cpp \
   testRegExpInstanceProperties.cpp \
   testResolveRecursion.cpp \
   testSameValue.cpp \
   testScriptObject.cpp \
   testSetProperty.cpp \
new file mode 100644
--- /dev/null
+++ b/js/src/jsapi-tests/testLooselyEqual.cpp
@@ -0,0 +1,168 @@
+#include "tests.h"
+#include <limits>
+#include <math.h>
+
+using namespace std;
+
+struct LooseEqualityFixture : public JSAPITest
+{
+    jsval qNaN;
+    jsval sNaN;
+    jsval d42;
+    jsval i42;
+    jsval undef;
+    jsval null;
+    jsval obj;
+    jsval poszero;
+    jsval negzero;
+
+    virtual ~LooseEqualityFixture() {}
+
+    virtual bool init() {
+        if (!JSAPITest::init())
+            return false;
+        qNaN = DOUBLE_TO_JSVAL(numeric_limits<double>::quiet_NaN());
+        sNaN = DOUBLE_TO_JSVAL(numeric_limits<double>::signaling_NaN());
+        d42 = DOUBLE_TO_JSVAL(42.0);
+        i42 = INT_TO_JSVAL(42);
+        undef = JSVAL_VOID;
+        null = JSVAL_NULL;
+        obj = OBJECT_TO_JSVAL(global);
+        poszero = DOUBLE_TO_JSVAL(0.0);
+        negzero = DOUBLE_TO_JSVAL(-0.0);
+#ifdef XP_WIN
+# define copysign _copysign
+#endif
+        JS_ASSERT(copysign(1.0, JSVAL_TO_DOUBLE(poszero)) == 1.0);
+        JS_ASSERT(copysign(1.0, JSVAL_TO_DOUBLE(negzero)) == -1.0);
+#ifdef XP_WIN
+# undef copysign
+#endif
+        return true;
+    }
+
+    bool leq(jsval x, jsval y) {
+        JSBool equal;
+        CHECK(JS_LooselyEqual(cx, x, y, &equal) && equal);
+        CHECK(JS_LooselyEqual(cx, y, x, &equal) && equal);
+        return true;
+    }
+
+    bool nleq(jsval x, jsval y) {
+        JSBool equal;
+        CHECK(JS_LooselyEqual(cx, x, y, &equal) && !equal);
+        CHECK(JS_LooselyEqual(cx, y, x, &equal) && !equal);
+        return true;
+    }
+};
+
+// 11.9.3 1a
+BEGIN_FIXTURE_TEST(LooseEqualityFixture, test_undef_leq_undef)
+{
+    CHECK(leq(JSVAL_VOID, JSVAL_VOID));
+    return true;
+}
+END_FIXTURE_TEST(LooseEqualityFixture, test_undef_leq_undef)
+
+// 11.9.3 1b
+BEGIN_FIXTURE_TEST(LooseEqualityFixture, test_null_leq_null)
+{
+    CHECK(leq(JSVAL_NULL, JSVAL_NULL));
+    return true;
+}
+END_FIXTURE_TEST(LooseEqualityFixture, test_null_leq_null)
+
+// 11.9.3 1ci
+BEGIN_FIXTURE_TEST(LooseEqualityFixture, test_nan_nleq_all)
+{
+    CHECK(nleq(qNaN, qNaN));
+    CHECK(nleq(qNaN, sNaN));
+
+    CHECK(nleq(sNaN, sNaN));
+    CHECK(nleq(sNaN, qNaN));
+
+    CHECK(nleq(qNaN, d42));
+    CHECK(nleq(qNaN, i42));
+    CHECK(nleq(qNaN, undef));
+    CHECK(nleq(qNaN, null));
+    CHECK(nleq(qNaN, obj));
+
+    CHECK(nleq(sNaN, d42));
+    CHECK(nleq(sNaN, i42));
+    CHECK(nleq(sNaN, undef));
+    CHECK(nleq(sNaN, null));
+    CHECK(nleq(sNaN, obj));
+    return true;
+}
+END_FIXTURE_TEST(LooseEqualityFixture, test_nan_nleq_all)
+
+// 11.9.3 1cii
+BEGIN_FIXTURE_TEST(LooseEqualityFixture, test_all_nleq_nan)
+{
+    CHECK(nleq(qNaN, qNaN));
+    CHECK(nleq(qNaN, sNaN));
+
+    CHECK(nleq(sNaN, sNaN));
+    CHECK(nleq(sNaN, qNaN));
+
+    CHECK(nleq(d42,   qNaN));
+    CHECK(nleq(i42,   qNaN));
+    CHECK(nleq(undef, qNaN));
+    CHECK(nleq(null,  qNaN));
+    CHECK(nleq(obj,   qNaN));
+
+    CHECK(nleq(d42,   sNaN));
+    CHECK(nleq(i42,   sNaN));
+    CHECK(nleq(undef, sNaN));
+    CHECK(nleq(null,  sNaN));
+    CHECK(nleq(obj,   sNaN));
+    return true;
+}
+END_FIXTURE_TEST(LooseEqualityFixture, test_all_nleq_nan)
+
+// 11.9.3 1ciii
+BEGIN_FIXTURE_TEST(LooseEqualityFixture, test_leq_same_nums)
+{
+    CHECK(leq(d42, d42));
+    CHECK(leq(i42, i42));
+    CHECK(leq(d42, i42));
+    CHECK(leq(i42, d42));
+    return true;
+}
+END_FIXTURE_TEST(LooseEqualityFixture, test_leq_same_nums)
+
+// 11.9.3 1civ
+BEGIN_FIXTURE_TEST(LooseEqualityFixture, test_pz_leq_nz)
+{
+    CHECK(leq(poszero, negzero));
+    return true;
+}
+END_FIXTURE_TEST(LooseEqualityFixture, test_pz_leq_nz)
+
+// 11.9.3 1cv
+BEGIN_FIXTURE_TEST(LooseEqualityFixture, test_nz_leq_pz)
+{
+    CHECK(leq(negzero, poszero));
+    return true;
+}
+END_FIXTURE_TEST(LooseEqualityFixture, test_nz_leq_pz)
+
+// 1cvi onwards NOT TESTED
+
+// 11.9.3 2
+BEGIN_FIXTURE_TEST(LooseEqualityFixture, test_null_leq_undef)
+{
+    CHECK(leq(null, undef));
+    return true;
+}
+END_FIXTURE_TEST(LooseEqualityFixture, test_null_leq_undef)
+
+// 11.9.3 3
+BEGIN_FIXTURE_TEST(LooseEqualityFixture, test_undef_leq_null)
+{
+    CHECK(leq(undef, null));
+    return true;
+}
+END_FIXTURE_TEST(LooseEqualityFixture, test_undef_leq_null)
+
+// 4 onwards NOT TESTED
--- a/js/src/jsapi-tests/testVersion.cpp
+++ b/js/src/jsapi-tests/testVersion.cpp
@@ -22,17 +22,18 @@ JSBool CaptureVersion(JSContext *cx, uin
 JSBool CheckOverride(JSContext *cx, uintN argc, jsval *vp);
 JSBool EvalScriptVersion16(JSContext *cx, uintN argc, jsval *vp);
 
 struct VersionFixture : public JSAPITest
 {
     JSVersion captured;
 
     virtual bool init() {
-        JSAPITest::init();
+        if (!JSAPITest::init())
+            return false;
         callbackData = this;
         captured = JSVERSION_UNKNOWN;
         return JS_DefineFunction(cx, global, "checkVersionHasXML", CheckVersionHasXML, 0, 0) &&
                JS_DefineFunction(cx, global, "disableXMLOption", DisableXMLOption, 0, 0) &&
                JS_DefineFunction(cx, global, "callSetVersion17", CallSetVersion17, 0, 0) &&
                JS_DefineFunction(cx, global, "checkNewScriptNoXML", CheckNewScriptNoXML, 0, 0) &&
                JS_DefineFunction(cx, global, "overrideVersion15", OverrideVersion15, 0, 0) &&
                JS_DefineFunction(cx, global, "captureVersion", CaptureVersion, 0, 0) &&
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -379,17 +379,17 @@ JS_AddArgumentFormatter(JSContext *cx, c
     while ((map = *mpp) != NULL) {
         /* Insert before any shorter string to match before prefixes. */
         if (map->length < length)
             break;
         if (map->length == length && !strcmp(map->format, format))
             goto out;
         mpp = &map->next;
     }
-    map = (JSArgumentFormatMap *) cx->malloc(sizeof *map);
+    map = (JSArgumentFormatMap *) cx->malloc_(sizeof *map);
     if (!map)
         return JS_FALSE;
     map->format = format;
     map->length = length;
     map->next = *mpp;
     *mpp = map;
 out:
     map->formatter = formatter;
@@ -402,17 +402,17 @@ JS_RemoveArgumentFormatter(JSContext *cx
     size_t length;
     JSArgumentFormatMap **mpp, *map;
 
     length = strlen(format);
     mpp = &cx->argumentFormatMap;
     while ((map = *mpp) != NULL) {
         if (map->length == length && !strcmp(map->format, format)) {
             *mpp = map->next;
-            cx->free(map);
+            cx->free_(map);
             return;
         }
         mpp = &map->next;
     }
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
@@ -515,16 +515,28 @@ JS_ValueToNumber(JSContext *cx, jsval v,
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DoubleIsInt32(jsdouble d, jsint *ip)
 {
     return JSDOUBLE_IS_INT32(d, (int32_t *)ip);
 }
 
+JS_PUBLIC_API(int32)
+JS_DoubleToInt32(jsdouble d)
+{
+    return js_DoubleToECMAInt32(d);
+}
+
+JS_PUBLIC_API(uint32)
+JS_DoubleToUint32(jsdouble d)
+{
+    return js_DoubleToECMAUint32(d);
+}
+
 JS_PUBLIC_API(JSBool)
 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
 
     AutoValueRooter tvr(cx, Valueify(v));
     return ValueToECMAInt32(cx, tvr.value(), (int32_t *)ip);
@@ -588,16 +600,23 @@ JS_GetTypeName(JSContext *cx, JSType typ
 JS_PUBLIC_API(JSBool)
 JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal)
 {
     assertSameCompartment(cx, v1, v2);
     return StrictlyEqual(cx, Valueify(v1), Valueify(v2), equal);
 }
 
 JS_PUBLIC_API(JSBool)
+JS_LooselyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal)
+{
+    assertSameCompartment(cx, v1, v2);
+    return LooselyEqual(cx, Valueify(v1), Valueify(v2), equal);
+}
+
+JS_PUBLIC_API(JSBool)
 JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same)
 {
     assertSameCompartment(cx, v1, v2);
     return SameValue(cx, Valueify(v1), Valueify(v2), same);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_IsBuiltinEvalFunction(JSFunction *fun)
@@ -645,23 +664,29 @@ JSRuntime::init(uint32 maxbytes)
             return false;
         if (!unjoinedFunctionCountMap.init())
             return false;
     }
     propTreeStatFilename = getenv("JS_PROPTREE_STATFILE");
     propTreeDumpFilename = getenv("JS_PROPTREE_DUMPFILE");
 #endif
 
-    if (!(atomsCompartment = js_new<JSCompartment>(this)) ||
+    if (!js_InitGC(this, maxbytes))
+        return false;
+
+    if (!(atomsCompartment = this->new_<JSCompartment>(this)) ||
         !atomsCompartment->init() ||
         !compartments.append(atomsCompartment)) {
+        Foreground::delete_(atomsCompartment);
         return false;
     }
 
-    if (!js_InitGC(this, maxbytes) || !js_InitAtomState(this))
+    atomsCompartment->setGCLastBytes(8192);
+
+    if (!js_InitAtomState(this))
         return false;
 
     wrapObjectCallback = js::TransparentObjectWrapper;
 
 #ifdef JS_THREADSAFE
     /* this is asymmetric with JS_ShutDown: */
     if (!js_SetupLocks(8, 16))
         return false;
@@ -750,35 +775,33 @@ JS_NewRuntime(uint32 maxbytes)
     JS_END_MACRO;
 #include "js.msg"
 #undef MSG_DEF
 
         js_NewRuntimeWasCalled = JS_TRUE;
     }
 #endif /* DEBUG */
 
-    void *mem = js_calloc(sizeof(JSRuntime));
+    void *mem = OffTheBooks::calloc_(sizeof(JSRuntime));
     if (!mem)
         return NULL;
 
     JSRuntime *rt = new (mem) JSRuntime();
     if (!rt->init(maxbytes)) {
         JS_DestroyRuntime(rt);
         return NULL;
     }
 
     return rt;
 }
 
 JS_PUBLIC_API(void)
 JS_DestroyRuntime(JSRuntime *rt)
 {
-    rt->~JSRuntime();
-
-    js_free(rt);
+    Foreground::delete_(rt);
 }
 
 #ifdef JS_REPRMETER
 namespace reprmeter {
     extern void js_DumpReprMeter();
 }
 #endif
 
@@ -1174,21 +1197,21 @@ JS_SetWrapObjectCallbacks(JSRuntime *rt,
 }
 
 JS_PUBLIC_API(JSCrossCompartmentCall *)
 JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target)
 {
     CHECK_REQUEST(cx);
 
     JS_ASSERT(target);
-    AutoCompartment *call = js_new<AutoCompartment>(cx, target);
+    AutoCompartment *call = cx->new_<AutoCompartment>(cx, target);
     if (!call)
         return NULL;
     if (!call->enter()) {
-        js_delete(call);
+        Foreground::delete_(call);
         return NULL;
     }
     return reinterpret_cast<JSCrossCompartmentCall *>(call);
 }
 
 JS_PUBLIC_API(JSCrossCompartmentCall *)
 JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target)
 {
@@ -1216,17 +1239,17 @@ JS_EnterCrossCompartmentCallScript(JSCon
 }
 
 JS_PUBLIC_API(void)
 JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
 {
     AutoCompartment *realcall = reinterpret_cast<AutoCompartment *>(call);
     CHECK_REQUEST(realcall->context);
     realcall->leave();
-    js_delete(realcall);
+    Foreground::delete_(realcall);
 }
 
 bool
 JSAutoEnterCompartment::enter(JSContext *cx, JSObject *target)
 {
     JS_ASSERT(!call);
     if (cx->compartment == target->getCompartment()) {
         call = reinterpret_cast<JSCrossCompartmentCall*>(1);
@@ -1874,17 +1897,17 @@ JS_EnumerateStandardClasses(JSContext *c
 namespace js {
 
 JSIdArray *
 NewIdArray(JSContext *cx, jsint length)
 {
     JSIdArray *ida;
 
     ida = (JSIdArray *)
-        cx->calloc(offsetof(JSIdArray, vector) + length * sizeof(jsval));
+        cx->calloc_(offsetof(JSIdArray, vector) + length * sizeof(jsval));
     if (ida)
         ida->length = length;
     return ida;
 }
 
 }
 
 /*
@@ -2035,45 +2058,45 @@ JS_ComputeThis(JSContext *cx, jsval *vp)
 {
     assertSameCompartment(cx, JSValueArray(vp, 2));
     return BoxThisForVp(cx, Valueify(vp)) ? vp[1] : JSVAL_NULL;
 }
 
 JS_PUBLIC_API(void *)
 JS_malloc(JSContext *cx, size_t nbytes)
 {
-    return cx->malloc(nbytes);
+    return cx->malloc_(nbytes);
 }
 
 JS_PUBLIC_API(void *)
 JS_realloc(JSContext *cx, void *p, size_t nbytes)
 {
-    return cx->realloc(p, nbytes);
+    return cx->realloc_(p, nbytes);
 }
 
 JS_PUBLIC_API(void)
 JS_free(JSContext *cx, void *p)
 {
-    return cx->free(p);
+    return cx->free_(p);
 }
 
 JS_PUBLIC_API(void)
 JS_updateMallocCounter(JSContext *cx, size_t nbytes)
 {
     return cx->runtime->updateMallocCounter(nbytes);
 }
 
 JS_PUBLIC_API(char *)
 JS_strdup(JSContext *cx, const char *s)
 {
     size_t n;
     void *p;
 
     n = strlen(s) + 1;
-    p = cx->malloc(n);
+    p = cx->malloc_(n);
     if (!p)
         return NULL;
     return (char *)memcpy(p, s, n);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
 {
@@ -2448,17 +2471,17 @@ DumpNotify(JSTracer *trc, void *thing, u
                     (const char *)dtrc->base.debugPrintArg,
                     dtrc->base.debugPrintIndex);
         edgeName = dtrc->buffer;
     } else {
         edgeName = (const char*)dtrc->base.debugPrintArg;
     }
 
     edgeNameSize = strlen(edgeName) + 1;
-    node = (JSHeapDumpNode *) js_malloc(offsetof(JSHeapDumpNode, edgeName) + edgeNameSize);
+    node = (JSHeapDumpNode *) cx->malloc_(offsetof(JSHeapDumpNode, edgeName) + edgeNameSize);
     if (!node) {
         dtrc->ok = JS_FALSE;
         return;
     }
 
     node->thing = thing;
     node->kind = kind;
     node->next = NULL;
@@ -2600,17 +2623,17 @@ JS_DumpHeap(JSContext *cx, FILE *fp, voi
                 }
             }
         }
 
         /* Move to next or parents next and free the node. */
         for (;;) {
             next = node->next;
             parent = node->parent;
-            js_free(node);
+            cx->free_(node);
             node = next;
             if (node)
                 break;
             if (!parent)
                 goto dump_out;
             JS_ASSERT(depth > 1);
             --depth;
             node = parent;
@@ -2818,17 +2841,17 @@ JS_SetScriptStackQuota(JSContext *cx, si
     cx->scriptStackQuota = quota;
 }
 
 /************************************************************************/
 
 JS_PUBLIC_API(void)
 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
 {
-    cx->free(ida);
+    cx->free_(ida);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
     return ValueToId(cx, Valueify(v), idp);
@@ -4562,17 +4585,17 @@ JS_CompileScriptForPrincipals(JSContext 
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     CHECK_REQUEST(cx);
 
     jschar *chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return NULL;
     JSObject *scriptObj =
         JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length, filename, lineno);
-    cx->free(chars);
+    cx->free_(chars);
     return scriptObj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_CompileScript(JSContext *cx, JSObject *obj, const char *bytes, size_t length,
                  const char *filename, uintN lineno)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
@@ -4610,17 +4633,17 @@ JS_BufferIsCompilableUnit(JSContext *cx,
                  * source, we return false so our caller knows to try to
                  * collect more buffered source.
                  */
                 result = JS_FALSE;
             }
             JS_SetErrorReporter(cx, older);
         }
     }
-    cx->free(chars);
+    cx->free_(chars);
     JS_RestoreExceptionState(cx, exnState);
     return result;
 }
 
 /* Use the fastest available getc. */
 #if defined(HAVE_GETC_UNLOCKED)
 # define fast_getc getc_unlocked
 #elif defined(HAVE__GETC_NOLOCK)
@@ -4646,48 +4669,48 @@ CompileFileHelper(JSContext *cx, JSObjec
     /* Read in the whole file, then compile it. */
     if (fp == stdin) {
         JS_ASSERT(len == 0);
         len = 8;  /* start with a small buffer, expand as necessary */
         int c;
         bool hitEOF = false;
         while (!hitEOF) {
             len *= 2;
-            jschar* tmpbuf = (jschar *) js_realloc(buf, len * sizeof(jschar));
+            jschar* tmpbuf = (jschar *) cx->realloc_(buf, len * sizeof(jschar));
             if (!tmpbuf) {
-                cx->free(buf);
+                cx->free_(buf);
                 return NULL;
             }
             buf = tmpbuf;
 
             while (i < len) {
                 c = fast_getc(fp);
                 if (c == EOF) {
                     hitEOF = true;
                     break;
                 }
                 buf[i++] = (jschar) (unsigned char) c;
             }
         }
     } else {
-        buf = (jschar *) js_malloc(len * sizeof(jschar));
+        buf = (jschar *) cx->malloc_(len * sizeof(jschar));
         if (!buf)
             return NULL;
 
         int c;
         while ((c = fast_getc(fp)) != EOF)
             buf[i++] = (jschar) (unsigned char) c;
     }
 
     JS_ASSERT(i <= len);
     len = i;
     uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
     script = Compiler::compileScript(cx, obj, NULL, principals, tcflags, buf, len, filename, 1,
                                      cx->findVersion());
-    js_free(buf);
+    cx->free_(buf);
     if (!script)
         return NULL;
 
     JSObject *scriptObj = js_NewScriptObject(cx, script);
     if (!scriptObj)
         js_DestroyScript(cx, script);
     
     return scriptObj;
@@ -4886,17 +4909,17 @@ JS_CompileFunctionForPrincipals(JSContex
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     jschar *chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return NULL;
     JSFunction *fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name,
                                                         nargs, argnames, chars, length,
                                                         filename, lineno);
-    cx->free(chars);
+    cx->free_(chars);
     return fun;
 }
 
 JS_PUBLIC_API(JSFunction *)
 JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
                    uintN nargs, const char **argnames,
                    const char *bytes, size_t length,
                    const char *filename, uintN lineno)
@@ -5049,17 +5072,17 @@ JS_EvaluateScriptForPrincipals(JSContext
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     size_t length = nbytes;
     jschar *chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return JS_FALSE;
     JSBool ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length,
                                                  filename, lineno, rval);
-    cx->free(chars);
+    cx->free_(chars);
     return ok;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_EvaluateScriptForPrincipalsVersion(JSContext *cx, JSObject *obj, JSPrincipals *principals,
                                       const char *bytes, uintN nbytes,
                                       const char *filename, uintN lineno, jsval *rval, JSVersion version)
 {
@@ -5274,17 +5297,17 @@ JS_NewStringCopyZ(JSContext *cx, const c
     if (!s)
         return cx->runtime->emptyString;
     n = strlen(s);
     js = js_InflateString(cx, s, &n);
     if (!js)
         return NULL;
     str = js_NewString(cx, js, n);
     if (!str)
-        cx->free(js);
+        cx->free_(js);
     return str;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_StringHasBeenInterned(JSString *str)
 {
     return str->isAtom();
 }
@@ -5824,17 +5847,17 @@ JS_PUBLIC_API(JSObject *)
 JS_NewRegExpObject(JSContext *cx, JSObject *obj, char *bytes, size_t length, uintN flags)
 {
     CHECK_REQUEST(cx);
     jschar *chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return NULL;
     RegExpStatics *res = RegExpStatics::extractFrom(obj);
     JSObject *reobj = RegExp::createObject(cx, res, chars, length, flags);
-    cx->free(chars);
+    cx->free_(chars);
     return reobj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewUCRegExpObject(JSContext *cx, JSObject *obj, jschar *chars, size_t length, uintN flags)
 {
     CHECK_REQUEST(cx);
     RegExpStatics *res = RegExpStatics::extractFrom(obj);
@@ -5879,17 +5902,17 @@ JS_ExecuteRegExp(JSContext *cx, JSObject
 JS_PUBLIC_API(JSObject *)
 JS_NewRegExpObjectNoStatics(JSContext *cx, char *bytes, size_t length, uintN flags)
 {
     CHECK_REQUEST(cx);
     jschar *chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return NULL;
     JSObject *obj = RegExp::createObjectNoStatics(cx, chars, length, flags);
-    cx->free(chars);
+    cx->free_(chars);
     return obj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewUCRegExpObjectNoStatics(JSContext *cx, jschar *chars, size_t length, uintN flags)
 {
     CHECK_REQUEST(cx);
     return RegExp::createObjectNoStatics(cx, chars, length, flags);
@@ -5986,17 +6009,17 @@ struct JSExceptionState {
 };
 
 JS_PUBLIC_API(JSExceptionState *)
 JS_SaveExceptionState(JSContext *cx)
 {
     JSExceptionState *state;
 
     CHECK_REQUEST(cx);
-    state = (JSExceptionState *) cx->malloc(sizeof(JSExceptionState));
+    state = (JSExceptionState *) cx->malloc_(sizeof(JSExceptionState));
     if (state) {
         state->throwing = JS_GetPendingException(cx, &state->exception);
         if (state->throwing && JSVAL_IS_GCTHING(state->exception))
             js_AddRoot(cx, Valueify(&state->exception), "JSExceptionState.exception");
     }
     return state;
 }
 
@@ -6017,17 +6040,17 @@ JS_PUBLIC_API(void)
 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
 {
     CHECK_REQUEST(cx);
     if (state) {
         if (state->throwing && JSVAL_IS_GCTHING(state->exception)) {
             assertSameCompartment(cx, state->exception);
             JS_RemoveValueRoot(cx, &state->exception);
         }
-        cx->free(state);
+        cx->free_(state);
     }
 }
 
 JS_PUBLIC_API(JSErrorReport *)
 JS_ErrorFromException(JSContext *cx, jsval v)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -659,16 +659,22 @@ extern JS_PUBLIC_API(JSString *)
 JS_ValueToSource(JSContext *cx, jsval v);
 
 extern JS_PUBLIC_API(JSBool)
 JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp);
 
 extern JS_PUBLIC_API(JSBool)
 JS_DoubleIsInt32(jsdouble d, jsint *ip);
 
+extern JS_PUBLIC_API(int32)
+JS_DoubleToInt32(jsdouble d);
+
+extern JS_PUBLIC_API(uint32)
+JS_DoubleToUint32(jsdouble d);
+
 /*
  * Convert a value to a number, then to an int32, according to the ECMA rules
  * for ToInt32.
  */
 extern JS_PUBLIC_API(JSBool)
 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip);
 
 /*
@@ -700,16 +706,19 @@ JS_TypeOfValue(JSContext *cx, jsval v);
 
 extern JS_PUBLIC_API(const char *)
 JS_GetTypeName(JSContext *cx, JSType type);
 
 extern JS_PUBLIC_API(JSBool)
 JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal);
 
 extern JS_PUBLIC_API(JSBool)
+JS_LooselyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal);
+
+extern JS_PUBLIC_API(JSBool)
 JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same);
 
 /* True iff fun is the global eval function. */
 extern JS_PUBLIC_API(JSBool)
 JS_IsBuiltinEvalFunction(JSFunction *fun);
 
 /* True iff fun is the Function constructor. */
 extern JS_PUBLIC_API(JSBool)
@@ -3224,34 +3233,34 @@ class JSAutoByteString {
     }
 
     JSAutoByteString(JS_GUARD_OBJECT_NOTIFIER_PARAM0)
       : mBytes(NULL) {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     ~JSAutoByteString() {
-        js_free(mBytes);
+        js::UnwantedForeground::free_(mBytes);
     }
 
     /* Take ownership of the given byte array. */
     void initBytes(char *bytes) {
         JS_ASSERT(!mBytes);
         mBytes = bytes;
     }
 
     char *encode(JSContext *cx, JSString *str) {
         JS_ASSERT(!mBytes);
         JS_ASSERT(cx);
         mBytes = JS_EncodeString(cx, str);
         return mBytes;
     }
 
     void clear() {
-        js_free(mBytes);
+        js::UnwantedForeground::free_(mBytes);
         mBytes = NULL;
     }
 
     char *ptr() const {
         return mBytes;
     }
 
     bool operator!() const {
@@ -3314,17 +3323,17 @@ struct JSStructuredCloneCallbacks {
 };
 
 JS_PUBLIC_API(JSBool)
 JS_ReadStructuredClone(JSContext *cx, const uint64 *data, size_t nbytes,
                        uint32 version, jsval *vp,
                        const JSStructuredCloneCallbacks *optionalCallbacks,
                        void *closure);
 
-/* Note: On success, the caller is responsible for calling js_free(*datap). */
+/* Note: On success, the caller is responsible for calling js::Foreground::free(*datap). */
 JS_PUBLIC_API(JSBool)
 JS_WriteStructuredClone(JSContext *cx, jsval v, uint64 **datap, size_t *nbytesp,
                         const JSStructuredCloneCallbacks *optionalCallbacks,
                         void *closure);
 
 JS_PUBLIC_API(JSBool)
 JS_StructuredClone(JSContext *cx, jsval v, jsval *vp,
                    const JSStructuredCloneCallbacks *optionalCallbacks,
--- a/js/src/jsarena.cpp
+++ b/js/src/jsarena.cpp
@@ -45,16 +45,18 @@
 #include <stdlib.h>
 #include <string.h>
 #include "jstypes.h"
 #include "jsstdint.h"
 #include "jsbit.h"
 #include "jsarena.h"
 #include "jsprvtd.h"
 
+using namespace js;
+
 #ifdef JS_ARENAMETER
 static JSArenaStats *arena_stats_list;
 
 #define COUNT(pool,what)  (pool)->stats.what++
 #else
 #define COUNT(pool,what)  /* nothing */
 #endif
 
@@ -155,22 +157,22 @@ JS_ArenaAllocate(JSArenaPool *pool, size
             extra = (nb > pool->arenasize) ? HEADER_SIZE(pool) : 0;
             hdrsz = sizeof *a + extra + pool->mask;
             gross = hdrsz + JS_MAX(nb, pool->arenasize);
             if (gross < nb)
                 return NULL;
             if (pool->quotap) {
                 if (gross > *pool->quotap)
                     return NULL;
-                b = (JSArena *) js_malloc(gross);
+                b = (JSArena *) OffTheBooks::malloc_(gross);
                 if (!b)
                     return NULL;
                 *pool->quotap -= gross;
             } else {
-                b = (JSArena *) js_malloc(gross);
+                b = (JSArena *) OffTheBooks::malloc_(gross);
                 if (!b)
                     return NULL;
             }
 
             b->next = NULL;
             b->limit = (jsuword)b + gross;
             JS_COUNT_ARENA(pool,++);
             COUNT(pool, nmallocs);
@@ -222,22 +224,22 @@ JS_ArenaRealloc(JSArenaPool *pool, void 
     extra = HEADER_SIZE(pool);                  /* oversized header holds ap */
     hdrsz = sizeof *a + extra + pool->mask;     /* header and alignment slop */
     gross = hdrsz + aoff;
     JS_ASSERT(gross > aoff);
     if (pool->quotap) {
         growth = gross - (a->limit - (jsuword) a);
         if (growth > *pool->quotap)
             return NULL;
-        a = (JSArena *) js_realloc(a, gross);
+        a = (JSArena *) OffTheBooks::realloc_(a, gross);
         if (!a)
             return NULL;
         *pool->quotap -= growth;
     } else {
-        a = (JSArena *) js_realloc(a, gross);
+        a = (JSArena *) OffTheBooks::realloc_(a, gross);
         if (!a)
             return NULL;
     }
 #ifdef JS_ARENAMETER
     pool->stats.nreallocs++;
 #endif
 
     if (a != *ap) {
@@ -310,17 +312,17 @@ FreeArenaList(JSArenaPool *pool, JSArena
 #endif
 
     do {
         *ap = a->next;
         if (pool->quotap)
             *pool->quotap += a->limit - (jsuword) a;
         JS_CLEAR_ARENA(a);
         JS_COUNT_ARENA(pool,--);
-        js_free(a);
+        UnwantedForeground::free_(a);
     } while ((a = *ap) != NULL);
 
     pool->current = head;
 }
 
 JS_PUBLIC_API(void)
 JS_ArenaRelease(JSArenaPool *pool, char *mark)
 {
@@ -349,17 +351,17 @@ JS_PUBLIC_API(void)
 JS_FinishArenaPool(JSArenaPool *pool)
 {
     FreeArenaList(pool, &pool->first);
 #ifdef JS_ARENAMETER
     {
         JSArenaStats *stats, **statsp;
 
         if (pool->stats.name) {
-            js_free(pool->stats.name);
+            UnwantedForeground::free_(pool->stats.name);
             pool->stats.name = NULL;
         }
         for (statsp = &arena_stats_list; (stats = *statsp) != 0;
              statsp = &stats->next) {
             if (stats == &pool->stats) {
                 *statsp = stats->next;
                 return;
             }
--- a/js/src/jsarena.h
+++ b/js/src/jsarena.h
@@ -197,17 +197,17 @@ struct JSArenaPool {
 #endif
 
 #define JS_ARENA_DESTROY(pool, a, pnext)                                      \
     JS_BEGIN_MACRO                                                            \
         JS_COUNT_ARENA(pool,--);                                              \
         if ((pool)->current == (a)) (pool)->current = &(pool)->first;         \
         *(pnext) = (a)->next;                                                 \
         JS_CLEAR_ARENA(a);                                                    \
-        js_free(a);                                                              \
+        js::UnwantedForeground::free_(a);                                      \
         (a) = NULL;                                                           \
     JS_END_MACRO
 
 /*
  * Initialize an arena pool with a minimum size per arena of size bytes.
  */
 extern JS_PUBLIC_API(void)
 JS_InitArenaPool(JSArenaPool *pool, const char *name, size_t size,
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1149,17 +1149,17 @@ array_toSource(JSContext *cx, uintN argc
     } else if (sharpchars) {
         MAKE_SHARP(he);
         sb.replaceRawBuffer(sharpchars, js_strlen(sharpchars));
     }
 #else
     if (IS_SHARP(he)) {
         if (!sb.append("[]"))
             goto out;
-        cx->free(sharpchars);
+        cx->free_(sharpchars);
         goto make_string;
     }
 #endif
 
     if (!sb.append('['))
         goto out;
 
     jsuint length;
@@ -1813,29 +1813,29 @@ js::array_sort(JSContext *cx, uintN argc
      * one while increasing the rooted amount of vec when we know that the
      * property at the corresponding index exists and its value must be rooted.
      *
      * In this way when sorting a huge mostly sparse array we will not
      * access the tail of vec corresponding to properties that do not
      * exist, allowing OS to avoiding committing RAM. See bug 330812.
      */
     {
-        Value *vec = (Value *) cx->malloc(2 * size_t(len) * sizeof(Value));
+        Value *vec = (Value *) cx->malloc_(2 * size_t(len) * sizeof(Value));
         if (!vec)
             return false;
 
         DEFINE_LOCAL_CLASS_OF_STATIC_FUNCTION(AutoFreeVector) {
             JSContext *const cx;
             Value *&vec;
            public:
             AutoFreeVector(JSContext *cx, Value *&vec) : cx(cx), vec(vec) { }
             ~AutoFreeVector() {
-                cx->free(vec);
+                cx->free_(vec);
             }
-        } free(cx, vec);
+        } free_(cx, vec);
 
         AutoArrayRooter tvr(cx, 0, vec);
 
         /*
          * By ECMA 262, 15.4.4.11, a property that does not exist (which we
          * call a "hole") is always greater than an existing property with
          * value undefined and that is always greater than any other property.
          * Thus to sort holes and undefs we simply count them, sort the rest
@@ -1935,17 +1935,17 @@ js::array_sort(JSContext *cx, uintN argc
                         return false;
                     // Copying v must come first, because the following line overwrites v
                     // when i == 0.
                     vec[2 * i + 1] = v;
                     vec[2 * i].setString(str);
                 } while (i != 0);
 
                 JS_ASSERT(tvr.array == vec);
-                vec = (Value *) cx->realloc(vec, 4 * size_t(newlen) * sizeof(Value));
+                vec = (Value *) cx->realloc_(vec, 4 * size_t(newlen) * sizeof(Value));
                 if (!vec) {
                     vec = tvr.array;  /* N.B. AutoFreeVector */
                     return false;
                 }
                 mergesort_tmp = vec + 2 * newlen;
                 MakeRangeGCSafe(mergesort_tmp, 2 * newlen);
                 tvr.changeArray(vec, newlen * 4);
                 elemsize = 2 * sizeof(Value);
@@ -3137,28 +3137,28 @@ js_ArrayInfo(JSContext *cx, uintN argc, 
         Value arg = Valueify(JS_ARGV(cx, vp)[i]);
 
         char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, arg, NULL);
         if (!bytes)
             return JS_FALSE;
         if (arg.isPrimitive() ||
             !(array = arg.toObjectOrNull())->isArray()) {
             fprintf(stderr, "%s: not array\n", bytes);
-            cx->free(bytes);
+            cx->free_(bytes);
             continue;
         }
         fprintf(stderr, "%s: %s (len %u", bytes,
                 array->isDenseArray() ? "dense" : "sparse",
                 array->getArrayLength());
         if (array->isDenseArray()) {
             fprintf(stderr, ", capacity %u",
                     array->getDenseArrayCapacity());
         }
         fputs(")\n", stderr);
-        cx->free(bytes);
+        cx->free_(bytes);
     }
 
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return true;
 }
 #endif
 
 JS_FRIEND_API(JSBool)
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -477,17 +477,17 @@ Atomize(JSContext *cx, const jschar *cha
         atom = AtomEntryToKey(*p);
     } else {
         SwitchToCompartment sc(cx, cx->runtime->atomsCompartment);
 
         JSFixedString *key;
         if (flags & ATOM_NOCOPY) {
             key = js_NewString(cx, const_cast<jschar *>(chars), length);
             if (!key) {
-                cx->free(const_cast<jschar *>(chars));
+                cx->free_(const_cast<jschar *>(chars));
                 return NULL;
             }
         } else {
             key = js_NewStringCopyN(cx, chars, length);
             if (!key)
                 return NULL;
         }
 
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -601,22 +601,22 @@ JSStructuredCloneReader::checkDouble(jsd
     return true;
 }
 
 class Chars {
     JSContext *cx;
     jschar *p;
   public:
     Chars() : p(NULL) {}
-    ~Chars() { if (p) cx->free(p); }
+    ~Chars() { if (p) cx->free_(p); }
 
     bool allocate(JSContext *cx, size_t len) {
         JS_ASSERT(!p);
         // We're going to null-terminate!
-        p = (jschar *) cx->malloc((len + 1) * sizeof(jschar));
+        p = (jschar *) cx->malloc_((len + 1) * sizeof(jschar));
         this->cx = cx;
         if (p) {
             p[len] = jschar(0);
             return true;
         }
         return false;
     }
     jschar *get() { return p; }
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -560,23 +560,23 @@ JSThreadData::purge(JSContext *cx)
 }
 
 #ifdef JS_THREADSAFE
 
 static JSThread *
 NewThread(void *id)
 {
     JS_ASSERT(js_CurrentThreadId() == id);
-    JSThread *thread = (JSThread *) js_calloc(sizeof(JSThread));
+    JSThread *thread = (JSThread *) OffTheBooks::calloc_(sizeof(JSThread));
     if (!thread)
         return NULL;
     JS_INIT_CLIST(&thread->contextList);
     thread->id = id;
     if (!thread->data.init()) {
-        js_free(thread);
+        Foreground::free_(thread);
         return NULL;
     }
     return thread;
 }
 
 static void
 DestroyThread(JSThread *thread)
 {
@@ -585,17 +585,17 @@ DestroyThread(JSThread *thread)
 
     /*
      * The conservative GC scanner should be disabled when the thread leaves
      * the last request.
      */
     JS_ASSERT(!thread->data.conservativeGC.hasStackToScan());
 
     thread->data.finish();
-    js_free(thread);
+    Foreground::free_(thread);
 }
 
 JSThread *
 js_CurrentThread(JSRuntime *rt)
 {
     void *id = js_CurrentThreadId();
     JS_LOCK_GC(rt);
 
@@ -742,17 +742,17 @@ js_NewContext(JSRuntime *rt, size_t stac
     JSBool ok, first;
     JSContextCallback cxCallback;
 
     /*
      * We need to initialize the new context fully before adding it to the
      * runtime list. After that it can be accessed from another thread via
      * js_ContextIterator.
      */
-    void *mem = js_calloc(sizeof *cx);
+    void *mem = OffTheBooks::calloc_(sizeof *cx);
     if (!mem)
         return NULL;
 
     cx = new (mem) JSContext(rt);
     cx->debugHooks = &rt->globalDebugHooks;
 #if JS_STACK_GROWTH_DIRECTION > 0
     cx->stackLimit = (jsuword) -1;
 #endif
@@ -1118,31 +1118,30 @@ FreeContext(JSContext *cx)
 #endif
 
     /* Free the stuff hanging off of cx. */
     VOUCH_DOES_NOT_REQUIRE_STACK();
     JS_FinishArenaPool(&cx->tempPool);
     JS_FinishArenaPool(&cx->regExpPool);
 
     if (cx->lastMessage)
-        js_free(cx->lastMessage);
+        cx->free_(cx->lastMessage);
 
     /* Remove any argument formatters. */
     JSArgumentFormatMap *map = cx->argumentFormatMap;
     while (map) {
         JSArgumentFormatMap *temp = map;
         map = map->next;
-        cx->free(temp);
+        cx->free_(temp);
     }
 
     JS_ASSERT(!cx->resolvingList);
 
     /* Finally, free cx itself. */
-    cx->~JSContext();
-    js_free(cx);
+    Foreground::delete_(cx);
 }
 
 JSContext *
 js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp)
 {
     JSContext *cx = *iterp;
 
     Conditionally<AutoLockGC> lockIf(!!unlocked, rt);
@@ -1363,18 +1362,18 @@ js_ReportErrorVA(JSContext *cx, uintN fl
     report.flags = flags;
     report.errorNumber = JSMSG_USER_DEFINED_ERROR;
     report.ucmessage = ucmessage = js_InflateString(cx, message, &messagelen);
     PopulateReportBlame(cx, &report);
 
     warning = JSREPORT_IS_WARNING(report.flags);
 
     ReportError(cx, message, &report, NULL, NULL);
-    js_free(message);
-    cx->free(ucmessage);
+    Foreground::free_(message);
+    Foreground::free_(ucmessage);
     return warning;
 }
 
 /*
  * The arguments from ap need to be packaged up into an array and stored
  * into the report struct.
  *
  * The format string addressed by the error number may contain operands
@@ -1409,17 +1408,17 @@ js_ExpandErrorArguments(JSContext *cx, J
         if (argCount > 0) {
             /*
              * Gather the arguments into an array, and accumulate
              * their sizes. We allocate 1 more than necessary and
              * null it out to act as the caboose when we free the
              * pointers later.
              */
             reportp->messageArgs = (const jschar **)
-                cx->malloc(sizeof(jschar *) * (argCount + 1));
+                cx->malloc_(sizeof(jschar *) * (argCount + 1));
             if (!reportp->messageArgs)
                 return JS_FALSE;
             reportp->messageArgs[argCount] = NULL;
             for (i = 0; i < argCount; i++) {
                 if (charArgs) {
                     char *charArg = va_arg(ap, char *);
                     size_t charArgLength = strlen(charArg);
                     reportp->messageArgs[i]
@@ -1453,19 +1452,19 @@ js_ExpandErrorArguments(JSContext *cx, J
                                  - (3 * argCount)       /* exclude the {n} */
                                  + totalArgsLength;
 
                 /*
                 * Note - the above calculation assumes that each argument
                 * is used once and only once in the expansion !!!
                 */
                 reportp->ucmessage = out = (jschar *)
-                    cx->malloc((expandedLength + 1) * sizeof(jschar));
+                    cx->malloc_((expandedLength + 1) * sizeof(jschar));
                 if (!out) {
-                    cx->free(buffer);
+                    cx->free_(buffer);
                     goto error;
                 }
                 while (*fmt) {
                     if (*fmt == '{') {
                         if (isdigit(fmt[1])) {
                             int d = JS7_UNDEC(fmt[1]);
                             JS_ASSERT(d < argCount);
                             js_strncpy(out, reportp->messageArgs[d],
@@ -1475,17 +1474,17 @@ js_ExpandErrorArguments(JSContext *cx, J
                             expandedArgs++;
                             continue;
                         }
                     }
                     *out++ = *fmt++;
                 }
                 JS_ASSERT(expandedArgs == argCount);
                 *out = 0;
-                cx->free(buffer);
+                cx->free_(buffer);
                 *messagep =
                     js_DeflateString(cx, reportp->ucmessage,
                                      (size_t)(out - reportp->ucmessage));
                 if (!*messagep)
                     goto error;
             }
         } else {
             /*
@@ -1504,40 +1503,40 @@ js_ExpandErrorArguments(JSContext *cx, J
             }
         }
     }
     if (*messagep == NULL) {
         /* where's the right place for this ??? */
         const char *defaultErrorMessage
             = "No error message available for error number %d";
         size_t nbytes = strlen(defaultErrorMessage) + 16;
-        *messagep = (char *)cx->malloc(nbytes);
+        *messagep = (char *)cx->malloc_(nbytes);
         if (!*messagep)
             goto error;
         JS_snprintf(*messagep, nbytes, defaultErrorMessage, errorNumber);
     }
     return JS_TRUE;
 
 error:
     if (reportp->messageArgs) {
         /* free the arguments only if we allocated them */
         if (charArgs) {
             i = 0;
             while (reportp->messageArgs[i])
-                cx->free((void *)reportp->messageArgs[i++]);
+                cx->free_((void *)reportp->messageArgs[i++]);
         }
-        cx->free((void *)reportp->messageArgs);
+        cx->free_((void *)reportp->messageArgs);
         reportp->messageArgs = NULL;
     }
     if (reportp->ucmessage) {
-        cx->free((void *)reportp->ucmessage);
+        cx->free_((void *)reportp->ucmessage);
         reportp->ucmessage = NULL;
     }
     if (*messagep) {
-        cx->free((void *)*messagep);
+        cx->free_((void *)*messagep);
         *messagep = NULL;
     }
     return JS_FALSE;
 }
 
 JSBool
 js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback,
                        void *userRef, const uintN errorNumber,
@@ -1559,45 +1558,45 @@ js_ReportErrorNumberVA(JSContext *cx, ui
     if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber,
                                  &message, &report, !!charArgs, ap)) {
         return JS_FALSE;
     }
 
     ReportError(cx, message, &report, callback, userRef);
 
     if (message)
-        cx->free(message);
+        cx->free_(message);
     if (report.messageArgs) {
         /*
          * js_ExpandErrorArguments owns its messageArgs only if it had to
          * inflate the arguments (from regular |char *|s).
          */
         if (charArgs) {
             int i = 0;
             while (report.messageArgs[i])
-                cx->free((void *)report.messageArgs[i++]);
+                cx->free_((void *)report.messageArgs[i++]);
         }
-        cx->free((void *)report.messageArgs);
+        cx->free_((void *)report.messageArgs);
     }
     if (report.ucmessage)
-        cx->free((void *)report.ucmessage);
+        cx->free_((void *)report.ucmessage);
 
     return warning;
 }
 
 JS_FRIEND_API(void)
 js_ReportErrorAgain(JSContext *cx, const char *message, JSErrorReport *reportp)
 {
     JSErrorReporter onError;
 
     if (!message)
         return;
 
     if (cx->lastMessage)
-        js_free(cx->lastMessage);
+        Foreground::free_(cx->lastMessage);
     cx->lastMessage = JS_strdup(cx, message);
     if (!cx->lastMessage)
         return;
     onError = cx->errorReporter;
 
     /*
      * If debugErrorHook is present then we give it a chance to veto
      * sending the error on to the regular ErrorReporter.
@@ -1645,17 +1644,17 @@ js_ReportIsNullOrUndefined(JSContext *cx
     } else {
         JS_ASSERT(v.isNull());
         ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
                                           js_GetErrorMessage, NULL,
                                           JSMSG_UNEXPECTED_TYPE, bytes,
                                           js_null_str, NULL);
     }
 
-    cx->free(bytes);
+    cx->free_(bytes);
     return ok;
 }
 
 void
 js_ReportMissingArg(JSContext *cx, const Value &v, uintN arg)
 {
     char argbuf[11];
     char *bytes;
@@ -1668,17 +1667,17 @@ js_ReportMissingArg(JSContext *cx, const
         bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK,
                                         v, atom);
         if (!bytes)
             return;
     }
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                          JSMSG_MISSING_FUN_ARG, argbuf,
                          bytes ? bytes : "");
-    cx->free(bytes);
+    cx->free_(bytes);
 }
 
 JSBool
 js_ReportValueErrorFlags(JSContext *cx, uintN flags, const uintN errorNumber,
                          intN spindex, const Value &v, JSString *fallback,
                          const char *arg1, const char *arg2)
 {
     char *bytes;
@@ -1687,17 +1686,17 @@ js_ReportValueErrorFlags(JSContext *cx, 
     JS_ASSERT(js_ErrorFormatString[errorNumber].argCount >= 1);
     JS_ASSERT(js_ErrorFormatString[errorNumber].argCount <= 3);
     bytes = DecompileValueGenerator(cx, spindex, v, fallback);
     if (!bytes)
         return JS_FALSE;
 
     ok = JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage,
                                       NULL, errorNumber, bytes, arg1, arg2);
-    cx->free(bytes);
+    cx->free_(bytes);
     return ok;
 }
 
 #if defined DEBUG && defined XP_UNIX
 /* For gdb usage. */
 void js_logon(JSContext *cx)  { cx->logfp = stderr; cx->logPrevPc = NULL; }
 void js_logoff(JSContext *cx) { cx->logfp = NULL; }
 #endif
@@ -2095,21 +2094,21 @@ JSRuntime::onTooMuchMalloc()
 }
 
 JS_FRIEND_API(void *)
 JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx)
 {
 #ifdef JS_THREADSAFE
     gcHelperThread.waitBackgroundSweepEnd(this);
     if (!p)
-        p = ::js_malloc(nbytes);
+        p = OffTheBooks::malloc_(nbytes);
     else if (p == reinterpret_cast<void *>(1))
-        p = ::js_calloc(nbytes);
+        p = OffTheBooks::calloc_(nbytes);
     else
-      p = ::js_realloc(p, nbytes);
+      p = OffTheBooks::realloc_(p, nbytes);
     if (p)
         return p;
 #endif
     if (cx)
         js_ReportOutOfMemory(cx);
     return NULL;
 }
 
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -40,23 +40,16 @@
 
 #ifndef jscntxt_h___
 #define jscntxt_h___
 /*
  * JS execution context.
  */
 #include <string.h>
 
-/* Gross special case for Gecko, which defines malloc/calloc/free. */
-#ifdef mozilla_mozalloc_macro_wrappers_h
-#  define JS_CNTXT_UNDEFD_MOZALLOC_WRAPPERS
-/* The "anti-header" */
-#  include "mozilla/mozalloc_undef_macro_wrappers.h"
-#endif
-
 #include "jsprvtd.h"
 #include "jsarena.h"
 #include "jsclist.h"
 #include "jslong.h"
 #include "jsatom.h"
 #include "jsdhash.h"
 #include "jsdtoa.h"
 #include "jsfun.h"
@@ -164,19 +157,19 @@ class ContextAllocPolicy
 {
     JSContext *cx;
 
   public:
     ContextAllocPolicy(JSContext *cx) : cx(cx) {}
     JSContext *context() const { return cx; }
 
     /* Inline definitions below. */
-    void *malloc(size_t bytes);
-    void free(void *p);
-    void *realloc(void *p, size_t bytes);
+    void *malloc_(size_t bytes);
+    void free_(void *p);
+    void *realloc_(void *p, size_t bytes);
     void reportAllocOverflow() const;
 };
 
 /*
  * A StackSegment (referred to as just a 'segment') contains a prev-linked set
  * of stack frames and the slots associated with each frame. A segment and its
  * contained frames/slots also have a precise memory layout that is described
  * in the js::StackSpace comment. A key layout invariant for segments is that
@@ -1344,51 +1337,57 @@ struct JSRuntime {
 
     void setGCTriggerFactor(uint32 factor);
     void setGCLastBytes(size_t lastBytes);
 
     /*
      * Call the system malloc while checking for GC memory pressure and
      * reporting OOM error when cx is not null.
      */
-    void* malloc(size_t bytes, JSContext *cx = NULL) {
+    void* malloc_(size_t bytes, JSContext *cx = NULL) {
         updateMallocCounter(bytes);
         void *p = ::js_malloc(bytes);
         return JS_LIKELY(!!p) ? p : onOutOfMemory(NULL, bytes, cx);
     }
 
     /*
      * Call the system calloc while checking for GC memory pressure and
      * reporting OOM error when cx is not null.
      */
-    void* calloc(size_t bytes, JSContext *cx = NULL) {
+    void* calloc_(size_t bytes, JSContext *cx = NULL) {
         updateMallocCounter(bytes);
         void *p = ::js_calloc(bytes);
         return JS_LIKELY(!!p) ? p : onOutOfMemory(reinterpret_cast<void *>(1), bytes, cx);
     }
 
-    void* realloc(void* p, size_t oldBytes, size_t newBytes, JSContext *cx = NULL) {
+    void* realloc_(void* p, size_t oldBytes, size_t newBytes, JSContext *cx = NULL) {
         JS_ASSERT(oldBytes < newBytes);
         updateMallocCounter(newBytes - oldBytes);
         void *p2 = ::js_realloc(p, newBytes);
         return JS_LIKELY(!!p2) ? p2 : onOutOfMemory(p, newBytes, cx);
     }
 
-    void* realloc(void* p, size_t bytes, JSContext *cx = NULL) {
+    void* realloc_(void* p, size_t bytes, JSContext *cx = NULL) {
         /*
          * For compatibility we do not account for realloc that increases
          * previously allocated memory.
          */
         if (!p)
             updateMallocCounter(bytes);
         void *p2 = ::js_realloc(p, bytes);
         return JS_LIKELY(!!p2) ? p2 : onOutOfMemory(p, bytes, cx);
     }
 
-    void free(void* p) { ::js_free(p); }
+    inline void free_(void* p) {
+        /* FIXME: Making this free in the background is buggy. Can it work? */
+        js::Foreground::free_(p);
+    }
+
+    JS_DECLARE_NEW_METHODS(malloc_, JS_ALWAYS_INLINE)
+    JS_DECLARE_DELETE_METHODS(free_, JS_ALWAYS_INLINE)
 
     bool isGCMallocLimitReached() const { return gcMallocBytes <= 0; }
 
     void resetGCMallocBytes() { gcMallocBytes = ptrdiff_t(gcMaxMallocBytes); }
 
     void setGCMaxMallocBytes(size_t value) {
         /*
          * For compatibility treat any value that exceeds PTRDIFF_T_MAX to
@@ -1978,91 +1977,56 @@ struct JSContext
 
     void leaveGenerator(JSGenerator *gen) {
         JS_ASSERT(genStack.back() == gen);
         genStack.popBack();
     }
 
 #ifdef JS_THREADSAFE
     /*
-     * When non-null JSContext::free delegates the job to the background
+     * When non-null JSContext::free_ delegates the job to the background
      * thread.
      */
     js::GCHelperThread *gcBackgroundFree;
 #endif
 
-    inline void* malloc(size_t bytes) {
-        return runtime->malloc(bytes, this);
+    inline void* malloc_(size_t bytes) {
+        return runtime->malloc_(bytes, this);
     }
 
     inline void* mallocNoReport(size_t bytes) {
         JS_ASSERT(bytes != 0);
-        return runtime->malloc(bytes, NULL);
+        return runtime->malloc_(bytes, NULL);
     }
 
-    inline void* calloc(size_t bytes) {
+    inline void* calloc_(size_t bytes) {
         JS_ASSERT(bytes != 0);
-        return runtime->calloc(bytes, this);
+        return runtime->calloc_(bytes, this);
     }
 
-    inline void* realloc(void* p, size_t bytes) {
-        return runtime->realloc(p, bytes, this);
+    inline void* realloc_(void* p, size_t bytes) {
+        return runtime->realloc_(p, bytes, this);
     }
 
-    inline void* realloc(void* p, size_t oldBytes, size_t newBytes) {
-        return runtime->realloc(p, oldBytes, newBytes, this);
+    inline void* realloc_(void* p, size_t oldBytes, size_t newBytes) {
+        return runtime->realloc_(p, oldBytes, newBytes, this);
     }
 
-    inline void free(void* p) {
+    inline void free_(void* p) {
 #ifdef JS_THREADSAFE
         if (gcBackgroundFree) {
             gcBackgroundFree->freeLater(p);
             return;
         }
 #endif
-        runtime->free(p);
-    }
-
-    /*
-     * In the common case that we'd like to allocate the memory for an object
-     * with cx->malloc/free, we cannot use overloaded C++ operators (no
-     * placement delete).  Factor the common workaround into one place.
-     */
-#define CREATE_BODY(parms)                                                    \
-    void *memory = this->malloc(sizeof(T));                                   \
-    if (!memory)                                                              \
-        return NULL;                                                          \
-    return new(memory) T parms;
-
-    template <class T>
-    JS_ALWAYS_INLINE T *create() {
-        CREATE_BODY(())
+        runtime->free_(p);
     }
 
-    template <class T, class P1>
-    JS_ALWAYS_INLINE T *create(const P1 &p1) {
-        CREATE_BODY((p1))
-    }
-
-    template <class T, class P1, class P2>
-    JS_ALWAYS_INLINE T *create(const P1 &p1, const P2 &p2) {
-        CREATE_BODY((p1, p2))
-    }
-
-    template <class T, class P1, class P2, class P3>
-    JS_ALWAYS_INLINE T *create(const P1 &p1, const P2 &p2, const P3 &p3) {
-        CREATE_BODY((p1, p2, p3))
-    }
-#undef CREATE_BODY
-
-    template <class T>
-    JS_ALWAYS_INLINE void destroy(T *p) {
-        p->~T();
-        this->free(p);
-    }
+    JS_DECLARE_NEW_METHODS(malloc_, inline)
+    JS_DECLARE_DELETE_METHODS(free_, inline)
 
     void purge();
 
     js::StackSpace &stack() const {
         return JS_THREAD_DATA(this)->stackSpace;
     }
 
 #ifdef DEBUG
@@ -2718,17 +2682,17 @@ class AutoReleasePtr {
 
   public:
     explicit AutoReleasePtr(JSContext *cx, void *ptr
                             JS_GUARD_OBJECT_NOTIFIER_PARAM)
       : cx(cx), ptr(ptr)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
-    ~AutoReleasePtr() { cx->free(ptr); }
+    ~AutoReleasePtr() { cx->free_(ptr); }
 };
 
 /*
  * FIXME: bug 602774: cleaner API for AutoReleaseNullablePtr
  */
 class AutoReleaseNullablePtr {
     JSContext   *cx;
     void        *ptr;
@@ -2740,20 +2704,20 @@ class AutoReleaseNullablePtr {
     explicit AutoReleaseNullablePtr(JSContext *cx, void *ptr
                                     JS_GUARD_OBJECT_NOTIFIER_PARAM)
       : cx(cx), ptr(ptr)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
     void reset(void *ptr2) {
         if (ptr)
-            cx->free(ptr);
+            cx->free_(ptr);
         ptr = ptr2;
     }
-    ~AutoReleaseNullablePtr() { if (ptr) cx->free(ptr); }
+    ~AutoReleaseNullablePtr() { if (ptr) cx->free_(ptr); }
 };
 
 class AutoLocalNameArray {
   public:
     explicit AutoLocalNameArray(JSContext *cx, JSFunction *fun
                                 JS_GUARD_OBJECT_NOTIFIER_PARAM)
       : context(cx),
         mark(JS_ARENA_MARK(&cx->tempPool)),
@@ -3190,31 +3154,31 @@ js_RegenerateShapeForGC(JSRuntime *rt)
     shape = (shape + 1) | (shape & js::SHAPE_OVERFLOW_BIT);
     rt->shapeGen = shape;
     return shape;
 }
 
 namespace js {
 
 inline void *
-ContextAllocPolicy::malloc(size_t bytes)
+ContextAllocPolicy::malloc_(size_t bytes)
 {
-    return cx->malloc(bytes);
+    return cx->malloc_(bytes);
 }
 
 inline void
-ContextAllocPolicy::free(void *p)
+ContextAllocPolicy::free_(void *p)
 {
-    cx->free(p);
+    cx->free_(p);
 }
 
 inline void *
-ContextAllocPolicy::realloc(void *p, size_t bytes)
+ContextAllocPolicy::realloc_(void *p, size_t bytes)
 {
-    return cx->realloc(p, bytes);
+    return cx->realloc_(p, bytes);
 }
 
 inline void
 ContextAllocPolicy::reportAllocOverflow() const
 {
     js_ReportAllocationOverflow(cx);
 }
 
@@ -3330,13 +3294,9 @@ NewIdArray(JSContext *cx, jsint length);
 
 } /* namespace js */
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #pragma warning(pop)
 #endif
 
-#ifdef JS_CNTXT_UNDEFD_MOZALLOC_WRAPPERS
-#  include "mozilla/mozalloc_macro_wrappers.h"
-#endif
-
 #endif /* jscntxt_h___ */
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -95,28 +95,28 @@ JSCompartment::JSCompartment(JSRuntime *
 #endif
 
     PodArrayZero(scriptsToGC);
 }
 
 JSCompartment::~JSCompartment()
 {
 #if ENABLE_YARR_JIT
-    js_delete(regExpAllocator);
+    Foreground::delete_(regExpAllocator);
 #endif
 
 #if defined JS_TRACER
     FinishJIT(&traceMonitor);
 #endif
 
 #ifdef JS_METHODJIT
-    js_delete(jaegerCompartment);
+    Foreground::delete_(jaegerCompartment);
 #endif
 
-    js_delete(mathCache);
+    Foreground::delete_(mathCache);
 
 #ifdef DEBUG
     for (size_t i = 0; i != JS_ARRAY_LENGTH(scriptsToGC); ++i)
         JS_ASSERT(!scriptsToGC[i]);
 #endif
 }
 
 bool
@@ -136,31 +136,31 @@ JSCompartment::init()
 #ifdef DEBUG
     if (rt->meterEmptyShapes()) {
         if (!emptyShapes.init())
             return false;
     }
 #endif
 
 #ifdef JS_TRACER
-    if (!InitJIT(&traceMonitor))
+    if (!InitJIT(&traceMonitor, rt))
         return false;
 #endif
 
 #if ENABLE_YARR_JIT
-    regExpAllocator = js_new<JSC::ExecutableAllocator>();
+    regExpAllocator = rt->new_<JSC::ExecutableAllocator>();
     if (!regExpAllocator)
         return false;
 #endif
 
     if (!backEdgeTable.init())
         return false;
 
 #ifdef JS_METHODJIT
-    if (!(jaegerCompartment = js_new<mjit::JaegerCompartment>()))
+    if (!(jaegerCompartment = rt->new_<mjit::JaegerCompartment>()))
         return false;
     return jaegerCompartment->Initialize();
 #else
     return true;
 #endif
 }
 
 bool
@@ -569,17 +569,17 @@ JSCompartment::purge(JSContext *cx)
     }
 #endif
 }
 
 MathCache *
 JSCompartment::allocMathCache(JSContext *cx)
 {
     JS_ASSERT(!mathCache);
-    mathCache = js_new<MathCache>();
+    mathCache = cx->new_<MathCache>();
     if (!mathCache)
         js_ReportOutOfMemory(cx);
     return mathCache;
 }
 
 size_t
 JSCompartment::backEdgeCount(jsbytecode *pc) const
 {
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -2401,17 +2401,17 @@ date_toSource(JSContext *cx, uintN argc,
 
     char *bytes = JS_smprintf("(new %s(%s))", js_Date_str, numStr);
     if (!bytes) {
         JS_ReportOutOfMemory(cx);
         return false;
     }
 
     JSString *str = JS_NewStringCopyZ(cx, bytes);
-    js_free(bytes);
+    cx->free_(bytes);
     if (!str)
         return false;
     vp->setString(str);
     return true;
 }
 #endif
 
 static JSBool
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -316,17 +316,17 @@ js_UntrapScriptCode(JSContext *cx, JSScr
                 size_t nbytes;
 
                 nbytes = script->length * sizeof(jsbytecode);
                 notes = script->notes();
                 for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
                     continue;
                 nbytes += (sn - notes + 1) * sizeof *sn;
 
-                code = (jsbytecode *) cx->malloc(nbytes);
+                code = (jsbytecode *) cx->malloc_(nbytes);
                 if (!code)
                     break;
                 memcpy(code, script->code, nbytes);
                 JS_PURGE_GSN_CACHE(cx);
             }
             code[trap->pc - script->code] = trap->op;
         }
     }
@@ -351,17 +351,17 @@ JS_SetTrap(JSContext *cx, JSScript *scri
     DBG_LOCK(rt);
     trap = FindTrap(rt, script, pc);
     if (trap) {
         JS_ASSERT(trap->script == script && trap->pc == pc);
         JS_ASSERT(*pc == JSOP_TRAP);
     } else {
         sample = rt->debuggerMutations;
         DBG_UNLOCK(rt);
-        trap = (JSTrap *) cx->malloc(sizeof *trap);
+        trap = (JSTrap *) cx->malloc_(sizeof *trap);
         if (!trap)
             return JS_FALSE;
         trap->closure = JSVAL_NULL;
         DBG_LOCK(rt);
         twin = (rt->debuggerMutations != sample)
                ? FindTrap(rt, script, pc)
                : NULL;
         if (twin) {
@@ -375,17 +375,17 @@ JS_SetTrap(JSContext *cx, JSScript *scri
             trap->op = (JSOp)*pc;
             *pc = JSOP_TRAP;
         }
     }
     trap->handler = handler;
     trap->closure = closure;
     DBG_UNLOCK(rt);
     if (junk)
-        cx->free(junk);
+        cx->free_(junk);
 
 #ifdef JS_METHODJIT
     if (script->hasJITCode()) {
         js::mjit::Recompiler recompiler(cx, script);
         if (!recompiler.recompile())
             return JS_FALSE;
     }
 #endif
@@ -410,17 +410,17 @@ JS_GetTrapOpcode(JSContext *cx, JSScript
 
 static void
 DestroyTrapAndUnlock(JSContext *cx, JSTrap *trap)
 {
     ++cx->runtime->debuggerMutations;
     JS_REMOVE_LINK(&trap->links);
     *trap->pc = (jsbytecode)trap->op;
     DBG_UNLOCK(cx->runtime);
-    cx->free(trap);
+    cx->free_(trap);
 }
 
 JS_PUBLIC_API(void)
 JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
              JSTrapHandler *handlerp, jsval *closurep)
 {
     JSTrap *trap;
     
@@ -653,17 +653,17 @@ DropWatchPointAndUnlock(JSContext *cx, J
             IsWatchedProperty(cx, wprop)) {
             shape = wp->object->changeProperty(cx, wprop, 0, wprop->attributes(),
                                                wprop->getter(), wp->setter);
             if (!shape)
                 ok = false;
         }
     }
 
-    cx->free(wp);
+    cx->free_(wp);
     return ok;
 }
 
 /*
  * NB: js_TraceWatchPoints does not acquire cx->runtime->debuggerLock, since
  * the debugger should never be racing with the GC (i.e., the debugger must
  * respect the request model). If any unmarked objects were marked, this
  * function returns true and the GC will iteratively call this function again
@@ -1147,17 +1147,17 @@ JS_SetWatchPoint(JSContext *cx, JSObject
     /*
      * At this point, prop/shape exists in obj, obj is locked, and we must
      * unlock the object before returning.
      */
     DBG_LOCK(rt);
     JSWatchPoint *wp = LockedFindWatchPoint(rt, obj, propid);
     if (!wp) {
         DBG_UNLOCK(rt);
-        wp = (JSWatchPoint *) cx->malloc(sizeof *wp);
+        wp = (JSWatchPoint *) cx->malloc_(sizeof *wp);
         if (!wp)
             return false;
         wp->handler = NULL;
         wp->closure = NULL;
         wp->object = obj;
         wp->shape = NULL;
         wp->flags = JSWP_LIVE;
 
@@ -1679,17 +1679,17 @@ JS_EvaluateInStackFrame(JSContext *cx, J
         return JS_FALSE;
 
     chars = js_InflateString(cx, bytes, &len);
     if (!chars)
         return JS_FALSE;
     length = (uintN) len;
     ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length, filename, lineno,
                                    rval);
-    cx->free(chars);
+    cx->free_(chars);
 
     return ok;
 }
 
 /************************************************************************/
 
 /* This all should be reworked to avoid requiring JSScopeProperty types. */
 
@@ -1785,17 +1785,17 @@ JS_GetPropertyDescArray(JSContext *cx, J
     /* Return an empty pda early if obj has no own properties. */
     if (obj->nativeEmpty()) {
         pda->length = 0;
         pda->array = NULL;
         return JS_TRUE;
     }
 
     uint32 n = obj->propertyCount();
-    JSPropertyDesc *pd = (JSPropertyDesc *) cx->malloc(size_t(n) * sizeof(JSPropertyDesc));
+    JSPropertyDesc *pd = (JSPropertyDesc *) cx->malloc_(size_t(n) * sizeof(JSPropertyDesc));
     if (!pd)
         return JS_FALSE;
     uint32 i = 0;
     for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront()) {
         if (!js_AddRoot(cx, Valueify(&pd[i].id), NULL))
             goto bad;
         if (!js_AddRoot(cx, Valueify(&pd[i].value), NULL))
             goto bad;
@@ -1826,17 +1826,17 @@ JS_PutPropertyDescArray(JSContext *cx, J
 
     pd = pda->array;
     for (i = 0; i < pda->length; i++) {
         js_RemoveRoot(cx->runtime, &pd[i].id);
         js_RemoveRoot(cx->runtime, &pd[i].value);
         if (pd[i].flags & JSPD_ALIAS)
             js_RemoveRoot(cx->runtime, &pd[i].alias);
     }
-    cx->free(pd);
+    cx->free_(pd);
 }
 
 /************************************************************************/
 
 JS_PUBLIC_API(JSBool)
 JS_SetDebuggerHandler(JSRuntime *rt, JSDebuggerHandler handler, void *closure)
 {
     rt->globalDebugHooks.debuggerHandler = handler;
@@ -2251,17 +2251,17 @@ js_StartVtune(JSContext *cx, uintN argc,
     if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
         str = JSVAL_TO_STRING(argv[0]);
         params.tb5Filename = js_DeflateString(cx, str->chars(), str->length());
     }
 
     status = VTStartSampling(&params);
 
     if (params.tb5Filename != default_filename)
-        cx->free(params.tb5Filename);
+        cx->free_(params.tb5Filename);
 
     if (status != 0) {
         if (status == VTAPI_MULTIPLE_RUNS)
             VTStopSampling(0);
         if (status < sizeof(vtuneErrorMessages))
             JS_ReportError(cx, "Vtune setup error: %s",
                            vtuneErrorMessages[status]);
         else
--- a/js/src/jsdhash.cpp
+++ b/js/src/jsdhash.cpp
@@ -42,17 +42,19 @@
  * Double hashing implementation.
  */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include "jsstdint.h"
 #include "jsbit.h"
 #include "jsdhash.h"
-#include "jsutil.h"     /* for JS_ASSERT */
+#include "jsutil.h"
+
+using namespace js;
 
 #ifdef JS_DHASHMETER
 # if defined MOZILLA_CLIENT && defined DEBUG_XXXbrendan
 #  include "nsTraceMalloc.h"
 # endif
 # define METER(x)       x
 #else
 # define METER(x)       /* nothing */
@@ -106,23 +108,23 @@
 #define INCREMENT_RECURSION_LEVEL(table_)   JS_BEGIN_MACRO JS_END_MACRO
 #define DECREMENT_RECURSION_LEVEL(table_)   JS_BEGIN_MACRO JS_END_MACRO
 
 #endif /* defined(DEBUG) */
 
 JS_PUBLIC_API(void *)
 JS_DHashAllocTable(JSDHashTable *table, uint32 nbytes)
 {
-    return js_malloc(nbytes);
+    return OffTheBooks::malloc_(nbytes);
 }
 
 JS_PUBLIC_API(void)
 JS_DHashFreeTable(JSDHashTable *table, void *ptr)
 {
-    js_free(ptr);
+    UnwantedForeground::free_(ptr);
 }
 
 JS_PUBLIC_API(JSDHashNumber)
 JS_DHashStringKey(JSDHashTable *table, const void *key)
 {
     JSDHashNumber h;
     const unsigned char *s;
 
@@ -175,17 +177,17 @@ JS_DHashClearEntryStub(JSDHashTable *tab
     memset(entry, 0, table->entrySize);
 }
 
 JS_PUBLIC_API(void)
 JS_DHashFreeStringKey(JSDHashTable *table, JSDHashEntryHdr *entry)
 {
     const JSDHashEntryStub *stub = (const JSDHashEntryStub *)entry;
 
-    js_free((void *) stub->key);
+    UnwantedForeground::free_((void *) stub->key);
     memset(entry, 0, table->entrySize);
 }
 
 JS_PUBLIC_API(void)
 JS_DHashFinalizeStub(JSDHashTable *table)
 {
 }
 
@@ -207,31 +209,31 @@ JS_DHashGetStubOps(void)
 }
 
 JS_PUBLIC_API(JSDHashTable *)
 JS_NewDHashTable(const JSDHashTableOps *ops, void *data, uint32 entrySize,
                  uint32 capacity)
 {
     JSDHashTable *table;
 
-    table = (JSDHashTable *) js_malloc(sizeof *table);
+    table = (JSDHashTable *) OffTheBooks::malloc_(sizeof *table);
     if (!table)
         return NULL;
     if (!JS_DHashTableInit(table, ops, data, entrySize, capacity)) {
-        js_free(table);
+        Foreground::free_(table);
         return NULL;
     }
     return table;
 }
 
 JS_PUBLIC_API(void)
 JS_DHashTableDestroy(JSDHashTable *table)
 {
     JS_DHashTableFinish(table);
-    js_free(table);
+    UnwantedForeground::free_(table);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DHashTableInit(JSDHashTable *table, const JSDHashTableOps *ops, void *data,
                   uint32 entrySize, uint32 capacity)
 {
     int log2;
     uint32 nbytes;
--- a/js/src/jsdtoa.cpp
+++ b/js/src/jsdtoa.cpp
@@ -48,16 +48,18 @@
 #include "jsprvtd.h"
 #include "jsnum.h"
 #include "jsbit.h"
 #include "jslibmath.h"
 #include "jscntxt.h"
 
 #include "jsobjinlines.h"
 
+using namespace js;
+
 #ifdef IS_LITTLE_ENDIAN
 #define IEEE_8087
 #else
 #define IEEE_MC68k
 #endif
 
 #ifndef Long
 #define Long int32
@@ -72,19 +74,26 @@
 #define Llong JSInt64
 #endif
 
 #ifndef ULlong
 #define ULlong JSUint64
 #endif
 */
 
+/*
+ * MALLOC gets declared external, and that doesn't work for class members, so
+ * wrap.
+ */
+inline void* dtoa_malloc(size_t size) { return OffTheBooks::malloc_(size); }
+inline void dtoa_free(void* p) { return UnwantedForeground::free_(p); }
+
 #define NO_GLOBAL_STATE
-#define MALLOC js_malloc
-#define FREE js_free
+#define MALLOC dtoa_malloc
+#define FREE dtoa_free
 #include "dtoa.c"
 
 /* Mapping of JSDToStrMode -> js_dtoa mode */
 static const uint8 dtoaModes[] = {
     0,   /* DTOSTR_STANDARD */
     0,   /* DTOSTR_STANDARD_EXPONENTIAL, */
     3,   /* DTOSTR_FIXED, */
     2,   /* DTOSTR_EXPONENTIAL, */
@@ -322,17 +331,17 @@ js_dtobasestr(DtoaState *state, int base
     char *q;
     uint32 digit;
     U di;                /* d truncated to an integer */
     U df;                /* The fractional part of d */
 
     JS_ASSERT(base >= 2 && base <= 36);
 
     dval(d) = dinput;
-    buffer = (char*) js_malloc(DTOBASESTR_BUFFER_SIZE);
+    buffer = (char*) OffTheBooks::malloc_(DTOBASESTR_BUFFER_SIZE);
     if (!buffer)
         return NULL;
     p = buffer;
 
     if (dval(d) < 0.0
 #if defined(XP_WIN) || defined(XP_OS2)
         && !((word0(d) & Exp_mask) == Exp_mask && ((word0(d) & Frac_mask) || word1(d))) /* Visual C++ doesn't know how to compare against NaN */
 #endif
@@ -366,17 +375,17 @@ js_dtobasestr(DtoaState *state, int base
         int bits;  /* Number of significant bits in di; not used. */
         Bigint *b = d2b(PASS_STATE di, &e, &bits);
         if (!b)
             goto nomem1;
         b = lshift(PASS_STATE b, e);
         if (!b) {
           nomem1:
             Bfree(PASS_STATE b);
-            js_free(buffer);
+            UnwantedForeground::free_(buffer);
             return NULL;
         }
         do {
             digit = divrem(b, base);
             JS_ASSERT(digit < (uint32)base);
             *p++ = BASEDIGIT(digit);
         } while (b->wds);
         Bfree(PASS_STATE b);
@@ -402,17 +411,17 @@ js_dtobasestr(DtoaState *state, int base
         b = d2b(PASS_STATE df, &e, &bbits);
         if (!b) {
           nomem2:
             Bfree(PASS_STATE b);
             Bfree(PASS_STATE s);
             if (mlo != mhi)
                 Bfree(PASS_STATE mlo);
             Bfree(PASS_STATE mhi);
-            js_free(buffer);
+            UnwantedForeground::free_(buffer);
             return NULL;
         }
         JS_ASSERT(e < 0);
         /* At this point df = b * 2^e.  e must be less than zero because 0 < df < 1. */
 
         s2 = -(int32)(word0(d) >> Exp_shift1 & Exp_mask>>Exp_shift1);
 #ifndef Sudden_Underflow
         if (!s2)
--- a/js/src/jsdtoa.h
+++ b/js/src/jsdtoa.h
@@ -133,16 +133,16 @@ js_dtostr(DtoaState *state, char *buffer
  * round-trip property (analogous to that of printing decimal numbers).  In
  * other words, if one were to read the resulting string in via a hypothetical
  * base-number-reading routine that rounds to the nearest IEEE double (and to
  * an even significand if there are two equally near doubles), then the result
  * would equal d (except for -0.0, which converts to "0", and NaN, which is
  * not equal to itself).
  *
  * Return NULL if out of memory.  If the result is not NULL, it must be
- * released via js_free().
+ * released via cx->free_().
  */
 char *
 js_dtobasestr(DtoaState *state, int base, double d);
 
 JS_END_EXTERN_C
 
 #endif /* jsdtoa_h___ */
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -138,20 +138,20 @@ bool JSCodeGenerator::init()
 
 JSCodeGenerator::~JSCodeGenerator()
 {
     JS_ARENA_RELEASE(codePool, codeMark);
     JS_ARENA_RELEASE(notePool, noteMark);
 
     /* NB: non-null only after OOM. */
     if (spanDeps)
-        parser->context->free(spanDeps);
+        parser->context->free_(spanDeps);
 
     if (upvarMap.vector)
-        parser->context->free(upvarMap.vector);
+        parser->context->free_(upvarMap.vector);
 }
 
 static ptrdiff_t
 EmitCheck(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t delta)
 {
     jsbytecode *base, *limit, *next;
     ptrdiff_t offset, length;
     size_t incr, size;
@@ -612,17 +612,17 @@ AddSpanDep(JSContext *cx, JSCodeGenerato
     if (index + 1 == 0) {
         ReportStatementTooLarge(cx, cg);
         return JS_FALSE;
     }
 
     if ((index & (index - 1)) == 0 &&
         (!(sdbase = cg->spanDeps) || index >= SPANDEPS_MIN)) {
         size = sdbase ? SPANDEPS_SIZE(index) : SPANDEPS_SIZE_MIN / 2;
-        sdbase = (JSSpanDep *) cx->realloc(sdbase, size + size);
+        sdbase = (JSSpanDep *) cx->realloc_(sdbase, size + size);
         if (!sdbase)
             return JS_FALSE;
         cg->spanDeps = sdbase;
     }
 
     cg->numSpanDeps = index + 1;
     sd = cg->spanDeps + index;
     sd->top = pc - CG_BASE(cg);
@@ -1228,17 +1228,17 @@ OptimizeSpanDeps(JSContext *cx, JSCodeGe
 #endif
 
     /*
      * Reset so we optimize at most once -- cg may be used for further code
      * generation of successive, independent, top-level statements.  No jump
      * can span top-level statements, because JS lacks goto.
      */
     size = SPANDEPS_SIZE(JS_BIT(JS_CeilingLog2(cg->numSpanDeps)));
-    cx->free(cg->spanDeps);
+    cx->free_(cg->spanDeps);
     cg->spanDeps = NULL;
     FreeJumpTargets(cg, cg->jumpTargets);
     cg->jumpTargets = NULL;
     cg->numSpanDeps = cg->numJumpTargets = 0;
     cg->spanDepTodo = CG_OFFSET(cg);
     return JS_TRUE;
 }
 
@@ -2296,17 +2296,17 @@ BindNameToSlot(JSContext *cx, JSCodeGene
             if (!ale)
                 return JS_FALSE;
             index = ALE_INDEX(ale);
             JS_ASSERT(index == cg->upvarList.count - 1);
 
             UpvarCookie *vector = cg->upvarMap.vector;
             uint32 length = cg->lexdeps.count;
             if (!vector || cg->upvarMap.length != length) {
-                vector = (UpvarCookie *) js_realloc(vector, length * sizeof *vector);
+                vector = (UpvarCookie *) cx->realloc_(vector, length * sizeof *vector);
                 if (!vector) {
                     JS_ReportOutOfMemory(cx);
                     return JS_FALSE;
                 }
                 cg->upvarMap.vector = vector;
                 cg->upvarMap.length = length;
             }
 
@@ -3287,17 +3287,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
                 if (!intmap &&
                     i < (INTMAP_LENGTH << JS_BITS_PER_WORD_LOG2)) {
                     intmap = intmap_space;
                     intmap_bitlen = INTMAP_LENGTH << JS_BITS_PER_WORD_LOG2;
                 } else {
                     /* Just grab 8K for the worst-case bitmap. */
                     intmap_bitlen = JS_BIT(16);
                     intmap = (jsbitmap *)
-                        cx->malloc((JS_BIT(16) >> JS_BITS_PER_WORD_LOG2)
+                        cx->malloc_((JS_BIT(16) >> JS_BITS_PER_WORD_LOG2)
                                    * sizeof(jsbitmap));
                     if (!intmap) {
                         JS_ReportOutOfMemory(cx);
                         return JS_FALSE;
                     }
                 }
                 memset(intmap, 0, intmap_bitlen >> JS_BITS_PER_BYTE_LOG2);
             }
@@ -3305,17 +3305,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
                 switchOp = JSOP_LOOKUPSWITCH;
                 continue;
             }
             JS_SET_BIT(intmap, i);
         }
 
       release:
         if (intmap && intmap != intmap_space)
-            cx->free(intmap);
+            cx->free_(intmap);
         if (!ok)
             return JS_FALSE;
 
         /*
          * Compute table length and select lookup instead if overlarge or
          * more than half-sparse.
          */
         if (switchOp == JSOP_TABLESWITCH) {
@@ -3449,17 +3449,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
 
             /*
              * Use malloc to avoid arena bloat for programs with many switches.
              * We free table if non-null at label out, so all control flow must
              * exit this function through goto out or goto bad.
              */
             if (tableLength != 0) {
                 tableSize = (size_t)tableLength * sizeof *table;
-                table = (JSParseNode **) cx->malloc(tableSize);
+                table = (JSParseNode **) cx->malloc_(tableSize);
                 if (!table)
                     return JS_FALSE;
                 memset(table, 0, tableSize);
                 for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
                     if (pn3->pn_type == TOK_DEFAULT)
                         continue;
                     i = pn3->pn_pval->toInt32();
                     i -= low;
@@ -3614,17 +3614,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
             if (!ok)
                 goto out;
             pc += JUMP_OFFSET_LEN;
         }
     }
 
 out:
     if (table)
-        cx->free(table);
+        cx->free_(table);
     if (ok) {
         ok = js_PopStatementCG(cx, cg);
 
 #if JS_HAS_BLOCK_SCOPE
         if (ok && pn->pn_right->pn_type == TOK_LEXICALSCOPE)
             ok = EmitLeaveBlock(cx, cg, JSOP_LEAVEBLOCK, box);
 #endif
     }
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -176,17 +176,17 @@ CopyErrorReport(JSContext *cx, JSErrorRe
     }
 
     /*
      * The mallocSize can not overflow since it represents the sum of the
      * sizes of already allocated objects.
      */
     mallocSize = sizeof(JSErrorReport) + argsArraySize + argsCopySize +
                  ucmessageSize + uclinebufSize + linebufSize + filenameSize;
-    cursor = (uint8 *)cx->malloc(mallocSize);
+    cursor = (uint8 *)cx->malloc_(mallocSize);
     if (!cursor)
         return NULL;
 
     copy = (JSErrorReport *)cursor;
     memset(cursor, 0, sizeof(JSErrorReport));
     cursor += sizeof(JSErrorReport);
 
     if (argsArraySize != 0) {
@@ -315,17 +315,17 @@ InitExnPrivate(JSContext *cx, JSObject *
     overflow = (stackDepth > ((size_t)-1 - size) / sizeof(JSStackTraceElem));
     size += stackDepth * sizeof(JSStackTraceElem);
     overflow |= (valueCount > ((size_t)-1 - size) / sizeof(jsval));
     size += valueCount * sizeof(jsval);
     if (overflow) {
         js_ReportAllocationOverflow(cx);
         return JS_FALSE;
     }
-    priv = (JSExnPrivate *)cx->malloc(size);
+    priv = (JSExnPrivate *)cx->malloc_(size);
     if (!priv)
         return JS_FALSE;
 
     /*
      * We initialize errorReport with a copy of report after setting the
      * private slot, to prevent GC accessing a junk value we clear the field
      * here.
      */
@@ -422,18 +422,18 @@ exn_trace(JSTracer *trc, JSObject *obj)
 static void
 exn_finalize(JSContext *cx, JSObject *obj)
 {
     JSExnPrivate *priv;
 
     priv = GetExnPrivate(cx, obj);
     if (priv) {
         if (priv->errorReport)
-            cx->free(priv->errorReport);
-        cx->free(priv);
+            cx->free_(priv->errorReport);
+        cx->free_(priv);
     }
 }
 
 static JSBool
 exn_enumerate(JSContext *cx, JSObject *obj)
 {
     JSAtomState *atomState;
     uintN i;
@@ -608,17 +608,17 @@ StackTraceToString(JSContext *cx, JSExnP
 
 #define APPEND_CHAR_TO_STACK(c)                                               \
     JS_BEGIN_MACRO                                                            \
         if (stacklen == stackmax) {                                           \
             void *ptr_;                                                       \
             if (stackmax >= STACK_LENGTH_LIMIT)                               \
                 goto done;                                                    \
             stackmax = stackmax ? 2 * stackmax : 64;                          \
-            ptr_ = cx->realloc(stackbuf, (stackmax+1) * sizeof(jschar));      \
+            ptr_ = cx->realloc_(stackbuf, (stackmax+1) * sizeof(jschar));      \
             if (!ptr_)                                                        \
                 goto bad;                                                     \
             stackbuf = (jschar *) ptr_;                                       \
         }                                                                     \
         stackbuf[stacklen++] = (c);                                           \
     JS_END_MACRO
 
 #define APPEND_STRING_TO_STACK(str)                                           \
@@ -631,17 +631,17 @@ StackTraceToString(JSContext *cx, JSExnP
                                                                               \
         if (length_ > stackmax - stacklen) {                                  \
             void *ptr_;                                                       \
             if (stackmax >= STACK_LENGTH_LIMIT ||                             \
                 length_ >= STACK_LENGTH_LIMIT - stacklen) {                   \
                 goto done;                                                    \
             }                                                                 \
             stackmax = JS_BIT(JS_CeilingLog2(stacklen + length_));            \
-            ptr_ = cx->realloc(stackbuf, (stackmax+1) * sizeof(jschar));      \
+            ptr_ = cx->realloc_(stackbuf, (stackmax+1) * sizeof(jschar));      \
             if (!ptr_)                                                        \
                 goto bad;                                                     \
             stackbuf = (jschar *) ptr_;                                       \
         }                                                                     \
         js_strncpy(stackbuf + stacklen, chars_, length_);                     \
         stacklen += length_;                                                  \
     JS_END_MACRO
 
@@ -682,29 +682,29 @@ StackTraceToString(JSContext *cx, JSExnP
         return cx->runtime->emptyString;
     }
     if (stacklen < stackmax) {
         /*
          * Realloc can fail when shrinking on some FreeBSD versions, so
          * don't use JS_realloc here; simply let the oversized allocation
          * be owned by the string in that rare case.
          */
-        void *shrunk = cx->realloc(stackbuf, (stacklen+1) * sizeof(jschar));
+        void *shrunk = cx->realloc_(stackbuf, (stacklen+1) * sizeof(jschar));
         if (shrunk)
             stackbuf = (jschar *) shrunk;
     }
 
     stackbuf[stacklen] = 0;
     str = js_NewString(cx, stackbuf, stacklen);
     if (str)
         return str;
 
   bad:
     if (stackbuf)
-        cx->free(stackbuf);
+        cx->free_(stackbuf);
     return NULL;
 }
 
 /* XXXbe Consolidate the ugly truth that we don't treat filename as UTF-8
          with these two functions. */
 static JSString *
 FilenameToString(JSContext *cx, const char *filename)
 {
@@ -822,17 +822,17 @@ exn_toString(JSContext *cx, uintN argc, 
         return JS_FALSE;
     message = JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v)
                                  : cx->runtime->emptyString;
 
     if (message->length() != 0) {
         name_length = name->length();
         message_length = message->length();
         length = (name_length ? name_length + 2 : 0) + message_length;
-        cp = chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar));
+        cp = chars = (jschar *) cx->malloc_((length + 1) * sizeof(jschar));
         if (!chars)
             return JS_FALSE;
 
         if (name_length) {
             const jschar *name_chars = name->getChars(cx);
             if (!name_chars)
                 return JS_FALSE;
             js_strncpy(cp, name_chars, name_length);
@@ -843,17 +843,17 @@ exn_toString(JSContext *cx, uintN argc, 
         if (!message_chars)
             return JS_FALSE;
         js_strncpy(cp, message_chars, message_length);
         cp += message_length;
         *cp = 0;
 
         result = js_NewString(cx, chars, length);
         if (!result) {
-            cx->free(chars);
+            cx->free_(chars);
             return JS_FALSE;
         }
     } else {
         result = name;
     }
 
     vp->setString(result);
     return JS_TRUE;
@@ -933,17 +933,17 @@ exn_toSource(JSContext *cx, uintN argc, 
                 /*
                  * no filename, but have line number,
                  * need to append ``, "", {lineno_as_str}''
                  */
                 length += 6 + lineno_length;
             }
         }
 
-        cp = chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar));
+        cp = chars = (jschar *) cx->malloc_((length + 1) * sizeof(jschar));
         if (!chars)
             return false;
 
         *cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' ';
         const jschar *name_chars = name->getChars(cx);
         if (!name_chars)
             return false;
         js_strncpy(cp, name_chars, name_length);
@@ -983,17 +983,17 @@ exn_toSource(JSContext *cx, uintN argc, 
             js_strncpy(cp, lineno_chars, lineno_length);
             cp += lineno_length;
         }
 
         *cp++ = ')'; *cp++ = ')'; *cp = 0;
 
         result = js_NewString(cx, chars, length);
         if (!result) {
-            cx->free(chars);
+            cx->free_(chars);
             return false;
         }
         vp->setString(result);
         return true;
     }
 }
 #endif
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -194,17 +194,17 @@ NewArguments(JSContext *cx, JSObject *pa
         return NULL;
 
     EmptyShape *emptyArgumentsShape = EmptyShape::getEmptyArgumentsShape(cx);
     if (!emptyArgumentsShape)
         return NULL;
     AutoShapeRooter shapeRoot(cx, emptyArgumentsShape);
 
     ArgumentsData *data = (ArgumentsData *)
-        cx->malloc(offsetof(ArgumentsData, slots) + argc * sizeof(Value));
+        cx->malloc_(offsetof(ArgumentsData, slots) + argc * sizeof(Value));
     if (!data)
         return NULL;
     SetValueRangeToUndefined(data->slots, argc);
 
     /* Can't fail from here on, so initialize everything in argsobj. */
     argsobj->init(cx, callee.getFunctionPrivate()->inStrictMode()
                   ? &StrictArgumentsClass
                   : &js_ArgumentsClass,
@@ -781,17 +781,17 @@ strictargs_enumerate(JSContext *cx, JSOb
     }
 
     return true;
 }
 
 static void
 args_finalize(JSContext *cx, JSObject *obj)
 {
-    cx->free((void *) obj->getArgsData());
+    cx->free_((void *) obj->getArgsData());
 }
 
 /*
  * If a generator's arguments or call object escapes, and the generator frame
  * is not executing, the generator object needs to be marked because it is not
  * otherwise reachable. An executing generator is rooted by its invocation.  To
  * distinguish the two cases (which imply different access paths to the
  * generator object), we use the JSFRAME_FLOATING_GENERATOR flag, which is only
@@ -1984,17 +1984,17 @@ fun_finalize(JSContext *cx, JSObject *ob
     /* Ignore newborn function objects. */
     JSFunction *fun = obj->getFunctionPrivate();
     if (!fun)
         return;
 
     /* Cloned function objects may be flat closures with upvars to free. */
     if (fun != obj) {
         if (fun->isFlatClosure() && fun->script()->bindings.hasUpvars())
-            cx->free((void *) obj->getFlatClosureUpvars());
+            cx->free_((void *) obj->getFlatClosureUpvars());
         return;
     }
 
     /*
      * Null-check fun->script() because the parser sets interpreted very early.
      */
     if (fun->isInterpreted() && fun->script())
         js_DestroyScriptFromGC(cx, fun->script());
@@ -2840,17 +2840,17 @@ js_AllocFlatClosure(JSContext *cx, JSFun
     JSObject *closure = CloneFunctionObject(cx, fun, scopeChain);
     if (!closure)
         return closure;
 
     uint32 nslots = fun->script()->bindings.countUpvars();
     if (nslots == 0)
         return closure;
 
-    Value *upvars = (Value *) cx->malloc(nslots * sizeof(Value));
+    Value *upvars = (Value *) cx->malloc_(nslots * sizeof(Value));
     if (!upvars)
         return NULL;
 
     closure->setFlatClosureUpvars(upvars);
     return closure;
 }
 
 JS_DEFINE_CALLINFO_3(extern, OBJECT, js_AllocFlatClosure,
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -43,17 +43,16 @@
  *
  * This GC allocates fixed-sized things with sizes up to GC_NBYTES_MAX (see
  * jsgc.h). It allocates from a special GC arena pool with each arena allocated
  * using malloc. It uses an ideally parallel array of flag bytes to hold the
  * mark bit, finalizer type index, etc.
  *
  * XXX swizzle page to freelist for better locality of reference
  */
-#include <stdlib.h>     /* for free */
 #include <math.h>
 #include <string.h>     /* for memset used when DEBUG */
 #include "jstypes.h"
 #include "jsstdint.h"
 #include "jsutil.h"
 #include "jshash.h"
 #include "jsbit.h"
 #include "jsclist.h"
@@ -398,17 +397,17 @@ ReleaseGCChunk(JSRuntime *rt, jsuword ch
 {
     void *p = reinterpret_cast<void *>(chunk);
     JS_ASSERT(p);
 #ifdef MOZ_GCTIMER
     JS_ATOMIC_INCREMENT(&destroyChunkCount);
 #endif
     JS_ASSERT(rt->gcStats.nchunks != 0);
     METER(rt->gcStats.nchunks--);
-    rt->gcChunkAllocator->free(p);
+    rt->gcChunkAllocator->free_(p);
 }
 
 inline Chunk *
 AllocateGCChunk(JSRuntime *rt)
 {
     Chunk *p = (Chunk *)rt->gcChunkAllocator->alloc();
 #ifdef MOZ_GCTIMER
     if (p)
@@ -422,17 +421,17 @@ inline void
 ReleaseGCChunk(JSRuntime *rt, Chunk *p)
 {
     JS_ASSERT(p);
 #ifdef MOZ_GCTIMER
     JS_ATOMIC_INCREMENT(&destroyChunkCount);
 #endif
     JS_ASSERT(rt->gcStats.nchunks != 0);
     METER(rt->gcStats.nchunks--);
-    rt->gcChunkAllocator->free(p);
+    rt->gcChunkAllocator->free_(p);
 }
 
 static Chunk *
 PickChunk(JSRuntime *rt)
 {
     Chunk *chunk;
     for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) {
         if (r.front()->hasAvailableArenas())
@@ -567,18 +566,16 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes
      */
     rt->gcMaxBytes = maxbytes;
     rt->setGCMaxMallocBytes(maxbytes);
 
     rt->gcEmptyArenaPoolLifespan = 30000;
 
     rt->gcTriggerFactor = uint32(100.0f * GC_HEAP_GROWTH_FACTOR);
 
-    rt->atomsCompartment->setGCLastBytes(8192);
-    
     /*
      * The assigned value prevents GC from running when GC memory is too low
      * (during JS engine start).
      */
     rt->setGCLastBytes(8192);
 
     rt->gcJitReleaseTime = PRMJ_Now() + JIT_SCRIPT_EIGHTH_LIFETIME;
 
@@ -864,17 +861,17 @@ js_FinishGC(JSRuntime *rt)
     if (JS_WANT_GC_METER_PRINT)
         js_DumpGCStats(rt, stdout);
 #endif
 
     /* Delete all remaining Compartments. */
     for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) {
         JSCompartment *comp = *c;
         comp->finishArenaLists();
-        js_delete(comp);
+        Foreground::delete_(comp);
     }
     rt->compartments.clear();
     rt->atomsCompartment = NULL;
 
     for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront())
         ReleaseGCChunk(rt, r.front());
     rt->gcChunkSet.clear();
 
@@ -1803,17 +1800,17 @@ js_FinalizeStringRT(JSRuntime *rt, JSStr
     } else {
         unsigned thingKind = str->arena()->header()->thingKind;
         JS_ASSERT(unsigned(FINALIZE_SHORT_STRING) <= thingKind &&
                   thingKind <= unsigned(FINALIZE_EXTERNAL_STRING));
 
         jschar *chars = const_cast<jschar *>(str->asFlat().chars());
         if (thingKind == FINALIZE_STRING) {
             rt->stringMemoryUsed -= str->length() * 2;
-            rt->free(chars);
+            rt->free_(chars);
         } else if (thingKind == FINALIZE_EXTERNAL_STRING) {
             ((JSExternalString *)str)->finalize();
         }
     }
 }
 
 template<typename T>
 static void
@@ -2045,26 +2042,26 @@ GCHelperThread::waitBackgroundSweepEnd(J
 
 JS_FRIEND_API(void)
 GCHelperThread::replenishAndFreeLater(void *ptr)
 {
     JS_ASSERT(freeCursor == freeCursorEnd);
     do {
         if (freeCursor && !freeVector.append(freeCursorEnd - FREE_ARRAY_LENGTH))
             break;
-        freeCursor = (void **) js_malloc(FREE_ARRAY_SIZE);
+        freeCursor = (void **) OffTheBooks::malloc_(FREE_ARRAY_SIZE);
         if (!freeCursor) {
             freeCursorEnd = NULL;
             break;
         }
         freeCursorEnd = freeCursor + FREE_ARRAY_LENGTH;
         *freeCursor++ = ptr;
         return;
     } while (false);
-    js_free(ptr);
+    Foreground::free_(ptr);
 }
 
 void
 GCHelperThread::doSweep()
 {
     if (freeCursor) {
         void **array = freeCursorEnd - FREE_ARRAY_LENGTH;
         freeElementsAndArray(array, freeCursor);
@@ -2127,17 +2124,17 @@ SweepCompartments(JSContext *cx, JSGCInv
         if (!compartment->hold &&
             (compartment->arenaListsAreEmpty() || gckind == GC_LAST_CONTEXT))
         {
             JS_ASSERT(compartment->freeLists.isEmpty());
             if (callback)
                 (void) callback(cx, compartment, JSCOMPARTMENT_DESTROY);
             if (compartment->principals)
                 JSPRINCIPALS_DROP(cx, compartment->principals);
-            js_delete(compartment);
+            cx->delete_(compartment);
             continue;
         }
         *write++ = compartment;
     }
     rt->compartments.resize(write - rt->compartments.begin());
 }
 
 /*
@@ -2719,45 +2716,46 @@ SetProtoCheckingForCycles(JSContext *cx,
 
     return !cycle;
 }
 
 JSCompartment *
 NewCompartment(JSContext *cx, JSPrincipals *principals)
 {
     JSRuntime *rt = cx->runtime;
-    JSCompartment *compartment = js_new<JSCompartment>(rt);
+    JSCompartment *compartment = cx->new_<JSCompartment>(rt);
     if (!compartment || !compartment->init()) {
-        js_delete(compartment);
+        Foreground::delete_(compartment);
         JS_ReportOutOfMemory(cx);
         return NULL;
     }
 
     if (principals) {
         compartment->principals = principals;
         JSPRINCIPALS_HOLD(cx, principals);
     }
 
     compartment->setGCLastBytes(8192);
 
     {
         AutoLockGC lock(rt);
 
         if (!rt->compartments.append(compartment)) {
             AutoUnlockGC unlock(rt);
+            Foreground::delete_(compartment);
             JS_ReportOutOfMemory(cx);
             return NULL;
         }
     }
 
     JSCompartmentCallback callback = rt->compartmentCallback;
     if (callback && !callback(cx, compartment, JSCOMPARTMENT_NEW)) {
         AutoLockGC lock(rt);
         rt->compartments.popBack();
-        js_delete(compartment);
+        Foreground::delete_(compartment);
         return NULL;
     }
     return compartment;
 }
 
 } /* namespace gc */
 
 void
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -35,23 +35,16 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsgc_h___
 #define jsgc_h___
 
-/* Gross special case for Gecko, which defines malloc/calloc/free. */
-#ifdef mozilla_mozalloc_macro_wrappers_h
-#  define JS_GC_UNDEFD_MOZALLOC_WRAPPERS
-/* The "anti-header" */
-#  include "mozilla/mozalloc_undef_macro_wrappers.h"
-#endif
-
 /*
  * JS Garbage Collector.
  */
 #include <setjmp.h>
 
 #include "jstypes.h"
 #include "jsprvtd.h"
 #include "jspubtd.h"
@@ -899,18 +892,18 @@ class GCHelperThread {
     void            **freeCursorEnd;
 
     JS_FRIEND_API(void)
     replenishAndFreeLater(void *ptr);
 
     static void freeElementsAndArray(void **array, void **end) {
         JS_ASSERT(array <= end);
         for (void **p = array; p != end; ++p)
-            js_free(*p);
-        js_free(array);
+            js::Foreground::free_(*p);
+        js::Foreground::free_(array);
     }
 
     static void threadMain(void* arg);
 
     void threadLoop(JSRuntime *rt);
     void doSweep();
 
   public:
@@ -1093,13 +1086,9 @@ NewCompartment(JSContext *cx, JSPrincipa
 } /* namespace gc */
 
 inline JSCompartment *
 JSObject::getCompartment() const
 {
     return compartment();
 }
 
-#ifdef JS_GC_UNDEFD_MOZALLOC_WRAPPERS
-#  include "mozilla/mozalloc_macro_wrappers.h"
-#endif
-
 #endif /* jsgc_h___ */
--- a/js/src/jsgcchunk.h
+++ b/js/src/jsgcchunk.h
@@ -65,17 +65,17 @@ class GCChunkAllocator {
     GCChunkAllocator() {}
     
     void *alloc() {
         void *chunk = doAlloc();
         JS_ASSERT(!(reinterpret_cast<jsuword>(chunk) & GC_CHUNK_MASK));
         return chunk;
     }
 
-    void free(void *chunk) {
+    void free_(void *chunk) {
         JS_ASSERT(chunk);
         JS_ASSERT(!(reinterpret_cast<jsuword>(chunk) & GC_CHUNK_MASK));
         doFree(chunk);
     }
     
   private:
     virtual void *doAlloc() {
         return AllocGCChunk();
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -168,18 +168,17 @@ GetGCKindSlots(FinalizeKind thingKind)
 template <typename T>
 JS_ALWAYS_INLINE T *
 NewFinalizableGCThing(JSContext *cx, unsigned thingKind)
 {
     JS_ASSERT(thingKind < js::gc::FINALIZE_LIMIT);
 #ifdef JS_THREADSAFE
     JS_ASSERT_IF((cx->compartment == cx->runtime->atomsCompartment),
                  (thingKind == js::gc::FINALIZE_STRING) ||
-                 (thingKind == js::gc::FINALIZE_SHORT_STRING) ||
-                 (thingKind == js::gc::FINALIZE_SHAPE));
+                 (thingKind == js::gc::FINALIZE_SHORT_STRING));
 #endif
 
     METER(cx->compartment->compartmentStats[thingKind].alloc++);
     do {
         js::gc::FreeCell *cell = cx->compartment->freeLists.getNext(thingKind);
         if (cell) {
             CheckGCFreeListLink(cell);
             return (T *)cell;
--- a/js/src/jshash.cpp
+++ b/js/src/jshash.cpp
@@ -43,16 +43,18 @@
 #include <stdlib.h>
 #include <string.h>
 #include "jstypes.h"
 #include "jsstdint.h"
 #include "jsbit.h"
 #include "jsutil.h"
 #include "jshash.h"
 
+using namespace js;
+
 /* Compute the number of buckets in ht */
 #define NBUCKETS(ht)    JS_BIT(JS_HASH_BITS - (ht)->shift)
 
 /* The smallest table has 16 buckets */
 #define MINBUCKETSLOG2  4
 #define MINBUCKETS      JS_BIT(MINBUCKETSLOG2)
 
 /* Compute the maximum entries given n buckets that we will tolerate, ~90% */
@@ -62,36 +64,36 @@
 #define UNDERLOADED(n)  (((n) > MINBUCKETS) ? ((n) >> 2) : 0)
 
 /*
 ** Stubs for default hash allocator ops.
 */
 static void *
 DefaultAllocTable(void *pool, size_t size)
 {
-    return js_malloc(size);
+    return OffTheBooks::malloc_(size);
 }
 
 static void
 DefaultFreeTable(void *pool, void *item, size_t size)
 {
-    js_free(item);
+    UnwantedForeground::free_(item);
 }
 
 static JSHashEntry *
 DefaultAllocEntry(void *pool, const void *key)
 {
-    return (JSHashEntry*) js_malloc(sizeof(JSHashEntry));
+    return (JSHashEntry*) OffTheBooks::malloc_(sizeof(JSHashEntry));
 }
 
 static void
 DefaultFreeEntry(void *pool, JSHashEntry *he, uintN flag)
 {
     if (flag == HT_FREE_ENTRY)
-        js_free(he);
+        UnwantedForeground::free_(he);
 }
 
 static JSHashAllocOps defaultHashAllocOps = {
     DefaultAllocTable, DefaultFreeTable,
     DefaultAllocEntry, DefaultFreeEntry
 };
 
 JS_PUBLIC_API(JSHashTable *)
--- a/js/src/jshashtable.h
+++ b/js/src/jshashtable.h
@@ -295,29 +295,29 @@ class HashTable : private AllocPolicy
         /* Avoid reserved hash codes. */
         if (!isLiveHash(keyHash))
             keyHash -= (sRemovedKey + 1);
         return keyHash & ~sCollisionBit;
     }
 
     static Entry *createTable(AllocPolicy &alloc, uint32 capacity)
     {
-        Entry *newTable = (Entry *)alloc.malloc(capacity * sizeof(Entry));
+        Entry *newTable = (Entry *)alloc.malloc_(capacity * sizeof(Entry));
         if (!newTable)
             return NULL;
         for (Entry *e = newTable, *end = e + capacity; e != end; ++e)
             new(e) Entry();
         return newTable;
     }
 
     static void destroyTable(AllocPolicy &alloc, Entry *oldTable, uint32 capacity)
     {
         for (Entry *e = oldTable, *end = e + capacity; e != end; ++e)
             e->~Entry();
-        alloc.free(oldTable);
+        alloc.free_(oldTable);
     }
 
   public:
     HashTable(AllocPolicy ap)
       : AllocPolicy(ap),
         entryCount(0),
         gen(0),
         removedCount(0),
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -1080,16 +1080,90 @@ HasInstance(JSContext *cx, JSObject *obj
     if (clasp->hasInstance)
         return clasp->hasInstance(cx, obj, v, bp);
     js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
                         JSDVG_SEARCH_STACK, ObjectValue(*obj), NULL);
     return JS_FALSE;
 }
 
 bool
+LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, JSBool *result)
+{
+#if JS_HAS_XML_SUPPORT
+    if (JS_UNLIKELY(lval.isObject() && lval.toObject().isXML()) ||
+                    (rval.isObject() && rval.toObject().isXML())) {
+        return js_TestXMLEquality(cx, lval, rval, result);
+    }
+#endif
+
+    if (SameType(lval, rval)) {
+        if (lval.isString()) {
+            JSString *l = lval.toString();
+            JSString *r = rval.toString();
+            return EqualStrings(cx, l, r, result);
+        }
+        
+        if (lval.isDouble()) {
+            double l = lval.toDouble(), r = rval.toDouble();
+            *result = JSDOUBLE_COMPARE(l, ==, r, false);
+            return true;
+        }
+        
+        if (lval.isObject()) {
+            JSObject *l = &lval.toObject();
+            JSObject *r = &rval.toObject();
+            l->assertSpecialEqualitySynced();
+
+            if (EqualityOp eq = l->getClass()->ext.equality) {
+                return eq(cx, l, &rval, result);
+            }
+
+            *result = l == r;
+            return true;
+        }
+
+        *result = lval.payloadAsRawUint32() == rval.payloadAsRawUint32();
+        return true;
+    }
+
+    if (lval.isNullOrUndefined()) {
+        *result = rval.isNullOrUndefined();
+        return true;
+    }
+    
+    if (rval.isNullOrUndefined()) {
+        *result = false;
+        return true;
+    }
+
+    Value lvalue = lval;
+    Value rvalue = rval;
+
+    if (lvalue.isObject() && !DefaultValue(cx, &lvalue.toObject(), JSTYPE_VOID, &lvalue))
+        return false;
+
+    if (rvalue.isObject() && !DefaultValue(cx, &rvalue.toObject(), JSTYPE_VOID, &rvalue))
+        return false;
+
+    if (lvalue.isString() && rvalue.isString()) {
+        JSString *l = lvalue.toString();
+        JSString *r = rvalue.toString();
+        return EqualStrings(cx, l, r, result);
+    }
+
+    double l, r;
+    if (!ValueToNumber(cx, lvalue, &l) ||
+        !ValueToNumber(cx, rvalue, &r)) {
+        return false;
+    }
+    *result = JSDOUBLE_COMPARE(l, ==, r, false);
+    return true;
+}
+
+bool
 StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref, JSBool *equal)
 {
     Value lval = lref, rval = rref;
     if (SameType(lval, rval)) {
         if (lval.isString())
             return EqualStrings(cx, lval.toString(), rval.toString(), equal);
         if (lval.isDouble()) {
             *equal = JSDOUBLE_COMPARE(lval.toDouble(), ==, rval.toDouble(), JS_FALSE);
@@ -1503,17 +1577,17 @@ js_LogOpcode(JSContext *cx)
         if (ndefs != 0 &&
             ndefs < regs->sp - fp->slots()) {
             for (n = -ndefs; n < 0; n++) {
                 char *bytes = DecompileValueGenerator(cx, n, regs->sp[n], NULL);
                 if (bytes) {
                     fprintf(logfp, "%s %s",
                             (n == -ndefs) ? "  output:" : ",",
                             bytes);
-                    cx->free(bytes);
+                    cx->free_(bytes);
                 } else {
                     JS_ClearPendingException(cx);
                 }
             }
             fprintf(logfp, " @ %u\n", (uintN) (regs->sp - fp->base()));
         }
         fprintf(logfp, "  stack: ");
         for (Value *siter = fp->base(); siter < regs->sp; siter++) {
@@ -1555,17 +1629,17 @@ js_LogOpcode(JSContext *cx)
     nuses = js_GetStackUses(&js_CodeSpec[op], op, regs->pc);
     if (nuses != 0) {
         for (n = -nuses; n < 0; n++) {
             char *bytes = DecompileValueGenerator(cx, n, regs->sp[n], NULL);
             if (bytes) {
                 fprintf(logfp, "%s %s",
                         (n == -nuses) ? "  inputs:" : ",",
                         bytes);
-                cx->free(bytes);
+                cx->free_(bytes);
             } else {
                 JS_ClearPendingException(cx);
             }
         }
         fprintf(logfp, " @ %u\n", (uintN) (regs->sp - fp->base()));
     }
     cx->logPrevPc = regs->pc;
 
@@ -1644,17 +1718,17 @@ js_DumpOpMeters()
                 total += count;
                 ++nedges;
             }
         }
     }
 
 # define SIGNIFICANT(count,total) (200. * (count) >= (total))
 
-    graph = (Edge *) js_calloc(nedges * sizeof graph[0]);
+    graph = (Edge *) OffTheBooks::calloc_(nedges * sizeof graph[0]);
     if (!graph)
         return;
     for (i = nedges = 0; i < JSOP_LIMIT; i++) {
         from = js_CodeName[i];
         for (j = 0; j < JSOP_LIMIT; j++) {
             count = succeeds[i][j];
             if (count != 0 && SIGNIFICANT(count, total)) {
                 graph[nedges].from = from;
@@ -1675,17 +1749,17 @@ js_DumpOpMeters()
             style = (i > nedges * .75) ? "dotted" :
                     (i > nedges * .50) ? "dashed" :
                     (i > nedges * .25) ? "solid" : "bold";
         }
         fprintf(fp, "  %s -> %s [label=\"%lu\" style=%s]\n",
                 graph[i].from, graph[i].to,
                 (unsigned long)graph[i].count, style);
     }
-    js_free(graph);
+    cx->free_(graph);
     fputs("}\n", fp);
     fclose(fp);
 
     name = getenv("JS_OPMETER_HIST");
     if (!name)
         name = "/tmp/ops.hist";
     fp = fopen(name, "w");
     if (!fp) {
@@ -3368,104 +3442,38 @@ BEGIN_CASE(JSOP_BITXOR)
 END_CASE(JSOP_BITXOR)
 
 BEGIN_CASE(JSOP_BITAND)
     BITWISE_OP(&);
 END_CASE(JSOP_BITAND)
 
 #undef BITWISE_OP
 
-/*
- * NB: These macros can't use JS_BEGIN_MACRO/JS_END_MACRO around their bodies
- * because they begin if/else chains, so callers must not put semicolons after
- * the call expressions!
- */
-#if JS_HAS_XML_SUPPORT
-#define XML_EQUALITY_OP(OP)                                                   \
-    if ((lval.isObject() && lval.toObject().isXML()) ||                       \
-        (rval.isObject() && rval.toObject().isXML())) {                       \
-        if (!js_TestXMLEquality(cx, lval, rval, &cond))                       \
-            goto error;                                                       \
-        cond = cond OP JS_TRUE;                                               \
-    } else
-#else
-#define XML_EQUALITY_OP(OP)             /* nothing */
-#endif
-
-#define EQUALITY_OP(OP, IFNAN)                                                \
+#define EQUALITY_OP(OP)                                                       \
     JS_BEGIN_MACRO                                                            \
-        JSBool cond;                                                          \
         Value rval = regs.sp[-1];                                             \
         Value lval = regs.sp[-2];                                             \
-        XML_EQUALITY_OP(OP)                                                   \
-        if (SameType(lval, rval)) {                                           \
-            if (lval.isString()) {                                            \
-                JSString *l = lval.toString(), *r = rval.toString();          \
-                JSBool equal;                                                 \
-                if (!EqualStrings(cx, l, r, &equal))                          \
-                    goto error;                                               \
-                cond = equal OP JS_TRUE;                                      \
-            } else if (lval.isDouble()) {                                     \
-                double l = lval.toDouble(), r = rval.toDouble();              \
-                cond = JSDOUBLE_COMPARE(l, OP, r, IFNAN);                     \
-            } else if (lval.isObject()) {                                     \
-                JSObject *l = &lval.toObject(), *r = &rval.toObject();        \
-                l->assertSpecialEqualitySynced();                             \
-                if (EqualityOp eq = l->getClass()->ext.equality) {            \
-                    if (!eq(cx, l, &rval, &cond))                             \
-                        goto error;                                           \
-                    cond = cond OP JS_TRUE;                                   \
-                } else {                                                      \
-                    cond = l OP r;                                            \
-                }                                                             \
-            } else {                                                          \
-                cond = lval.payloadAsRawUint32() OP rval.payloadAsRawUint32();\
-            }                                                                 \
-        } else {                                                              \
-            if (lval.isNullOrUndefined()) {                                   \
-                cond = rval.isNullOrUndefined() OP true;                      \
-            } else if (rval.isNullOrUndefined()) {                            \
-                cond = true OP false;                                         \
-            } else {                                                          \
-                if (lval.isObject())                                          \
-                    DEFAULT_VALUE(cx, -2, JSTYPE_VOID, lval);                 \
-                if (rval.isObject())                                          \
-                    DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval);                 \
-                if (lval.isString() && rval.isString()) {                     \
-                    JSString *l = lval.toString(), *r = rval.toString();      \
-                    JSBool equal;                                             \
-                    if (!EqualStrings(cx, l, r, &equal))                      \
-                        goto error;                                           \
-                    cond = equal OP JS_TRUE;                                  \
-                } else {                                                      \
-                    double l, r;                                              \
-                    if (!ValueToNumber(cx, lval, &l) ||                       \
-                        !ValueToNumber(cx, rval, &r)) {                       \
-                        goto error;                                           \
-                    }                                                         \
-                    cond = JSDOUBLE_COMPARE(l, OP, r, IFNAN);                 \
-                }                                                             \
-            }                                                                 \
-        }                                                                     \
+        JSBool cond;                                                          \
+        if (!LooselyEqual(cx, lval, rval, &cond))                             \
+            goto error;                                                       \
+        cond = cond OP JS_TRUE;                                               \
         TRY_BRANCH_AFTER_COND(cond, 2);                                       \
         regs.sp--;                                                            \
         regs.sp[-1].setBoolean(cond);                                         \
     JS_END_MACRO
 
 BEGIN_CASE(JSOP_EQ)
-    EQUALITY_OP(==, false);
+    EQUALITY_OP(==);
 END_CASE(JSOP_EQ)
 
 BEGIN_CASE(JSOP_NE)
-    EQUALITY_OP(!=, true);
+    EQUALITY_OP(!=);
 END_CASE(JSOP_NE)
 
 #undef EQUALITY_OP
-#undef XML_EQUALITY_OP
-#undef EXTENDED_EQUALITY_OP
 
 #define STRICT_EQUALITY_OP(OP, COND)                                          \
     JS_BEGIN_MACRO                                                            \
         const Value &rref = regs.sp[-1];                                      \
         const Value &lref = regs.sp[-2];                                      \
         JSBool equal;                                                         \
         if (!StrictlyEqual(cx, lref, rref, &equal))                           \
             goto error;                                                       \
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -1072,16 +1072,19 @@ extern JS_REQUIRES_STACK bool
 RunScript(JSContext *cx, JSScript *script, JSStackFrame *fp);
 
 extern bool
 CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs);
 
 extern bool
 StrictlyEqual(JSContext *cx, const Value &lval, const Value &rval, JSBool *equal);
 
+extern bool
+LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, JSBool *equal);
+
 /* === except that NaN is the same as NaN and -0 is not the same as +0. */
 extern bool
 SameValue(JSContext *cx, const Value &v1, const Value &v2, JSBool *same);
 
 extern JSType
 TypeOfValue(JSContext *cx, const Value &v);
 
 inline bool
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -122,17 +122,17 @@ NativeIterator::mark(JSTracer *trc)
 
 static void
 iterator_finalize(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->getClass() == &js_IteratorClass);
 
     NativeIterator *ni = obj->getNativeIterator();
     if (ni) {
-        cx->free(ni);
+        cx->free_(ni);
         obj->setNativeIterator(NULL);
     }
 }
 
 static void
 iterator_trace(JSTracer *trc, JSObject *obj)
 {
     NativeIterator *ni = obj->getNativeIterator();
@@ -332,17 +332,17 @@ namespace js {
 
 bool
 VectorToIdArray(JSContext *cx, AutoIdVector &props, JSIdArray **idap)
 {
     JS_STATIC_ASSERT(sizeof(JSIdArray) > sizeof(jsid));
     size_t len = props.length();
     size_t idsz = len * sizeof(jsid);
     size_t sz = (sizeof(JSIdArray) - sizeof(jsid)) + idsz;
-    JSIdArray *ida = static_cast<JSIdArray *>(cx->malloc(sz));
+    JSIdArray *ida = static_cast<JSIdArray *>(cx->malloc_(sz));
     if (!ida)
         return false;
 
     ida->length = static_cast<jsint>(len);
     memcpy(ida->vector, props.begin(), idsz);
     *idap = ida;
     return true;
 }
@@ -436,17 +436,17 @@ NewIteratorObject(JSContext *cx, uintN f
     return NewBuiltinClassInstance(cx, &js_IteratorClass);
 }
 
 NativeIterator *
 NativeIterator::allocateIterator(JSContext *cx, uint32 slength, const AutoIdVector &props)
 {
     size_t plength = props.length();
     NativeIterator *ni = (NativeIterator *)
-        cx->malloc(sizeof(NativeIterator) + plength * sizeof(jsid) + slength * sizeof(uint32));
+        cx->malloc_(sizeof(NativeIterator) + plength * sizeof(jsid) + slength * sizeof(uint32));
     if (!ni)
         return NULL;
     ni->props_array = ni->props_cursor = (jsid *) (ni + 1);
     ni->props_end = (jsid *)ni->props_array + plength;
     if (plength)
         memcpy(ni->props_array, props.begin(), plength * sizeof(jsid));
     return ni;
 }
@@ -1064,17 +1064,17 @@ generator_finalize(JSContext *cx, JSObje
 
     /*
      * gen is open when a script has not called its close method while
      * explicitly manipulating it.
      */
     JS_ASSERT(gen->state == JSGEN_NEWBORN ||
               gen->state == JSGEN_CLOSED ||
               gen->state == JSGEN_OPEN);
-    cx->free(gen);
+    cx->free_(gen);
 }
 
 static void
 generator_trace(JSTracer *trc, JSObject *obj)
 {
     JSGenerator *gen = (JSGenerator *) obj->getPrivate();
     if (!gen)
         return;
@@ -1161,17 +1161,17 @@ js_NewGenerator(JSContext *cx)
 
     /* Compute JSGenerator size. */
     uintN nbytes = sizeof(JSGenerator) +
                    (-1 + /* one Value included in JSGenerator */
                     vplen +
                     VALUES_PER_STACK_FRAME +
                     stackfp->numSlots()) * sizeof(Value);
 
-    JSGenerator *gen = (JSGenerator *) cx->malloc(nbytes);
+    JSGenerator *gen = (JSGenerator *) cx->malloc_(nbytes);
     if (!gen)
         return NULL;
 
     /* Cut up floatingStack space. */
     Value *genvp = gen->floatingStack;
     JSStackFrame *genfp = reinterpret_cast<JSStackFrame *>(genvp + vplen);
 
     /* Initialize JSGenerator. */
--- a/js/src/jslock.cpp
+++ b/js/src/jslock.cpp
@@ -300,17 +300,17 @@ struct JSFatLock {
     int         susp;
     PRLock      *slock;
     PRCondVar   *svar;
     JSFatLock   *next;
     JSFatLock   **prevp;
 };
 
 typedef struct JSFatLockTable {
-    JSFatLock   *free;
+    JSFatLock   *free_;
     JSFatLock   *taken;
 } JSFatLockTable;
 
 #define GLOBAL_LOCK_INDEX(id)   (((uint32)(jsuword)(id)>>2) & global_locks_mask)
 
 static void
 js_Dequeue(JSThinLock *);
 
@@ -359,32 +359,32 @@ js_FinishLock(JSThinLock *tl)
 #endif
 }
 
 #ifndef NSPR_LOCK
 
 static JSFatLock *
 NewFatlock()
 {
-    JSFatLock *fl = (JSFatLock *)js_malloc(sizeof(JSFatLock)); /* for now */
+    JSFatLock *fl = (JSFatLock *) OffTheBooks::malloc_(sizeof(JSFatLock)); /* for now */
     if (!fl) return NULL;
     fl->susp = 0;
     fl->next = NULL;
     fl->prevp = NULL;
     fl->slock = PR_NewLock();
     fl->svar = PR_NewCondVar(fl->slock);
     return fl;
 }
 
 static void
 DestroyFatlock(JSFatLock *fl)
 {
     PR_DestroyLock(fl->slock);
     PR_DestroyCondVar(fl->svar);
-    js_free(fl);
+    UnwantedForeground::free_(fl);
 }
 
 static JSFatLock *
 ListOfFatlocks(int listc)
 {
     JSFatLock *m;
     JSFatLock *m0;
     int i;
@@ -413,25 +413,25 @@ static uint32          fl_list_table_len
 static uint32          fl_list_chunk_len = 0;
 
 static JSFatLock *
 GetFatlock(void *id)
 {
     JSFatLock *m;
 
     uint32 i = GLOBAL_LOCK_INDEX(id);
-    if (fl_list_table[i].free == NULL) {
+    if (fl_list_table[i].free_ == NULL) {
 #ifdef DEBUG
         if (fl_list_table[i].taken)
             printf("Ran out of fat locks!\n");
 #endif
-        fl_list_table[i].free = ListOfFatlocks(fl_list_chunk_len);
+        fl_list_table[i].free_ = ListOfFatlocks(fl_list_chunk_len);
     }
-    m = fl_list_table[i].free;
-    fl_list_table[i].free = m->next;
+    m = fl_list_table[i].free_;
+    fl_list_table[i].free_ = m->next;
     m->susp = 0;
     m->next = fl_list_table[i].taken;
     m->prevp = &fl_list_table[i].taken;
     if (fl_list_table[i].taken)
         fl_list_table[i].taken->prevp = &m->next;
     fl_list_table[i].taken = m;
     return m;
 }
@@ -445,18 +445,18 @@ PutFatlock(JSFatLock *m, void *id)
 
     /* Unlink m from fl_list_table[i].taken. */
     *m->prevp = m->next;
     if (m->next)
         m->next->prevp = m->prevp;
 
     /* Insert m in fl_list_table[i].free. */
     i = GLOBAL_LOCK_INDEX(id);
-    m->next = fl_list_table[i].free;
-    fl_list_table[i].free = m;
+    m->next = fl_list_table[i].free_;
+    fl_list_table[i].free_ = m;
 }
 
 #endif /* !NSPR_LOCK */
 
 JSBool
 js_SetupLocks(int listc, int globc)
 {
 #ifndef NSPR_LOCK
@@ -468,63 +468,63 @@ js_SetupLocks(int listc, int globc)
     if (listc > 10000 || listc < 0) /* listc == fat lock list chunk length */
         printf("Bad number %d in js_SetupLocks()!\n", listc);
     if (globc > 100 || globc < 0)   /* globc == number of global locks */
         printf("Bad number %d in js_SetupLocks()!\n", listc);
 #endif
     global_locks_log2 = JS_CeilingLog2(globc);
     global_locks_mask = JS_BITMASK(global_locks_log2);
     global_lock_count = JS_BIT(global_locks_log2);
-    global_locks = (PRLock **) js_malloc(global_lock_count * sizeof(PRLock*));
+    global_locks = (PRLock **) OffTheBooks::malloc_(global_lock_count * sizeof(PRLock*));
     if (!global_locks)
         return JS_FALSE;
     for (i = 0; i < global_lock_count; i++) {
         global_locks[i] = PR_NewLock();
         if (!global_locks[i]) {
             global_lock_count = i;
             js_CleanupLocks();
             return JS_FALSE;
         }
     }
-    fl_list_table = (JSFatLockTable *) js_malloc(i * sizeof(JSFatLockTable));
+    fl_list_table = (JSFatLockTable *) OffTheBooks::malloc_(i * sizeof(JSFatLockTable));
     if (!fl_list_table) {
         js_CleanupLocks();
         return JS_FALSE;
     }
     fl_list_table_len = global_lock_count;
     for (i = 0; i < global_lock_count; i++)
-        fl_list_table[i].free = fl_list_table[i].taken = NULL;
+        fl_list_table[i].free_ = fl_list_table[i].taken = NULL;
     fl_list_chunk_len = listc;
 #endif /* !NSPR_LOCK */
     return JS_TRUE;
 }
 
 void
 js_CleanupLocks()
 {
 #ifndef NSPR_LOCK
     uint32 i;
 
     if (global_locks) {
         for (i = 0; i < global_lock_count; i++)
             PR_DestroyLock(global_locks[i]);
-        js_free(global_locks);
+        UnwantedForeground::free_(global_locks);
         global_locks = NULL;
         global_lock_count = 1;
         global_locks_log2 = 0;
         global_locks_mask = 0;
     }
     if (fl_list_table) {
         for (i = 0; i < fl_list_table_len; i++) {
-            DeleteListOfFatlocks(fl_list_table[i].free);
-            fl_list_table[i].free = NULL;
+            DeleteListOfFatlocks(fl_list_table[i].free_);
+            fl_list_table[i].free_ = NULL;
             DeleteListOfFatlocks(fl_list_table[i].taken);
             fl_list_table[i].taken = NULL;
         }
-        js_free(fl_list_table);
+        UnwantedForeground::free_(fl_list_table);
         fl_list_table = NULL;
         fl_list_table_len = 0;
     }
 #endif /* !NSPR_LOCK */
 }
 
 #ifdef NSPR_LOCK
 
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -108,38 +108,38 @@ JS_STATIC_ASSERT(uintptr_t(PTRDIFF_MAX) 
  * If we're accumulating a decimal number and the number is >= 2^53, then the
  * fast result from the loop in GetPrefixInteger may be inaccurate. Call
  * js_strtod_harder to get the correct answer.
  */
 static bool
 ComputeAccurateDecimalInteger(JSContext *cx, const jschar *start, const jschar *end, jsdouble *dp)
 {
     size_t length = end - start;
-    char *cstr = static_cast<char *>(cx->malloc(length + 1));
+    char *cstr = static_cast<char *>(cx->malloc_(length + 1));
     if (!cstr)
         return false;
 
     for (size_t i = 0; i < length; i++) {
         char c = char(start[i]);
         JS_ASSERT(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'));
         cstr[i] = c;
     }
     cstr[length] = 0;
 
     char *estr;
     int err = 0;
     *dp = js_strtod_harder(JS_THREAD_DATA(cx)->dtoaState, cstr, &estr, &err);
     if (err == JS_DTOA_ENOMEM) {
         JS_ReportOutOfMemory(cx);
-        cx->free(cstr);
+        cx->free_(cstr);
         return false;
     }
     if (err == JS_DTOA_ERANGE && *dp == HUGE_VAL)
         *dp = js_PositiveInfinity;
-    cx->free(cstr);
+    cx->free_(cstr);
     return true;
 }
 
 class BinaryDigitReader
 {
     const int base;      /* Base of number; must be a power of 2 */
     int digit;           /* Current digit value in radix given by base */
     int digitMask;       /* Mask to extract the next bit from digit */
@@ -592,17 +592,17 @@ num_toSource(JSContext *cx, uintN argc, 
 ToCStringBuf::ToCStringBuf() :dbuf(NULL)
 {
     JS_STATIC_ASSERT(sbufSize >= DTOSTR_STANDARD_BUFFER_SIZE);
 }
 
 ToCStringBuf::~ToCStringBuf()
 {
     if (dbuf)
-        js_free(dbuf);
+        UnwantedForeground::free_(dbuf);
 }
 
 JSString * JS_FASTCALL
 js_IntToString(JSContext *cx, int32 si)
 {
     uint32 ui;
     if (si >= 0) {
         if (JSAtom::hasIntStatic(si))
@@ -788,17 +788,17 @@ num_toLocaleString(JSContext *cx, uintN 
         nrepeat = (remainder - 1) / tmpGroup[-1];
         buflen += thousandsLength * nrepeat;
         remainder -= nrepeat * tmpGroup[-1];
     } else {
         nrepeat = 0;
     }
     tmpGroup--;
 
-    buf = (char *)cx->malloc(buflen + 1);
+    buf = (char *)cx->malloc_(buflen + 1);
     if (!buf)
         return JS_FALSE;
 
     tmpDest = buf;
     tmpSrc = num;
 
     while (*tmpSrc == '-' || remainder--) {
         JS_ASSERT(tmpDest - buf < buflen);
@@ -824,22 +824,22 @@ num_toLocaleString(JSContext *cx, uintN 
         strcpy(tmpDest, nint + 1);
     } else {
         JS_ASSERT(tmpDest - buf + ptrdiff_t(strlen(nint)) <= buflen);
         strcpy(tmpDest, nint);
     }
 
     if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode) {
         JSBool ok = cx->localeCallbacks->localeToUnicode(cx, buf, Jsvalify(vp));
-        cx->free(buf);
+        cx->free_(buf);
         return ok;
     }
 
     str = js_NewStringCopyN(cx, buf, buflen);
-    cx->free(buf);
+    cx->free_(buf);
     if (!str)
         return JS_FALSE;
 
     vp->setString(str);
     return JS_TRUE;
 }
 
 JSBool
@@ -1049,19 +1049,19 @@ js_InitRuntimeNumberState(JSContext *cx)
     return rt->thousandsSeparator && rt->decimalSeparator && rt->numGrouping;
 }
 
 void
 js_FinishRuntimeNumberState(JSContext *cx)
 {
     JSRuntime *rt = cx->runtime;
 
-    cx->free((void *) rt->thousandsSeparator);
-    cx->free((void *) rt->decimalSeparator);
-    cx->free((void *) rt->numGrouping);
+    cx->free_((void *) rt->thousandsSeparator);
+    cx->free_((void *) rt->decimalSeparator);
+    cx->free_((void *) rt->numGrouping);
     rt->thousandsSeparator = rt->decimalSeparator = rt->numGrouping = NULL;
 }
 
 JSObject *
 js_InitNumberClass(JSContext *cx, JSObject *obj)
 {
     JSObject *proto, *ctor;
     JSRuntime *rt;
@@ -1410,17 +1410,17 @@ js_strtod(JSContext *cx, const jschar *s
     JSBool negative;
     jsdouble d;
 
     s1 = js_SkipWhiteSpace(s, send);
     length = send - s1;
 
     /* Use cbuf to avoid malloc */
     if (length >= sizeof cbuf) {
-        cstr = (char *) cx->malloc(length + 1);
+        cstr = (char *) cx->malloc_(length + 1);
         if (!cstr)
            return JS_FALSE;
     } else {
         cstr = cbuf;
     }
 
     for (i = 0; i != length; i++) {
         if (s1[i] >> 8)
@@ -1441,13 +1441,13 @@ js_strtod(JSContext *cx, const jschar *s
         if (d == HUGE_VAL)
             d = js_PositiveInfinity;
         else if (d == -HUGE_VAL)
             d = js_NegativeInfinity;
     }
 
     i = estr - cstr;
     if (cstr != cbuf)
-        cx->free(cstr);
+        cx->free_(cstr);
     *ep = i ? s1 + i : s;
     *dp = d;
     return JS_TRUE;
 }
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -219,17 +219,17 @@ struct ToCStringBuf
 {
     /*
      * The longest possible result that would need to fit in sbuf is
      * (-0x80000000).toString(2), which has length 33.  Longer cases are
      * possible, but they'll go in dbuf.
      */
     static const size_t sbufSize = 34;
     char sbuf[sbufSize];
-    char *dbuf;     /* must be allocated with js_malloc() */
+    char *dbuf;
 
     ToCStringBuf();
     ~ToCStringBuf();
 };
 
 /*
  * Convert a number to a C string.  When base==10, this function implements
  * ToString() as specified by ECMA-262-5 section 9.8.1.  It handles integral
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -380,17 +380,17 @@ js_EnterSharpObject(JSContext *cx, JSObj
 
 out:
     JS_ASSERT(he);
     if ((sharpid & SHARP_BIT) == 0) {
         if (idap && !ida) {
             ida = JS_Enumerate(cx, obj);
             if (!ida) {
                 if (*sp) {
-                    cx->free(*sp);
+                    cx->free_(*sp);
                     *sp = NULL;
                 }
                 goto bad;
             }
         }
         map->depth++;
     }
 
@@ -520,30 +520,30 @@ obj_toSource(JSContext *cx, uintN argc, 
 #endif
         goto make_string;
     }
     JS_ASSERT(ida);
     ok = JS_TRUE;
 
     if (!chars) {
         /* If outermost, allocate 4 + 1 for "({})" and the terminator. */
-        chars = (jschar *) cx->runtime->malloc(((outermost ? 4 : 2) + 1) * sizeof(jschar));
+        chars = (jschar *) cx->malloc_(((outermost ? 4 : 2) + 1) * sizeof(jschar));
         nchars = 0;
         if (!chars)
             goto error;
         if (outermost)
             chars[nchars++] = '(';
     } else {
         /* js_EnterSharpObject returned a string of the form "#n=" in chars. */
         MAKE_SHARP(he);
         nchars = js_strlen(chars);
         chars = (jschar *)
-            js_realloc((ochars = chars), (nchars + 2 + 1) * sizeof(jschar));
+            cx->realloc_((ochars = chars), (nchars + 2 + 1) * sizeof(jschar));
         if (!chars) {
-            js_free(ochars);
+            Foreground::free_(ochars);
             goto error;
         }
         if (outermost) {
             /*
              * No need for parentheses around the whole shebang, because #n=
              * unambiguously begins an object initializer, and never a block
              * statement.
              */
@@ -734,17 +734,17 @@ obj_toSource(JSContext *cx, uintN argc, 
             /* Account for the trailing null. */
             SAFE_ADD((outermost ? 2 : 1) + 1);
 #undef SAFE_ADD
 
             if (curlen > size_t(-1) / sizeof(jschar))
                 goto overflow;
 
             /* Allocate 1 + 1 at end for closing brace and terminating 0. */
-            chars = (jschar *) js_realloc((ochars = chars), curlen * sizeof(jschar));
+            chars = (jschar *) cx->realloc_((ochars = chars), curlen * sizeof(jschar));
             if (!chars) {
                 chars = ochars;
                 goto overflow;
             }
 
             if (comma) {
                 chars[nchars++] = comma[0];
                 chars[nchars++] = comma[1];
@@ -768,85 +768,85 @@ obj_toSource(JSContext *cx, uintN argc, 
             if (vsharplength) {
                 js_strncpy(&chars[nchars], vsharp, vsharplength);
                 nchars += vsharplength;
             }
             js_strncpy(&chars[nchars], vchars, vlength);
             nchars += vlength;
 
             if (vsharp)
-                cx->free(vsharp);
+                cx->free_(vsharp);
         }
     }
 
     chars[nchars++] = '}';
     if (outermost)
         chars[nchars++] = ')';
     chars[nchars] = 0;
 
   error:
     js_LeaveSharpObject(cx, &ida);
 
     if (!ok) {
         if (chars)
-            js_free(chars);
+            Foreground::free_(chars);
         goto out;
     }
 
     if (!chars) {
         JS_ReportOutOfMemory(cx);
         ok = JS_FALSE;
         goto out;
     }
   make_string:
     str = js_NewString(cx, chars, nchars);
     if (!str) {
-        js_free(chars);
+        cx->free_(chars);
         ok = JS_FALSE;
         goto out;
     }
     vp->setString(str);
     ok = JS_TRUE;
   out:
     return ok;
 
   overflow:
-    cx->free(vsharp);
-    js_free(chars);
+    cx->free_(vsharp);
+    cx->free_(chars);
     chars = NULL;
     goto error;
 }
 #endif /* JS_HAS_TOSOURCE */
 
 namespace js {
 
 JSString *
 obj_toStringHelper(JSContext *cx, JSObject *obj)
 {
     if (obj->isProxy())
         return JSProxy::obj_toString(cx, obj);
 
     const char *clazz = obj->getClass()->name;
     size_t nchars = 9 + strlen(clazz); /* 9 for "[object ]" */
-    jschar *chars = (jschar *) cx->malloc((nchars + 1) * sizeof(jschar));
+    jschar *chars = (jschar *) cx->malloc_((nchars + 1) * sizeof(jschar));
     if (!chars)
         return NULL;
 
     const char *prefix = "[object ";
     nchars = 0;
     while ((chars[nchars] = (jschar)*prefix) != 0)
         nchars++, prefix++;
     while ((chars[nchars] = (jschar)*clazz) != 0)
         nchars++, clazz++;
     chars[nchars++] = ']';
     chars[nchars] = 0;
 
     JSString *str = js_NewString(cx, chars, nchars);
     if (!str)
-        cx->free(chars);
+        cx->free_(chars);
     return str;
 }
 
 }
 
 /* ES5 15.2.4.2.  Note steps 1 and 2 are errata. */
 static JSBool
 obj_toString(JSContext *cx, uintN argc, Value *vp)
@@ -3993,17 +3993,17 @@ JSObject::allocSlots(JSContext *cx, size
     JS_ASSERT(newcap >= oldcap && !hasSlotsArray());
 
     if (newcap > NSLOTS_LIMIT) {
         if (!JS_ON_TRACE(cx))
             js_ReportAllocationOverflow(cx);
         return false;
     }
 
-    Value *tmpslots = (Value*) cx->malloc(newcap * sizeof(Value));
+    Value *tmpslots = (Value*) cx->malloc_(newcap * sizeof(Value));
     if (!tmpslots)
         return false;  /* Leave slots at inline buffer. */
     slots = tmpslots;
     capacity = newcap;
 
     /* Copy over anything from the inline buffer. */
     memcpy(slots, fixedSlots(), oldcap * sizeof(Value));
     ClearValueRange(slots + oldcap, newcap - oldcap, isDenseArray());
@@ -4041,17 +4041,17 @@ JSObject::growSlots(JSContext *cx, size_
         JS_ReportOutOfMemory(cx);
         return false;
     }
 
     /* If nothing was allocated yet, treat it as initial allocation. */
     if (!hasSlotsArray())
         return allocSlots(cx, actualCapacity);
 
-    Value *tmpslots = (Value*) cx->realloc(slots, oldcap * sizeof(Value), actualCapacity * sizeof(Value));
+    Value *tmpslots = (Value*) cx->realloc_(slots, oldcap * sizeof(Value), actualCapacity * sizeof(Value));
     if (!tmpslots)
         return false;    /* Leave dslots as its old size. */
     slots = tmpslots;
     capacity = actualCapacity;
 
     /* Initialize the additional slots we added. */
     ClearValueRange(slots + oldcap, actualCapacity - oldcap, isDenseArray());
     return true;
@@ -4071,17 +4071,17 @@ JSObject::shrinkSlots(JSContext *cx, siz
     }
 
     uint32 fill = newcap;
     if (newcap < SLOT_CAPACITY_MIN)
         newcap = SLOT_CAPACITY_MIN;
     if (newcap < numFixedSlots())
         newcap = numFixedSlots();
 
-    Value *tmpslots = (Value*) cx->realloc(slots, newcap * sizeof(Value));
+    Value *tmpslots = (Value*) cx->realloc_(slots, newcap * sizeof(Value));
     if (!tmpslots)
         return;  /* Leave slots at its old size. */
     slots = tmpslots;
     capacity = newcap;
 
     if (fill < newcap) {
         /* Clear any excess holes if we tried to shrink below SLOT_CAPACITY_MIN. */
         ClearValueRange(slots + fill, newcap - fill, isDenseArray());
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -36,23 +36,16 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsobj_h___
 #define jsobj_h___
 
-/* Gross special case for Gecko, which defines malloc/calloc/free. */
-#ifdef mozilla_mozalloc_macro_wrappers_h
-#  define JS_OBJ_UNDEFD_MOZALLOC_WRAPPERS
-/* The "anti-header" */
-#  include "mozilla/mozalloc_undef_macro_wrappers.h"
-#endif
-
 /*
  * JS object definitions.
  *
  * A JS object consists of a possibly-shared object descriptor containing
  * ordered property names, called the map; and a dense vector of property
  * values, called slots.  The map/slot pointer pair is GC'ed, while the map
  * is reference counted and the slot vector is malloc'ed.
  */
@@ -1979,13 +1972,9 @@ extern bool
 IsBuiltinEvalForScope(JSObject *scopeChain, const js::Value &v);
 
 /* True iff fun is a built-in eval function. */
 extern bool
 IsAnyBuiltinEval(JSFunction *fun);
 
 }
 
-#ifdef JS_OBJ_UNDEFD_MOZALLOC_WRAPPERS
-#  include "mozilla/mozalloc_macro_wrappers.h"
-#endif
-
 #endif /* jsobj_h___ */
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -795,17 +795,17 @@ JSObject::finish(JSContext *cx)
 {
 #ifdef DEBUG
     if (isNative())
         JS_LOCK_RUNTIME_VOID(cx->runtime, cx->runtime->liveObjectProps -= propertyCount());
 #endif
     if (hasSlotsArray())
         freeSlotsArray(cx);
     if (emptyShapes)
-        cx->free(emptyShapes);
+        cx->free_(emptyShapes);
 }
 
 inline bool
 JSObject::initSharingEmptyShape(JSContext *cx,
                                 js::Class *aclasp,
                                 JSObject *proto,
                                 JSObject *parent,
                                 void *privateValue,
@@ -822,17 +822,17 @@ JSObject::initSharingEmptyShape(JSContex
     setMap(empty);
     return true;
 }
 
 inline void
 JSObject::freeSlotsArray(JSContext *cx)
 {
     JS_ASSERT(hasSlotsArray());
-    cx->free(slots);
+    cx->free_(slots);
 }
 
 inline void
 JSObject::revertToFixedSlots(JSContext *cx)
 {
     JS_ASSERT(hasSlotsArray());
     size_t fixed = numFixedSlots();
     JS_ASSERT(capacity >= fixed);
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -710,17 +710,17 @@ js_BeginJSONParse(JSContext *cx, Value *
 {
     if (!cx)
         return NULL;
 
     JSObject *arr = NewDenseEmptyArray(cx);
     if (!arr)
         return NULL;
 
-    JSONParser *jp = cx->create<JSONParser>(cx);
+    JSONParser *jp = cx->new_<JSONParser>(cx);
     if (!jp)
         return NULL;
 
     jp->objectStack = arr;
     if (!JS_AddNamedObjectRoot(cx, &jp->objectStack, "JSON parse stack"))
         goto bad;
 
     jp->statep = jp->stateStack;
@@ -766,17 +766,17 @@ js_FinishJSONParse(JSContext *cx, JSONPa
     if (!early_ok) {
         ok = false;
     } else if (!ok) {
         JSONParseError(jp, cx);
     } else if (reviver.isObject() && reviver.toObject().isCallable()) {
         ok = Revive(cx, reviver, vp);
     }
 
-    cx->destroy(jp);
+    cx->delete_(jp);
 
     return ok;
 }
 
 static JSBool
 PushState(JSContext *cx, JSONParser *jp, JSONParserState state)
 {
     if (*jp->statep == JSON_PARSE_STATE_FINISHED) {
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -257,17 +257,17 @@ public:
             script->code = newCode;
         }
     }
     ~AutoScriptUntrapper()
     {
         ptrdiff_t delta = newPC - origPC;
         if (delta) {
             jsbytecode *oldCode = script->code - delta;
-            cx->free(script->code);
+            cx->free_(script->code);
             script->code = oldCode;
             script->main -= delta;
         }
     }
 };
 
 #ifdef DEBUG
 
@@ -692,17 +692,17 @@ Sprint(Sprinter *sp, const char *format,
     va_start(ap, format);
     bp = JS_vsmprintf(format, ap);      /* XXX vsaprintf */
     va_end(ap);
     if (!bp) {
         JS_ReportOutOfMemory(sp->context);
         return -1;
     }
     offset = SprintCString(sp, bp);
-    js_free(bp);
+    sp->context->free_(bp);
     return offset;
 }
 
 } // namespace js
 
 const char js_EscapeMap[] = {
     '\b', 'b',
     '\f', 'f',
@@ -824,17 +824,17 @@ struct JSPrinter {
 };
 
 JSPrinter *
 js_NewPrinter(JSContext *cx, const char *name, JSFunction *fun,
               uintN indent, JSBool pretty, JSBool grouped, JSBool strict)
 {
     JSPrinter *jp;
 
-    jp = (JSPrinter *) cx->malloc(sizeof(JSPrinter));
+    jp = (JSPrinter *) cx->malloc_(sizeof(JSPrinter));
     if (!jp)
         return NULL;
     INIT_SPRINTER(cx, &jp->sprinter, &jp->pool, 0);
     JS_InitArenaPool(&jp->pool, name, 256, 1, &cx->scriptStackQuota);
     jp->indent = indent;
     jp->pretty = !!pretty;
     jp->grouped = !!grouped;
     jp->strict = !!strict;
@@ -852,17 +852,17 @@ js_NewPrinter(JSContext *cx, const char 
     }
     return jp;
 }
 
 void
 js_DestroyPrinter(JSPrinter *jp)
 {
     JS_FinishArenaPool(&jp->pool);
-    jp->sprinter.context->free(jp);
+    jp->sprinter.context->free_(jp);
 }
 
 JSString *
 js_GetPrinterOutput(JSPrinter *jp)
 {
     JSContext *cx;
     JSString *str;
 
@@ -924,29 +924,29 @@ js_printf(JSPrinter *jp, const char *for
         }
         fp[cc] = '\0';
         format = fp;
     }
 
     /* Allocate temp space, convert format, and put. */
     bp = JS_vsmprintf(format, ap);      /* XXX vsaprintf */
     if (fp) {
-        jp->sprinter.context->free(fp);
+        jp->sprinter.context->free_(fp);
         format = NULL;
     }
     if (!bp) {
         JS_ReportOutOfMemory(jp->sprinter.context);
         va_end(ap);
         return -1;
     }
 
     cc = strlen(bp);
     if (SprintPut(&jp->sprinter, bp, (size_t)cc) < 0)
         cc = -1;
-    js_free(bp);
+    jp->sprinter.context->free_(bp);
 
     va_end(ap);
     return cc;
 }
 
 JSBool
 js_puts(JSPrinter *jp, const char *s)
 {
@@ -1022,17 +1022,17 @@ GetOff(SprintStack *ss, uintN i)
                                     ss->printer->fun, pc);
         if (!bytes)
             return 0;
         if (bytes != FAILED_EXPRESSION_DECOMPILER) {
             off = SprintCString(&ss->sprinter, bytes);
             if (off < 0)
                 off = 0;
             ss->offsets[i] = off;
-            ss->sprinter.context->free(bytes);
+            ss->sprinter.context->free_(bytes);
             return off;
         }
         if (!ss->sprinter.base && SprintPut(&ss->sprinter, "", 0) >= 0) {
             memset(ss->sprinter.base, 0, ss->sprinter.offset);
             ss->offsets[i] = -1;
         }
     }
     return 0;
@@ -2585,24 +2585,24 @@ Decompile(SprintStack *ss, jsbytecode *p
                      * The offset tells distance to the end of the right-hand
                      * operand of the comma operator.
                      */
                     done = pc + len;
                     pc += js_GetSrcNoteOffset(sn, 0);
                     len = 0;
 
                     if (!Decompile(ss, done, pc - done, JSOP_POP)) {
-                        cx->free((char *)lval);
+                        cx->free_((char *)lval);
                         return NULL;
                     }
 
                     /* Pop Decompile result and print comma expression. */
                     rval = POP_STR();
                     todo = Sprint(&ss->sprinter, "%s, %s", lval, rval);
-                    cx->free((char *)lval);
+                    cx->free_((char *)lval);
                     break;
 
                   case SRC_HIDDEN:
                     /* Hide this pop, it's from a goto in a with or for/in. */
                     todo = -2;
                     break;
 
                   case SRC_DECL:
@@ -2624,26 +2624,26 @@ Decompile(SprintStack *ss, jsbytecode *p
 
                         lval = JS_strdup(cx, PopStr(ss, JSOP_NOP));
                         if (!lval)
                             return NULL;
 
                         /* Set saveop to reflect what we will push. */
                         saveop = JSOP_LEAVEBLOCKEXPR;
                         if (!Decompile(ss, pc, len, saveop)) {
-                            cx->free((char *)lval);
+                            cx->free_((char *)lval);
                             return NULL;
                         }
                         rval = PopStr(ss, JSOP_SETNAME);
                         todo = Sprint(&ss->sprinter,
                                       (*rval == '{')
                                       ? "let (%s) (%s)"
                                       : "let (%s) %s",
                                       lval, rval);
-                        cx->free((char *)lval);
+                        cx->free_((char *)lval);
                     }
                     break;
 
                   default:
                     /* Turn off parens around a yield statement. */
                     if (ss->opcodes[ss->top-1] == JSOP_YIELD)
                         op = JSOP_NOP;
 
@@ -2696,17 +2696,17 @@ Decompile(SprintStack *ss, jsbytecode *p
               {
                 JSAtom **atomv, *smallv[5];
 
                 LOAD_OBJECT(0);
                 argc = OBJ_BLOCK_COUNT(cx, obj);
                 if ((size_t)argc <= JS_ARRAY_LENGTH(smallv)) {
                     atomv = smallv;
                 } else {
-                    atomv = (JSAtom **) cx->malloc(argc * sizeof(JSAtom *));
+                    atomv = (JSAtom **) cx->malloc_(argc * sizeof(JSAtom *));
                     if (!atomv)
                         return NULL;
                 }
 
                 MUST_FLOW_THROUGH("enterblock_out");
 #define LOCAL_ASSERT_OUT(expr) LOCAL_ASSERT_CUSTOM(expr, ok = JS_FALSE; \
                                                    goto enterblock_out)
                 for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront()) {
@@ -2832,17 +2832,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                     break;
                 }
 
                 todo = -2;
 
 #undef LOCAL_ASSERT_OUT
               enterblock_out:
                 if (atomv != smallv)
-                    cx->free(atomv);
+                    cx->free_(atomv);
                 if (!ok)
                     return NULL;
               }
               break;
 
               case JSOP_LEAVEBLOCK:
               case JSOP_LEAVEBLOCKEXPR:
               {
@@ -3358,29 +3358,29 @@ Decompile(SprintStack *ss, jsbytecode *p
                   case SRC_COND:
                     xval = JS_strdup(cx, POP_STR());
                     if (!xval)
                         return NULL;
                     len = js_GetSrcNoteOffset(sn, 0);
                     DECOMPILE_CODE(pc + oplen, len - oplen);
                     lval = JS_strdup(cx, POP_STR());
                     if (!lval) {
-                        cx->free((void *)xval);
+                        cx->free_((void *)xval);
                         return NULL;
                     }
                     pc += len;
                     LOCAL_ASSERT(*pc == JSOP_GOTO || *pc == JSOP_GOTOX);
                     oplen = js_CodeSpec[*pc].length;
                     len = GetJumpOffset(pc, pc);
                     DECOMPILE_CODE(pc + oplen, len - oplen);
                     rval = POP_STR();
                     todo = Sprint(&ss->sprinter, "%s ? %s : %s",
                                   xval, lval, rval);
-                    cx->free((void *)xval);
-                    cx->free((void *)lval);
+                    cx->free_((void *)xval);
+                    cx->free_((void *)lval);
                     break;
 
                   default:
                     break;
                 }
                 break;
               }
 
@@ -3397,37 +3397,37 @@ Decompile(SprintStack *ss, jsbytecode *p
                 /* Top of stack is the first clause in a disjunction (||). */
                 lval = JS_strdup(cx, POP_STR());
                 if (!lval)
                     return NULL;
                 done = pc + GetJumpOffset(pc, pc);
                 pc += len;
                 len = done - pc;
                 if (!Decompile(ss, pc, len, op)) {
-                    cx->free((char *)lval);
+                    cx->free_((char *)lval);
                     return NULL;
                 }
                 rval = POP_STR();
                 if (jp->pretty &&
                     jp->indent + 4 + strlen(lval) + 4 + strlen(rval) > 75) {
                     rval = JS_strdup(cx, rval);
                     if (!rval) {
                         tail = -1;
                     } else {
                         todo = Sprint(&ss->sprinter, "%s %s\n", lval, xval);
                         tail = Sprint(&ss->sprinter, "%*s%s",
                                       jp->indent + 4, "", rval);
-                        cx->free((char *)rval);
+                        cx->free_((char *)rval);
                     }
                     if (tail < 0)
                         todo = -1;
                 } else {
                     todo = Sprint(&ss->sprinter, "%s %s %s", lval, xval, rval);
                 }
-                cx->free((char *)lval);
+                cx->free_((char *)lval);
                 break;
 
               case JSOP_AND:
               case JSOP_ANDX:
                 xval = "&&";
                 goto do_logical_connective;
 
               case JSOP_FORARG:
@@ -3608,17 +3608,17 @@ Decompile(SprintStack *ss, jsbytecode *p
 
               case JSOP_NEW:
               case JSOP_CALL:
               case JSOP_EVAL:
               case JSOP_FUNCALL:
               case JSOP_FUNAPPLY:
                 argc = GET_ARGC(pc);
                 argv = (char **)
-                    cx->malloc((size_t)(argc + 1) * sizeof *argv);
+                    cx->malloc_((size_t)(argc + 1) * sizeof *argv);
                 if (!argv)
                     return NULL;
 
                 op = JSOP_SETNAME;
                 ok = JS_TRUE;
                 for (i = argc; i > 0; i--)
                     argv[i] = JS_strdup(cx, POP_STR());
 
@@ -3667,18 +3667,18 @@ Decompile(SprintStack *ss, jsbytecode *p
                         ok = JS_FALSE;
                         break;
                     }
                 }
                 if (Sprint(&ss->sprinter, rval) < 0)
                     ok = JS_FALSE;
 
                 for (i = 0; i <= argc; i++)
-                    cx->free(argv[i]);
-                cx->free(argv);
+                    cx->free_(argv[i]);
+                cx->free_(argv);
                 if (!ok)
                     return NULL;
                 break;
 
               case JSOP_SETCALL:
                 todo = Sprint(&ss->sprinter, "");
                 break;
 
@@ -4192,17 +4192,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                      * the top of ss2 because both ss and ss2 arena-allocate
                      * from cx's tempPool.
                      */
                     rval = JS_strdup(cx, PopStr(&ss2, op));
                     JS_ARENA_RELEASE(&cx->tempPool, mark);
                     if (!rval)
                         return NULL;
                     todo = SprintCString(&ss->sprinter, rval);
-                    cx->free((void *)rval);
+                    cx->free_((void *)rval);
                     break;
                 }
 #endif /* JS_HAS_GENERATOR_EXPRS */
                 /* FALL THROUGH */
 
                 LOAD_FUNCTION(0);
                 {
                     /*
@@ -4264,17 +4264,17 @@ Decompile(SprintStack *ss, jsbytecode *p
 
                 n = high - low + 1;
                 if (n == 0) {
                     table = NULL;
                     j = 0;
                     ok = JS_TRUE;
                 } else {
                     table = (TableEntry *)
-                            cx->malloc((size_t)n * sizeof *table);
+                            cx->malloc_((size_t)n * sizeof *table);
                     if (!table)
                         return NULL;
                     for (i = j = 0; i < n; i++) {
                         table[j].label = NULL;
                         off2 = GetJumpOffset(pc, pc2);
                         if (off2) {
                             sn = js_GetSrcNote(jp->script, pc2);
                             if (sn) {
@@ -4284,33 +4284,33 @@ Decompile(SprintStack *ss, jsbytecode *p
                             table[j].key = INT_TO_JSVAL(low + i);
                             table[j].offset = off2;
                             table[j].order = j;
                             j++;
                         }
                         pc2 += jmplen;
                     }
                     tmp = (TableEntry *)
-                          cx->malloc((size_t)j * sizeof *table);
+                          cx->malloc_((size_t)j * sizeof *table);
                     if (tmp) {
                         VOUCH_DOES_NOT_REQUIRE_STACK();
                         ok = js_MergeSort(table, (size_t)j, sizeof(TableEntry),
                                           CompareOffsets, NULL, tmp,
                                           JS_SORTING_GENERIC);
-                        cx->free(tmp);
+                        cx->free_(tmp);
                     } else {
                         ok = JS_FALSE;
                     }
                 }
 
                 if (ok) {
                     ok = DecompileSwitch(ss, table, (uintN)j, pc, len, off,
                                          JS_FALSE);
                 }
-                cx->free(table);
+                cx->free_(table);
                 if (!ok)
                     return NULL;
                 todo = -2;
                 break;
               }
 
               case JSOP_LOOKUPSWITCH:
               case JSOP_LOOKUPSWITCHX:
@@ -4326,17 +4326,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                                                    : JUMPX_OFFSET_LEN;
                 pc2 = pc;
                 off = GetJumpOffset(pc, pc2);
                 pc2 += jmplen;
                 npairs = GET_UINT16(pc2);
                 pc2 += UINT16_LEN;
 
                 table = (TableEntry *)
-                    cx->malloc((size_t)npairs * sizeof *table);
+                    cx->malloc_((size_t)npairs * sizeof *table);
                 if (!table)
                     return NULL;
                 for (k = 0; k < npairs; k++) {
                     sn = js_GetSrcNote(jp->script, pc2);
                     if (sn) {
                         LOCAL_ASSERT(SN_TYPE(sn) == SRC_LABEL);
                         GET_SOURCE_NOTE_ATOM(sn, table[k].label);
                     } else {
@@ -4347,17 +4347,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                     off2 = GetJumpOffset(pc, pc2);
                     pc2 += jmplen;
                     table[k].key = Jsvalify(jp->script->getConst(constIndex));
                     table[k].offset = off2;
                 }
 
                 ok = DecompileSwitch(ss, table, (uintN)npairs, pc, len, off,
                                      JS_FALSE);
-                cx->free(table);
+                cx->free_(table);
                 if (!ok)
                     return NULL;
                 todo = -2;
                 break;
               }
 
               case JSOP_CONDSWITCH:
               {
@@ -4391,17 +4391,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                 }
 
                 /*
                  * Allocate table and rescan the cases using their srcnotes,
                  * stashing each case's delta from switch top in table[i].key,
                  * and the distance to its statements in table[i].offset.
                  */
                 table = (TableEntry *)
-                    cx->malloc((size_t)ncases * sizeof *table);
+                    cx->malloc_((size_t)ncases * sizeof *table);
                 if (!table)
                     return NULL;
                 pc2 = pc;
                 off2 = off;
                 for (i = 0; i < ncases; i++) {
                     pc2 += off2;
                     LOCAL_ASSERT(*pc2 == JSOP_CASE || *pc2 == JSOP_DEFAULT ||
                                  *pc2 == JSOP_CASEX || *pc2 == JSOP_DEFAULTX);
@@ -4421,17 +4421,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                  * case at the end.
                  */
                 off = JSVAL_TO_INT(table[ncases-1].key);
                 pc2 = pc + off;
                 off += GetJumpOffset(pc2, pc2);
 
                 ok = DecompileSwitch(ss, table, (uintN)ncases, pc, len, off,
                                      JS_TRUE);
-                cx->free(table);
+                cx->free_(table);
                 if (!ok)
                     return NULL;
                 todo = -2;
                 break;
               }
 
               case JSOP_CASE:
               case JSOP_CASEX:
@@ -4766,17 +4766,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                 rval = JS_strdup(cx, POP_STR());
                 if (!rval)
                     return NULL;
                 todo = SprintPut(&ss->sprinter, "<?", 2);
                 ok = QuoteString(&ss->sprinter, atom, 0) &&
                      (*rval == '\0' ||
                       (SprintPut(&ss->sprinter, " ", 1) >= 0 &&
                        SprintCString(&ss->sprinter, rval)));
-                cx->free((char *)rval);
+                cx->free_((char *)rval);
                 if (!ok)
                     return NULL;
                 SprintPut(&ss->sprinter, "?>", 2);
                 break;
 
               case JSOP_GETFUNNS:
                 todo = SprintPut(&ss->sprinter, js_function_str, 8);
                 break;
@@ -5114,17 +5114,17 @@ js_DecompileValueGenerator(JSContext *cx
     if (spindex != JSDVG_IGNORE_STACK) {
         jsbytecode **pcstack;
 
         /*
          * Prepare computing pcstack containing pointers to opcodes that
          * populated interpreter's stack with its current content.
          */
         pcstack = (jsbytecode **)
-                  cx->malloc(StackDepth(script) * sizeof *pcstack);
+                  cx->malloc_(StackDepth(script) * sizeof *pcstack);
         if (!pcstack)
             return NULL;
         intN pcdepth = ReconstructPCStack(cx, script, pc, pcstack);
         if (pcdepth < 0)
             goto release_pcstack;
 
         if (spindex != JSDVG_SEARCH_STACK) {
             JS_ASSERT(spindex < 0);
@@ -5156,17 +5156,17 @@ js_DecompileValueGenerator(JSContext *cx
              * combination of calls to produce a situation where this is not
              * what we want, we just use the current pc.
              */
             if (sp < stackBase + pcdepth)
                 pc = pcstack[sp - stackBase];
         }
 
       release_pcstack:
-        cx->free(pcstack);
+        cx->free_(pcstack);
         if (pcdepth < 0)
             goto do_fallback;
     }
 
     {
         jsbytecode* basepc = cx->regs->pc;
         jsbytecode* savedImacropc = fp->maybeImacropc();
         if (savedImacropc) {
@@ -5289,17 +5289,17 @@ DecompileExpression(JSContext *cx, JSScr
     }
     len = end - begin;
     if (len <= 0) {
         name = FAILED_EXPRESSION_DECOMPILER;
         goto out;
     }
 
     pcstack = (jsbytecode **)
-              cx->malloc(StackDepth(script) * sizeof *pcstack);
+              cx->malloc_(StackDepth(script) * sizeof *pcstack);
     if (!pcstack) {
         name = NULL;
         goto out;
     }
 
     MUST_FLOW_THROUGH("out");
     pcdepth = ReconstructPCStack(cx, script, begin, pcstack);
     if (pcdepth < 0) {
@@ -5316,17 +5316,17 @@ DecompileExpression(JSContext *cx, JSScr
         if (DecompileCode(jp, script, begin, (uintN) len, (uintN) pcdepth)) {
             name = (jp->sprinter.base) ? jp->sprinter.base : (char *) "";
             name = JS_strdup(cx, name);
         }
         js_DestroyPrinter(jp);
     }
 
 out:
-    cx->free(pcstack);
+    cx->free_(pcstack);
     return name;
 }
 
 uintN
 js_ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc)
 {
     return ReconstructPCStack(cx, script, pc, NULL);
 }
@@ -5398,17 +5398,17 @@ static intN
 SimulateImacroCFG(JSContext *cx, JSScript *script,
                   uintN pcdepth, jsbytecode *pc, jsbytecode *target,
                   jsbytecode **pcstack)
 {
     size_t nbytes = 0;
     jsbytecode** tmp_pcstack = NULL;
     if (pcstack) {
         nbytes = StackDepth(script) * sizeof *pcstack;
-        tmp_pcstack = (jsbytecode **) cx->malloc(nbytes);
+        tmp_pcstack = (jsbytecode **) cx->malloc_(nbytes);
         if (!tmp_pcstack)
             return -1;
         memcpy(tmp_pcstack, pcstack, nbytes);
     }
 
     ptrdiff_t oplen;
     for (; pc < target; pc += oplen) {
         JSOp op = js_GetOpcode(cx, script, pc);
@@ -5440,23 +5440,23 @@ SimulateImacroCFG(JSContext *cx, JSScrip
     if (pc > target)
         goto failure;
 
     LOCAL_ASSERT(pc == target);
 
   success:
     if (tmp_pcstack) {
         memcpy(pcstack, tmp_pcstack, nbytes);
-        cx->free(tmp_pcstack);
+        cx->free_(tmp_pcstack);
     }
     return pcdepth;
 
   failure:
     if (tmp_pcstack)
-        cx->free(tmp_pcstack);
+        cx->free_(tmp_pcstack);
     return -1;
 }
 
 #undef LOCAL_ASSERT
 #define LOCAL_ASSERT(expr)      LOCAL_ASSERT_RV(expr, -1);
 
 static intN
 ReconstructImacroPCStack(JSContext *cx, JSScript *script,
@@ -5548,8 +5548,44 @@ ReconstructPCStack(JSContext *cx, JSScri
 
     }
     LOCAL_ASSERT(pc == target);
     return pcdepth;
 }
 
 #undef LOCAL_ASSERT
 #undef LOCAL_ASSERT_RV
+
+namespace js {
+
+bool
+CallResultEscapes(jsbytecode *pc)
+{
+    /*
+     * If we see any of these sequences, the result is unused:
+     * - call / pop
+     * - call / trace / pop
+     *
+     * If we see any of these sequences, the result is only tested for nullness:
+     * - call / ifeq
+     * - call / trace / ifeq
+     * - call / not / ifeq
+     * - call / trace / not / ifeq
+     */
+
+    if (*pc != JSOP_CALL)
+        return true;
+
+    pc += JSOP_CALL_LENGTH;
+
+    if (*pc == JSOP_TRACE)
+        pc += JSOP_TRACE_LENGTH;
+
+    if (*pc == JSOP_POP)
+        return false;
+
+    if (*pc == JSOP_NOT)
+        pc += JSOP_NOT_LENGTH;
+
+    return (*pc != JSOP_IFEQ);
+}
+
+} // namespace js
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -511,16 +511,19 @@ extern ptrdiff_t
 SprintCString(Sprinter *sp, const char *s);
 
 extern ptrdiff_t
 SprintString(Sprinter *sp, JSString *str);
 
 extern ptrdiff_t
 Sprint(Sprinter *sp, const char *format, ...);
 
+extern bool
+CallResultEscapes(jsbytecode *pc);
+
 }
 #endif
 
 #ifdef DEBUG
 #ifdef __cplusplus
 /*
  * Disassemblers, for debugging only.
  */
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -9745,23 +9745,23 @@ js_FoldConstants(JSContext *cx, JSParseN
                     return JS_FALSE;
                 /* XXX fold only if all operands convert to string */
                 if (pn2->pn_type != TOK_STRING)
                     return JS_TRUE;
                 length += pn2->pn_atom->length();
             }
 
             /* Allocate a new buffer and string descriptor for the result. */
-            jschar *chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar));
+            jschar *chars = (jschar *) cx->malloc_((length + 1) * sizeof(jschar));
             if (!chars)
                 return JS_FALSE;
             chars[length] = 0;
             JSString *str = js_NewString(cx, chars, length);
             if (!str) {
-                cx->free(chars);
+                cx->free_(chars);
                 return JS_FALSE;
             }
 
             /* Fill the buffer, advancing chars and recycling kids as we go. */
             for (pn2 = pn1; pn2; pn2 = RecycleTree(pn2, tc)) {
                 JSAtom *atom = pn2->pn_atom;
                 size_t length2 = atom->length();
                 js_strncpy(chars, atom->chars(), length2);
--- a/js/src/jsparse.h
+++ b/js/src/jsparse.h
@@ -1011,21 +1011,21 @@ struct JSFunctionBoxQueue {
     size_t count()  { return head - tail; }
     size_t length() { return lengthMask + 1; }
 
     JSFunctionBoxQueue()
       : vector(NULL), head(0), tail(0), lengthMask(0) { }
 
     bool init(uint32 count) {
         lengthMask = JS_BITMASK(JS_CeilingLog2(count));
-        vector = js_array_new<JSFunctionBox*>(length());
+        vector = js::OffTheBooks::array_new<JSFunctionBox*>(length());
         return !!vector;
     }
 
-    ~JSFunctionBoxQueue() { js_array_delete(vector); }
+    ~JSFunctionBoxQueue() { js::UnwantedForeground::array_delete(vector); }
 
     void push(JSFunctionBox *funbox) {
         if (!funbox->queued) {
             JS_ASSERT(count() < length());
             vector[head++ & lengthMask] = funbox;
             funbox->queued = true;
         }
     }
--- a/js/src/jsprf.cpp
+++ b/js/src/jsprf.cpp
@@ -47,16 +47,18 @@
 #include <stdlib.h>
 #include "jsprf.h"
 #include "jsstdint.h"
 #include "jslong.h"
 #include "jsutil.h"
 #include "jspubtd.h"
 #include "jsstr.h"
 
+using namespace js;
+
 /*
 ** Note: on some platforms va_list is defined as an array,
 ** and requires array notation.
 */
 #ifdef HAVE_VA_COPY
 #define VARARGS_ASSIGN(foo, bar)        VA_COPY(foo,bar)
 #elif defined(HAVE_VA_LIST_AS_ARRAY)
 #define VARARGS_ASSIGN(foo, bar)        foo[0] = bar[0]
@@ -407,17 +409,17 @@ static int cvt_ws(SprintfState *ss, cons
      * and malloc() is used to allocate the buffer buffer.
      */
     if (ws) {
         int slen = js_strlen(ws);
         char *s = js_DeflateString(NULL, ws, slen);
         if (!s)
             return -1; /* JSStuffFunc error indicator. */
         result = cvt_s(ss, s, width, prec, flags);
-        js_free(s);
+        UnwantedForeground::free_(s);
     } else {
         result = cvt_s(ss, NULL, width, prec, flags);
     }
     return result;
 }
 
 /*
 ** BuildArgArray stands for Numbered Argument list Sprintf
@@ -625,17 +627,17 @@ static struct NumArgState* BuildArgArray
 
     /*
     ** third pass
     ** fill the nas[cn].ap
     */
 
     if( *rv < 0 ){
         if( nas != nasArray )
-            js_free( nas );
+            UnwantedForeground::free_( nas );
         return NULL;
     }
 
     cn = 0;
     while( cn < number ){
         if( nas[cn].type == TYPE_UNKNOWN ){
             cn++;
             continue;
@@ -662,17 +664,17 @@ static struct NumArgState* BuildArgArray
         case TYPE_WSTRING:      (void)va_arg( ap, jschar* );            break;
 
         case TYPE_INTSTR:       (void)va_arg( ap, JSIntn* );            break;
 
         case TYPE_DOUBLE:       (void)va_arg( ap, double );             break;
 
         default:
             if( nas != nasArray )
-                js_free( nas );
+                UnwantedForeground::free_( nas );
             *rv = -1;
             return NULL;
         }
 
         cn++;
     }
 
 
@@ -751,17 +753,17 @@ static int dosprintf(SprintfState *ss, c
             i = 0;
             while( c && c != '$' ){         /* should imporve error check later */
                 i = ( i * 10 ) + ( c - '0' );
                 c = *fmt++;
             }
 
             if( nas[i-1].type == TYPE_UNKNOWN ){
                 if( nas && ( nas != nasArray ) )
-                    js_free( nas );
+                    UnwantedForeground::free_( nas );
                 return -1;
             }
 
             ap = nas[i-1].ap;
             dolPt = fmt;
             c = *fmt++;
         }
 
@@ -1032,17 +1034,17 @@ static int dosprintf(SprintfState *ss, c
             }
         }
     }
 
     /* Stuff trailing NUL */
     rv = (*ss->stuff)(ss, "\0", 1);
 
     if( nas && ( nas != nasArray ) ){
-        js_free( nas );
+        UnwantedForeground::free_( nas );
     }
 
     return rv;
 }
 
 /************************************************************************/
 
 static int FuncStuff(SprintfState *ss, const char *sp, JSUint32 len)
@@ -1093,19 +1095,19 @@ static int GrowStuff(SprintfState *ss, c
     char *newbase;
     JSUint32 newlen;
 
     off = ss->cur - ss->base;
     if (off + len >= ss->maxlen) {
         /* Grow the buffer */
         newlen = ss->maxlen + ((len > 32) ? len : 32);
         if (ss->base) {
-            newbase = (char*) js_realloc(ss->base, newlen);
+            newbase = (char*) OffTheBooks::realloc_(ss->base, newlen);
         } else {
-            newbase = (char*) js_malloc(newlen);
+            newbase = (char*) OffTheBooks::malloc_(newlen);
         }
         if (!newbase) {
             /* Ran out of memory */
             return -1;
         }
         ss->base = newbase;
         ss->maxlen = newlen;
         ss->cur = ss->base + off;
@@ -1134,32 +1136,32 @@ JS_PUBLIC_API(char *) JS_smprintf(const 
     return rv;
 }
 
 /*
 ** Free memory allocated, for the caller, by JS_smprintf
 */
 JS_PUBLIC_API(void) JS_smprintf_free(char *mem)
 {
-        js_free(mem);
+        Foreground::free_(mem);
 }
 
 JS_PUBLIC_API(char *) JS_vsmprintf(const char *fmt, va_list ap)
 {
     SprintfState ss;
     int rv;
 
     ss.stuff = GrowStuff;
     ss.base = 0;
     ss.cur = 0;
     ss.maxlen = 0;
     rv = dosprintf(&ss, fmt, ap);
     if (rv < 0) {
         if (ss.base) {
-            js_free(ss.base);
+            Foreground::free_(ss.base);
         }
         return 0;
     }
     return ss.base;
 }
 
 /*
 ** Stuff routine that discards overflow data
@@ -1248,15 +1250,15 @@ JS_PUBLIC_API(char *) JS_vsprintf_append
     } else {
         ss.base = 0;
         ss.cur = 0;
         ss.maxlen = 0;
     }
     rv = dosprintf(&ss, fmt, ap);
     if (rv < 0) {
         if (ss.base) {
-            js_free(ss.base);
+            Foreground::free_(ss.base);
         }
         return 0;
     }
     return ss.base;
 }
 
--- a/js/src/jspropertycache.cpp
+++ b/js/src/jspropertycache.cpp
@@ -56,17 +56,16 @@ PropertyCache::fill(JSContext *cx, JSObj
     jsuword kshape, vshape;
     JSOp op;
     const JSCodeSpec *cs;
     PCVal vword;
     PropertyCacheEntry *entry;
 
     JS_ASSERT(this == &JS_PROPERTY_CACHE(cx));
     JS_ASSERT(!cx->runtime->gcRunning);
-    JS_ASSERT_IF(adding, !obj->isCall());
 
     if (js_IsPropertyCacheDisabled(cx)) {
         PCMETER(disfills++);
         return JS_NO_PROP_CACHE_FILL;
     }
 
     /*
      * Check for fill from js_SetPropertyHelper where the setter removed shape
--- a/js/src/jspropertytree.cpp
+++ b/js/src/jspropertytree.cpp
@@ -75,23 +75,19 @@ PropertyTree::newShape(JSContext *cx)
     JS_COMPARTMENT_METER(compartment->livePropTreeNodes++);
     JS_COMPARTMENT_METER(compartment->totalPropTreeNodes++);
     return shape;
 }
 
 static KidsHash *
 HashChildren(Shape *kid1, Shape *kid2)
 {
-    void *mem = js_malloc(sizeof(KidsHash));
-    if (!mem)
-        return NULL;
-
-    KidsHash *hash = new (mem) KidsHash();
-    if (!hash->init(2)) {
-        js_free(hash);
+    KidsHash *hash = OffTheBooks::new_<KidsHash>();
+    if (!hash || !hash->init(2)) {
+        Foreground::delete_(hash);
         return NULL;
     }
 
     JS_ALWAYS_TRUE(hash->putNew(kid1));
     JS_ALWAYS_TRUE(hash->putNew(kid2));
     return hash;
 }
 
@@ -339,17 +335,17 @@ Shape::finalize(JSContext *cx)
 
     if (inDictionary()) {
         JS_COMPARTMENT_METER(compartment()->liveDictModeNodes--);
     } else {
         if (parent && parent->isMarked())
             parent->removeChild(this);
 
         if (kids.isHash())
-            js_delete(kids.toHash());
+            cx->delete_(kids.toHash());
     }
 
     freeTable(cx);
     JS_COMPARTMENT_METER(compartment()->livePropTreeNodes--);
 }
 
 void
 js::PropertyTree::dumpShapeStats()
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -74,17 +74,17 @@ using namespace js::gc;
  * provide an appropriate finalizer. We store an instance of that js::Class in
  * a global reserved slot.
  */
 
 static void
 resc_finalize(JSContext *cx, JSObject *obj)
 {
     RegExpStatics *res = static_cast<RegExpStatics *>(obj->getPrivate());
-    cx->destroy<RegExpStatics>(res);
+    cx->delete_(res);
 }
 
 static void
 resc_trace(JSTracer *trc, JSObject *obj)
 {
     void *pdata = obj->getPrivate();
     JS_ASSERT(pdata);
     RegExpStatics *res = static_cast<RegExpStatics *>(pdata);
@@ -583,17 +583,17 @@ EscapeNakedForwardSlashes(JSContext *cx,
         return unescaped;
 
     size_t len = newChars.length();
     if (!newChars.append('\0'))
         return NULL;
     jschar *chars = newChars.extractRawBuffer();
     JSString *escaped = js_NewString(cx, chars, len);
     if (!escaped)
-        cx->free(chars);
+        cx->free_(chars);
     return escaped;
 }
 
 static bool
 SwapRegExpInternals(JSContext *cx, JSObject *obj, Value *rval, JSString *str, uint32 flags = 0)
 {
     flags |= cx->regExpStatics()->getFlags();
     AlreadyIncRefed<RegExp> re = RegExp::create(cx, str, flags);
--- a/js/src/jsregexpinlines.h
+++ b/js/src/jsregexpinlines.h
@@ -65,17 +65,17 @@ namespace js {
 extern Class regexp_statics_class;
 
 static inline JSObject *
 regexp_statics_construct(JSContext *cx, JSObject *parent)
 {
     JSObject *obj = NewObject<WithProto::Given>(cx, &regexp_statics_class, NULL, parent);
     if (!obj)
         return NULL;
-    RegExpStatics *res = cx->create<RegExpStatics>();
+    RegExpStatics *res = cx->new_<RegExpStatics>();
     if (!res)
         return NULL;
     obj->setPrivate(static_cast<void *>(res));
     return obj;
 }
 
 /*
  * The "meat" of the builtin regular expression objects: it contains the
@@ -112,26 +112,25 @@ class RegExp
 
     RegExp(JSLinearString *source, uint32 flags, JSCompartment *compartment)
       : compiled(), source(source), refCount(1), parenCount(0), flags(flags)
 #ifdef DEBUG
         , compartment(compartment)
 #endif
     { }
 
+    JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
+
     ~RegExp() {
 #if !ENABLE_YARR_JIT
         if (compiled)
             jsRegExpFree(compiled);
 #endif
     }
 
-    /* Constructor/destructor are hidden; called by cx->create/destroy. */
-    friend struct ::JSContext;
-
     bool compileHelper(JSContext *cx, JSLinearString &pattern);
     bool compile(JSContext *cx);
     static const uint32 allFlags = JSREG_FOLD | JSREG_GLOB | JSREG_MULTILINE | JSREG_STICKY;
     void handlePCREError(JSContext *cx, int error);
     void handleYarrError(JSContext *cx, int error);
     static inline bool initArena(JSContext *cx);
     static inline void checkMatchPairs(JSString *input, int *buf, size_t matchItemCount);
     static JSObject *createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemCount);
@@ -414,21 +413,21 @@ RegExp::executeInternal(JSContext *cx, R
 
 inline AlreadyIncRefed<RegExp>
 RegExp::create(JSContext *cx, JSString *source, uint32 flags)
 {
     typedef AlreadyIncRefed<RegExp> RetType;
     JSLinearString *flatSource = source->ensureLinear(cx);
     if (!flatSource)
         return RetType(NULL);
-    RegExp *self = cx->create<RegExp>(flatSource, flags, cx->compartment);
+    RegExp *self = cx->new_<RegExp>(flatSource, flags, cx->compartment);
     if (!self)
         return RetType(NULL);
     if (!self->compile(cx)) {
-        cx->destroy<RegExp>(self);
+        Foreground::delete_(self);
         return RetType(NULL);
     }
     return RetType(self);
 }
 
 inline JSObject *
 RegExp::createObject(JSContext *cx, RegExpStatics *res, const jschar *chars, size_t length,
                      uint32 flags)
@@ -571,17 +570,17 @@ RegExp::incref(JSContext *cx)
 
 inline void
 RegExp::decref(JSContext *cx)
 {
 #ifdef DEBUG
     assertSameCompartment(cx, compartment);
 #endif
     if (--refCount == 0)
-        cx->destroy<RegExp>(this);
+        cx->delete_(this);
 }
 
 inline RegExp *
 RegExp::extractFrom(JSObject *obj)
 {
     JS_ASSERT_IF(obj, obj->isRegExp());
     RegExp *re = static_cast<RegExp *>(obj->getPrivate());
 #ifdef DEBUG
--- a/js/src/jsscan.cpp
+++ b/js/src/jsscan.cpp
@@ -225,17 +225,17 @@ TokenStream::init(const jschar *base, si
     maybeStrSpecial[PARA_SEPARATOR & 0xff] = true;
     maybeStrSpecial[EOF & 0xff] = true;
     return true;
 }
 
 TokenStream::~TokenStream()
 {
     if (flags & TSF_OWNFILENAME)
-        cx->free((void *) filename);
+        cx->free_((void *) filename);
 }
 
 /* Use the fastest available getc. */
 #if defined(HAVE_GETC_UNLOCKED)
 # define fast_getc getc_unlocked
 #elif defined(HAVE__GETC_NOLOCK)
 # define fast_getc _getc_nolock
 #else
@@ -470,17 +470,17 @@ TokenStream::reportCompileErrorNumberVA(
      *
      * So we don't even try, leaving report.linebuf and friends zeroed.  This
      * means that any error involving a multi-line token (eg. an unterminated
      * multi-line string literal) won't have a context printed.
      */
     if (report.lineno == lineno) {
         size_t linelength = userbuf.findEOL() - linebase;
 
-        linechars = (jschar *)cx->malloc((linelength + 1) * sizeof(jschar));
+        linechars = (jschar *)cx->malloc_((linelength + 1) * sizeof(jschar));
         if (!linechars) {
             warning = false;
             goto out;
         }
         memcpy(linechars, linebase, linelength * sizeof(jschar));
         linechars[linelength] = 0;
         linebytes = js_DeflateString(cx, linechars, linelength);
         if (!linebytes) {
@@ -522,31 +522,31 @@ TokenStream::reportCompileErrorNumberVA(
 
         /* Report the error */
         if (reportError && cx->errorReporter)
             cx->errorReporter(cx, message, &report);
     }
 
   out:
     if (linebytes)
-        cx->free(linebytes);
+        cx->free_(linebytes);
     if (linechars)
-        cx->free(linechars);
+        cx->free_(linechars);
     if (message)
-        cx->free(message);
+        cx->free_(message);
     if (report.ucmessage)
-        cx->free((void *)report.ucmessage);
+        cx->free_((void *)report.ucmessage);
 
     if (report.messageArgs) {
         if (!(flags & JSREPORT_UC)) {
             i = 0;
             while (report.messageArgs[i])
-                cx->free((void *)report.messageArgs[i++]);
+                cx->free_((void *)report.messageArgs[i++]);
         }
-        cx->free((void *)report.messageArgs);
+        cx->free_((void *)report.messageArgs);
     }
 
     return warning;
 }
 
 bool
 js::ReportStrictModeError(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSParseNode *pn,
                           uintN errorNumber, ...)
@@ -701,17 +701,17 @@ TokenStream::getXMLEntity()
   badncr:
     msg = JSMSG_BAD_XML_NCR;
   bad:
     /* No match: throw a TypeError per ECMA-357 10.3.2.1 step 8(a). */
     JS_ASSERT((tb.end() - bp) >= 1);
     bytes = js_DeflateString(cx, bp + 1, (tb.end() - bp) - 1);
     if (bytes) {
         ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, msg, bytes);
-        cx->free(bytes);
+        cx->free_(bytes);
     }
     return JS_FALSE;
 }
 
 #endif /* JS_HAS_XML_SUPPORT */
 
 /*
  * We have encountered a '\': check for a Unicode escape sequence after it.
@@ -1657,17 +1657,17 @@ TokenStream::getTokenInternal()
                                     continue;
                                 }
                             }
                         }
                         filenameBuf[i] = '\0';
                         if (c == EOF || c == '\n') {
                             if (i > 0) {
                                 if (flags & TSF_OWNFILENAME)
-                                    cx->free((void *) filename);
+                                    cx->free_((void *) filename);
                                 filename = JS_strdup(cx, filenameBuf);
                                 if (!filename)
                                     goto error;
                                 flags |= TSF_OWNFILENAME;
                             }
                             lineno = line;
                         }
                     }
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -152,20 +152,20 @@ PropertyTable::init(JSRuntime *rt, Shape
      * event, let's try to grow, overallocating to hold at least twice the
      * current population.
      */
     uint32 sizeLog2 = JS_CeilingLog2(2 * entryCount);
     if (sizeLog2 < MIN_SIZE_LOG2)
         sizeLog2 = MIN_SIZE_LOG2;
 
     /*
-     * Use rt->calloc for memory accounting and overpressure handling
+     * Use rt->calloc_ for memory accounting and overpressure handling
      * without OOM reporting. See PropertyTable::change.
      */
-    entries = (Shape **) rt->calloc(JS_BIT(sizeLog2) * sizeof(Shape *));
+    entries = (Shape **) rt->calloc_(JS_BIT(sizeLog2) * sizeof(Shape *));
     if (!entries) {
         METER(tableAllocFails);
         return false;
     }
 
     hashShift = JS_DHASH_BITS - sizeLog2;
     for (Shape::Range r = lastProp->all(); !r.empty(); r.popFront()) {
         const Shape &shape = r.front();
@@ -182,20 +182,20 @@ PropertyTable::init(JSRuntime *rt, Shape
     }
     return true;
 }
 
 bool
 Shape::hashify(JSRuntime *rt)
 {
     JS_ASSERT(!hasTable());
-    void* mem = rt->malloc(sizeof(PropertyTable));
-    if (!mem)
+    PropertyTable *table = rt->new_<PropertyTable>(entryCount());
+    if (!table)
         return false;
-    setTable(new(mem) PropertyTable(entryCount()));
+    setTable(table);
     return getTable()->init(rt, this);
 }
 
 #ifdef DEBUG
 # include "jsprf.h"
 # define LIVE_SCOPE_METER(cx,expr) JS_LOCK_RUNTIME_VOID(cx->runtime,expr)
 #else
 # define LIVE_SCOPE_METER(cx,expr) /* nothing */
@@ -318,27 +318,24 @@ PropertyTable::change(int log2Delta, JSC
 {
     int oldlog2, newlog2;
     uint32 oldsize, newsize, nbytes;
     Shape **newTable, **oldTable, **spp, **oldspp, *shape;
 
     JS_ASSERT(entries);
 
     /*
-     * Grow, shrink, or compress by changing this->entries. Here, we prefer
-     * cx->runtime->calloc to js_calloc, which on OOM waits for a background
-     * thread to finish sweeping and retry, if appropriate. Avoid cx->calloc
-     * so our caller can be in charge of whether to JS_ReportOutOfMemory.
+     * Grow, shrink, or compress by changing this->entries.
      */
     oldlog2 = JS_DHASH_BITS - hashShift;
     newlog2 = oldlog2 + log2Delta;
     oldsize = JS_BIT(oldlog2);
     newsize = JS_BIT(newlog2);
     nbytes = PROPERTY_TABLE_NBYTES(newsize);
-    newTable = (Shape **) cx->runtime->calloc(nbytes);
+    newTable = (Shape **) cx->calloc_(nbytes);
     if (!newTable) {
         METER(tableAllocFails);
         return false;
     }
 
     /* Now that we have newTable allocated, update members. */
     hashShift = JS_DHASH_BITS - newlog2;
     removedCount = 0;
@@ -353,22 +350,18 @@ PropertyTable::change(int log2Delta, JSC
             METER(changeSearches);
             spp = search(shape->id, true);
             JS_ASSERT(SHAPE_IS_FREE(*spp));
             *spp = shape;
         }
         oldsize--;
     }
 
-    /*
-     * Finally, free the old entries storage. Note that cx->runtime->free just
-     * calls js_free. Use js_free here to match PropertyTable::~PropertyTable,
-     * which cannot have a cx or rt parameter.
-     */
-    js_free(oldTable);
+    /* Finally, free the old entries storage. */
+    cx->free_(oldTable);
     return true;
 }
 
 bool
 PropertyTable::grow(JSContext *cx)
 {
     JS_ASSERT(needsToGrow());
 
--- a/js/src/jsscope.h
+++ b/js/src/jsscope.h
@@ -237,17 +237,17 @@ struct PropertyTable {
         entryCount(nentries),
         removedCount(0),
         freelist(SHAPE_INVALID_SLOT)
     {
         /* NB: entries is set by init, which must be called. */
     }
 
     ~PropertyTable() {
-        js_free(entries);
+        js::UnwantedForeground::free_(entries);
     }
 
     /* By definition, hashShift = JS_DHASH_BITS - log2(capacity). */
     uint32 capacity() const { return JS_BIT(JS_DHASH_BITS - hashShift); }
 
     /* Whether we need to grow.  We want to do this if the load factor is >= 0.75 */
     bool needsToGrow() const {
         uint32 size = capacity();
@@ -258,17 +258,17 @@ struct PropertyTable {
      * Try to grow the table.  On failure, reports out of memory on cx
      * and returns false.  This will make any extant pointers into the
      * table invalid.  Don't call this unless needsToGrow() is true.
      */
     bool grow(JSContext *cx);
 
     /*
      * NB: init and change are fallible but do not report OOM, so callers can
-     * cope or ignore. They do however use JSRuntime's calloc method in order
+     * cope or ignore. They do however use JSRuntime's calloc_ method in order
      * to update the malloc counter on success.
      */
     bool            init(JSRuntime *rt, js::Shape *lastProp);
     bool            change(int log2Delta, JSContext *cx);
     js::Shape       **search(jsid id, bool adding);
 };
 
 } /* namespace js */
--- a/js/src/jsscopeinlines.h
+++ b/js/src/jsscopeinlines.h
@@ -52,41 +52,41 @@
 #include "jsgcinlines.h"
 #include "jscntxtinlines.h"
 #include "jsobjinlines.h"
 
 inline void
 js::Shape::freeTable(JSContext *cx)
 {
     if (hasTable()) {
-        cx->destroy(getTable());
+        cx->delete_(getTable());
         setTable(NULL);
     }
 }
 
 inline js::EmptyShape *
 JSObject::getEmptyShape(JSContext *cx, js::Class *aclasp,
                         /* gc::FinalizeKind */ unsigned kind)
 {
     JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
     int i = kind - js::gc::FINALIZE_OBJECT0;
 
     if (!emptyShapes) {
         emptyShapes = (js::EmptyShape**)
-            cx->calloc(sizeof(js::EmptyShape*) * js::gc::JS_FINALIZE_OBJECT_LIMIT);
+            cx->calloc_(sizeof(js::EmptyShape*) * js::gc::JS_FINALIZE_OBJECT_LIMIT);
         if (!emptyShapes)
             return NULL;
 
         /*
          * Always fill in emptyShapes[0], so canProvideEmptyShape works.
          * Other empty shapes are filled in lazily.
          */
         emptyShapes[0] = js::EmptyShape::create(cx, aclasp);
         if (!emptyShapes[0]) {
-            cx->free(emptyShapes);
+            cx->free_(emptyShapes);
             emptyShapes = NULL;
             return NULL;
         }
     }
 
     JS_ASSERT(aclasp == emptyShapes[0]->getClass());
 
     if (!emptyShapes[i]) {
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -584,32 +584,32 @@ js_XDRScript(JSXDRState *xdr, JSScript *
         if (!code)
             goto error;
     }
 
     xdr->script = script;
     ok = JS_XDRBytes(xdr, (char *) code, length * sizeof(jsbytecode));
 
     if (code != script->code)
-        cx->free(code);
+        cx->free_(code);
 
     if (!ok)
         goto error;
 
     if (!JS_XDRBytes(xdr, (char *)notes, nsrcnotes * sizeof(jssrcnote)) ||
         !JS_XDRUint32(xdr, &lineno) ||
         !JS_XDRUint32(xdr, &nslots)) {
         goto error;
     }
 
     if (xdr->mode == JSXDR_DECODE && state->filename) {
         if (!state->filenameSaved) {
             const char *filename = state->filename;
             filename = js_SaveScriptFilename(xdr->cx, filename);
-            xdr->cx->free((void *) state->filename);
+            xdr->cx->free_((void *) state->filename);
             state->filename = filename;
             state->filenameSaved = true;
             if (!filename)
                 goto error;
         }
         script->filename = state->filename;
     }
 
@@ -798,40 +798,40 @@ typedef struct ScriptFilenameEntry {
     uint32              flags;          /* user-defined filename prefix flags */
     JSPackedBool        mark;           /* GC mark flag */
     char                filename[3];    /* two or more bytes, NUL-terminated */
 } ScriptFilenameEntry;
 
 static void *
 js_alloc_table_space(void *priv, size_t size)
 {
-    return js_malloc(size);
+    return OffTheBooks::malloc_(size);
 }
 
 static void
 js_free_table_space(void *priv, void *item, size_t size)
 {
-    js_free(item);
+    UnwantedForeground::free_(item);
 }
 
 static JSHashEntry *
 js_alloc_sftbl_entry(void *priv, const void *key)
 {
     size_t nbytes = offsetof(ScriptFilenameEntry, filename) +
                     strlen((const char *) key) + 1;
 
-    return (JSHashEntry *) js_malloc(JS_MAX(nbytes, sizeof(JSHashEntry)));
+    return (JSHashEntry *) OffTheBooks::malloc_(JS_MAX(nbytes, sizeof(JSHashEntry)));
 }
 
 static void
 js_free_sftbl_entry(void *priv, JSHashEntry *he, uintN flag)
 {
     if (flag != HT_FREE_ENTRY)
         return;
-    js_free(he);
+    UnwantedForeground::free_(he);
 }
 
 static JSHashAllocOps sftbl_alloc_ops = {
     js_alloc_table_space,   js_free_table_space,
     js_alloc_sftbl_entry,   js_free_sftbl_entry
 };
 
 static void
@@ -882,17 +882,17 @@ js_FreeRuntimeScriptState(JSRuntime *rt)
 {
     if (!rt->scriptFilenameTable)
         return;
 
     while (!JS_CLIST_IS_EMPTY(&rt->scriptFilenamePrefixes)) {
         ScriptFilenamePrefix *sfp = (ScriptFilenamePrefix *)
                                     rt->scriptFilenamePrefixes.next;
         JS_REMOVE_LINK(&sfp->links);
-        js_free(sfp);
+        UnwantedForeground::free_(sfp);
     }
     FinishRuntimeScriptState(rt);
 }
 
 #ifdef DEBUG_brendan
 #define DEBUG_SFTBL
 #endif
 #ifdef DEBUG_SFTBL
@@ -945,17 +945,17 @@ SaveScriptFilename(JSRuntime *rt, const 
                 sfp = NULL;
                 break;
             }
             sfp = NULL;
         }
 
         if (!sfp) {
             /* No such prefix: add one now. */
-            sfp = (ScriptFilenamePrefix *) js_malloc(sizeof(ScriptFilenamePrefix));
+            sfp = (ScriptFilenamePrefix *) rt->malloc_(sizeof(ScriptFilenamePrefix));
             if (!sfp)
                 return NULL;
             JS_INSERT_AFTER(&sfp->links, link);
             sfp->name = sfe->filename;
             sfp->length = length;
             sfp->flags = 0;
         }
 
@@ -1224,17 +1224,17 @@ JSScript::NewScript(JSContext *cx, uint3
          */
         constPadding = (8 - (size % 8)) % 8;
         size += constPadding + nconsts * sizeof(Value);
     }
 
     size += length * sizeof(jsbytecode) +
             nsrcnotes * sizeof(jssrcnote);
 
-    script = (JSScript *) cx->malloc(size);
+    script = (JSScript *) cx->malloc_(size);
     if (!script)
         return NULL;
 
     PodZero(script);
     script->length = length;
     script->version = version;
     new (&script->bindings) Bindings(cx, emptyCallShape);
 
@@ -1459,17 +1459,17 @@ JSScript::NewScriptFromCG(JSContext *cx,
     if (cg->flags & TCF_HAS_SINGLETONS)
         script->hasSingletons = true;
 
     if (cg->upvarList.count != 0) {
         JS_ASSERT(cg->upvarList.count <= cg->upvarMap.length);
         memcpy(script->upvars()->vector, cg->upvarMap.vector,
                cg->upvarList.count * sizeof(uint32));
         cg->upvarList.clear();
-        cx->free(cg->upvarMap.vector);
+        cx->free_(cg->upvarMap.vector);
         cg->upvarMap.vector = NULL;
     }
 
     if (cg->globalUses.length()) {
         memcpy(script->globals()->vector, &cg->globalUses[0],
                cg->globalUses.length() * sizeof(GlobalSlotArray::Entry));
     }
 
@@ -1621,17 +1621,17 @@ DestroyScript(JSContext *cx, JSScript *s
     PurgeScriptFragments(&script->compartment->traceMonitor, script);
 #endif
 
 #if defined(JS_METHODJIT)
     mjit::ReleaseScriptCode(cx, script);
 #endif
     JS_REMOVE_LINK(&script->links);
 
-    cx->free(script);
+    cx->free_(script);
 }
 
 void
 js_DestroyScript(JSContext *cx, JSScript *script)
 {
     JS_ASSERT(!cx->runtime->gcRunning);
     js_CallDestroyScriptHook(cx, script);
     DestroyScript(cx, script);
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -211,18 +211,18 @@ RopeCapacityFor(size_t length)
 
 static JS_ALWAYS_INLINE jschar *
 AllocChars(JSContext *maybecx, size_t wholeCapacity)
 {
     /* +1 for the null char at the end. */
     JS_STATIC_ASSERT(JSString::MAX_LENGTH * sizeof(jschar) < UINT32_MAX);
     size_t bytes = (wholeCapacity + 1) * sizeof(jschar);
     if (maybecx)
-        return (jschar *)maybecx->malloc(bytes);
-    return (jschar *)js_malloc(bytes);
+        return (jschar *)maybecx->malloc_(bytes);
+    return (jschar *)OffTheBooks::malloc_(bytes);
 }
 
 JSFlatString *
 JSRope::flatten(JSContext *maybecx)
 {
     /*
      * Perform a depth-first dag traversal, splatting each node's characters
      * into a contiguous buffer. Visit each rope node three times:
@@ -378,17 +378,17 @@ js_ConcatStrings(JSContext *cx, JSString
 
 JSFixedString *
 JSDependentString::undepend(JSContext *cx)
 {
     JS_ASSERT(isDependent());
 
     size_t n = length();
     size_t size = (n + 1) * sizeof(jschar);
-    jschar *s = (jschar *) cx->malloc(size);
+    jschar *s = (jschar *) cx->malloc_(size);
     if (!s)
         return NULL;
 
     cx->runtime->stringMemoryUsed += size;
 
     PodCopy(s, chars(), n);
     s[n] = 0;
 
@@ -565,17 +565,17 @@ js_str_escape(JSContext *cx, uintN argc,
         }
     }
 
     if (newlength >= ~(size_t)0 / sizeof(jschar)) {
         js_ReportAllocationOverflow(cx);
         return JS_FALSE;
     }
 
-    jschar *newchars = (jschar *) cx->malloc((newlength + 1) * sizeof(jschar));
+    jschar *newchars = (jschar *) cx->malloc_((newlength + 1) * sizeof(jschar));
     if (!newchars)
         return JS_FALSE;
     size_t i, ni;
     for (i = 0, ni = 0; i < length; i++) {
         jschar ch;
         if ((ch = chars[i]) < 128 && IS_OK(ch, mask)) {
             newchars[ni++] = ch;
         } else if (ch < 256) {
@@ -595,17 +595,17 @@ js_str_escape(JSContext *cx, uintN argc,
             newchars[ni++] = digits[ch & 0xF];
         }
     }
     JS_ASSERT(ni == newlength);
     newchars[newlength] = 0;
 
     JSString *retstr = js_NewString(cx, newchars, newlength);
     if (!retstr) {
-        cx->free(newchars);
+        cx->free_(newchars);
         return JS_FALSE;
     }
     rval->setString(retstr);
     return JS_TRUE;
 }
 #undef IS_OK
 
 static JSBool
@@ -621,17 +621,17 @@ str_unescape(JSContext *cx, uintN argc, 
     JSLinearString *str = ArgToRootedString(cx, argc, vp, 0);
     if (!str)
         return false;
 
     size_t length = str->length();
     const jschar *chars = str->chars();
 
     /* Don't bother allocating less space for the new string. */
-    jschar *newchars = (jschar *) cx->malloc((length + 1) * sizeof(jschar));
+    jschar *newchars = (jschar *) cx->malloc_((length + 1) * sizeof(jschar));
     if (!newchars)
         return false;
     size_t ni = 0, i = 0;
     while (i < length) {
         jschar ch = chars[i++];
         if (ch == '%') {
             if (i + 1 < length &&
                 JS7_ISHEX(chars[i]) && JS7_ISHEX(chars[i + 1]))
@@ -650,17 +650,17 @@ str_unescape(JSContext *cx, uintN argc, 
             }
         }
         newchars[ni++] = ch;
     }
     newchars[ni] = 0;
 
     JSString *retstr = js_NewString(cx, newchars, ni);
     if (!retstr) {
-        cx->free(newchars);
+        cx->free_(newchars);
         return JS_FALSE;
     }
     vp->setString(retstr);
     return JS_TRUE;
 }
 
 #if JS_HAS_UNEVAL
 static JSBool
@@ -859,32 +859,32 @@ str_toSource(JSContext *cx, uintN argc, 
 
     JS::Anchor<JSString *> anchor(str);
     size_t k = str->length();
     const jschar *s = str->getChars(cx);
     if (!s)
         return false;
 
     size_t n = j + k + 2;
-    jschar *t = (jschar *) cx->malloc((n + 1) * sizeof(jschar));
+    jschar *t = (jschar *) cx->malloc_((n + 1) * sizeof(jschar));
     if (!t)
         return false;
 
     size_t i;
     for (i = 0; i < j; i++)
         t[i] = buf[i];
     for (j = 0; j < k; i++, j++)
         t[i] = s[j];
     t[i++] = ')';
     t[i++] = ')';
     t[i] = 0;
 
     str = js_NewString(cx, t, n);
     if (!str) {
-        cx->free(t);
+        cx->free_(t);
         return false;
     }
     vp->setString(str);
     return true;
 }
 
 #endif /* JS_HAS_TOSOURCE */
 
@@ -973,25 +973,25 @@ str_substring(JSContext *cx, uintN argc,
 JSString* JS_FASTCALL
 js_toLowerCase(JSContext *cx, JSString *str)
 {
     size_t n = str->length();
     const jschar *s = str->getChars(cx);
     if (!s)
         return NULL;
 
-    jschar *news = (jschar *) cx->malloc((n + 1) * sizeof(jschar));
+    jschar *news = (jschar *) cx->malloc_((n + 1) * sizeof(jschar));
     if (!news)
         return NULL;
     for (size_t i = 0; i < n; i++)
         news[i] = JS_TOLOWER(s[i]);
     news[n] = 0;
     str = js_NewString(cx, news, n);
     if (!str) {
-        cx->free(news);
+        cx->free_(news);
         return NULL;
     }
     return str;
 }
 
 static JSBool
 str_toLowerCase(JSContext *cx, uintN argc, Value *vp)
 {
@@ -1024,25 +1024,25 @@ str_toLocaleLowerCase(JSContext *cx, uin
 
 JSString* JS_FASTCALL
 js_toUpperCase(JSContext *cx, JSString *str)
 {
     size_t n = str->length();
     const jschar *s = str->getChars(cx);
     if (!s)
         return NULL;
-    jschar *news = (jschar *) cx->malloc((n + 1) * sizeof(jschar));
+    jschar *news = (jschar *) cx->malloc_((n + 1) * sizeof(jschar));
     if (!news)
         return NULL;
     for (size_t i = 0; i < n; i++)
         news[i] = JS_TOUPPER(s[i]);
     news[n] = 0;
     str = js_NewString(cx, news, n);
     if (!str) {
-        cx->free(news);
+        cx->free_(news);
         return NULL;
     }
     return str;
 }
 
 static JSBool
 str_toUpperCase(JSContext *cx, uintN argc, Value *vp)
 {
@@ -3089,17 +3089,17 @@ tagify(JSContext *cx, const char *begin,
     size_t endlen = strlen(end);
     taglen += str->length() + 2 + endlen + 1;           /* 'str</end>' */
 
     if (taglen >= ~(size_t)0 / sizeof(jschar)) {
         js_ReportAllocationOverflow(cx);
         return false;
     }
 
-    jschar *tagbuf = (jschar *) cx->malloc((taglen + 1) * sizeof(jschar));
+    jschar *tagbuf = (jschar *) cx->malloc_((taglen + 1) * sizeof(jschar));
     if (!tagbuf)
         return false;
 
     size_t j = 0;
     tagbuf[j++] = '<';
     for (size_t i = 0; i < beglen; i++)
         tagbuf[j++] = (jschar)begin[i];
     if (param) {
@@ -3118,17 +3118,17 @@ tagify(JSContext *cx, const char *begin,
     for (size_t i = 0; i < endlen; i++)
         tagbuf[j++] = (jschar)end[i];
     tagbuf[j++] = '>';
     JS_ASSERT(j == taglen);
     tagbuf[j] = 0;
 
     JSString *retstr = js_NewString(cx, tagbuf, taglen);
     if (!retstr) {
-        js_free((char *)tagbuf);
+        Foreground::free_((char *)tagbuf);
         return false;
     }
     vp->setString(retstr);
     return true;
 }
 
 static JSBool
 tagify_value(JSContext *cx, uintN argc, Value *vp,
@@ -3495,31 +3495,31 @@ str_fromCharCode(JSContext *cx, uintN ar
         if (!ValueToUint16(cx, argv[0], &code))
             return JS_FALSE;
         if (JSAtom::hasUnitStatic(code)) {
             vp->setString(&JSAtom::unitStatic(code));
             return JS_TRUE;
         }
         argv[0].setInt32(code);
     }
-    jschar *chars = (jschar *) cx->malloc((argc + 1) * sizeof(jschar));
+    jschar *chars = (jschar *) cx->malloc_((argc + 1) * sizeof(jschar));
     if (!chars)
         return JS_FALSE;
     for (uintN i = 0; i < argc; i++) {
         uint16_t code;
         if (!ValueToUint16(cx, argv[i], &code)) {
-            cx->free(chars);
+            cx->free_(chars);
             return JS_FALSE;
         }
         chars[i] = (jschar)code;
     }
     chars[argc] = 0;
     JSString *str = js_NewString(cx, chars, argc);
     if (!str) {
-        cx->free(chars);
+        cx->free_(chars);
         return JS_FALSE;
     }
     vp->setString(str);
     return JS_TRUE;
 }
 
 #ifdef JS_TRACER
 static JSString* FASTCALL
@@ -3641,27 +3641,27 @@ StringBuffer::finishString()
     jschar *buf = cb.extractRawBuffer();
     if (!buf)
         return NULL;
 
     /* For medium/big buffers, avoid wasting more than 1/4 of the memory. */
     JS_ASSERT(capacity >= length);
     if (capacity > sMinWasteSize && capacity - length > (length >> 2)) {
         size_t bytes = sizeof(jschar) * (length + 1);
-        jschar *tmp = (jschar *)cx->realloc(buf, bytes);
+        jschar *tmp = (jschar *)cx->realloc_(buf, bytes);
         if (!tmp) {
-            cx->free(buf);
+            cx->free_(buf);
             return NULL;
         }
         buf = tmp;
     }
 
     JSFixedString *str = js_NewString(cx, buf, length);
     if (!str)
-        cx->free(buf);
+        cx->free_(buf);
     return str;
 }
 
 JSAtom *
 StringBuffer::finishAtom()
 {
     JSContext *cx = context();
 
@@ -3717,57 +3717,57 @@ void printJSStringStats(JSRuntime *rt)
 #endif
 
 JSFixedString *
 js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n)
 {
     if (JSShortString::lengthFits(n))
         return NewShortString(cx, s, n);
 
-    jschar *news = (jschar *) cx->malloc((n + 1) * sizeof(jschar));
+    jschar *news = (jschar *) cx->malloc_((n + 1) * sizeof(jschar));
     if (!news)
         return NULL;
     js_strncpy(news, s, n);
     news[n] = 0;
     JSFixedString *str = js_NewString(cx, news, n);
     if (!str)
-        cx->free(news);
+        cx->free_(news);
     return str;
 }
 
 JSFixedString *
 js_NewStringCopyN(JSContext *cx, const char *s, size_t n)
 {
     if (JSShortString::lengthFits(n))
         return NewShortString(cx, s, n);
 
     jschar *chars = js_InflateString(cx, s, &n);
     if (!chars)
         return NULL;
     JSFixedString *str = js_NewString(cx, chars, n);
     if (!str)
-        cx->free(chars);
+        cx->free_(chars);
     return str;
 }
 
 JSFixedString *
 js_NewStringCopyZ(JSContext *cx, const jschar *s)
 {
     size_t n = js_strlen(s);
     if (JSShortString::lengthFits(n))
         return NewShortString(cx, s, n);
 
     size_t m = (n + 1) * sizeof(jschar);
-    jschar *news = (jschar *) cx->malloc(m);
+    jschar *news = (jschar *) cx->malloc_(m);
     if (!news)
         return NULL;
     memcpy(news, s, m);
     JSFixedString *str = js_NewString(cx, news, n);
     if (!str)
-        cx->free(news);
+        cx->free_(news);
     return str;
 }
 
 JSFixedString *
 js_NewStringCopyZ(JSContext *cx, const char *s)
 {
     return js_NewStringCopyN(cx, s, strlen(s));
 }
@@ -4029,28 +4029,28 @@ js_InflateString(JSContext *cx, const ch
     JSBool ok;
 #endif
 
     nbytes = *lengthp;
     if (js_CStringsAreUTF8 || useCESU8) {
         if (!js_InflateUTF8StringToBuffer(cx, bytes, nbytes, NULL, &nchars,
                                           useCESU8))
             goto bad;
-        chars = (jschar *) cx->malloc((nchars + 1) * sizeof (jschar));
+        chars = (jschar *) cx->malloc_((nchars + 1) * sizeof (jschar));
         if (!chars)
             goto bad;
 #ifdef DEBUG
         ok =
 #endif
             js_InflateUTF8StringToBuffer(cx, bytes, nbytes, chars, &nchars,
                                          useCESU8);
         JS_ASSERT(ok);
     } else {
         nchars = nbytes;
-        chars = (jschar *) cx->malloc((nchars + 1) * sizeof(jschar));
+        chars = (jschar *) cx->malloc_((nchars + 1) * sizeof(jschar));
         if (!chars)
             goto bad;
         for (i = 0; i < nchars; i++)
             chars[i] = (unsigned char) bytes[i];
     }
     *lengthp = nchars;
     chars[nchars] = 0;
     return chars;
@@ -4075,27 +4075,27 @@ js_DeflateString(JSContext *cx, const js
 #ifdef DEBUG
     JSBool ok;
 #endif
 
     if (js_CStringsAreUTF8) {
         nbytes = js_GetDeflatedStringLength(cx, chars, nchars);
         if (nbytes == (size_t) -1)
             return NULL;
-        bytes = (char *) (cx ? cx->malloc(nbytes + 1) : js_malloc(nbytes + 1));
+        bytes = (char *) (cx ? cx->malloc_(nbytes + 1) : OffTheBooks::malloc_(nbytes + 1));
         if (!bytes)
             return NULL;
 #ifdef DEBUG
         ok =
 #endif
             js_DeflateStringToBuffer(cx, chars, nchars, bytes, &nbytes);
         JS_ASSERT(ok);
     } else {
         nbytes = nchars;
-        bytes = (char *) (cx ? cx->malloc(nbytes + 1) : js_malloc(nbytes + 1));
+        bytes = (char *) (cx ? cx->malloc_(nbytes + 1) : OffTheBooks::malloc_(nbytes + 1));
         if (!bytes)
             return NULL;
         for (i = 0; i < nbytes; i++)
             bytes[i] = (char) chars[i];
     }
     bytes[nbytes] = 0;
     return bytes;
 }
--- a/js/src/jsstrinlines.h
+++ b/js/src/jsstrinlines.h
@@ -464,17 +464,17 @@ JSString::finalize(JSContext *cx)
     JS_ASSERT(!isStaticAtom() && !isShort());
 
     JS_RUNTIME_UNMETER(cx->runtime, liveStrings);
 
     if (isDependent()) {
         JS_RUNTIME_UNMETER(cx->runtime, liveDependentStrings);
     } else if (isFlat()) {
         cx->runtime->stringMemoryUsed -= length() * 2;
-        cx->free(const_cast<jschar *>(asFlat().chars()));
+        cx->free_(const_cast<jschar *>(asFlat().chars()));
     } else {
         JS_ASSERT(isRope());
     }
 }
 
 inline void
 JSShortString::finalize(JSContext *cx)
 {
--- a/js/src/jstl.h
+++ b/js/src/jstl.h
@@ -41,23 +41,16 @@
 #define jstl_h_
 
 #include "jsbit.h"
 #include "jsstaticcheck.h"
 
 #include <new>
 #include <string.h>
 
-/* Gross special case for Gecko, which defines malloc/calloc/free. */
-#ifdef mozilla_mozalloc_macro_wrappers_h
-#  define JSSTL_UNDEFD_MOZALLOC_WRAPPERS
-/* The "anti-header" */
-#  include "mozilla/mozalloc_undef_macro_wrappers.h"
-#endif
-
 namespace js {
 
 /* JavaScript Template Library. */
 namespace tl {
 
 /* Compute min/max/clamp. */
 template <size_t i, size_t j> struct Min {
     static const size_t result = i < j ? i : j;
@@ -237,32 +230,32 @@ JS_ALWAYS_INLINE size_t
 PointerRangeSize(T *begin, T *end)
 {
     return (size_t(end) - size_t(begin)) / sizeof(T);
 }
 
 /*
  * Allocation policies.  These model the concept:
  *  - public copy constructor, assignment, destructor
- *  - void *malloc(size_t)
+ *  - void *malloc_(size_t)
  *      Responsible for OOM reporting on NULL return value.
- *  - void *realloc(size_t)
+ *  - void *realloc_(size_t)
  *      Responsible for OOM reporting on NULL return value.
- *  - void free(void *)
+ *  - void free_(void *)
  *  - reportAllocOverflow()
  *      Called on overflow before the container returns NULL.
  */
 
 /* Policy for using system memory functions and doing no error reporting. */
 class SystemAllocPolicy
 {
   public:
-    void *malloc(size_t bytes) { return js_malloc(bytes); }
-    void *realloc(void *p, size_t bytes) { return js_realloc(p, bytes); }
-    void free(void *p) { js_free(p); }
+    void *malloc_(size_t bytes) { return js::OffTheBooks::malloc_(bytes); }
+    void *realloc_(void *p, size_t bytes) { return js::OffTheBooks::realloc_(p, bytes); }
+    void free_(void *p) { js::UnwantedForeground::free_(p); }
     void reportAllocOverflow() const {}
 };
 
 /*
  * This utility pales in comparison to Boost's aligned_storage. The utility
  * simply assumes that JSUint64 is enough alignment for anyone. This may need
  * to be extended one day...
  *
@@ -494,13 +487,9 @@ template <class T>
 static T&
 InitConst(const T &t)
 {
     return const_cast<T &>(t);
 }
 
 } /* namespace js */
 
-#ifdef JSSTL_UNDEFD_MOZALLOC_WRAPPERS
-#  include "mozilla/mozalloc_macro_wrappers.h"
-#endif
-
 #endif /* jstl_h_ */
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -143,23 +143,23 @@ using namespace js::tjit;
  *
  * FIXME: bug 624590 is open to fix these problems.
  */
 #define OUT_OF_MEMORY_ABORT(msg)    JS_Assert(msg, __FILE__, __LINE__);
 
 /* Implement embedder-specific nanojit members. */
 
 /* 
- * Nanojit requires infallible allocations most of the time.  We satisfy this
- * by reserving some space in each allocator which is used as a fallback if
- * js_calloc() fails.  Ideallly this reserve space should be big enough to
- * allow for all infallible requests made to the allocator until the next OOM
- * check occurs, but it turns out that's impossible to guarantee (though it
- * should be unlikely).  So we abort if the reserve runs out;  this is better
- * than allowing memory errors to occur.
+ * Nanojit requires infallible allocations most of the time. We satisfy this by
+ * reserving some space in each allocator which is used as a fallback if
+ * rt->calloc_() fails. Ideally this reserve space should be big enough to allow
+ * for all infallible requests made to the allocator until the next OOM check
+ * occurs, but it turns out that's impossible to guarantee (though it should be
+ * unlikely). So we abort if the reserve runs out;  this is better than
+ * allowing memory errors to occur.
  *
  * The space calculations are as follows... between OOM checks, each
  * VMAllocator can do (ie. has been seen to do) the following maximum
  * allocations on 64-bits:
  *
  * - dataAlloc: 31 minimum-sized chunks (MIN_CHUNK_SZB) in assm->compile()
  *   (though arbitrarily more could occur due to LabelStateMap additions done
  *   when handling labels):  62,248 bytes.  This one is the most likely to
@@ -185,17 +185,17 @@ nanojit::Allocator::allocChunk(size_t nb
 {
     VMAllocator *vma = (VMAllocator*)this;
     /*
      * Nb: it's conceivable that request 1 might fail (in which case
      * mOutOfMemory will be set) and then request 2 succeeds.  The subsequent
      * OOM check will still fail, which is what we want, and the success of
      * request 2 makes it less likely that the reserve space will overflow.
      */
-    void *p = js_calloc(nbytes);
+    void *p = vma->mRt->calloc_(nbytes);
     if (p) {
         vma->mSize += nbytes;
     } else {
         vma->mOutOfMemory = true;
         if (!fallible) {
             p = (void *)vma->mReserveCurr;
             vma->mReserveCurr += nbytes;
             if (vma->mReserveCurr > vma->mReserveLimit)
@@ -206,17 +206,17 @@ nanojit::Allocator::allocChunk(size_t nb
     }
     return p;
 }
 
 void
 nanojit::Allocator::freeChunk(void *p) {
     VMAllocator *vma = (VMAllocator*)this;
     if (p < vma->mReserve || uintptr_t(p) >= vma->mReserveLimit)
-        js_free(p);
+        UnwantedForeground::free_(p);
 }
 
 void
 nanojit::Allocator::postReset() {
     VMAllocator *vma = (VMAllocator*)this;
     vma->mOutOfMemory = false;
     vma->mSize = 0;
     vma->mReserveCurr = uintptr_t(vma->mReserve);
@@ -1079,17 +1079,18 @@ void
 TraceRecorder::tprint(const char *format, LIns *ins1, LIns *ins2, LIns *ins3, LIns *ins4,
                       LIns *ins5, LIns *ins6)
 {
     LIns* insa[] = { ins1, ins2, ins3, ins4, ins5, ins6 };
     tprint(format, 6, insa);
 }
 #endif
 
-Tracker::Tracker()
+Tracker::Tracker(JSContext *cx)
+    : cx(cx)
 {
     pagelist = NULL;
 }
 
 Tracker::~Tracker()
 {
     clear();
 }
@@ -1118,30 +1119,30 @@ Tracker::findTrackerPage(const void* v) 
     }
     return NULL;
 }
 
 struct Tracker::TrackerPage*
 Tracker::addTrackerPage(const void* v)
 {
     jsuword base = getTrackerPageBase(v);
-    struct TrackerPage* p = (struct TrackerPage*) js_calloc(sizeof(*p));
+    struct TrackerPage* p = (struct TrackerPage*) cx->calloc_(sizeof(*p));
     p->base = base;
     p->next = pagelist;
     pagelist = p;
     return p;
 }
 
 void
 Tracker::clear()
 {
     while (pagelist) {
         TrackerPage* p = pagelist;
         pagelist = pagelist->next;
-        js_free(p);
+        cx->free_(p);
     }
 }
 
 bool
 Tracker::has(const void *v) const
 {
     return get(v) != NULL;
 }
@@ -2239,18 +2240,18 @@ TraceRecorder::TraceRecorder(JSContext* 
     cx_ins(NULL),
     eos_ins(NULL),
     eor_ins(NULL),
     loopLabel(NULL),
     importTypeMap(&tempAlloc(), tm->oracle),
     lirbuf(new (tempAlloc()) LirBuffer(tempAlloc())),
     mark(*traceMonitor->traceAlloc),
     numSideExitsBefore(tree->sideExits.length()),
-    tracker(),
-    nativeFrameTracker(),
+    tracker(cx),
+    nativeFrameTracker(cx),
     global_slots(NULL),
     callDepth(anchor ? anchor->calldepth : 0),
     atoms(FrameAtomBase(cx, cx->fp())),
     consts(JSScript::isValidOffset(cx->fp()->script()->constOffset)
            ? cx->fp()->script()->consts()->vector
            : NULL),
     strictModeCode_ins(NULL),
     cfgMerges(&tempAlloc()),
@@ -2475,19 +2476,17 @@ TraceRecorder::finishSuccessfully()
     AUDIT(traceCompleted);
     mark.commit();
 
     /* Grab local copies of members needed after destruction of |this|. */
     JSContext* localcx = cx;
     TraceMonitor* localtm = traceMonitor;
 
     localtm->recorder = NULL;
-    /* We can't (easily) use js_delete() here because the destructor is private. */
-    this->~TraceRecorder();
-    js_free(this);
+    cx->delete_(this);
 
     /* Catch OOM that occurred during recording. */
     if (localtm->outOfMemory() || OverfullJITCache(localcx, localtm)) {
         ResetJIT(localcx, localtm, FR_OOM);
         return ARECORD_ABORTED;
     }
     return ARECORD_COMPLETED;
 }
@@ -2529,19 +2528,17 @@ TraceRecorder::finishAbort(const char* r
         fragment->root->sideExits.setLength(numSideExitsBefore);
     }
 
     /* Grab local copies of members needed after destruction of |this|. */
     JSContext* localcx = cx;
     TraceMonitor* localtm = traceMonitor;
 
     localtm->recorder = NULL;
-    /* We can't (easily) use js_delete() here because the destructor is private. */
-    this->~TraceRecorder();
-    js_free(this);
+    cx->delete_(this);
 
     /* Catch OOM that occurred during recording. */
     if (localtm->outOfMemory() || OverfullJITCache(localcx, localtm)) {
         ResetJIT(localcx, localtm, FR_OOM);
         return JIT_RESET;
     }
     return NORMAL_ABORT;
 }
@@ -4498,22 +4495,22 @@ TraceRecorder::compile()
         ++tree->branchCount;
     if (outOfMemory())
         return ARECORD_STOP;
 
     /* :TODO: windows support */
 #if defined DEBUG && !defined WIN32
     /* Associate a filename and line number with the fragment. */
     const char* filename = cx->fp()->script()->filename;
-    char* label = (char*)js_malloc((filename ? strlen(filename) : 7) + 16);
+    char* label = (char*) cx->malloc_((filename ? strlen(filename) : 7) + 16);
     if (label) {
         sprintf(label, "%s:%u", filename ? filename : "<stdin>",
                 js_FramePCToLineNumber(cx, cx->fp()));
         lirbuf->printer->addrNameMap->addAddrRange(fragment, sizeof(Fragment), 0, label);
-        js_free(label);
+        cx->free_(label);
     }
 #endif
 
     Assembler *assm = traceMonitor->assembler;
     JS_ASSERT(!assm->error());
     assm->compile(fragment, tempAlloc(), /*optimize*/true verbose_only(, lirbuf->printer));
 
     if (assm->error()) {
@@ -5566,23 +5563,19 @@ TraceRecorder::startRecorder(JSContext* 
                              unsigned stackSlots, unsigned ngslots,
                              JSValueType* typeMap, VMSideExit* expectedInnerExit,
                              JSScript* outerScript, jsbytecode* outerPC, uint32 outerArgc,
                              bool speculate)
 {
     JS_ASSERT(!tm->needFlush);
     JS_ASSERT_IF(cx->fp()->hasImacropc(), f->root != f);
 
-    /* We can't (easily) use js_new() here because the constructor is private. */
-    void *memory = js_malloc(sizeof(TraceRecorder));
-    tm->recorder = memory
-                 ? new(memory) TraceRecorder(cx, tm, anchor, f, stackSlots, ngslots, typeMap,
+    tm->recorder = cx->new_<TraceRecorder>(cx, tm, anchor, f, stackSlots, ngslots, typeMap,
                                              expectedInnerExit, outerScript, outerPC, outerArgc,
-                                             speculate)
-                 : NULL;
+                                             speculate);
 
     if (!tm->recorder || tm->outOfMemory() || OverfullJITCache(cx, tm)) {
         ResetJIT(cx, tm, FR_OOM);
         return false;
     }
 
     return true;
 }
@@ -7627,28 +7620,28 @@ SetMaxCodeCacheBytes(JSContext* cx, uint
     if (bytes > 1 G)
         bytes = 1 G;
     if (bytes < 128 K)
         bytes = 128 K;
     JS_THREAD_DATA(cx)->maxCodeCacheBytes = bytes;
 }
 
 bool
-InitJIT(TraceMonitor *tm)
+InitJIT(TraceMonitor *tm, JSRuntime* rt)
 {
 #if defined JS_JIT_SPEW
     tm->profAlloc = NULL;
     /* Set up debug logging. */
     if (!did_we_set_up_debug_logging) {
         InitJITLogController();
         did_we_set_up_debug_logging = true;
     }
     /* Set up fragprofiling, if required. */
     if (LogController.lcbits & LC_FragProfile) {
-        tm->profAlloc = js_new<VMAllocator>((char*)NULL, 0); /* no reserve needed in debug builds */
+        tm->profAlloc = rt->new_<VMAllocator>(rt, (char*)NULL, 0); /* no reserve needed in debug builds */
         if (!tm->profAlloc)
             goto error;
         tm->profTab = new (*tm->profAlloc) FragStatsMap(*tm->profAlloc);
     }
     tm->lastFragID = 0;
 #else
     PodZero(&LogController);
 #endif
@@ -7673,44 +7666,46 @@ InitJIT(TraceMonitor *tm)
 
         // Sanity-check the configuration detection.
         //  * We don't understand architectures prior to ARMv4.
         JS_ASSERT(arm_arch >= 4);
 #endif
         did_we_check_processor_features = true;
     }
 
-    #define CHECK_ALLOC(lhs, rhs) \
-        do { lhs = (rhs); if (!lhs) goto error; } while (0)
-
-    CHECK_ALLOC(tm->oracle, js_new<Oracle>());
+    #define CHECK_NEW(lhs, type, args) \
+        do { lhs = rt->new_<type> args; if (!lhs) goto error; } while (0)
+    #define CHECK_MALLOC(lhs, conversion, size) \
+        do { lhs = (conversion)(rt->malloc_(size)); if (!lhs) goto error; } while (0)
+
+    CHECK_NEW(tm->oracle, Oracle, ());
 
     tm->profile = NULL;
     
-    CHECK_ALLOC(tm->recordAttempts, js_new<RecordAttemptMap>());
+    CHECK_NEW(tm->recordAttempts, RecordAttemptMap, ());
     if (!tm->recordAttempts->init(PC_HASH_COUNT))
         goto error;
 
-    CHECK_ALLOC(tm->loopProfiles, js_new<LoopProfileMap>());
+    CHECK_NEW(tm->loopProfiles, LoopProfileMap, ());
     if (!tm->loopProfiles->init(PC_HASH_COUNT))
         goto error;
 
     tm->flushEpoch = 0;
     
     char *dataReserve, *traceReserve, *tempReserve;
-    CHECK_ALLOC(dataReserve, (char *)js_malloc(DataReserveSize));
-    CHECK_ALLOC(traceReserve, (char *)js_malloc(TraceReserveSize));
-    CHECK_ALLOC(tempReserve, (char *)js_malloc(TempReserveSize));
-    CHECK_ALLOC(tm->dataAlloc, js_new<VMAllocator>(dataReserve, DataReserveSize));
-    CHECK_ALLOC(tm->traceAlloc, js_new<VMAllocator>(traceReserve, TraceReserveSize));
-    CHECK_ALLOC(tm->tempAlloc, js_new<VMAllocator>(tempReserve, TempReserveSize));
-    CHECK_ALLOC(tm->codeAlloc, js_new<CodeAlloc>());
-    CHECK_ALLOC(tm->frameCache, js_new<FrameInfoCache>(tm->dataAlloc));
-    CHECK_ALLOC(tm->storage, js_new<TraceNativeStorage>());
-    CHECK_ALLOC(tm->cachedTempTypeMap, js_new<TypeMap>((Allocator*)NULL, tm->oracle));
+    CHECK_MALLOC(dataReserve, char*, DataReserveSize);
+    CHECK_MALLOC(traceReserve, char*, TraceReserveSize);
+    CHECK_MALLOC(tempReserve, char*, TempReserveSize);
+    CHECK_NEW(tm->dataAlloc, VMAllocator, (rt, dataReserve, DataReserveSize));
+    CHECK_NEW(tm->traceAlloc, VMAllocator, (rt, traceReserve, TraceReserveSize));
+    CHECK_NEW(tm->tempAlloc, VMAllocator, (rt, tempReserve, TempReserveSize));
+    CHECK_NEW(tm->codeAlloc, CodeAlloc, ());
+    CHECK_NEW(tm->frameCache, FrameInfoCache, (tm->dataAlloc));
+    CHECK_NEW(tm->storage, TraceNativeStorage, ());
+    CHECK_NEW(tm->cachedTempTypeMap, TypeMap, ((Allocator*)NULL, tm->oracle));
     tm->flush();
     verbose_only( tm->branches = NULL; )
 
 #if !defined XP_WIN
     debug_only(PodZero(&jitstats));
 #endif
 
 #ifdef JS_JIT_SPEW
@@ -7783,19 +7778,19 @@ FinishJIT(TraceMonitor *tm)
 #define JITSTAT(x) /* nothing */
 #include "jitstats.tbl"
 #undef JITSTAT
 #undef MONITOR_JITSTAT
         debug_only_print0(LC_TMStats, "\n");
     }
 #endif
 
-    js_delete(tm->recordAttempts);
-    js_delete(tm->loopProfiles);
-    js_delete(tm->oracle);
+    Foreground::delete_(tm->recordAttempts);
+    Foreground::delete_(tm->loopProfiles);
+    Foreground::delete_(tm->oracle);
 
 #ifdef DEBUG
     // Recover profiling data from expiring Fragments, and display
     // final results.
     if (LogController.lcbits & LC_FragProfile) {
 
         for (Seq<Fragment*>* f = tm->branches; f; f = f->tail)
             FragProfiling_FragFinalizer(f->head, tm);
@@ -7805,45 +7800,45 @@ FinishJIT(TraceMonitor *tm)
                 JS_ASSERT(f->root == f);
                 for (TreeFragment *p = f; p; p = p->peer)
                     FragProfiling_FragFinalizer(p, tm);
             }
         }
 
         if (tm->profTab)
             FragProfiling_showResults(tm);
-        js_delete(tm->profAlloc);
+        Foreground::delete_(tm->profAlloc);
 
     } else {
         NanoAssert(!tm->profTab);
         NanoAssert(!tm->profAlloc);
     }
 #endif
 
     PodArrayZero(tm->vmfragments);
 
-    js_delete(tm->frameCache);
+    Foreground::delete_(tm->frameCache);
     tm->frameCache = NULL;
 
-    js_delete(tm->codeAlloc);
+    Foreground::delete_(tm->codeAlloc);
     tm->codeAlloc = NULL;
 
-    js_delete(tm->dataAlloc);
+    Foreground::delete_(tm->dataAlloc);
     tm->dataAlloc = NULL;
 
-    js_delete(tm->traceAlloc);
+    Foreground::delete_(tm->traceAlloc);
     tm->traceAlloc = NULL;
 
-    js_delete(tm->tempAlloc);
+    Foreground::delete_(tm->tempAlloc);
     tm->tempAlloc = NULL;
 
-    js_delete(tm->storage);
+    Foreground::delete_(tm->storage);
     tm->storage = NULL;
 
-    js_delete(tm->cachedTempTypeMap);
+    Foreground::delete_(tm->cachedTempTypeMap);
     tm->cachedTempTypeMap = NULL;
 }
 
 JS_REQUIRES_STACK void
 PurgeScriptFragments(TraceMonitor* tm, JSScript* script)
 {
     debug_only_printf(LC_TMTracer,
                       "Purging fragments for JSScript %p.\n", (void*)script);
@@ -11435,57 +11430,34 @@ TraceRecorder::callNative(uintN argc, JS
                     CHECK_STATUS(getCharCodeAt(str, str_ins, idx_ins, &charCode_ins));
                     set(&vp[0], charCode_ins);
                     pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
                     return RECORD_CONTINUE;
                 }
             }
         } else if (vp[2].isString() && mode == JSOP_CALL) {
             if (native == js_regexp_exec) {
-                jsbytecode *pc = cx->regs->pc;
                 /*
-                 * If we see any of these sequences, the result is unused:
-                 * - call / pop
-                 * - call / trace / pop
-                 *
-                 * If we see any of these sequences, the result is only tested for nullness:
-                 * - call / ifeq
-                 * - call / trace / ifeq
-                 * - call / not / ifeq
-                 * - call / trace / not / ifeq
-                 *
-                 * In either case, we replace the call to RegExp.exec() on the
+                 * If the result of the call will be unused or only tested against
+                 * nullness, we replace the call to RegExp.exec() on the
                  * stack with a call to RegExp.test() because "r.exec(s) !=
                  * null" is equivalent to "r.test(s)".  This avoids building
                  * the result array, which can be expensive.  This requires
                  * that RegExp.prototype.test() hasn't been changed;  we check this.
                  */
-                if (pc[0] == JSOP_CALL) {
-                    if ((pc[JSOP_CALL_LENGTH] == JSOP_POP) ||
-                        (pc[JSOP_CALL_LENGTH] == JSOP_TRACE &&
-                         pc[JSOP_CALL_LENGTH + JSOP_TRACE_LENGTH] == JSOP_POP) ||
-                        (pc[JSOP_CALL_LENGTH] == JSOP_IFEQ) ||
-                        (pc[JSOP_CALL_LENGTH] == JSOP_TRACE &&
-                         pc[JSOP_CALL_LENGTH + JSOP_TRACE_LENGTH] == JSOP_IFEQ) ||
-                        (pc[JSOP_CALL_LENGTH] == JSOP_NOT &&
-                         pc[JSOP_CALL_LENGTH + JSOP_NOT_LENGTH] == JSOP_IFEQ) ||
-                        (pc[JSOP_CALL_LENGTH] == JSOP_TRACE &&
-                         pc[JSOP_CALL_LENGTH + JSOP_TRACE_LENGTH] == JSOP_NOT &&
-                         pc[JSOP_CALL_LENGTH + JSOP_TRACE_LENGTH + JSOP_NOT_LENGTH] == JSOP_IFEQ))
-                    {
-                        JSObject* proto;
-                        jsid id = ATOM_TO_JSID(cx->runtime->atomState.testAtom);
-                        /* Get RegExp.prototype.test() and check it hasn't been changed. */
-                        if (js_GetClassPrototype(cx, NULL, JSProto_RegExp, &proto)) {
-                            if (JSObject *tmp = HasNativeMethod(proto, id, js_regexp_test)) {
-                                vp[0] = ObjectValue(*tmp);
-                                funobj = tmp;
-                                fun = tmp->getFunctionPrivate();
-                                native = js_regexp_test;
-                            }
+                if (!CallResultEscapes(cx->regs->pc)) {
+                    JSObject* proto;
+                    jsid id = ATOM_TO_JSID(cx->runtime->atomState.testAtom);
+                    /* Get RegExp.prototype.test() and check it hasn't been changed. */
+                    if (js_GetClassPrototype(cx, NULL, JSProto_RegExp, &proto)) {
+                        if (JSObject *tmp = HasNativeMethod(proto, id, js_regexp_test)) {
+                            vp[0] = ObjectValue(*tmp);
+                            funobj = tmp;
+                            fun = tmp->getFunctionPrivate();
+                            native = js_regexp_test;
                         }
                     }
                 }
             }
         }
         break;
 
       case 2:
@@ -16658,17 +16630,17 @@ StartTraceVisNative(JSContext *cx, uintN
     JSBool ok;
 
     if (argc > 0 && JSVAL_IS_STRING(JS_ARGV(cx, vp)[0])) {
         JSString *str = JSVAL_TO_STRING(JS_ARGV(cx, vp)[0]);
         char *filename = js_DeflateString(cx, str->chars(), str->length());
         if (!filename)
             goto error;
         ok = StartTraceVis(filename);
-        cx->free(filename);
+        cx->free_(filename);
     } else {
         ok = StartTraceVis();
     }
 
     if (ok) {
         fprintf(stderr, "started TraceVis recording\n");
         JS_SET_RVAL(cx, vp, JSVAL_VOID);
         return true;
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -71,34 +71,34 @@ public:
         if (!_max)
             _max = 8;
         _max = JS_MAX(_max * 2, size);
         if (alloc) {
             T* tmp = new (*alloc) T[_max];
             memcpy(tmp, _data, _len * sizeof(T));
             _data = tmp;
         } else {
-            _data = (T*)js_realloc(_data, _max * sizeof(T));
+            _data = (T*) js::OffTheBooks::realloc_(_data, _max * sizeof(T));
         }
 #if defined(DEBUG)
         memset(&_data[_len], 0xcd, _max - _len);
 #endif
     }
 
     Queue(nanojit::Allocator* alloc)
         : alloc(alloc)
     {
         this->_max =
         this->_len = 0;
         this->_data = NULL;
     }
 
     ~Queue() {
         if (!alloc)
-            js_free(_data);
+            js::UnwantedForeground::free_(_data);
     }
 
     bool contains(T a) {
         for (unsigned n = 0; n < _len; ++n) {
             if (_data[n] == a)
                 return true;
         }
         return false;
@@ -194,22 +194,25 @@ class Tracker {
 
     struct TrackerPage {
         struct TrackerPage* next;
         jsuword             base;
         nanojit::LIns*      map[TRACKER_PAGE_ENTRIES];
     };
     struct TrackerPage* pagelist;
 
+    /* Keep track of memory allocation. */
+    JSContext* cx;
+
     jsuword             getTrackerPageBase(const void* v) const;
     jsuword             getTrackerPageOffset(const void* v) const;
     struct TrackerPage* findTrackerPage(const void* v) const;
     struct TrackerPage* addTrackerPage(const void* v);
 public:
-    Tracker();
+    Tracker(JSContext* cx);
     ~Tracker();
 
     bool            has(const void* v) const;
     nanojit::LIns*  get(const void* v) const;
     void            set(const void* v, nanojit::LIns* ins);
     void            clear();
 };
 
@@ -402,25 +405,28 @@ struct VMSideExit : public nanojit::Side
 
     inline TreeFragment* root() {
         return fromFrag()->root;
     }
 };
 
 class VMAllocator : public nanojit::Allocator
 {
-
 public:
-    VMAllocator(char* reserve, size_t reserveSize)
-      : mOutOfMemory(false), mSize(0), mReserve(reserve),
-        mReserveCurr(uintptr_t(reserve)), mReserveLimit(uintptr_t(reserve + reserveSize))
+    VMAllocator(JSRuntime *rt, char* reserve, size_t reserveSize)
+      : mOutOfMemory(false)
+      , mSize(0)
+      , mReserve(reserve)
+      , mReserveCurr(uintptr_t(reserve))
+      , mReserveLimit(uintptr_t(reserve + reserveSize))
+      , mRt(rt)
     {}
 
     ~VMAllocator() {
-        js_free(mReserve);
+        js::UnwantedForeground::free_(mReserve);
     }
 
     size_t size() {
         return mSize;
     }
 
     bool outOfMemory() {
         return mOutOfMemory;
@@ -467,16 +473,19 @@ public:
 
     bool mOutOfMemory;
     size_t mSize;
 
     /* See nanojit::Allocator::allocChunk() for details on these. */
     char* mReserve;
     uintptr_t mReserveCurr;
     uintptr_t mReserveLimit;
+
+    /* To keep track of allocation. */
+    JSRuntime* mRt;
 };
 
 struct FrameInfo {
     JSObject*       block;      // caller block chain head
     jsbytecode*     pc;         // caller fp->regs->pc
     jsbytecode*     imacpc;     // caller fp->imacpc
     uint32          spdist;     // distance from fp->slots to fp->regs->sp at JSOP_CALL
 
@@ -979,16 +988,18 @@ typedef HashMap<nanojit::LIns*, JSObject
 # define AbortRecording(cx, reason) AbortRecordingImpl(cx)
 #endif
 
 void
 AbortProfiling(JSContext *cx);
 
 class TraceRecorder
 {
+    JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
+
     /*************************************************************** Recording session constants */
 
     /* The context in which recording started. */
     JSContext* const                cx;
 
     /* Cached value of JS_TRACE_MONITOR(cx). */
     TraceMonitor* const             traceMonitor;
 
@@ -1686,17 +1697,17 @@ RecordTracePoint(JSContext*, uintN& inli
 extern JS_REQUIRES_STACK TracePointAction
 MonitorTracePoint(JSContext*, uintN& inlineCallCount, bool* blacklist,
                   void** traceData, uintN *traceEpoch, uint32 *loopCounter, uint32 hits);
 
 extern JS_REQUIRES_STACK TraceRecorder::AbortResult
 AbortRecording(JSContext* cx, const char* reason);
 
 extern bool
-InitJIT(TraceMonitor *tm);
+InitJIT(TraceMonitor *tm, JSRuntime *rt);
 
 extern void
 FinishJIT(TraceMonitor *tm);
 
 extern void
 PurgeScriptFragments(TraceMonitor* tm, JSScript* script);
 
 extern bool
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -118,17 +118,17 @@ ArrayBuffer::prop_getByteLength(JSContex
 }
 
 void
 ArrayBuffer::class_finalize(JSContext *cx, JSObject *obj)
 {
     ArrayBuffer *abuf = ArrayBuffer::fromJSObject(obj);
     if (abuf) {
         abuf->freeStorage(cx);
-        cx->destroy<ArrayBuffer>(abuf);
+        cx->delete_(abuf);
     }
 }
 
 /*
  * new ArrayBuffer(byteLength)
  */
 JSBool
 ArrayBuffer::class_constructor(JSContext *cx, uintN argc, Value *vp)
@@ -156,49 +156,49 @@ ArrayBuffer::create(JSContext *cx, int32
          * We're just not going to support arrays that are bigger than what will fit
          * as an integer value; if someone actually ever complains (validly), then we
          * can fix.
          */
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
         return NULL;
     }
 
-    ArrayBuffer *abuf = cx->create<ArrayBuffer>();
+    ArrayBuffer *abuf = cx->new_<ArrayBuffer>();
     if (!abuf)
         return NULL;
 
     if (!abuf->allocateStorage(cx, nbytes)) {
-        cx->destroy<ArrayBuffer>(abuf);
+        Foreground::delete_(abuf);
         return NULL;
     }
 
     obj->setPrivate(abuf);
     return obj;
 }
 
 bool
 ArrayBuffer::allocateStorage(JSContext *cx, uint32 nbytes)
 {
     JS_ASSERT(data == 0);
 
     if (nbytes) {
-        data = cx->calloc(nbytes);
+        data = cx->calloc_(nbytes);
         if (!data)
             return false;
     }
 
     byteLength = nbytes;
     return true;
 }
 
 void
 ArrayBuffer::freeStorage(JSContext *cx)
 {
     if (data) {
-        cx->free(data);
+        cx->free_(data);
 #ifdef DEBUG
         // the destructor asserts that data is 0 in debug builds
         data = NULL;
 #endif
     }
 }
 
 ArrayBuffer::~ArrayBuffer()
@@ -722,17 +722,17 @@ class TypedArrayTemplate
 
     static JSObject *
     createTypedArray(JSContext *cx, JSObject *bufobj, uint32 byteOffset, uint32 len)
     {
         JSObject *obj = NewBuiltinClassInstance(cx, slowClass());
         if (!obj)
             return NULL;
 
-        ThisTypeArray *tarray = cx->create<ThisTypeArray>(bufobj, byteOffset, len);
+        ThisTypeArray *tarray = cx->new_<ThisTypeArray>(bufobj, byteOffset, len);
         if (!tarray)
             return NULL;
 
         JS_ASSERT(obj->getClass() == slowClass());
         obj->setSharedNonNativeMap();
         obj->clasp = fastClass();
         obj->setPrivate(tarray);
 
@@ -827,17 +827,17 @@ class TypedArrayTemplate
         return createTypedArrayWithOffsetLength(cx, dataObj, byteOffset, length);
     }
 
     static void
     class_finalize(JSContext *cx, JSObject *obj)
     {
         ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
         if (tarray)
-            cx->destroy<ThisTypeArray>(tarray);
+            cx->delete_(tarray);
     }
 
     /* subarray(start[, end]) */
     static JSBool
     fun_subarray(JSContext *cx, uintN argc, Value *vp)
     {
         JSObject *obj = ToObject(cx, &vp[1]);
         if (!obj)
@@ -1259,17 +1259,17 @@ class TypedArrayTemplate
 
         if (tarray->type == type) {
             memmove(dest, tarray->data, tarray->byteLength);
             return true;
         }
 
         // We have to make a copy of the source array here, since
         // there's overlap, and we have to convert types.
-        void *srcbuf = cx->malloc(tarray->byteLength);
+        void *srcbuf = cx->malloc_(tarray->byteLength);
         if (!srcbuf)
             return false;
         memcpy(srcbuf, tarray->data, tarray->byteLength);
 
         switch (tarray->type) {
           case TypedArray::TYPE_INT8: {
             int8 *src = (int8*) srcbuf;
             for (uintN i = 0; i < tarray->length; ++i)
@@ -1319,17 +1319,17 @@ class TypedArrayTemplate
                 *dest++ = NativeType(*src++);
             break;
           }
           default:
             JS_NOT_REACHED("copyFromWithOverlap with a TypedArray of unknown type");
             break;
         }
 
-        js_free(srcbuf);
+        UnwantedForeground::free_(srcbuf);
         return true;
     }
 
     static JSObject *
     createBufferWithSizeAndCount(JSContext *cx, uint32 count)
     {
         size_t size = sizeof(NativeType);
         if (size != 0 && count >= INT32_MAX / size) {
--- a/js/src/jsutil.cpp
+++ b/js/src/jsutil.cpp
@@ -316,17 +316,17 @@ CallTree(void **bp)
                  ? strdup(symbol)
                  : JS_smprintf("%s+%X",
                                info.dli_fname ? info.dli_fname : "main",
                                offset);
         if (!method)
             return NULL;
 
         /* Create a new callsite record. */
-        site = (JSCallsite *) js_malloc(sizeof(JSCallsite));
+        site = (JSCallsite *) OffTheBooks::malloc(sizeof(JSCallsite));
         if (!site)
             return NULL;
 
         /* Insert the new site into the tree. */
         site->pc = (uint32)pc;
         site->name = method;
         site->library = info.dli_fname;
         site->offset = offset;
--- a/js/src/jsutil.h
+++ b/js/src/jsutil.h
@@ -223,17 +223,21 @@ extern JS_PUBLIC_DATA(JSUint32) OOM_coun
             return NULL; \
         } \
     } while (0)
 
 #else
 #define JS_OOM_POSSIBLY_FAIL() do {} while(0)
 #endif
 
-
+/*
+ * SpiderMonkey code should not be calling these allocation functions directly.
+ * Instead, all calls should go through JSRuntime, JSContext or OffTheBooks.
+ * However, js_free() can be called directly.
+ */
 static JS_INLINE void* js_malloc(size_t bytes) {
     JS_OOM_POSSIBLY_FAIL();
     return malloc(bytes);
 }
 
 static JS_INLINE void* js_calloc(size_t bytes) {
     JS_OOM_POSSIBLY_FAIL();
     return calloc(bytes, 1);
@@ -246,104 +250,271 @@ static JS_INLINE void* js_realloc(void* 
 
 static JS_INLINE void js_free(void* p) {
     free(p);
 }
 #endif/* JS_USE_CUSTOM_ALLOCATOR */
 
 JS_END_EXTERN_C
 
+
+
 #ifdef __cplusplus
 
 /* 
- * Using vanilla new/new[] is unsafe in SpiderMonkey because they throw on
- * failure instead of returning NULL, which is what SpiderMonkey expects.
- * js_new()/js_array_new() should be used instead, and memory allocated with
- * them should be deallocated with js_delete()/js_array_delete().
+ * User guide to memory memangement within SpiderMonkey:
+ *
+ * Quick tips:
+ *
+ *   Allocation:
+ *   - Prefer to allocate using JSContext:
+ *       cx->{malloc_,realloc_,calloc_,new_,new_array}
+ *
+ *   - If no JSContext is available, use a JSRuntime:
+ *       rt->{malloc_,realloc_,calloc_,new_,new_array}
+ *
+ *   - As a last resort, use unaccounted allocation ("OffTheBooks"):
+ *       js::OffTheBooks::{malloc_,realloc_,calloc_,new_,new_array}
+ *
+ *   Deallocation:
+ *   - When the deallocation occurs on a slow path, use:
+ *       Foreground::{free_,delete_,array_delete}
+ *
+ *   - Otherwise deallocate on a background thread using a JSContext:
+ *       cx->{free_,delete_,array_delete}
+ *  
+ *   - If no JSContext is available, use a JSRuntime:
+ *       rt->{free_,delete_,array_delete}
+ *
+ *   - As a last resort, use UnwantedForeground deallocation:
+ *       js::UnwantedForeground::{free_,delete_,array_delete}
+ *
+ * General tips:
+ *
+ *   - Mixing and matching these allocators is allowed (you may free memory
+ *     allocated by any allocator, with any deallocator).
+ * 
+ *   - Never, ever use normal C/C++ memory management:
+ *       malloc, free, new, new[], delete, operator new, etc.
  *
- * If you have a class with a private constructor or destructor, you can
- * make js_new/js_delete a friend.  This can be fiddly, and the interaction of
- * template functions, friend functions and namespaces can overwhelm even
- * modern compilers.  Manual inlining is probably easier.
+ *   - Never, ever use low-level SpiderMonkey allocators:
+ *       js_malloc(), js_free(), js_calloc(), js_realloc()
+ *     Their use is reserved for the other memory managers.
+ *
+ *   - Classes which have private constructors or destructors should have
+ *     JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR added to their
+ *     declaration.
+ * 
+ * Details:
+ *
+ *   Using vanilla new/new[] is unsafe in SpiderMonkey because they throw on
+ *   failure instead of returning NULL, which is what SpiderMonkey expects.
+ *   (Even overriding them is unsafe, as the system's C++ runtime library may
+ *   throw, which we do not support. We also can't just use the 'nothrow'
+ *   variant of new/new[], because we want to mediate *all* allocations
+ *   within SpiderMonkey, to satisfy any embedders using
+ *   JS_USE_CUSTOM_ALLOCATOR.)
  *
- * (If you're wondering why we can't just use the 'nothrow' variant of
- * new/new[], it's because we want to mediate *all* allocations within
- * SpiderMonkey, to satisfy any embedders using JS_USE_CUSTOM_ALLOCATOR.)
+ *   JSContexts and JSRuntimes keep track of memory allocated, and use this
+ *   accounting to schedule GC. OffTheBooks does not. We'd like to remove
+ *   OffTheBooks allocations as much as possible (bug 636558).
+ *
+ *   On allocation failure, a JSContext correctly reports an error, which a
+ *   JSRuntime and OffTheBooks does not.
+ *
+ *   A JSContext deallocates in a background thread. A JSRuntime might
+ *   deallocate in the background in the future, but does not now. Foreground
+ *   deallocation is preferable on slow paths. UnwantedForeground deallocations
+ *   occur where we have no JSContext or JSRuntime, and the deallocation is not
+ *   on a slow path. We want to remove UnwantedForeground deallocations (bug
+ *   636561).
+ *
+ *   JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR makes the allocation
+ *   classes friends with your class, giving them access to private
+ *   constructors and destructors.
+ *
+ *   |make check| does a source level check on the number of uses OffTheBooks,
+ *   UnwantedForeground, js_malloc, js_free etc, to prevent regressions. If you
+ *   really must add one, update Makefile.in, and run |make check|.
+ *
+ *   |make check| also statically prevents the use of vanilla new/new[].
  */
 
-#define JS_NEW_BODY(t, parms)                                                 \
-    void *memory = js_malloc(sizeof(t));                                      \
+#define JS_NEW_BODY(allocator, t, parms)                                       \
+    void *memory = allocator(sizeof(t));                                       \
     return memory ? new(memory) t parms : NULL;
 
-template <class T>
-JS_ALWAYS_INLINE T *js_new() {
-    JS_NEW_BODY(T, ())
-}
-
-template <class T, class P1>
-JS_ALWAYS_INLINE T *js_new(const P1 &p1) {
-    JS_NEW_BODY(T, (p1))
-}
-
-template <class T, class P1, class P2>
-JS_ALWAYS_INLINE T *js_new(const P1 &p1, const P2 &p2) {
-    JS_NEW_BODY(T, (p1, p2))
-}
-
-template <class T, class P1, class P2, class P3>
-JS_ALWAYS_INLINE T *js_new(const P1 &p1, const P2 &p2, const P3 &p3) {
-    JS_NEW_BODY(T, (p1, p2, p3))
-}
-
-template <class T, class P1, class P2, class P3, class P4>
-JS_ALWAYS_INLINE T *js_new(const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4) {
-    JS_NEW_BODY(T, (p1, p2, p3, p4))
-}
-
-/* ...add additional js_new()s as necessary... */
-
-#undef JS_NEW_BODY
+/*
+ * Given a class which should provide new_() methods, add
+ * JS_DECLARE_NEW_METHODS (see JSContext for a usage example). This
+ * adds new_()s with up to 12 parameters. Add more versions of new_ below if
+ * you need more than 12 parameters.  
+ *
+ * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS,
+ * or the build will break.
+ */
+#define JS_DECLARE_NEW_METHODS(ALLOCATOR, QUALIFIERS)\
+    template <class T>\
+    QUALIFIERS T *new_() {\
+        JS_NEW_BODY(ALLOCATOR, T, ())\
+    }\
+\
+    template <class T, class P1>\
+    QUALIFIERS T *new_(const P1 &p1) {\
+        JS_NEW_BODY(ALLOCATOR, T, (p1))\
+    }\
+\
+    template <class T, class P1, class P2>\
+    QUALIFIERS T *new_(const P1 &p1, const P2 &p2) {\
+        JS_NEW_BODY(ALLOCATOR, T, (p1, p2))\
+    }\
+\
+    template <class T, class P1, class P2, class P3>\
+    QUALIFIERS T *new_(const P1 &p1, const P2 &p2, const P3 &p3) {\
+        JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3))\
+    }\
+\
+    template <class T, class P1, class P2, class P3, class P4>\
+    QUALIFIERS T *new_(const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4) {\
+        JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4))\
+    }\
+\
+    template <class T, class P1, class P2, class P3, class P4, class P5>\
+    QUALIFIERS T *new_(const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4, const P5 &p5) {\
+        JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5))\
+    }\
+\
+    template <class T, class P1, class P2, class P3, class P4, class P5, class P6>\
+    QUALIFIERS T *new_(const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4, const P5 &p5, const P6 &p6) {\
+        JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6))\
+    }\
+\
+    template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7>\
+    QUALIFIERS T *new_(const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4, const P5 &p5, const P6 &p6, const P7 &p7) {\
+        JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7))\
+    }\
+\
+    template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>\
+    QUALIFIERS T *new_(const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4, const P5 &p5, const P6 &p6, const P7 &p7, const P8 &p8) {\
+        JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8))\
+    }\
+\
+    template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>\
+    QUALIFIERS T *new_(const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4, const P5 &p5, const P6 &p6, const P7 &p7, const P8 &p8, const P9 &p9) {\
+        JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9))\
+    }\
+\
+    template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10>\
+    QUALIFIERS T *new_(const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4, const P5 &p5, const P6 &p6, const P7 &p7, const P8 &p8, const P9 &p9, const P10 &p10) {\
+        JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10))\
+    }\
+\
+    template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11>\
+    QUALIFIERS T *new_(const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4, const P5 &p5, const P6 &p6, const P7 &p7, const P8 &p8, const P9 &p9, const P10 &p10, const P11 &p11) {\
+        JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11))\
+    }\
+\
+    template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11, class P12>\
+    QUALIFIERS T *new_(const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4, const P5 &p5, const P6 &p6, const P7 &p7, const P8 &p8, const P9 &p9, const P10 &p10, const P11 &p11, const P12 &p12) {\
+        JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12))\
+    }\
+    static const int JSMinAlignment = 8;\
+    template <class T>\
+    QUALIFIERS T *array_new(size_t n) {\
+        /* The length is stored just before the vector memory. */\
+        uint64 numBytes64 = uint64(JSMinAlignment) + uint64(sizeof(T)) * uint64(n);\
+        size_t numBytes = size_t(numBytes64);\
+        if (numBytes64 != numBytes) {\
+            JS_ASSERT(0);   /* we want to know if this happens in debug builds */\
+            return NULL;\
+        }\
+        void *memory = ALLOCATOR(numBytes);\
+        if (!memory)\
+            return NULL;\
+        *(size_t *)memory = n;\
+        memory = (void*)(uintptr_t(memory) + JSMinAlignment);\
+        return new(memory) T[n];\
+    }\
 
-template <class T>
-JS_ALWAYS_INLINE void js_delete(T *p) {
-    if (p) {
-        p->~T();
-        js_free(p);
-    }
-}
 
-static const int JSMinAlignment = 8;
+#define JS_DECLARE_DELETE_METHODS(DEALLOCATOR, QUALIFIERS)\
+    template <class T>\
+    QUALIFIERS void delete_(T *p) {\
+        if (p) {\
+            p->~T();\
+            DEALLOCATOR(p);\
+        }\
+    }\
+\
+    template <class T>\
+    QUALIFIERS void array_delete(T *p) {\
+        if (p) {\
+            void* p0 = (void *)(uintptr_t(p) - js::OffTheBooks::JSMinAlignment);\
+            size_t n = *(size_t *)p0;\
+            for (size_t i = 0; i < n; i++)\
+                (p + i)->~T();\
+            DEALLOCATOR(p0);\
+        }\
+    }
 
-template <class T>
-JS_ALWAYS_INLINE T *js_array_new(size_t n) {
-	/* The length is stored just before the vector memory. */
-    uint64 numBytes64 = uint64(JSMinAlignment) + uint64(sizeof(T)) * uint64(n);
-    size_t numBytes = size_t(numBytes64);
-    if (numBytes64 != numBytes) {
-        JS_ASSERT(0);   /* we want to know if this happens in debug builds */
-        return NULL;
+
+/*
+ * In general, all allocations should go through a JSContext or JSRuntime, so
+ * that the garbage collector knows how much memory has been allocated. In
+ * cases where it is difficult to use a JSContext or JSRuntime, OffTheBooks can
+ * be used, though this is undesirable.
+ */
+namespace js {
+class OffTheBooks {
+public:
+    JS_DECLARE_NEW_METHODS(::js_malloc, JS_ALWAYS_INLINE static)
+
+    static JS_INLINE void* malloc_(size_t bytes) {
+        return ::js_malloc(bytes);
     }
-    void *memory = js_malloc(numBytes);
-    if (!memory)
-        return NULL;
-	*(size_t *)memory = n;
-	memory = (void*)(uintptr_t(memory) + JSMinAlignment);
-    return new(memory) T[n];
-}
+
+    static JS_INLINE void* calloc_(size_t bytes) {
+        return ::js_calloc(bytes);
+    }
+
+    static JS_INLINE void* realloc_(void* p, size_t bytes) {
+        return ::js_realloc(p, bytes);
+    }
+};
 
-template <class T>
-JS_ALWAYS_INLINE void js_array_delete(T *p) {
-    if (p) {
-		void* p0 = (void *)(uintptr_t(p) - JSMinAlignment);
-		size_t n = *(size_t *)p0;
-		for (size_t i = 0; i < n; i++)
-			(p + i)->~T();
-		js_free(p0);
+/*
+ * We generally prefer deallocating using JSContext because it can happen in
+ * the background. On slow paths, we may prefer foreground allocation.
+ */
+class Foreground {
+public:
+    /* See parentheses comment above. */
+    static JS_ALWAYS_INLINE void free_(void* p) {
+        ::js_free(p);
     }
-}
+
+    JS_DECLARE_DELETE_METHODS(::js_free, JS_ALWAYS_INLINE static)
+};
+
+class UnwantedForeground : public Foreground {
+};
+
+} /* namespace js */
+
+/*
+ * Note lack of ; in JSRuntime below. This is intentional so "calling" this
+ * looks "normal".
+ */
+#define JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR \
+    friend class js::OffTheBooks;\
+    friend class js::Foreground;\
+    friend class js::UnwantedForeground;\
+    friend struct ::JSContext;\
+    friend struct ::JSRuntime
+
 
 /**
  * The following classes are designed to cause assertions to detect
  * inadvertent use of guard objects as temporaries.  In other words,
  * when we have a guard object whose only purpose is its constructor and
  * destructor (and is never otherwise referenced), the intended use
  * might be:
  *     JSAutoTempValueRooter tvr(cx, 1, &val);
--- a/js/src/jsvector.h
+++ b/js/src/jsvector.h
@@ -45,22 +45,16 @@
 #include "jsprvtd.h"
 
 /* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4345)
 #endif
 
-/* Gross special case for Gecko, which defines malloc/calloc/free. */
-#ifdef mozilla_mozalloc_macro_wrappers_h
-#  define JSVECTOR_UNDEFD_MOZALLOC_WRAPPERS
-#  include "mozilla/mozalloc_undef_macro_wrappers.h"
-#endif
-
 namespace js {
 
 /*
  * This template class provides a default implementation for vector operations
  * when the element type is not known to be a POD, as judged by IsPodType.
  */
 template <class T, size_t N, class AP, bool IsPod>
 struct VectorImpl
@@ -100,23 +94,23 @@ struct VectorImpl
     /*
      * Grows the given buffer to have capacity newcap, preserving the objects
      * constructed in the range [begin, end) and updating v. Assumes that (1)
      * newcap has not overflowed, and (2) multiplying newcap by sizeof(T) will
      * not overflow.
      */
     static inline bool growTo(Vector<T,N,AP> &v, size_t newcap) {
         JS_ASSERT(!v.usingInlineStorage());
-        T *newbuf = reinterpret_cast<T *>(v.malloc(newcap * sizeof(T)));
+        T *newbuf = reinterpret_cast<T *>(v.malloc_(newcap * sizeof(T)));
         if (!newbuf)
             return false;
         for (T *dst = newbuf, *src = v.beginNoCheck(); src != v.endNoCheck(); ++dst, ++src)
             new(dst) T(*src);
         VectorImpl::destroy(v.beginNoCheck(), v.endNoCheck());
-        v.free(v.mBegin);
+        v.free_(v.mBegin);
         v.mBegin = newbuf;
         /* v.mLength is unchanged. */
         v.mCapacity = newcap;
         return true;
     }
 };
 
 /*
@@ -158,17 +152,17 @@ struct VectorImpl<T, N, AP, true>
     static inline void copyConstructN(T *dst, size_t n, const T &t) {
         for (T *p = dst, *end = dst + n; p != end; ++p)
             *p = t;
     }
 
     static inline bool growTo(Vector<T,N,AP> &v, size_t newcap) {
         JS_ASSERT(!v.usingInlineStorage());
         size_t bytes = sizeof(T) * newcap;
-        T *newbuf = reinterpret_cast<T *>(v.realloc(v.mBegin, bytes));
+        T *newbuf = reinterpret_cast<T *>(v.realloc_(v.mBegin, bytes));
         if (!newbuf)
             return false;
         v.mBegin = newbuf;
         /* v.mLength is unchanged. */
         v.mCapacity = newcap;
         return true;
     }
 };
@@ -446,17 +440,17 @@ Vector<T,N,AllocPolicy>::Vector(AllocPol
 
 template <class T, size_t N, class AP>
 JS_ALWAYS_INLINE
 Vector<T,N,AP>::~Vector()
 {
     REENTRANCY_GUARD_ET_AL;
     Impl::destroy(beginNoCheck(), endNoCheck());
     if (!usingInlineStorage())
-        this->free(beginNoCheck());
+        this->free_(beginNoCheck());
 }
 
 /*
  * Calculate a new capacity that is at least lengthInc greater than
  * curLength and check for overflow.
  */
 template <class T, size_t N, class AP>
 STATIC_POSTCONDITION(!return || newCap >= curLength + lengthInc)
@@ -514,17 +508,17 @@ inline bool
 Vector<T,N,AP>::convertToHeapStorage(size_t lengthInc)
 {
     JS_ASSERT(usingInlineStorage());
     size_t newCap;
     if (!calculateNewCapacity(mLength, lengthInc, newCap))
         return false;
 
     /* Allocate buffer. */
-    T *newBuf = reinterpret_cast<T *>(this->malloc(newCap * sizeof(T)));
+    T *newBuf = reinterpret_cast<T *>(this->malloc_(newCap * sizeof(T)));
     if (!newBuf)
         return false;
 
     /* Copy inline elements into heap buffer. */
     Impl::copyConstruct(newBuf, beginNoCheck(), endNoCheck());
     Impl::destroy(beginNoCheck(), endNoCheck());
 
     /* Switch in heap buffer. */
@@ -796,17 +790,17 @@ Vector<T,N,AP>::popCopy()
 }
 
 template <class T, size_t N, class AP>
 inline T *
 Vector<T,N,AP>::extractRawBuffer()
 {
     T *ret;
     if (usingInlineStorage()) {
-        ret = reinterpret_cast<T *>(this->malloc(mLength * sizeof(T)));
+        ret = reinterpret_cast<T *>(this->malloc_(mLength * sizeof(T)));
         if (!ret)
             return NULL;
         Impl::copyConstruct(ret, beginNoCheck(), endNoCheck());
         Impl::destroy(beginNoCheck(), endNoCheck());
         /* mBegin, mCapacity are unchanged. */
         mLength = 0;
     } else {
         ret = mBegin;
@@ -824,44 +818,40 @@ template <class T, size_t N, class AP>
 inline void
 Vector<T,N,AP>::replaceRawBuffer(T *p, size_t length)
 {
     REENTRANCY_GUARD_ET_AL;
 
     /* Destroy what we have. */
     Impl::destroy(beginNoCheck(), endNoCheck());
     if (!usingInlineStorage())
-        this->free(beginNoCheck());
+        this->free_(beginNoCheck());
 
     /* Take in the new buffer. */
     if (length <= sInlineCapacity) {
         /*
          * We convert to inline storage if possible, even though p might
          * otherwise be acceptable.  Maybe this behaviour should be
          * specifiable with an argument to this function.
          */
         mBegin = (T *)storage.addr();
         mLength = length;
         mCapacity = sInlineCapacity;
         Impl::copyConstruct(mBegin, p, p + length);
         Impl::destroy(p, p + length);
-        this->free(p);
+        this->free_(p);
     } else {
         mBegin = p;
         mLength = length;
         mCapacity = length;
     }
 #ifdef DEBUG
     mReserved = length;
 #endif
 }
 
 }  /* namespace js */
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 
-#ifdef JSVECTOR_UNDEFD_MOZALLOC_WRAPPERS
-#  include "mozilla/mozalloc_macro_wrappers.h"
-#endif
-
 #endif /* jsvector_h_ */
--- a/js/src/jsxdrapi.cpp
+++ b/js/src/jsxdrapi.cpp
@@ -90,17 +90,17 @@ typedef struct JSXDRMemState {
     JS_END_MACRO
 
 #define MEM_NEED(xdr, bytes)                                                  \
     JS_BEGIN_MACRO                                                            \
         if ((xdr)->mode == JSXDR_ENCODE) {                                    \
             if (MEM_LIMIT(xdr) &&                                             \
                 MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) {                    \
                 uint32 limit_ = JS_ROUNDUP(MEM_COUNT(xdr) + bytes, MEM_BLOCK);\
-                void *data_ = (xdr)->cx->realloc(MEM_BASE(xdr), limit_);      \
+                void *data_ = (xdr)->cx->realloc_(MEM_BASE(xdr), limit_);      \
                 if (!data_)                                                   \
                     return 0;                                                 \
                 MEM_BASE(xdr) = (char *) data_;                               \
                 MEM_LIMIT(xdr) = limit_;                                      \
             }                                                                 \
         } else {                                                              \
             MEM_LEFT(xdr, bytes);                                             \
         }                                                                     \
@@ -216,17 +216,17 @@ static uint32
 mem_tell(JSXDRState *xdr)
 {
     return MEM_COUNT(xdr);
 }
 
 static void
 mem_finalize(JSXDRState *xdr)
 {
-    xdr->cx->free(MEM_BASE(xdr));
+    xdr->cx->free_(MEM_BASE(xdr));
 }
 
 static JSXDROps xdrmem_ops = {
     mem_get32,      mem_set32,      mem_getbytes,   mem_setbytes,
     mem_raw,        mem_seek,       mem_tell,       mem_finalize
 };
 
 JS_PUBLIC_API(void)
@@ -240,23 +240,23 @@ JS_XDRInitBase(JSXDRState *xdr, JSXDRMod
     xdr->userdata = NULL;
     xdr->script = NULL;
     xdr->state = NULL;
 }
 
 JS_PUBLIC_API(JSXDRState *)
 JS_XDRNewMem(JSContext *cx, JSXDRMode mode)
 {
-    JSXDRState *xdr = (JSXDRState *) cx->malloc(sizeof(JSXDRMemState));
+    JSXDRState *xdr = (JSXDRState *) cx->malloc_(sizeof(JSXDRMemState));
     if (!xdr)
         return NULL;
     JS_XDRInitBase(xdr, mode, cx);
     if (mode == JSXDR_ENCODE) {
-        if (!(MEM_BASE(xdr) = (char *) cx->malloc(MEM_BLOCK))) {
-            cx->free(xdr);
+        if (!(MEM_BASE(xdr) = (char *) cx->malloc_(MEM_BLOCK))) {
+            cx->free_(xdr);
             return NULL;
         }
     } else {
         /* XXXbe ok, so better not deref MEM_BASE(xdr) if not ENCODE */
         MEM_BASE(xdr) = NULL;
     }
     xdr->ops = &xdrmem_ops;
     MEM_COUNT(xdr) = 0;
@@ -300,21 +300,21 @@ JS_XDRMemResetData(JSXDRState *xdr)
 }
 
 JS_PUBLIC_API(void)
 JS_XDRDestroy(JSXDRState *xdr)
 {
     JSContext *cx = xdr->cx;
     xdr->ops->finalize(xdr);
     if (xdr->registry) {
-        cx->free(xdr->registry);
+        cx->free_(xdr->registry);
         if (xdr->reghash)
             JS_DHashTableDestroy((JSDHashTable *) xdr->reghash);
     }
-    cx->free(xdr);
+    cx->free_(xdr);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_XDRUint8(JSXDRState *xdr, uint8 *b)
 {
     uint32 l = *b;
     if (!JS_XDRUint32(xdr, &l))
         return JS_FALSE;
@@ -382,22 +382,22 @@ JS_PUBLIC_API(JSBool)
 JS_XDRCString(JSXDRState *xdr, char **sp)
 {
     uint32 len;
 
     if (xdr->mode == JSXDR_ENCODE)
         len = strlen(*sp);
     JS_XDRUint32(xdr, &len);
     if (xdr->mode == JSXDR_DECODE) {
-        if (!(*sp = (char *) xdr->cx->malloc(len + 1)))
+        if (!(*sp = (char *) xdr->cx->malloc_(len + 1)))
             return JS_FALSE;
     }
     if (!JS_XDRBytes(xdr, *sp, len)) {
         if (xdr->mode == JSXDR_DECODE)
-            xdr->cx->free(*sp);
+            xdr->cx->free_(*sp);
         return JS_FALSE;
     }
     if (xdr->mode == JSXDR_DECODE) {
         (*sp)[len] = '\0';
     }
     return JS_TRUE;
 }
 
@@ -452,17 +452,17 @@ JS_XDRString(JSXDRState *xdr, JSString *
                                                     &len, true));
     } else {
         jschar *chars = js_InflateString(xdr->cx, buf, &len, true);
         if (!chars)
             return false;
 
         *strp = js_NewString(xdr->cx, chars, len);
         if (!*strp) {
-            xdr->cx->free(chars);
+            xdr->cx->free_(chars);
             return false;
         }
     }
 
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
@@ -691,17 +691,17 @@ XDRScriptState::XDRScriptState(JSXDRStat
 
     xdr->state = this;
 }
 
 XDRScriptState::~XDRScriptState()
 {
     xdr->state = NULL;
     if (xdr->mode == JSXDR_DECODE && filename && !filenameSaved)
-        xdr->cx->free((void *)filename);
+        xdr->cx->free_((void *)filename);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_XDRScriptObject(JSXDRState *xdr, JSObject **scriptObjp)
 {
     JS_ASSERT(!xdr->state);
 
     JSScript *script;
@@ -763,17 +763,17 @@ JS_XDRRegisterClass(JSXDRState *xdr, JSC
     uintN numclasses, maxclasses;
     JSClass **registry;
 
     numclasses = xdr->numclasses;
     maxclasses = xdr->maxclasses;
     if (numclasses == maxclasses) {
         maxclasses = (maxclasses == 0) ? CLASS_REGISTRY_MIN : maxclasses << 1;
         registry = (JSClass **)
-            xdr->cx->realloc(xdr->registry, maxclasses * sizeof(JSClass *));
+            xdr->cx->realloc_(xdr->registry, maxclasses * sizeof(JSClass *));
         if (!registry)
             return JS_FALSE;
         xdr->registry = registry;
         xdr->maxclasses = maxclasses;
     } else {
         JS_ASSERT(numclasses && numclasses < maxclasses);
         registry = xdr->registry;
     }
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -424,30 +424,30 @@ ConvertQNameToString(JSContext *cx, JSOb
     }
     str = js_ConcatStrings(cx, str, obj->getQNameLocalName());
     if (!str)
         return NULL;
 
     if (obj->getClass() == &js_AttributeNameClass) {
         JS::Anchor<JSString *> anchor(str);
         size_t length = str->length();
-        jschar *chars = (jschar *) cx->malloc((length + 2) * sizeof(jschar));
+        jschar *chars = (jschar *) cx->malloc_((length + 2) * sizeof(jschar));
         if (!chars)
             return JS_FALSE;
         *chars = '@';
         const jschar *strChars = str->getChars(cx);
         if (!strChars) {
-            cx->free(chars);
+            cx->free_(chars);
             return NULL;
         }
         js_strncpy(chars + 1, strChars, length);
         chars[++length] = 0;
         str = js_NewString(cx, chars, length);
         if (!str) {
-            cx->free(chars);
+            cx->free_(chars);
             return NULL;
         }
     }
     return str;
 }
 
 static JSBool
 qname_toString(JSContext *cx, uintN argc, Value *vp)
@@ -884,29 +884,29 @@ XMLArrayCursorTrace(JSTracer *trc, JSXML
 /* NB: called with null cx from the GC, via xml_trace => JSXMLArray::trim. */
 bool
 JSXMLArray::setCapacity(JSContext *cx, uint32 newCapacity)
 {
     if (newCapacity == 0) {
         /* We could let realloc(p, 0) free this, but purify gets confused. */
         if (vector) {
             if (cx)
-                cx->free(vector);
+                cx->free_(vector);
             else
-                js_free(vector);
+                Foreground::free_(vector);
         }
         vector = NULL;
     } else {
         void **tmp;
 
         if (
 #if JS_BITS_PER_WORD == 32
             (size_t)newCapacity > ~(size_t)0 / sizeof(void *) ||
 #endif
-            !(tmp = (void **) js_realloc(vector, newCapacity * sizeof(void *)))) {
+            !(tmp = (void **) OffTheBooks::realloc_(vector, newCapacity * sizeof(void *)))) {
             if (cx)
                 JS_ReportOutOfMemory(cx);
             return false;
         }
         vector = tmp;
     }
     capacity = JSXML_PRESET_CAPACITY | newCapacity;
     return true;
@@ -919,17 +919,17 @@ JSXMLArray::trim()
         return;
     if (length < capacity)
         setCapacity(NULL, length);
 }
 
 void
 JSXMLArray::finish(JSContext *cx)
 {
-    cx->free(vector);
+    cx->free_(vector);
 
     while (JSXMLArrayCursor *cursor = cursors)
         cursor->disconnect();
 
 #ifdef DEBUG
     memset(this, 0xd5, sizeof *this);
 #endif
 }
@@ -983,17 +983,17 @@ XMLArrayAddMember(JSContext *cx, JSXMLAr
                 JS_CEILING_LOG2(log2, capacity);
                 capacity = JS_BIT(log2);
             }
             if (
 #if JS_BITS_PER_WORD == 32
                 (size_t)capacity > ~(size_t)0 / sizeof(void *) ||
 #endif
                 !(vector = (void **)
-                           js_realloc(array->vector, capacity * sizeof(void *)))) {
+                           cx->realloc_(array->vector, capacity * sizeof(void *)))) {
                 JS_ReportOutOfMemory(cx);
                 return JS_FALSE;
             }
             array->capacity = capacity;
             array->vector = vector;
             for (i = array->length; i < index; i++)
                 vector[i] = NULL;
         }
@@ -1064,20 +1064,20 @@ XMLArrayTruncate(JSContext *cx, JSXMLArr
     void **vector;
 
     JS_ASSERT(!array->cursors);
     if (length >= array->length)
         return;
 
     if (length == 0) {
         if (array->vector)
-            cx->free(array->vector);
+            cx->free_(array->vector);
         vector = NULL;
     } else {
-        vector = (void **) js_realloc(array->vector, length * sizeof(void *));
+        vector = (void **) cx->realloc_(array->vector, length * sizeof(void *));
         if (!vector)
             return;
     }
 
     if (array->length > length)
         array->length = length;
     array->capacity = length;
     array->vector = vector;
@@ -1702,32 +1702,32 @@ ParseXMLSource(JSContext *cx, JSString *
     if (!uri)
         return NULL;
 
     urilen = uri->length();
     srclen = src->length();
     length = constrlen(prefix) + urilen + constrlen(middle) + srclen +
              constrlen(suffix);
 
-    chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar));
+    chars = (jschar *) cx->malloc_((length + 1) * sizeof(jschar));
     if (!chars)
         return NULL;
 
     dstlen = length;
     js_InflateStringToBuffer(cx, prefix, constrlen(prefix), chars, &dstlen);
     offset = dstlen;
     js_strncpy(chars + offset, uri->chars(), urilen);
     offset += urilen;
     dstlen = length - offset + 1;
     js_InflateStringToBuffer(cx, middle, constrlen(middle), chars + offset,
                              &dstlen);
     offset += dstlen;
     srcp = src->getChars(cx);
     if (!srcp) {
-        cx->free(chars);
+        cx->free_(chars);
         return NULL;
     }
     js_strncpy(chars + offset, srcp, srclen);
     offset += srclen;
     dstlen = length - offset + 1;
     js_InflateStringToBuffer(cx, suffix, constrlen(suffix), chars + offset,
                              &dstlen);
     chars [offset + dstlen] = 0;
@@ -1752,30 +1752,30 @@ ParseXMLSource(JSContext *cx, JSString *
         }
     }
 
     {
         Parser parser(cx);
         if (parser.init(chars, length, filename, lineno, cx->findVersion())) {
             JSObject *scopeChain = GetScopeChain(cx);
             if (!scopeChain) {
-                cx->free(chars);
+                cx->free_(chars);
                 return NULL;
             }
             JSParseNode *pn = parser.parseXMLText(scopeChain, false);
             uintN flags;
             if (pn && GetXMLSettingFlags(cx, &flags)) {
                 AutoNamespaceArray namespaces(cx);
                 if (namespaces.array.setCapacity(cx, 1))
                     xml = ParseNodeToXML(&parser, pn, &namespaces.array, flags);
             }
         }
     }
 
-    cx->free(chars);
+    cx->free_(chars);
     return xml;
 
 #undef constrlen
 }
 
 /*
  * Errata in 10.3.1, 10.4.1, and 13.4.4.24 (at least).
  *
@@ -2287,17 +2287,17 @@ GeneratePrefix(JSContext *cx, JSLinearSt
      * without this branch executing) plus the space for storing a hyphen and
      * the serial number (avoiding reallocation if a collision happens).
      */
     bp = (jschar *) cp;
     newlength = length;
     if (STARTS_WITH_XML(cp, length) || !IsXMLName(cp, length)) {
         newlength = length + 2 + (size_t) log10((double) decls->length);
         bp = (jschar *)
-             cx->malloc((newlength + 1) * sizeof(jschar));
+             cx->malloc_((newlength + 1) * sizeof(jschar));
         if (!bp)
             return NULL;
 
         bp[newlength] = 0;
         for (i = 0; i < newlength; i++)
              bp[i] = 'a';
     }
 
@@ -2312,17 +2312,17 @@ GeneratePrefix(JSContext *cx, JSLinearSt
             ns = XMLARRAY_MEMBER(decls, i, JSObject);
             if (ns && (nsprefix = ns->getNamePrefix()) &&
                 nsprefix->length() == newlength &&
                 !memcmp(nsprefix->chars(), bp,
                         newlength * sizeof(jschar))) {
                 if (bp == cp) {
                     newlength = length + 2 + (size_t) log10((double) n);
                     bp = (jschar *)
-                         cx->malloc((newlength + 1) * sizeof(jschar));
+                         cx->malloc_((newlength + 1) * sizeof(jschar));
                     if (!bp)
                         return NULL;
                     js_strncpy(bp, cp, length);
                 }
 
                 ++serial;
                 JS_ASSERT(serial <= n);
                 dp = bp + length + 2 + (size_t) log10((double) serial);
@@ -2339,17 +2339,17 @@ GeneratePrefix(JSContext *cx, JSLinearSt
     } while (!done);
 
     if (bp == cp) {
         offset = cp - start;
         prefix = js_NewDependentString(cx, uri, offset, length);
     } else {
         prefix = js_NewString(cx, bp, newlength);
         if (!prefix)
-            cx->free(bp);
+            cx->free_(bp);
     }
     return prefix;
 }
 
 static JSBool
 namespace_match(const void *a, const void *b)
 {
     const JSObject *nsa = (const JSObject *) a;
@@ -4881,17 +4881,17 @@ xml_enumerate(JSContext *cx, JSObject *o
     length = JSXML_LENGTH(xml);
 
     switch (enum_op) {
       case JSENUMERATE_INIT:
       case JSENUMERATE_INIT_ALL:
         if (length == 0) {
             statep->setInt32(0);
         } else {
-            cursor = cx->create<JSXMLArrayCursor>(&xml->xml_kids);
+            cursor = cx->new_<JSXMLArrayCursor>(&xml->xml_kids);
             if (!cursor)
                 return JS_FALSE;
             statep->setPrivate(cursor);
         }
         if (idp)
             *idp = INT_TO_JSID(length);
         break;
 
@@ -4907,17 +4907,17 @@ xml_enumerate(JSContext *cx, JSObject *o
             break;
         }
         /* FALL THROUGH */
 
       case JSENUMERATE_DESTROY:
         if (!statep->isInt32(0)) {
             cursor = (JSXMLArrayCursor *) statep->toPrivate();
             if (cursor)
-                cx->destroy(cursor);
+                cx->delete_(cursor);
         }
         statep->setNull();
         break;
     }
     return JS_TRUE;
 }
 
 static JSType
@@ -7329,17 +7329,17 @@ js_AddAttributePart(JSContext *cx, JSBoo
         return NULL;
 
     size_t len2 = str2->length();
     const jschar *chars2 = str2->getChars(cx);
     if (!chars2)
         return NULL;
 
     size_t newlen = (isName) ? len + 1 + len2 : len + 2 + len2 + 1;
-    jschar *newchars = (jschar *) cx->malloc((newlen+1) * sizeof(jschar));
+    jschar *newchars = (jschar *) cx->malloc_((newlen+1) * sizeof(jschar));
     if (!newchars)
         return NULL;
 
     js_strncpy(newchars, chars, len);
     newchars += len;
     if (isName) {
         *newchars++ = ' ';
         js_strncpy(newchars, chars2, len2);
@@ -7577,17 +7577,17 @@ xmlfilter_trace(JSTracer *trc, JSObject 
 
 static void
 xmlfilter_finalize(JSContext *cx, JSObject *obj)
 {
     JSXMLFilter *filter = (JSXMLFilter *) obj->getPrivate();
     if (!filter)
         return;
 
-    cx->destroy(filter);
+    cx->delete_(filter);
 }
 
 Class js_XMLFilterClass = {
     "XMLFilter",
     JSCLASS_HAS_PRIVATE | JSCLASS_IS_ANONYMOUS,
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
@@ -7647,17 +7647,17 @@ js_StepXMLListFilter(JSContext *cx, JSBo
         filterobj = NewNonFunction<WithProto::Given>(cx, &js_XMLFilterClass, NULL, NULL);
         if (!filterobj)
             return JS_FALSE;
 
         /*
          * Init all filter fields before setPrivate exposes it to
          * xmlfilter_trace or xmlfilter_finalize.
          */
-        filter = cx->create<JSXMLFilter>(list, &list->xml_kids);
+        filter = cx->new_<JSXMLFilter>(list, &list->xml_kids);
         if (!filter)
             return JS_FALSE;
         filterobj->setPrivate(filter);
 
         /* Store filterobj to use in the later iterations. */
         sp[-2] = OBJECT_TO_JSVAL(filterobj);
 
         resobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -182,17 +182,17 @@ mjit::Compiler::performCompilation(JITSc
 
     this->analysis = &analysis;
 
     if (!frame.init()) {
         js_ReportOutOfMemory(cx);
         return Compile_Error;
     }
 
-    jumpMap = (Label *)cx->malloc(sizeof(Label) * script->length);
+    jumpMap = (Label *)cx->malloc_(sizeof(Label) * script->length);
     if (!jumpMap) {
         js_ReportOutOfMemory(cx);
         return Compile_Error;
     }
 #ifdef DEBUG
     for (uint32 i = 0; i < script->length; i++)
         jumpMap[i] = Label();
 #endif
@@ -229,18 +229,18 @@ mjit::Compiler::performCompilation(JITSc
 
     return Compile_Okay;
 }
 
 #undef CHECK_STATUS
 
 mjit::Compiler::~Compiler()
 {
-    cx->free(jumpMap);
-    cx->free(savedTraps);
+    cx->free_(jumpMap);
+    cx->free_(savedTraps);
 }
 
 CompileStatus JS_NEVER_INLINE
 mjit::TryCompile(JSContext *cx, JSStackFrame *fp)
 {
     JS_ASSERT(cx->fp() == fp);
 
 #if JS_HAS_SHARP_VARS
@@ -255,17 +255,17 @@ mjit::TryCompile(JSContext *cx, JSStackF
     Compiler cc(cx, fp);
 
     return cc.compile();
 }
 
 bool
 mjit::Compiler::loadOldTraps(const Vector<CallSite> &sites)
 {
-    savedTraps = (bool *)cx->calloc(sizeof(bool) * script->length);
+    savedTraps = (bool *)cx->calloc_(sizeof(bool) * script->length);
     if (!savedTraps)
         return false;
     
     for (size_t i = 0; i < sites.length(); i++) {
         const CallSite &site = sites[i];
         if (site.isTrap())
             savedTraps[site.pcOffset] = true;
     }
@@ -442,17 +442,17 @@ mjit::Compiler::finishThisUp(JITScript *
 #endif
 #if defined JS_POLYIC
                         sizeof(ic::PICInfo) * pics.length() +
                         sizeof(ic::GetElementIC) * getElemICs.length() +
                         sizeof(ic::SetElementIC) * setElemICs.length() +
 #endif
                         sizeof(CallSite) * callSites.length();
 
-    uint8 *cursor = (uint8 *)cx->calloc(totalBytes);
+    uint8 *cursor = (uint8 *)cx->calloc_(totalBytes);
     if (!cursor) {
         execPool->release();
         js_ReportOutOfMemory(cx);
         return Compile_Error;
     }
 
     JITScript *jit = new(cursor) JITScript;
     cursor += sizeof(JITScript);
--- a/js/src/methodjit/FrameState.cpp
+++ b/js/src/methodjit/FrameState.cpp
@@ -57,17 +57,17 @@ FrameState::FrameState(JSContext *cx, JS
     closedArgs(NULL),
     usesArguments(script->usesArguments),
     inTryBlock(false)
 {
 }
 
 FrameState::~FrameState()
 {
-    cx->free(entries);
+    cx->free_(entries);
 }
 
 bool
 FrameState::init()
 {
     // nslots + nargs + 2 (callee, this)
     uint32 nentries = feLimit();
     if (!nentries) {
@@ -81,17 +81,17 @@ FrameState::init()
                         sizeof(FrameEntry *) * nentries +                   // tracker.entries
                         (eval
                          ? 0
                          : sizeof(JSPackedBool) * script->nslots) +         // closedVars[]
                         (eval || usesArguments
                          ? 0
                          : sizeof(JSPackedBool) * nargs);                   // closedArgs[]
 
-    uint8 *cursor = (uint8 *)cx->calloc(totalBytes);
+    uint8 *cursor = (uint8 *)cx->calloc_(totalBytes);
     if (!cursor)
         return false;
 
 #if defined JS_NUNBOX32
     if (!reifier.init(nentries))
         return false;
 #endif
 
--- a/js/src/methodjit/ImmutableSync.cpp
+++ b/js/src/methodjit/ImmutableSync.cpp
@@ -49,23 +49,23 @@ using namespace js::mjit;
 
 ImmutableSync::ImmutableSync(JSContext *cx, const FrameState &frame)
   : cx(cx), entries(NULL), frame(frame), generation(0)
 {
 }
 
 ImmutableSync::~ImmutableSync()
 {
-    cx->free(entries);
+    cx->free_(entries);
 }
 
 bool
 ImmutableSync::init(uint32 nentries)
 {
-    entries = (SyncEntry *)cx->calloc(sizeof(SyncEntry) * nentries);
+    entries = (SyncEntry *)cx->calloc_(sizeof(SyncEntry) * nentries);
     return !!entries;
 }
 
 void
 ImmutableSync::reset(Assembler *masm, Registers avail, FrameEntry *top, FrameEntry *bottom)
 {
     this->avail = avail;
     this->masm = masm;
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -618,17 +618,17 @@ JS_STATIC_ASSERT(offsetof(VMFrame, regs.
 JS_STATIC_ASSERT(JSVAL_TAG_MASK == 0xFFFF800000000000LL);
 JS_STATIC_ASSERT(JSVAL_PAYLOAD_MASK == 0x00007FFFFFFFFFFFLL);
 
 #endif                   /* _WIN64 */
 
 bool
 JaegerCompartment::Initialize()
 {
-    execAlloc_ = js_new<JSC::ExecutableAllocator>();
+    execAlloc_ = js::OffTheBooks::new_<JSC::ExecutableAllocator>();
     if (!execAlloc_)
         return false;
     
     TrampolineCompiler tc(execAlloc_, &trampolines);
     if (!tc.compile()) {
         delete execAlloc_;
         return false;
     }
@@ -642,17 +642,17 @@ JaegerCompartment::Initialize()
 
     return true;
 }
 
 void
 JaegerCompartment::Finish()
 {
     TrampolineCompiler::release(&trampolines);
-    js_delete(execAlloc_);
+    Foreground::delete_(execAlloc_);
 #ifdef JS_METHODJIT_PROFILE_STUBS
     FILE *fp = fopen("/tmp/stub-profiling", "wt");
 # define OPDEF(op,val,name,image,length,nuses,ndefs,prec,format) \
     fprintf(fp, "%03d %s %d\n", val, #op, StubCallsForOp[val]);
 # include "jsopcode.tbl"
 # undef OPDEF
     fclose(fp);
 #endif
@@ -904,26 +904,26 @@ mjit::ReleaseScriptCode(JSContext *cx, J
     // will get called again when the script is destroyed, so we
     // must protect against calling ReleaseScriptCode twice.
     JITScript *jscr;
 
     if ((jscr = script->jitNormal)) {
         cx->runtime->mjitMemoryUsed -= jscr->scriptDataSize() + jscr->mainCodeSize();
 
         jscr->~JITScript();
-        cx->free(jscr);
+        cx->free_(jscr);
         script->jitNormal = NULL;
         script->jitArityCheckNormal = NULL;
     }
 
     if ((jscr = script->jitCtor)) {
         cx->runtime->mjitMemoryUsed -= jscr->scriptDataSize() + jscr->mainCodeSize();
 
         jscr->~JITScript();
-        cx->free(jscr);
+        cx->free_(jscr);
         script->jitCtor = NULL;
         script->jitArityCheckCtor = NULL;
     }
 }
 
 #ifdef JS_METHODJIT_PROFILE_STUBS
 void JS_FASTCALL
 mjit::ProfileStubCall(VMFrame &f)
--- a/js/src/methodjit/MethodJIT.h
+++ b/js/src/methodjit/MethodJIT.h
@@ -228,19 +228,19 @@ class CompilerAllocPolicy : public Conte
         return p;
     }
 
   public:
     CompilerAllocPolicy(JSContext *cx, bool *oomFlag)
     : ContextAllocPolicy(cx), oomFlag(oomFlag) {}
     CompilerAllocPolicy(JSContext *cx, Compiler &compiler);
 
-    void *malloc(size_t bytes) { return checkAlloc(ContextAllocPolicy::malloc(bytes)); }
-    void *realloc(void *p, size_t bytes) {
-        return checkAlloc(ContextAllocPolicy::realloc(p, bytes));
+    void *malloc_(size_t bytes) { return checkAlloc(ContextAllocPolicy::malloc_(bytes)); }
+    void *realloc_(void *p, size_t bytes) {
+        return checkAlloc(ContextAllocPolicy::realloc_(p, bytes));
     }
 };
 
 namespace ic {
 # if defined JS_POLYIC
     struct PICInfo;
     struct GetElementIC;
     struct SetElementIC;
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -895,17 +895,27 @@ class CallCompiler : public BaseCompiler
 
         masm.setupABICall(Registers::NormalCall, 3);
         masm.storeArg(2, vpReg);
         if (ic.frameSize.isStatic())
             masm.storeArg(1, Imm32(ic.frameSize.staticArgc()));
         else
             masm.storeArg(1, argcReg.reg());
         masm.storeArg(0, cxReg);
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, fun->u.n.native), false);
+
+        js::Native native = fun->u.n.native;
+
+        /*
+         * Call RegExp.test instead of exec if the result will not be used or
+         * will only be used to test for existence.
+         */
+        if (native == js_regexp_exec && !CallResultEscapes(f.regs.pc))
+            native = js_regexp_test;
+
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, native), false);
 
         Jump hasException = masm.branchTest32(Assembler::Zero, Registers::ReturnReg,
                                               Registers::ReturnReg);
         
 
         Jump done = masm.jump();
 
         /* Move JaegerThrowpoline into register for very far jump on x64. */
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -555,16 +555,17 @@ class SetPropCompiler : public PICStubCo
                 getter = CastAsPropertyOp(funobj);
             }
 
             /*
              * Define the property but do not set it yet. For setmethod,
              * populate the slot to satisfy the method invariant (in case we
              * hit an early return below).
              */
+            id = js_CheckForStringIndex(id);
             const Shape *shape =
                 obj->putProperty(cx, id, getter, clasp->setProperty,
                                  SHAPE_INVALID_SLOT, JSPROP_ENUMERATE, flags, 0);
             if (!shape)
                 return error();
             if (flags & Shape::METHOD)
                 obj->nativeSetSlot(shape->slot, f.regs.sp[-1]);
 
@@ -2130,17 +2131,17 @@ GetElementIC::attachGetProp(JSContext *c
     buffer.link(done, fastPathRejoin);
 
     CodeLocationLabel cs = buffer.finalize();
 #if DEBUG
     char *chars = js_DeflateString(cx, v.toString()->getChars(cx), v.toString()->length());
     JaegerSpew(JSpew_PICs, "generated %s stub at %p for atom 0x%x (\"%s\") shape 0x%x (%s: %d)\n",
                js_CodeName[op], cs.executableAddress(), id, chars, holder->shape(),
                cx->fp()->script()->filename, js_FramePCToLineNumber(cx, cx->fp()));
-    cx->free(chars);
+    cx->free_(chars);
 #endif
 
     // Update the inline guards, if needed.
     if (shouldPatchInlineTypeGuard() || shouldPatchUnconditionalClaspGuard()) {
         Repatcher repatcher(cx->fp()->jit());
 
         if (shouldPatchInlineTypeGuard()) {
             // A type guard is present in the inline path, and this is the
--- a/js/src/methodjit/PolyIC.h
+++ b/js/src/methodjit/PolyIC.h
@@ -152,17 +152,17 @@ class BasePolyIC : public BaseIC {
   public:
     BasePolyIC() {
         u.execPool = NULL;
     }
 
     ~BasePolyIC() {
         releasePools();
         if (areMultiplePools())
-            js_delete(multiplePools());
+            Foreground::delete_(multiplePools());
     }
 
     void reset() {
         BaseIC::reset();
         releasePools();
         if (areZeroPools()) {
             // Common case:  do nothing.
         } else if (isOnePool()) {
@@ -187,21 +187,21 @@ class BasePolyIC : public BaseIC {
     bool addPool(JSContext *cx, JSC::ExecutablePool *pool) {
         if (areZeroPools()) {
             u.execPool = pool;
             return true;
         }
         if (isOnePool()) {
             JSC::ExecutablePool *oldPool = u.execPool;
             JS_ASSERT(!isTagged(oldPool));
-            ExecPoolVector *execPools = js_new<ExecPoolVector>(SystemAllocPolicy()); 
+            ExecPoolVector *execPools = cx->new_<ExecPoolVector>(SystemAllocPolicy()); 
             if (!execPools)
                 return false;
             if (!execPools->append(oldPool) || !execPools->append(pool)) {
-                js_delete(execPools);
+                Foreground::delete_(execPools);
                 return false;
             }
             u.taggedExecPools = tag(execPools);
             return true;
         }
         return multiplePools()->append(pool); 
     }
 };
--- a/js/src/perf/jsperf.cpp
+++ b/js/src/perf/jsperf.cpp
@@ -58,31 +58,31 @@ pm_construct(JSContext* cx, uintN argc, 
 
     JSObject *obj = JS_NewObjectForConstructor(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     if (!JS_FreezeObject(cx, obj))
         return JS_FALSE;
 
-    PerfMeasurement* p = js_new<PerfMeasurement>(PerfMeasurement::EventMask(mask));
+    PerfMeasurement* p = cx->new_<PerfMeasurement>(PerfMeasurement::EventMask(mask));
     if (!p) {
         JS_ReportOutOfMemory(cx);
         return JS_FALSE;
     }
 
     JS_SetPrivate(cx, obj, p);
     *vp = OBJECT_TO_JSVAL(obj);
     return JS_TRUE;
 }
 
 static void
 pm_finalize(JSContext* cx, JSObject* obj)
 {
-    js_delete((PerfMeasurement*) JS_GetPrivate(cx, obj));
+    cx->delete_((PerfMeasurement*) JS_GetPrivate(cx, obj));
 }
 
 // Property access
 
 #define GETTER(name)                                                    \
     static JSBool                                                       \
     pm_get_##name(JSContext* cx, JSObject* obj, jsid /*unused*/, jsval* vp) \
     {                                                                   \
--- a/js/src/perf/pm_linux.cpp
+++ b/js/src/perf/pm_linux.cpp
@@ -34,16 +34,18 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "jsperf.h"
 #include "jsutil.h"
 
+using namespace js;
+
 /* This variant of nsIPerfMeasurement uses the perf_event interface
  * added in Linux 2.6.31.  We key compilation of this file off the
  * existence of <linux/perf_event.h>.
  */
 
 #include <linux/perf_event.h>
 #include <new>
 #include <sys/syscall.h>
@@ -260,17 +262,17 @@ Impl::stop(PerfMeasurement* counters)
 } // anonymous namespace
 
 
 namespace JS {
 
 #define initCtr(flag) ((eventsMeasured & flag) ? 0 : -1)
 
 PerfMeasurement::PerfMeasurement(PerfMeasurement::EventMask toMeasure)
-  : impl(js_new<Impl>()),
+  : impl(OffTheBooks::new_<Impl>()),
     eventsMeasured(impl ? static_cast<Impl*>(impl)->init(toMeasure)
                    : EventMask(0)),
     cpu_cycles(initCtr(CPU_CYCLES)),
     instructions(initCtr(INSTRUCTIONS)),
     cache_references(initCtr(CACHE_REFERENCES)),
     cache_misses(initCtr(CACHE_MISSES)),
     branch_instructions(initCtr(BRANCH_INSTRUCTIONS)),
     branch_misses(initCtr(BRANCH_MISSES)),
@@ -281,17 +283,17 @@ PerfMeasurement::PerfMeasurement(PerfMea
     cpu_migrations(initCtr(CPU_MIGRATIONS))
 {
 }
 
 #undef initCtr
 
 PerfMeasurement::~PerfMeasurement()
 {
-    js_delete(static_cast<Impl*>(impl));
+    js::Foreground::delete_(static_cast<Impl*>(impl));
 }
 
 void
 PerfMeasurement::start()
 {
     if (impl)
         static_cast<Impl*>(impl)->start();
 }
--- a/js/src/shell/Makefile.in
+++ b/js/src/shell/Makefile.in
@@ -51,17 +51,17 @@ CPPSRCS		= \
   $(NULL)
 
 DEFINES         += -DEXPORT_JS_API
 
 LIBS      = $(NSPR_LIBS) $(EDITLINE_LIBS) $(DEPTH)/$(LIB_PREFIX)js_static.$(LIB_SUFFIX)
 
 LOCAL_INCLUDES += -I$(topsrcdir) -I..
 
-FAIL_ON_WARNINGS = 1
+#FAIL_ON_WARNINGS = 1
 
 ifdef _MSC_VER
 ifdef WINCE
 WIN32_EXE_LDFLAGS += -ENTRY:mainACRTStartup
 endif
 endif
 
 ifeq ($(OS_ARCH),Darwin)
--- a/js/src/tests/js1_8_5/regress/jstests.list
+++ b/js/src/tests/js1_8_5/regress/jstests.list
@@ -94,8 +94,9 @@ fails-if(xulRuntime.shell) script regres
 script regress-634210-1.js
 script regress-634210-2.js
 script regress-634210-3.js
 script regress-634210-4.js
 script regress-635195.js
 script regress-636394.js
 script regress-636364.js
 script regress-640075.js
+script regress-643222.js
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8_5/regress/regress-643222.js
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+/* This shouldn't trigger an assertion. */
+(function () {
+    eval("var x=delete(x)")
+})();
+
+reportCompare(0, 0, "ok");
--- a/js/src/tests/manifest.py
+++ b/js/src/tests/manifest.py
@@ -71,17 +71,19 @@ class XULInfoTester:
             cmd = [ self.js_bin, '-e', self.js_prolog, '-e', 'print(!!(%s))'%cond ]
             p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
             out, err = p.communicate()
             if out in ('true\n', 'true\r\n'):
                 ans = True
             elif out in ('false\n', 'false\r\n'):
                 ans = False
             else:
-                raise Exception("Failed to test XUL condition '%s'"%cond)
+                raise Exception(("Failed to test XUL condition %r;"
+                                 + " output was %r, stderr was %r")
+                                 % (cond, out, err))
             self.cache[cond] = ans
         return ans
 
 class NullXULInfoTester:
     """Can be used to parse manifests without a JS shell."""
     def test(self, cond):
         return False
 
--- a/js/src/yarr/pcre/pcre_compile.cpp
+++ b/js/src/yarr/pcre/pcre_compile.cpp
@@ -2583,19 +2583,17 @@ JSRegExp* jsRegExpCompile(const UChar* p
     int length = calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode);
     if (errorcode)
         return returnError(errorcode, error);
     
     if (length > MAX_PATTERN_SIZE)
         return returnError(ERR16, error);
     
     size_t size = length + sizeof(JSRegExp);
-    // FIXME: bug 574459 -- no NULL check
-    JSRegExp* re = reinterpret_cast<JSRegExp*>(js_array_new<char>(size));
-    
+    JSRegExp* re = reinterpret_cast<JSRegExp*>(js::OffTheBooks::array_new<char>(size));
     if (!re)
         return returnError(ERR13, error);
     
     re->options = (ignoreCase ? IgnoreCaseOption : 0) | (multiline ? MatchAcrossMultipleLinesOption : 0);
     
     /* The starting points of the name/number translation table and of the code are
      passed around in the compile data block. */
     
@@ -2640,17 +2638,17 @@ JSRegExp* jsRegExpCompile(const UChar* p
      subpattern. */
     
     if (re->topBackref > re->topBracket)
         errorcode = ERR15;
     
     /* Failed to compile, or error while post-processing */
     
     if (errorcode != ERR0) {
-        js_array_delete(reinterpret_cast<char*>(re));
+        js::Foreground::array_delete(reinterpret_cast<char*>(re));
         return returnError(errorcode, error);
     }
     
     /* If the anchored option was not passed, set the flag if we can determine that
      the pattern is anchored by virtue of ^ characters or \A or anything else (such
      as starting with .* when DOTALL is set).
      
      Otherwise, if we know what the first character has to be, save it, because that
@@ -2695,10 +2693,10 @@ JSRegExp* jsRegExpCompile(const UChar* p
     if (numSubpatterns)
         *numSubpatterns = re->topBracket;
 
     return re;
 }
 
 void jsRegExpFree(JSRegExp* re)
 {
-    js_array_delete(reinterpret_cast<char*>(re));
+    js::Foreground::array_delete(reinterpret_cast<char*>(re));
 }
--- a/js/src/yarr/pcre/pcre_exec.cpp
+++ b/js/src/yarr/pcre/pcre_exec.cpp
@@ -389,17 +389,17 @@ struct MatchStack {
     bool canUseStackBufferForNextFrame() {
         return size < numFramesOnStack;
     }
     
     MatchFrame* allocateNextFrame() {
         if (canUseStackBufferForNextFrame())
             return currentFrame + 1;
         // FIXME: bug 574459 -- no NULL check
-        MatchFrame *frame = js_new<MatchFrame>();
+        MatchFrame *frame = js::OffTheBooks::new_<MatchFrame>();
         frame->init(regExpPool);
         return frame;
     }
     
     void pushNewFrame(const unsigned char* instructionPtr, BracketChainNode* bracketChain, ReturnLocation returnLocation) {
         MatchFrame* newframe = allocateNextFrame();
         newframe->previousFrame = currentFrame;
 
@@ -412,17 +412,17 @@ struct MatchStack {
 
         currentFrame = newframe;
     }
     
     void popCurrentFrame() {
         MatchFrame* oldFrame = currentFrame;
         currentFrame = currentFrame->previousFrame;
         if (size > numFramesOnStack)
-            js_delete(oldFrame);
+            js::Foreground::delete_(oldFrame);
         size--;
     }
 
     void popAllFrames() {
         while (size)
             popCurrentFrame();
     }
 };
--- a/js/src/yarr/yarr/RegExpJitTables.h
+++ b/js/src/yarr/yarr/RegExpJitTables.h
@@ -2625,46 +2625,46 @@ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
 };
 
 
 CharacterClass* digitsCreate()
 {
     // FIXME: bug 574459 -- no NULL check
-    CharacterClass* characterClass = js_new<CharacterClass>((CharacterClassTable*)NULL);
+    CharacterClass* characterClass = js::OffTheBooks::new_<CharacterClass>((CharacterClassTable*)NULL);
     characterClass->m_ranges.append(CharacterRange(0x30, 0x39));
     return characterClass;
 }
 
 CharacterClass* nondigitsCreate()
 {
     // FIXME: bug 574459 -- no NULL check
-    CharacterClass* characterClass = js_new<CharacterClass>((CharacterClassTable*)NULL);
+    CharacterClass* characterClass = js::OffTheBooks::new_<CharacterClass>((CharacterClassTable*)NULL);
     characterClass->m_ranges.append(CharacterRange(0x00, 0x2f));
     characterClass->m_ranges.append(CharacterRange(0x3a, 0x7f));
     characterClass->m_rangesUnicode.append(CharacterRange(0x0080, 0xffff));
     return characterClass;
 }
 
 CharacterClass* newlineCreate()
 {
     // FIXME: bug 574459 -- no NULL check
-    CharacterClass* characterClass = js_new<CharacterClass>((CharacterClassTable*)NULL);
+    CharacterClass* characterClass = js::OffTheBooks::new_<CharacterClass>((CharacterClassTable*)NULL);
     characterClass->m_matches.append(0x0a);
     characterClass->m_matches.append(0x0d);
     characterClass->m_matchesUnicode.append(0x2028);
     characterClass->m_matchesUnicode.append(0x2029);
     return characterClass;
 }
 
 CharacterClass* spacesCreate()
 {
     // FIXME: bug 574459 -- no NULL check
-    CharacterClass* characterClass = js_new<CharacterClass>(CharacterClassTable::create(_spacesData, false));
+    CharacterClass* characterClass = js::OffTheBooks::new_<CharacterClass>(CharacterClassTable::create(_spacesData, false));
     characterClass->m_ranges.append(CharacterRange(0x09, 0x0d));
     characterClass->m_matches.append(0x20);
     characterClass->m_matchesUnicode.append(0x00a0);
     characterClass->m_matchesUnicode.append(0x1680);
     characterClass->m_matchesUnicode.append(0x180e);
     characterClass->m_rangesUnicode.append(CharacterRange(0x2000, 0x200a));
     characterClass->m_matchesUnicode.append(0x2028);
     characterClass->m_matchesUnicode.append(0x2029);
@@ -2672,17 +2672,17 @@ CharacterClass* spacesCreate()
     characterClass->m_matchesUnicode.append(0x205f);
     characterClass->m_matchesUnicode.append(0x3000);
     return characterClass;
 }
 
 CharacterClass* nonspacesCreate()
 {
     // FIXME: bug 574459 -- no NULL check
-    CharacterClass* characterClass = js_new<CharacterClass>(CharacterClassTable::create(_spacesData, true));
+    CharacterClass* characterClass = js::OffTheBooks::new_<CharacterClass>(CharacterClassTable::create(_spacesData, true));
     characterClass->m_ranges.append(CharacterRange(0x00, 0x08));
     characterClass->m_ranges.append(CharacterRange(0x0e, 0x1f));
     characterClass->m_ranges.append(CharacterRange(0x21, 0x7f));
     characterClass->m_rangesUnicode.append(CharacterRange(0x0080, 0x009f));
     characterClass->m_rangesUnicode.append(CharacterRange(0x00a1, 0x167f));
     characterClass->m_rangesUnicode.append(CharacterRange(0x1681, 0x180d));
     characterClass->m_rangesUnicode.append(CharacterRange(0x180f, 0x1fff));
     characterClass->m_rangesUnicode.append(CharacterRange(0x200b, 0x2027));
@@ -2691,30 +2691,30 @@ CharacterClass* nonspacesCreate()
     characterClass->m_rangesUnicode.append(CharacterRange(0x2060, 0x2fff));
     characterClass->m_rangesUnicode.append(CharacterRange(0x3001, 0xffff));
     return characterClass;
 }
 
 CharacterClass* nonwordcharCreate()
 {
     // FIXME: bug 574459 -- no NULL check
-    CharacterClass* characterClass = js_new<CharacterClass>(CharacterClassTable::create(_wordcharData, true));
+    CharacterClass* characterClass = js::OffTheBooks::new_<CharacterClass>(CharacterClassTable::create(_wordcharData, true));
     characterClass->m_ranges.append(CharacterRange(0x00, 0x2f));
     characterClass->m_ranges.append(CharacterRange(0x3a, 0x40));
     characterClass->m_ranges.append(CharacterRange(0x5b, 0x5e));
     characterClass->m_matches.append(0x60);
     characterClass->m_ranges.append(CharacterRange(0x7b, 0x7f));
     characterClass->m_rangesUnicode.append(CharacterRange(0x0080, 0xffff));
     return characterClass;
 }
 
 CharacterClass* wordcharCreate()
 {
     // FIXME: bug 574459 -- no NULL check
-    CharacterClass* characterClass = js_new<CharacterClass>(CharacterClassTable::create(_wordcharData, false));
+    CharacterClass* characterClass = js::OffTheBooks::new_<CharacterClass>(CharacterClassTable::create(_wordcharData, false));
     characterClass->m_ranges.append(CharacterRange(0x30, 0x39));
     characterClass->m_ranges.append(CharacterRange(0x41, 0x5a));
     characterClass->m_matches.append(0x5f);
     characterClass->m_ranges.append(CharacterRange(0x61, 0x7a));
     return characterClass;
 }
 
 
--- a/js/src/yarr/yarr/RegexCompiler.cpp
+++ b/js/src/yarr/yarr/RegexCompiler.cpp
@@ -135,17 +135,17 @@ public:
                 }
             }
         }
     }
 
     CharacterClass* charClass()
     {
         // FIXME: bug 574459 -- no NULL check
-        CharacterClass* characterClass = js_new<CharacterClass>((CharacterClassTable*)NULL);
+        CharacterClass* characterClass = js::OffTheBooks::new_<CharacterClass>((CharacterClassTable*)NULL);
 
         characterClass->m_matches.append(m_matches);
         characterClass->m_ranges.append(m_ranges);
         characterClass->m_matchesUnicode.append(m_matchesUnicode);
         characterClass->m_rangesUnicode.append(m_rangesUnicode);
 
         reset();
 
@@ -341,26 +341,26 @@ public:
 
     void atomParenthesesSubpatternBegin(bool capture = true)
     {
         unsigned subpatternId = m_pattern.m_numSubpatterns + 1;
         if (capture)
             m_pattern.m_numSubpatterns++;
 
         // FIXME: bug 574459 -- no NULL check
-        PatternDisjunction* parenthesesDisjunction = js_new<PatternDisjunction>(m_alternative);
+        PatternDisjunction* parenthesesDisjunction = js::OffTheBooks::new_<PatternDisjunction>(m_alternative);
         m_pattern.m_disjunctions.append(parenthesesDisjunction);
         m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture));
         m_alternative = parenthesesDisjunction->addNewAlternative();
     }
 
     void atomParentheticalAssertionBegin(bool invert = false)
     {
         // FIXME: bug 574459 -- no NULL check
-        PatternDisjunction* parenthesesDisjunction = js_new<PatternDisjunction>(m_alternative);
+        PatternDisjunction* parenthesesDisjunction = js::OffTheBooks::new_<PatternDisjunction>(m_alternative);
         m_pattern.m_disjunctions.append(parenthesesDisjunction);
         m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, invert));
         m_alternative = parenthesesDisjunction->addNewAlternative();
     }
 
     void atomParenthesesEnd()
     {
         JS_ASSERT(m_alternative->m_parent);
@@ -396,17 +396,17 @@ public:
         }
 
         m_alternative->m_terms.append(PatternTerm(subpatternId));
     }
 
     PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction)
     {
         // FIXME: bug 574459 -- no NULL check
-        PatternDisjunction* newDisjunction = js_new<PatternDisjunction>();
+        PatternDisjunction* newDisjunction = js::OffTheBooks::new_<PatternDisjunction>();
 
         newDisjunction->m_parent = disjunction->m_parent;
         for (unsigned alt = 0; alt < disjunction->m_alternatives.length(); ++alt) {
             PatternAlternative* alternative = disjunction->m_alternatives[alt];
             PatternAlternative* newAlternative = newDisjunction->addNewAlternative();
             for (unsigned i = 0; i < alternative->m_terms.length(); ++i)
                 newAlternative->m_terms.append(copyTerm(alternative->m_terms[i]));
         }
@@ -467,17 +467,17 @@ public:
     void disjunction()
     {
         m_alternative = m_alternative->m_parent->addNewAlternative();
     }
 
     void regexBegin()
     {
         // FIXME: bug 574459 -- no NULL check
-        m_pattern.m_body = js_new<PatternDisjunction>();
+        m_pattern.m_body = js::OffTheBooks::new_<PatternDisjunction>();
         m_alternative = m_pattern.m_body->addNewAlternative();
         m_pattern.m_disjunctions.append(m_pattern.m_body);
     }
     void regexEnd()
     {
     }
     void regexError()
     {
--- a/js/src/yarr/yarr/RegexPattern.h
+++ b/js/src/yarr/yarr/RegexPattern.h
@@ -55,32 +55,33 @@ struct CharacterRange {
     }
 };
 
 /*
  * Wraps a table and indicates inversion. Can be efficiently borrowed
  * between character classes, so it's refcounted.
  */
 struct CharacterClassTable {
+
+    JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
+
     const char* m_table;
     bool m_inverted;
     jsrefcount m_refcount;
 
     /* Ownership transferred to caller. */
     static CharacterClassTable *create(const char* table, bool inverted)
     {
         // FIXME: bug 574459 -- no NULL checks done by any of the callers, all
         // of which are in RegExpJitTables.h.
-        /* We can't (easily) use js_new() here because the constructor is private. */
-        void *memory = js_malloc(sizeof(CharacterClassTable));
-        return memory ? new(memory) CharacterClassTable(table, inverted) : NULL;
+        return js::OffTheBooks::new_<CharacterClassTable>(table, inverted);
     }
 
     void incref() { JS_ATOMIC_INCREMENT(&m_refcount); }
-    void decref() { if (JS_ATOMIC_DECREMENT(&m_refcount) == 0) js_delete(this); }
+    void decref() { if (JS_ATOMIC_DECREMENT(&m_refcount) == 0) js::Foreground::delete_(this); }
 
 private:
     CharacterClassTable(const char* table, bool inverted)
         : m_table(table)
         , m_inverted(inverted)
         , m_refcount(0)
     {
     }
@@ -225,16 +226,19 @@ struct PatternTerm {
     void quantify(unsigned count, QuantifierType type)
     {
         quantityCount = count;
         quantityType = type;
     }
 };
 
 struct PatternAlternative {
+
+    JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
+
     PatternAlternative(PatternDisjunction* disjunction)
         : m_parent(disjunction)
         , m_onceThrough(false)
         , m_hasFixedSize(false)
         , m_startsWithBOL(false)
         , m_containsBOL(false)
     {
     }
@@ -270,35 +274,38 @@ struct PatternAlternative {
     bool m_containsBOL : 1;
 };
 
 template<typename T, size_t N, class AP>
 static inline void
 deleteAllValues(js::Vector<T*,N,AP> &vector)
 {
     for (T** t = vector.begin(); t < vector.end(); ++t)
-        js_delete(*t);
+        js::Foreground::delete_(*t);
 }
 
 struct PatternDisjunction {
+
+    JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
+
     PatternDisjunction(PatternAlternative* parent = 0)
         : m_parent(parent)
         , m_hasFixedSize(false)
     {
     }
     
     ~PatternDisjunction()
     {
         deleteAllValues(m_alternatives);
     }
 
     PatternAlternative* addNewAlternative()
     {
         // FIXME: bug 574459 -- no NULL check
-        PatternAlternative* alternative = js_new<PatternAlternative>(this);
+        PatternAlternative* alternative = js::OffTheBooks::new_<PatternAlternative>(this);
         m_alternatives.append(alternative);
         return alternative;
     }
 
     js::Vector<PatternAlternative*, 0, js::SystemAllocPolicy> m_alternatives;
     PatternAlternative* m_parent;
     unsigned m_minimumSize;
     unsigned m_callFrameSize;
--- a/layout/style/nsNthIndexCache.h
+++ b/layout/style/nsNthIndexCache.h
@@ -102,19 +102,19 @@ private:
     // If 0, the node is not at any index in its parent.
     // The first subscript is 0 for -child and 1 for -of-type, the second
     // subscript is 0 for nth- and 1 for nth-last-.
     PRInt32 mNthIndices[2][2];
   };
 
   class SystemAllocPolicy {
   public:
-    void *malloc(size_t bytes) { return ::malloc(bytes); }
-    void *realloc(void *p, size_t bytes) { return ::realloc(p, bytes); }
-    void free(void *p) { ::free(p); }
+    void *malloc_(size_t bytes) { return ::malloc(bytes); }
+    void *realloc_(void *p, size_t bytes) { return ::realloc(p, bytes); }
+    void free_(void *p) { ::free(p); }
     void reportAllocOverflow() const {}
   };
 
   typedef js::HashMap<nsIContent*, CacheEntry, js::DefaultHasher<nsIContent*>,
                       SystemAllocPolicy> Cache;
 
   Cache mCache;
 };
--- a/xpcom/build/nsXULAppAPI.h
+++ b/xpcom/build/nsXULAppAPI.h
@@ -540,17 +540,17 @@ class MessageLoop;
 
 XRE_API(void,
         XRE_ShutdownChildProcess, ())
 
 XRE_API(MessageLoop*,
         XRE_GetIOMessageLoop, ())
 
 struct JSContext;
-struct JSString;
+class JSString;
 
 XRE_API(bool,
         XRE_SendTestShellCommand, (JSContext* aCx,
                                    JSString* aCommand,
                                    void* aCallback))
 struct JSObject;
 
 XRE_API(bool,