зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
7986d9113d
Коммит
0a424b0867
|
@ -801,6 +801,7 @@ JSRuntime::JSRuntime()
|
||||||
negativeInfinityValue(UndefinedValue()),
|
negativeInfinityValue(UndefinedValue()),
|
||||||
positiveInfinityValue(UndefinedValue()),
|
positiveInfinityValue(UndefinedValue()),
|
||||||
emptyString(NULL),
|
emptyString(NULL),
|
||||||
|
sourceHook(NULL),
|
||||||
debugMode(false),
|
debugMode(false),
|
||||||
spsProfiler(thisFromCtor()),
|
spsProfiler(thisFromCtor()),
|
||||||
profilingScripts(false),
|
profilingScripts(false),
|
||||||
|
|
|
@ -716,6 +716,8 @@ struct JSRuntime : js::RuntimeFriendFields
|
||||||
return !JS_CLIST_IS_EMPTY(&contextList);
|
return !JS_CLIST_IS_EMPTY(&contextList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_SourceHook sourceHook;
|
||||||
|
|
||||||
/* Per runtime debug hooks -- see jsprvtd.h and jsdbgapi.h. */
|
/* Per runtime debug hooks -- see jsprvtd.h and jsdbgapi.h. */
|
||||||
JSDebugHooks debugHooks;
|
JSDebugHooks debugHooks;
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,12 @@
|
||||||
using namespace js;
|
using namespace js;
|
||||||
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_FRIEND_API(void)
|
||||||
JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
|
JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
|
||||||
{
|
{
|
||||||
|
|
|
@ -175,6 +175,11 @@ JS_END_EXTERN_C
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#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 {
|
namespace js {
|
||||||
|
|
||||||
struct RuntimeFriendFields {
|
struct RuntimeFriendFields {
|
||||||
|
|
|
@ -590,7 +590,10 @@ JSFunction::toString(JSContext *cx, bool bodyOnly, bool lambdaParen)
|
||||||
return NULL;
|
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));
|
RootedString src(cx, script()->sourceData(cx));
|
||||||
if (!src)
|
if (!src)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -686,6 +689,13 @@ JSFunction::toString(JSContext *cx, bool bodyOnly, bool lambdaParen)
|
||||||
if (!out.append(")"))
|
if (!out.append(")"))
|
||||||
return NULL;
|
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 {
|
} else {
|
||||||
JS_ASSERT(!(flags & JSFUN_EXPR_CLOSURE));
|
JS_ASSERT(!(flags & JSFUN_EXPR_CLOSURE));
|
||||||
if ((!bodyOnly && !out.append("() {\n ")) ||
|
if ((!bodyOnly && !out.append("() {\n ")) ||
|
||||||
|
|
|
@ -1070,6 +1070,35 @@ SourceCompressorThread::waitOnCompression(SourceCompressionToken *userTok)
|
||||||
}
|
}
|
||||||
#endif /* JS_THREADSAFE */
|
#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 *
|
JSFixedString *
|
||||||
JSScript::sourceData(JSContext *cx)
|
JSScript::sourceData(JSContext *cx)
|
||||||
{
|
{
|
||||||
|
@ -1147,7 +1176,8 @@ ScriptSource::substring(JSContext *cx, uint32_t start, uint32_t stop)
|
||||||
|
|
||||||
ScriptSource *
|
ScriptSource *
|
||||||
ScriptSource::createFromSource(JSContext *cx, const jschar *src, uint32_t length,
|
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)));
|
ScriptSource *ss = static_cast<ScriptSource *>(cx->malloc_(sizeof(*ss)));
|
||||||
if (!ss)
|
if (!ss)
|
||||||
|
@ -1160,6 +1190,7 @@ ScriptSource::createFromSource(JSContext *cx, const jschar *src, uint32_t length
|
||||||
}
|
}
|
||||||
ss->next = NULL;
|
ss->next = NULL;
|
||||||
ss->length_ = length;
|
ss->length_ = length;
|
||||||
|
ss->compressedLength = 0;
|
||||||
ss->marked = ss->onRuntime_ = false;
|
ss->marked = ss->onRuntime_ = false;
|
||||||
ss->argumentsNotIncluded_ = argumentsNotIncluded;
|
ss->argumentsNotIncluded_ = argumentsNotIncluded;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -1176,6 +1207,8 @@ ScriptSource::createFromSource(JSContext *cx, const jschar *src, uint32_t length
|
||||||
ss->marked = true;
|
ss->marked = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
JS_ASSERT_IF(ownSource, !tok);
|
||||||
|
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
if (tok) {
|
if (tok) {
|
||||||
tok->ss = ss;
|
tok->ss = ss;
|
||||||
|
@ -1183,21 +1216,23 @@ ScriptSource::createFromSource(JSContext *cx, const jschar *src, uint32_t length
|
||||||
cx->runtime->sourceCompressorThread.compress(tok);
|
cx->runtime->sourceCompressorThread.compress(tok);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
ss->considerCompressing(cx->runtime, src);
|
ss->considerCompressing(cx->runtime, src, ownSource);
|
||||||
|
|
||||||
|
|
||||||
return ss;
|
return ss;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ScriptSource::considerCompressing(JSRuntime *rt, const jschar *src)
|
ScriptSource::considerCompressing(JSRuntime *rt, const jschar *src, bool ownSource)
|
||||||
{
|
{
|
||||||
JS_ASSERT(!ready());
|
JS_ASSERT(!ready());
|
||||||
const size_t memlen = length_ * sizeof(jschar);
|
const size_t memlen = length_ * sizeof(jschar);
|
||||||
const size_t COMPRESS_THRESHOLD = 512;
|
const size_t COMPRESS_THRESHOLD = 512;
|
||||||
|
|
||||||
size_t compressedLen;
|
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,
|
TryCompressString(reinterpret_cast<const unsigned char *>(src), memlen,
|
||||||
data.compressed, &compressedLen))
|
data.compressed, &compressedLen))
|
||||||
{
|
{
|
||||||
|
@ -1207,7 +1242,6 @@ ScriptSource::considerCompressing(JSRuntime *rt, const jschar *src)
|
||||||
data.compressed = static_cast<unsigned char *>(mem);
|
data.compressed = static_cast<unsigned char *>(mem);
|
||||||
JS_ASSERT(data.compressed);
|
JS_ASSERT(data.compressed);
|
||||||
} else {
|
} else {
|
||||||
compressedLength = 0;
|
|
||||||
PodCopy(data.source, src, length_);
|
PodCopy(data.source, src, length_);
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
|
@ -620,6 +620,8 @@ struct JSScript : public js::gc::Cell
|
||||||
|
|
||||||
JSFixedString *sourceData(JSContext *cx);
|
JSFixedString *sourceData(JSContext *cx);
|
||||||
|
|
||||||
|
bool loadSource(JSContext *cx, bool *worked);
|
||||||
|
|
||||||
/* Return whether this script was compiled for 'eval' */
|
/* Return whether this script was compiled for 'eval' */
|
||||||
bool isForEval() { return isCachedEval || isActiveEval; }
|
bool isForEval() { return isCachedEval || isActiveEval; }
|
||||||
|
|
||||||
|
@ -978,7 +980,8 @@ struct ScriptSource
|
||||||
const jschar *src,
|
const jschar *src,
|
||||||
uint32_t length,
|
uint32_t length,
|
||||||
bool argumentsNotIncluded = false,
|
bool argumentsNotIncluded = false,
|
||||||
SourceCompressionToken *tok = NULL);
|
SourceCompressionToken *tok = NULL,
|
||||||
|
bool ownSource = false);
|
||||||
void attachToRuntime(JSRuntime *rt);
|
void attachToRuntime(JSRuntime *rt);
|
||||||
void mark() { JS_ASSERT(ready_); JS_ASSERT(onRuntime_); marked = true; }
|
void mark() { JS_ASSERT(ready_); JS_ASSERT(onRuntime_); marked = true; }
|
||||||
void destroy(JSRuntime *rt);
|
void destroy(JSRuntime *rt);
|
||||||
|
@ -1000,7 +1003,7 @@ struct ScriptSource
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool compressed() { return !!compressedLength; }
|
bool compressed() { return !!compressedLength; }
|
||||||
void considerCompressing(JSRuntime *rt, const jschar *src);
|
void considerCompressing(JSRuntime *rt, const jschar *src, bool ownSource = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
|
|
Загрузка…
Ссылка в новой задаче