Bug 761723 - Add a runtime hook to retrieve source that wasn't saved. r=luke

--HG--
extra : rebase_source : de2e88f79e1e2a4a75ff5c5b296dbae052e4b076
This commit is contained in:
Benjamin Peterson 2012-07-20 20:19:17 +02:00
parent 3e366b4012
commit 8e3b8e5b26
7 changed files with 69 additions and 8 deletions

View File

@ -801,6 +801,7 @@ JSRuntime::JSRuntime()
negativeInfinityValue(UndefinedValue()),
positiveInfinityValue(UndefinedValue()),
emptyString(NULL),
sourceHook(NULL),
debugMode(false),
spsProfiler(thisFromCtor()),
profilingScripts(false),

View File

@ -716,6 +716,8 @@ struct JSRuntime : js::RuntimeFriendFields
return !JS_CLIST_IS_EMPTY(&contextList);
}
JS_SourceHook sourceHook;
/* Per runtime debug hooks -- see jsprvtd.h and jsdbgapi.h. */
JSDebugHooks debugHooks;

View File

@ -22,6 +22,12 @@
using namespace js;
using namespace JS;
JS_FRIEND_API(void)
JS_SetSourceHook(JSRuntime *rt, JS_SourceHook hook)
{
rt->sourceHook = hook;
}
JS_FRIEND_API(void)
JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
{

View File

@ -175,6 +175,11 @@ JS_END_EXTERN_C
#ifdef __cplusplus
typedef bool (* JS_SourceHook)(JSContext *cx, JSScript *script, char **src, uint32_t *length);
extern JS_FRIEND_API(void)
JS_SetSourceHook(JSRuntime *rt, JS_SourceHook hook);
namespace js {
struct RuntimeFriendFields {

View File

@ -590,7 +590,10 @@ JSFunction::toString(JSContext *cx, bool bodyOnly, bool lambdaParen)
return NULL;
}
}
if (isInterpreted() && script()->source) {
bool haveSource = isInterpreted();
if (haveSource && !script()->source && !script()->loadSource(cx, &haveSource))
return NULL;
if (haveSource) {
RootedString src(cx, script()->sourceData(cx));
if (!src)
return NULL;
@ -686,6 +689,13 @@ JSFunction::toString(JSContext *cx, bool bodyOnly, bool lambdaParen)
if (!out.append(")"))
return NULL;
}
} else if (isInterpreted()) {
if ((!bodyOnly && !out.append("() {\n ")) ||
!out.append("[sourceless code]") ||
(!bodyOnly && !out.append("\n}")))
return NULL;
if (!lambdaParen && (flags & JSFUN_LAMBDA) && (!out.append(")")))
return NULL;
} else {
JS_ASSERT(!(flags & JSFUN_EXPR_CLOSURE));
if ((!bodyOnly && !out.append("() {\n ")) ||

View File

@ -1070,6 +1070,35 @@ SourceCompressorThread::waitOnCompression(SourceCompressionToken *userTok)
}
#endif /* JS_THREADSAFE */
bool
JSScript::loadSource(JSContext *cx, bool *worked)
{
JS_ASSERT(!source);
*worked = false;
if (!cx->runtime->sourceHook)
return true;
char *src = NULL;
uint32_t length;
if (!cx->runtime->sourceHook(cx, this, &src, &length))
return false;
if (!src)
return true;
size_t newLength = length;
jschar *usrc = InflateString(cx, src, &newLength);
cx->free_(src);
if (!usrc)
return false;
ScriptSource *ss = ScriptSource::createFromSource(cx, usrc, length, false, NULL, true);
if (!ss) {
cx->free_(usrc);
return false;
}
source = ss;
ss->attachToRuntime(cx->runtime);
*worked = true;
return true;
}
JSFixedString *
JSScript::sourceData(JSContext *cx)
{
@ -1147,7 +1176,8 @@ ScriptSource::substring(JSContext *cx, uint32_t start, uint32_t stop)
ScriptSource *
ScriptSource::createFromSource(JSContext *cx, const jschar *src, uint32_t length,
bool argumentsNotIncluded, SourceCompressionToken *tok)
bool argumentsNotIncluded, SourceCompressionToken *tok,
bool ownSource)
{
ScriptSource *ss = static_cast<ScriptSource *>(cx->malloc_(sizeof(*ss)));
if (!ss)
@ -1160,6 +1190,7 @@ ScriptSource::createFromSource(JSContext *cx, const jschar *src, uint32_t length
}
ss->next = NULL;
ss->length_ = length;
ss->compressedLength = 0;
ss->marked = ss->onRuntime_ = false;
ss->argumentsNotIncluded_ = argumentsNotIncluded;
#ifdef DEBUG
@ -1176,6 +1207,8 @@ ScriptSource::createFromSource(JSContext *cx, const jschar *src, uint32_t length
ss->marked = true;
#endif
JS_ASSERT_IF(ownSource, !tok);
#ifdef JS_THREADSAFE
if (tok) {
tok->ss = ss;
@ -1183,21 +1216,23 @@ ScriptSource::createFromSource(JSContext *cx, const jschar *src, uint32_t length
cx->runtime->sourceCompressorThread.compress(tok);
} else
#endif
ss->considerCompressing(cx->runtime, src);
ss->considerCompressing(cx->runtime, src, ownSource);
return ss;
}
void
ScriptSource::considerCompressing(JSRuntime *rt, const jschar *src)
ScriptSource::considerCompressing(JSRuntime *rt, const jschar *src, bool ownSource)
{
JS_ASSERT(!ready());
const size_t memlen = length_ * sizeof(jschar);
const size_t COMPRESS_THRESHOLD = 512;
size_t compressedLen;
if (memlen >= COMPRESS_THRESHOLD &&
if (ownSource) {
data.source = const_cast<jschar *>(src);
} else if (memlen >= COMPRESS_THRESHOLD &&
TryCompressString(reinterpret_cast<const unsigned char *>(src), memlen,
data.compressed, &compressedLen))
{
@ -1207,7 +1242,6 @@ ScriptSource::considerCompressing(JSRuntime *rt, const jschar *src)
data.compressed = static_cast<unsigned char *>(mem);
JS_ASSERT(data.compressed);
} else {
compressedLength = 0;
PodCopy(data.source, src, length_);
}
#ifdef DEBUG

View File

@ -620,6 +620,8 @@ struct JSScript : public js::gc::Cell
JSFixedString *sourceData(JSContext *cx);
bool loadSource(JSContext *cx, bool *worked);
/* Return whether this script was compiled for 'eval' */
bool isForEval() { return isCachedEval || isActiveEval; }
@ -978,7 +980,8 @@ struct ScriptSource
const jschar *src,
uint32_t length,
bool argumentsNotIncluded = false,
SourceCompressionToken *tok = NULL);
SourceCompressionToken *tok = NULL,
bool ownSource = false);
void attachToRuntime(JSRuntime *rt);
void mark() { JS_ASSERT(ready_); JS_ASSERT(onRuntime_); marked = true; }
void destroy(JSRuntime *rt);
@ -1000,7 +1003,7 @@ struct ScriptSource
private:
bool compressed() { return !!compressedLength; }
void considerCompressing(JSRuntime *rt, const jschar *src);
void considerCompressing(JSRuntime *rt, const jschar *src, bool ownSource = false);
};
#ifdef JS_THREADSAFE