Bug 809292 - Deal with all source data allocation in one function. r=njn

This commit is contained in:
Benjamin Peterson 2012-11-08 09:24:46 -05:00
parent 4ecc61cba4
commit eb9e9406cc
2 changed files with 42 additions and 31 deletions

View File

@ -944,8 +944,7 @@ SourceCompressorThread::internalCompress()
// Try to keep the maximum memory usage down by only allocating half the // Try to keep the maximum memory usage down by only allocating half the
// size of the string, first. // size of the string, first.
size_t firstSize = nbytes / 2; size_t firstSize = nbytes / 2;
ss->data.compressed = static_cast<unsigned char *>(js_malloc(firstSize)); if (!ss->adjustDataSize(firstSize))
if (!ss->data.compressed)
return false; return false;
Compressor comp(reinterpret_cast<const unsigned char *>(tok->chars), nbytes); Compressor comp(reinterpret_cast<const unsigned char *>(tok->chars), nbytes);
if (!comp.init()) if (!comp.init())
@ -964,13 +963,8 @@ SourceCompressorThread::internalCompress()
// The compressed output is greater than half the size of the // The compressed output is greater than half the size of the
// original string. Reallocate to the full size. // original string. Reallocate to the full size.
void *newmem = js_realloc(ss->data.compressed, nbytes); if (!ss->adjustDataSize(nbytes))
if (!newmem) {
js_free(ss->data.compressed);
ss->data.compressed = NULL;
return false; return false;
}
ss->data.compressed = static_cast<unsigned char *>(newmem);
comp.setOutput(ss->data.compressed, nbytes); comp.setOutput(ss->data.compressed, nbytes);
break; break;
} }
@ -988,22 +982,12 @@ SourceCompressorThread::internalCompress()
} }
#endif #endif
if (compressedLength == 0) { if (compressedLength == 0) {
// Note ss->data.source might be NULL. if (!ss->adjustDataSize(nbytes))
jschar *buf = static_cast<jschar *>(js_realloc(ss->data.source, nbytes));
if (!buf) {
if (ss->data.source) {
js_free(ss->data.source);
ss->data.source = NULL;
}
return false; return false;
}
ss->data.source = buf;
PodCopy(ss->data.source, tok->chars, ss->length()); PodCopy(ss->data.source, tok->chars, ss->length());
} else { } else {
// Shrink the buffer to the size of the compressed data. Shouldn't fail. // Shrink the buffer to the size of the compressed data. Shouldn't fail.
void *newmem = js_realloc(ss->data.compressed, compressedLength); JS_ALWAYS_TRUE(ss->adjustDataSize(compressedLength));
JS_ASSERT(newmem);
ss->data.compressed = static_cast<unsigned char *>(newmem);
} }
ss->compressedLength_ = compressedLength; ss->compressedLength_ = compressedLength;
return true; return true;
@ -1085,6 +1069,29 @@ SourceCompressorThread::abort(SourceCompressionToken *userTok)
} }
#endif /* JS_THREADSAFE */ #endif /* JS_THREADSAFE */
static const unsigned char emptySource[] = "";
/* Adjust the amount of memory this script source uses for source data,
reallocating if needed. */
bool
ScriptSource::adjustDataSize(size_t nbytes)
{
// Allocating 0 bytes has undefined behavior, so special-case it.
if (nbytes == 0) {
if (data.compressed != emptySource)
js_free(data.compressed);
data.compressed = const_cast<unsigned char *>(emptySource);
return true;
}
// |data.compressed| can be NULL.
void *buf = js_realloc(data.compressed, nbytes);
if (!buf && data.compressed != emptySource)
js_free(data.compressed);
data.compressed = static_cast<unsigned char *>(buf);
return !!data.compressed;
}
void void
JSScript::setScriptSource(ScriptSource *ss) JSScript::setScriptSource(ScriptSource *ss)
{ {
@ -1210,8 +1217,7 @@ ScriptSource::setSourceCopy(JSContext *cx, StableCharPtr src, uint32_t length,
} else } else
#endif #endif
{ {
data.source = cx->runtime->pod_malloc<jschar>(length); if (!adjustDataSize(sizeof(jschar) * length))
if (!data.source)
return false; return false;
PodCopy(data.source, src.get(), length_); PodCopy(data.source, src.get(), length_);
} }
@ -1257,7 +1263,7 @@ void
ScriptSource::destroy(JSRuntime *rt) ScriptSource::destroy(JSRuntime *rt)
{ {
JS_ASSERT(ready()); JS_ASSERT(ready());
js_free(data.compressed); adjustDataSize(0);
js_free(sourceMap_); js_free(sourceMap_);
#ifdef DEBUG #ifdef DEBUG
ready_ = false; ready_ = false;
@ -1270,9 +1276,9 @@ ScriptSource::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf)
{ {
JS_ASSERT(ready()); JS_ASSERT(ready());
// data is a union, but both members are pointers to allocated memory or // |data| is a union, but both members are pointers to allocated memory,
// NULL, so just using compressed will work. // |emptySource|, or NULL, so just using |data.compressed| will work.
return mallocSizeOf(this) + mallocSizeOf(data.compressed); return mallocSizeOf(this) + ((data.compressed != emptySource) ? mallocSizeOf(data.compressed) : 0);
} }
template<XDRMode mode> template<XDRMode mode>
@ -1305,8 +1311,7 @@ ScriptSource::performXDR(XDRState<mode> *xdr)
size_t byteLen = compressedLength ? compressedLength : (length * sizeof(jschar)); size_t byteLen = compressedLength ? compressedLength : (length * sizeof(jschar));
if (mode == XDR_DECODE) { if (mode == XDR_DECODE) {
data.compressed = static_cast<unsigned char *>(xdr->cx()->malloc_(byteLen)); if (!adjustDataSize(byteLen))
if (!data.compressed)
return false; return false;
} }
if (!xdr->codeBytes(data.compressed, byteLen)) { if (!xdr->codeBytes(data.compressed, byteLen)) {

View File

@ -990,9 +990,14 @@ struct ScriptSource
friend class SourceCompressorThread; friend class SourceCompressorThread;
private: private:
union { union {
// When the script source is ready, compressedLength_ != 0 implies // Before setSourceCopy or setSource are successfully called, this union
// compressed holds the compressed data; otherwise, source holds the // has a NULL pointer. When the script source is ready,
// uncompressed source. // compressedLength_ != 0 implies compressed holds the compressed data;
// otherwise, source holds the uncompressed source. There is a special
// pointer |emptySource| for source code for length 0.
//
// The only function allowed to malloc, realloc, or free the pointers in
// this union is adjustDataSize(). Don't do it elsewhere.
jschar *source; jschar *source;
unsigned char *compressed; unsigned char *compressed;
} data; } data;
@ -1068,6 +1073,7 @@ struct ScriptSource
size_t computedSizeOfData() const { size_t computedSizeOfData() const {
return compressed() ? compressedLength_ : sizeof(jschar) * length_; return compressed() ? compressedLength_ : sizeof(jschar) * length_;
} }
bool adjustDataSize(size_t nbytes);
}; };
class ScriptSourceHolder class ScriptSourceHolder