mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to fx-team. a=merge
This commit is contained in:
commit
0cd1d876ea
5
CLOBBER
5
CLOBBER
@ -22,6 +22,5 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 800200: Removing the old JavaScript debugging API, js/jsd. I'm advised
|
||||
that our build system doesn't cope well with deletions, and that a spoonful
|
||||
of clobber helps the medicine go down (in a most delightful way).
|
||||
Bustage pile-up on inbound that appears to need clobbering to go away for good.
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7a32f4ce7f922ed174946cfe322f3d6df40f18ea"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="b597b86274ab109d7ef530bc0c4b6adccddae4e4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7a32f4ce7f922ed174946cfe322f3d6df40f18ea"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="b597b86274ab109d7ef530bc0c4b6adccddae4e4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="96cdde4b5b5d8d3785b36c3c68cd746aff3005cc"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7f9ec13a30f1b2cc8bdb1a199b7da54b9ab8860f"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="276ce45e78b09c4a4ee643646f691d22804754c1">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7a32f4ce7f922ed174946cfe322f3d6df40f18ea"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="b597b86274ab109d7ef530bc0c4b6adccddae4e4"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7a32f4ce7f922ed174946cfe322f3d6df40f18ea"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="b597b86274ab109d7ef530bc0c4b6adccddae4e4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7a32f4ce7f922ed174946cfe322f3d6df40f18ea"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="b597b86274ab109d7ef530bc0c4b6adccddae4e4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="96cdde4b5b5d8d3785b36c3c68cd746aff3005cc"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7f9ec13a30f1b2cc8bdb1a199b7da54b9ab8860f"/>
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "dd04ca4b91cdb034a4b90a924b14cd066677b05b",
|
||||
"revision": "92bddc1a99aa2d80d58fc28749fecedbf5c692f1",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7a32f4ce7f922ed174946cfe322f3d6df40f18ea"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="b597b86274ab109d7ef530bc0c4b6adccddae4e4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7a32f4ce7f922ed174946cfe322f3d6df40f18ea"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="b597b86274ab109d7ef530bc0c4b6adccddae4e4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7a32f4ce7f922ed174946cfe322f3d6df40f18ea"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="b597b86274ab109d7ef530bc0c4b6adccddae4e4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="96cdde4b5b5d8d3785b36c3c68cd746aff3005cc"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7f9ec13a30f1b2cc8bdb1a199b7da54b9ab8860f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7a32f4ce7f922ed174946cfe322f3d6df40f18ea"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="b597b86274ab109d7ef530bc0c4b6adccddae4e4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
19
client.mk
19
client.mk
@ -165,7 +165,7 @@ OBJDIR_TARGETS = install export libs clean realclean distclean maybe_clobber_pro
|
||||
|
||||
# The default rule is build
|
||||
build::
|
||||
$(MAKE) -f $(TOPSRCDIR)/client.mk $(if $(MOZ_PGO),profiledbuild,realbuild)
|
||||
$(MAKE) -f $(TOPSRCDIR)/client.mk $(if $(MOZ_PGO),profiledbuild,realbuild) CREATE_MOZCONFIG_JSON=
|
||||
|
||||
# Define mkdir
|
||||
include $(TOPSRCDIR)/config/makefiles/makeutils.mk
|
||||
@ -218,12 +218,12 @@ everything: clean build
|
||||
# is usable in multi-pass builds, where you might not have a runnable
|
||||
# application until all the build passes and postflight scripts have run.
|
||||
profiledbuild::
|
||||
$(MAKE) -f $(TOPSRCDIR)/client.mk realbuild MOZ_PROFILE_GENERATE=1 MOZ_PGO_INSTRUMENTED=1
|
||||
$(MAKE) -f $(TOPSRCDIR)/client.mk realbuild MOZ_PROFILE_GENERATE=1 MOZ_PGO_INSTRUMENTED=1 CREATE_MOZCONFIG_JSON=
|
||||
$(MAKE) -C $(OBJDIR) package MOZ_PGO_INSTRUMENTED=1 MOZ_INTERNAL_SIGNING_FORMAT= MOZ_EXTERNAL_SIGNING_FORMAT=
|
||||
rm -f $(OBJDIR)/jarlog/en-US.log
|
||||
MOZ_PGO_INSTRUMENTED=1 JARLOG_FILE=jarlog/en-US.log EXTRA_TEST_ARGS=10 $(MAKE) -C $(OBJDIR) pgo-profile-run
|
||||
$(MAKE) -f $(TOPSRCDIR)/client.mk maybe_clobber_profiledbuild
|
||||
$(MAKE) -f $(TOPSRCDIR)/client.mk realbuild MOZ_PROFILE_USE=1
|
||||
$(MAKE) -f $(TOPSRCDIR)/client.mk maybe_clobber_profiledbuild CREATE_MOZCONFIG_JSON=
|
||||
$(MAKE) -f $(TOPSRCDIR)/client.mk realbuild MOZ_PROFILE_USE=1 CREATE_MOZCONFIG_JSON=
|
||||
|
||||
#####################################################
|
||||
# Build date unification
|
||||
@ -333,9 +333,14 @@ configure-preqs = \
|
||||
$(OBJDIR)/.mozconfig.json \
|
||||
$(NULL)
|
||||
|
||||
CREATE_MOZCONFIG_JSON := $(shell $(TOPSRCDIR)/mach environment --format=json -o $(OBJDIR)/.mozconfig.json)
|
||||
$(OBJDIR)/.mozconfig.json: $(call mkdir_deps,$(OBJDIR))
|
||||
@$(TOPSRCDIR)/mach environment --format=json -o $@
|
||||
CREATE_MOZCONFIG_JSON = $(shell $(TOPSRCDIR)/mach environment --format=json -o $(OBJDIR)/.mozconfig.json)
|
||||
# Force CREATE_MOZCONFIG_JSON above to be resolved, without side effects in
|
||||
# case the result is non empty, and allowing an override on the make command
|
||||
# line not running the command (using := $(shell) still runs the shell command).
|
||||
ifneq (,$(CREATE_MOZCONFIG_JSON))
|
||||
endif
|
||||
|
||||
$(OBJDIR)/.mozconfig.json: $(call mkdir_deps,$(OBJDIR)) ;
|
||||
|
||||
save-mozconfig: $(FOUND_MOZCONFIG)
|
||||
-cp $(FOUND_MOZCONFIG) $(OBJDIR)/.mozconfig
|
||||
|
@ -895,7 +895,7 @@ nsScriptLoader::AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest)
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
|
||||
JS::CompileOptions options(cx);
|
||||
FillCompileOptionsForRequest(aRequest, global, &options);
|
||||
FillCompileOptionsForRequest(jsapi, aRequest, global, &options);
|
||||
|
||||
if (!JS::CanCompileOffThread(cx, options, aRequest->mScriptTextLength)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -1066,7 +1066,8 @@ nsScriptLoader::GetScriptGlobalObject()
|
||||
}
|
||||
|
||||
void
|
||||
nsScriptLoader::FillCompileOptionsForRequest(nsScriptLoadRequest *aRequest,
|
||||
nsScriptLoader::FillCompileOptionsForRequest(const AutoJSAPI &jsapi,
|
||||
nsScriptLoadRequest *aRequest,
|
||||
JS::Handle<JSObject *> aScopeChain,
|
||||
JS::CompileOptions *aOptions)
|
||||
{
|
||||
@ -1085,15 +1086,9 @@ nsScriptLoader::FillCompileOptionsForRequest(nsScriptLoadRequest *aRequest,
|
||||
aOptions->setOriginPrincipals(nsJSPrincipals::get(aRequest->mOriginPrincipal));
|
||||
}
|
||||
|
||||
AutoJSContext cx;
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JS::Value> elementVal(cx);
|
||||
MOZ_ASSERT(aRequest->mElement);
|
||||
// XXXbz this is super-fragile, because the code that _uses_ the
|
||||
// JS::CompileOptions is nowhere near us, but we have to coordinate
|
||||
// compartments with it... and in particular, it will compile in the
|
||||
// compartment of aScopeChain, so we want to wrap into that compartment as
|
||||
// well.
|
||||
JSAutoCompartment ac(cx, aScopeChain);
|
||||
if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, aRequest->mElement,
|
||||
&elementVal,
|
||||
/* aAllowWrapping = */ true))) {
|
||||
@ -1165,7 +1160,7 @@ nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest,
|
||||
}
|
||||
|
||||
JS::CompileOptions options(entryScript.cx());
|
||||
FillCompileOptionsForRequest(aRequest, global, &options);
|
||||
FillCompileOptionsForRequest(entryScript, aRequest, global, &options);
|
||||
rv = nsJSUtils::EvaluateString(entryScript.cx(), aSrcBuf, global, options,
|
||||
aOffThreadToken);
|
||||
}
|
||||
|
@ -25,6 +25,12 @@ namespace JS {
|
||||
class SourceBufferHolder;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class AutoJSAPI;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// Script loader implementation
|
||||
//////////////////////////////////////////////////////////////
|
||||
@ -312,7 +318,8 @@ private:
|
||||
void **aOffThreadToken);
|
||||
|
||||
already_AddRefed<nsIScriptGlobalObject> GetScriptGlobalObject();
|
||||
void FillCompileOptionsForRequest(nsScriptLoadRequest *aRequest,
|
||||
void FillCompileOptionsForRequest(const mozilla::dom::AutoJSAPI &jsapi,
|
||||
nsScriptLoadRequest *aRequest,
|
||||
JS::Handle<JSObject *> aScopeChain,
|
||||
JS::CompileOptions *aOptions);
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "gfxPattern.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "gfxUtils.h"
|
||||
|
||||
#include "CanvasUtils.h"
|
||||
@ -437,6 +438,11 @@ WebGLContext::SetContextOptions(JSContext* aCx, JS::Handle<JS::Value> aOptions)
|
||||
// enforce that if stencil is specified, we also give back depth
|
||||
newOpts.depth |= newOpts.stencil;
|
||||
|
||||
// Don't do antialiasing if we've disabled MSAA.
|
||||
if (!gfxPrefs::MSAALevel()) {
|
||||
newOpts.antialias = false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
GenerateWarning("aaHint: %d stencil: %d depth: %d alpha: %d premult: %d preserve: %d\n",
|
||||
newOpts.antialias ? 1 : 0,
|
||||
|
@ -119,10 +119,6 @@ bool WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
|
||||
gl->IsSupported(GLFeature::texture_half_float);
|
||||
case WebGLExtensionID::OES_texture_half_float_linear:
|
||||
return gl->IsSupported(GLFeature::texture_half_float_linear);
|
||||
case WebGLExtensionID::WEBGL_color_buffer_float:
|
||||
return WebGLExtensionColorBufferFloat::IsSupported(this);
|
||||
case WebGLExtensionID::EXT_color_buffer_half_float:
|
||||
return WebGLExtensionColorBufferHalfFloat::IsSupported(this);
|
||||
case WebGLExtensionID::OES_vertex_array_object:
|
||||
return WebGLExtensionVertexArray::IsSupported(this);
|
||||
case WebGLExtensionID::EXT_texture_filter_anisotropic:
|
||||
@ -168,6 +164,10 @@ bool WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
|
||||
switch (ext) {
|
||||
case WebGLExtensionID::EXT_blend_minmax:
|
||||
return WebGLExtensionBlendMinMax::IsSupported(this);
|
||||
case WebGLExtensionID::EXT_color_buffer_half_float:
|
||||
return WebGLExtensionColorBufferHalfFloat::IsSupported(this);
|
||||
case WebGLExtensionID::WEBGL_color_buffer_float:
|
||||
return WebGLExtensionColorBufferFloat::IsSupported(this);
|
||||
default:
|
||||
// For warnings-as-errors.
|
||||
break;
|
||||
|
@ -416,7 +416,7 @@ skip-if = true # bug 493692
|
||||
skip-if = true # bug 1021673
|
||||
[test_seek_out_of_range.html]
|
||||
[test_seek.html]
|
||||
skip-if = true # Intermittent test failures in bug 1023564 and bug 981153
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' # Intermittent test failures in bug 1023564 and bug 981153
|
||||
[test_seek2.html]
|
||||
[test_seekable1.html]
|
||||
[test_seekable2.html]
|
||||
|
@ -68,16 +68,10 @@ SVGPathElement::PathLength()
|
||||
}
|
||||
|
||||
float
|
||||
SVGPathElement::GetTotalLength(ErrorResult& rv)
|
||||
SVGPathElement::GetTotalLength()
|
||||
{
|
||||
RefPtr<Path> flat = GetPathForLengthOrPositionMeasuring();
|
||||
|
||||
if (!flat) {
|
||||
rv.Throw(NS_ERROR_FAILURE);
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
return flat->ComputeLength();
|
||||
return flat ? flat->ComputeLength() : 0.f;
|
||||
}
|
||||
|
||||
already_AddRefed<nsISVGPoint>
|
||||
@ -353,7 +347,11 @@ SVGPathElement::GetPathLengthScale(PathLengthScaleForType aFor)
|
||||
float authorsPathLengthEstimate = mPathLength.GetAnimValue();
|
||||
if (authorsPathLengthEstimate > 0) {
|
||||
RefPtr<Path> path = GetPathForLengthOrPositionMeasuring();
|
||||
|
||||
if (!path) {
|
||||
// The path is empty or invalid so its length must be zero and
|
||||
// we know that 0 / authorsPathLengthEstimate = 0.
|
||||
return 0.0;
|
||||
}
|
||||
if (aFor == eForTextPath) {
|
||||
// For textPath, a transform on the referenced path affects the
|
||||
// textPath layout, so when calculating the actual path length
|
||||
@ -365,12 +363,9 @@ SVGPathElement::GetPathLengthScale(PathLengthScaleForType aFor)
|
||||
path = builder->Finish();
|
||||
}
|
||||
}
|
||||
|
||||
if (path) {
|
||||
return path->ComputeLength() / authorsPathLengthEstimate;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
|
@ -88,7 +88,7 @@ public:
|
||||
|
||||
// WebIDL
|
||||
already_AddRefed<SVGAnimatedNumber> PathLength();
|
||||
float GetTotalLength(ErrorResult& rv);
|
||||
float GetTotalLength();
|
||||
already_AddRefed<nsISVGPoint> GetPointAtLength(float distance, ErrorResult& rv);
|
||||
uint32_t GetPathSegAtLength(float distance);
|
||||
already_AddRefed<DOMSVGPathSegClosePath> CreateSVGPathSegClosePath();
|
||||
|
@ -32,6 +32,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1024926
|
||||
|
||||
is(path.getTotalLength(), 150, "Unexpected path length");
|
||||
|
||||
while (path.pathSegList.numberOfItems > 0) {
|
||||
path.pathSegList.removeItem(0);
|
||||
}
|
||||
|
||||
is(path.getTotalLength(), 0, "Unexpected path length");
|
||||
|
||||
SimpleTest.finish();
|
||||
|
||||
</script>
|
||||
|
@ -69,3 +69,5 @@ if (f3Main() !== lastSum)
|
||||
|
||||
if (!this.jsFuns)
|
||||
postMessage("ok");
|
||||
else
|
||||
complete();
|
||||
|
@ -17,10 +17,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=929236
|
||||
|
||||
<script>
|
||||
var jsFuns = SpecialPowers.Cu.getJSTestingFunctions();
|
||||
ok(jsFuns.isAsmJSCompilationAvailable(), "asm.js compilation is available");
|
||||
|
||||
// generate a big ol asm.js module and compile it async so that we can hit
|
||||
// the asm.js cache.
|
||||
|
||||
var code = "function f() { 'use asm';\n";
|
||||
for (var i = 0; i < 5000; i++)
|
||||
@ -56,8 +52,18 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=929236
|
||||
}
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
// generate a big ol asm.js module and compile it async so that we can hit
|
||||
// the asm.js cache.
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
evalAsync(code);
|
||||
}
|
||||
|
||||
if (!jsFuns.isAsmJSCompilationAvailable()) {
|
||||
ok(true, "isAsmJSCompilationAvailable is false, skipping this test!");
|
||||
} else {
|
||||
runTest();
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
@ -17,7 +17,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=944821
|
||||
|
||||
<script>
|
||||
var jsFuns = SpecialPowers.Cu.getJSTestingFunctions();
|
||||
ok(jsFuns.isAsmJSCompilationAvailable(), "compilation is available");
|
||||
|
||||
var assertCacheHit = false;
|
||||
|
||||
// generate four slightly different big asm.js modules and compile them async
|
||||
// so that we can hit the asm.js cache.
|
||||
@ -50,11 +51,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=944821
|
||||
document.body.appendChild(script);
|
||||
}
|
||||
|
||||
for (var i = 0; i < N; i++)
|
||||
evalAsync(codes[i]);
|
||||
|
||||
var finishedCount = 0;
|
||||
var assertCacheHit = false;
|
||||
function finishedEvalAsync() {
|
||||
finishedCount++;
|
||||
|
||||
@ -69,7 +66,18 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=944821
|
||||
}
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
for (var i = 0; i < N; i++)
|
||||
evalAsync(codes[i]);
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
}
|
||||
|
||||
if (!jsFuns.isAsmJSCompilationAvailable()) {
|
||||
ok(true, "isAsmJSCompilationAvailable is false, skipping this test!");
|
||||
} else {
|
||||
runTest();
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
@ -17,19 +17,31 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=854209
|
||||
|
||||
<script>
|
||||
var jsFuns = SpecialPowers.Cu.getJSTestingFunctions();
|
||||
ok(jsFuns.isAsmJSCompilationAvailable(), "asm.js compilation is available");
|
||||
</script>
|
||||
|
||||
<script src="http://mochi.test:8888/tests/dom/asmjscache/test/file_slow.js"></script>
|
||||
|
||||
<script>
|
||||
var w = new Worker('http://mochi.test:8888/tests/dom/asmjscache/test/file_slow.js');
|
||||
w.onmessage = function(e) {
|
||||
ok(e.data === "ok", "Worker asm.js tests");
|
||||
var completed = 0;
|
||||
function complete() {
|
||||
if (++completed == 2)
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
if (!jsFuns.isAsmJSCompilationAvailable()) {
|
||||
ok(true, "isAsmJSCompilationAvailable is false, skipping this test!");
|
||||
} else {
|
||||
var script = document.createElement("script");
|
||||
script.src = "http://mochi.test:8888/tests/dom/asmjscache/test/file_slow.js";
|
||||
document.body.appendChild(script);
|
||||
|
||||
var w = new Worker('http://mochi.test:8888/tests/dom/asmjscache/test/file_slow.js');
|
||||
w.onmessage = function(e) {
|
||||
ok(e.data === "ok", "Worker asm.js tests");
|
||||
complete();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
@ -17,8 +17,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=941830
|
||||
|
||||
<script>
|
||||
var jsFuns = SpecialPowers.Cu.getJSTestingFunctions();
|
||||
ok(jsFuns.isAsmJSCompilationAvailable());
|
||||
|
||||
function runTest() {
|
||||
var asmjsCode = "function f() { 'use asm';";
|
||||
for (var i = 0; i < 5000; i++)
|
||||
asmjsCode += "function g" + i + "() { return " + i + "}";
|
||||
@ -61,6 +61,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=941830
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
}
|
||||
|
||||
if (!jsFuns.isAsmJSCompilationAvailable()) {
|
||||
ok(true, "isAsmJSCompilationAvailable is false, skipping this test!");
|
||||
} else {
|
||||
runTest();
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
@ -101,6 +101,11 @@ void
|
||||
CustomEvent::GetDetail(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aRetval)
|
||||
{
|
||||
if (!mDetail) {
|
||||
aRetval.setNull();
|
||||
return;
|
||||
}
|
||||
|
||||
VariantToJsval(aCx, mDetail, aRetval);
|
||||
}
|
||||
|
||||
|
5
dom/events/crashtests/1033343.html
Normal file
5
dom/events/crashtests/1033343.html
Normal file
@ -0,0 +1,5 @@
|
||||
<script>
|
||||
|
||||
document.createEvent('CustomEvent').detail;
|
||||
|
||||
</script>
|
@ -5,6 +5,7 @@ load 422009-1.xhtml
|
||||
load 457776-1.html
|
||||
load 496308-1.html
|
||||
load 682637-1.html
|
||||
load 1033343.html
|
||||
load eventctor-nulldictionary.html
|
||||
load eventctor-nullstorage.html
|
||||
load recursive-onload.html
|
||||
|
@ -42,6 +42,14 @@ var _fromByTestLists =
|
||||
toComp: "8px"}),
|
||||
new AnimTestcaseFromBy("1px", "10px", { midComp: "6px", toComp: "11px"}),
|
||||
],
|
||||
lengthPxSVG: [
|
||||
new AnimTestcaseFromBy("0px", "8px", { fromComp: "0",
|
||||
midComp: "4",
|
||||
toComp: "8"}),
|
||||
new AnimTestcaseFromBy("1px", "10px", { fromComp: "1",
|
||||
midComp: "6",
|
||||
toComp: "11"}),
|
||||
],
|
||||
opacity: [
|
||||
new AnimTestcaseFromBy("1", "-1", { midComp: "0.5", toComp: "0"}),
|
||||
new AnimTestcaseFromBy("0.4", "-0.6", { midComp: "0.1", toComp: "0"}),
|
||||
@ -137,5 +145,5 @@ var gFromByBundles =
|
||||
]),
|
||||
new TestcaseBundle(gPropList.stroke_width,
|
||||
[].concat(_fromByTestLists.lengthNoUnitsSVG,
|
||||
_fromByTestLists.lengthPx))
|
||||
_fromByTestLists.lengthPxSVG))
|
||||
];
|
||||
|
@ -103,6 +103,20 @@ var _fromToTestLists = {
|
||||
new AnimTestcaseFromTo("10px", "20px", { midComp: "15px"}),
|
||||
new AnimTestcaseFromTo("41px", "1px", { midComp: "21px"}),
|
||||
],
|
||||
lengthPxSVG: [
|
||||
new AnimTestcaseFromTo("0px", "12px", { fromComp: "0",
|
||||
midComp: "6",
|
||||
toComp: "12"}),
|
||||
new AnimTestcaseFromTo("16px", "0px", { fromComp: "16",
|
||||
midComp: "8",
|
||||
toComp: "0"}),
|
||||
new AnimTestcaseFromTo("10px", "20px", { fromComp: "10",
|
||||
midComp: "15",
|
||||
toComp: "20"}),
|
||||
new AnimTestcaseFromTo("41px", "1px", { fromComp: "41",
|
||||
midComp: "21",
|
||||
toComp: "1"}),
|
||||
],
|
||||
lengthPctSVG: [
|
||||
new AnimTestcaseFromTo("20.5%", "0.5%", { midComp: "10.5%" }),
|
||||
],
|
||||
@ -111,6 +125,14 @@ var _fromToTestLists = {
|
||||
"need support for interpolating between " +
|
||||
"px and percent values"),
|
||||
],
|
||||
lengthPxNoUnitsSVG: [
|
||||
new AnimTestcaseFromTo("10", "20px", { fromComp: "10",
|
||||
midComp: "15",
|
||||
toComp: "20"}),
|
||||
new AnimTestcaseFromTo("10px", "20", { fromComp: "10",
|
||||
midComp: "15",
|
||||
toComp: "20"}),
|
||||
],
|
||||
opacity: [
|
||||
new AnimTestcaseFromTo("1", "0", { midComp: "0.5" }),
|
||||
new AnimTestcaseFromTo("0.2", "0.12", { midComp: "0.16" }),
|
||||
@ -385,9 +407,10 @@ var gFromToBundles = [
|
||||
])),
|
||||
new TestcaseBundle(gPropList.stroke_dashoffset,
|
||||
[].concat(_fromToTestLists.lengthNoUnitsSVG,
|
||||
_fromToTestLists.lengthPx,
|
||||
_fromToTestLists.lengthPxSVG,
|
||||
_fromToTestLists.lengthPxPctSVG,
|
||||
_fromToTestLists.lengthPctSVG)),
|
||||
_fromToTestLists.lengthPctSVG,
|
||||
_fromToTestLists.lengthPxNoUnitsSVG)),
|
||||
new TestcaseBundle(gPropList.stroke_linecap, [
|
||||
new AnimTestcaseFromTo("butt", "round"),
|
||||
new AnimTestcaseFromTo("round", "square"),
|
||||
@ -403,11 +426,12 @@ var gFromToBundles = [
|
||||
new TestcaseBundle(gPropList.stroke_opacity, _fromToTestLists.opacity),
|
||||
new TestcaseBundle(gPropList.stroke_width,
|
||||
[].concat(_fromToTestLists.lengthNoUnitsSVG,
|
||||
_fromToTestLists.lengthPx,
|
||||
_fromToTestLists.lengthPxSVG,
|
||||
_fromToTestLists.lengthPxPctSVG,
|
||||
_fromToTestLists.lengthPctSVG, [
|
||||
_fromToTestLists.lengthPctSVG,
|
||||
_fromToTestLists.lengthPxNoUnitsSVG, [
|
||||
new AnimTestcaseFromTo("inherit", "7px",
|
||||
{ fromComp: "1px", midComp: "4px"}),
|
||||
{ fromComp: "1", midComp: "4", toComp: "7" }),
|
||||
])),
|
||||
new TestcaseBundle(gPropList.text_anchor, [
|
||||
new AnimTestcaseFromTo("start", "middle"),
|
||||
|
@ -92,15 +92,6 @@ var _pacedTestLists =
|
||||
comp1: "8"
|
||||
}),
|
||||
],
|
||||
lengthPx : [
|
||||
new AnimTestcasePaced("0px; 2px; 6px",
|
||||
{ comp0: "0px",
|
||||
comp1_6: "1px",
|
||||
comp1_3: "2px",
|
||||
comp2_3: "4px",
|
||||
comp1: "6px"
|
||||
}),
|
||||
],
|
||||
lengthPx : [
|
||||
new AnimTestcasePaced("0px; 2px; 6px",
|
||||
{ comp0: "0px",
|
||||
@ -117,6 +108,22 @@ var _pacedTestLists =
|
||||
comp1: "8px"
|
||||
}),
|
||||
],
|
||||
lengthPxSVG : [
|
||||
new AnimTestcasePaced("0px; 2px; 6px",
|
||||
{ comp0: "0",
|
||||
comp1_6: "1",
|
||||
comp1_3: "2",
|
||||
comp2_3: "4",
|
||||
comp1: "6"
|
||||
}),
|
||||
new AnimTestcasePaced("10px; 12px; 8px",
|
||||
{ comp0: "10",
|
||||
comp1_6: "11",
|
||||
comp1_3: "12",
|
||||
comp2_3: "10",
|
||||
comp1: "8"
|
||||
}),
|
||||
],
|
||||
lengthPctSVG : [
|
||||
new AnimTestcasePaced("5%; 6%; 4%",
|
||||
{ comp0: "5%",
|
||||
@ -291,12 +298,12 @@ var gPacedBundles =
|
||||
])),
|
||||
new TestcaseBundle(gPropList.stroke_dashoffset,
|
||||
[].concat(_pacedTestLists.lengthNoUnitsSVG,
|
||||
_pacedTestLists.lengthPx,
|
||||
_pacedTestLists.lengthPxSVG,
|
||||
_pacedTestLists.lengthPctSVG,
|
||||
_pacedTestLists.lengthPxPctSVG)),
|
||||
new TestcaseBundle(gPropList.stroke_width,
|
||||
[].concat(_pacedTestLists.lengthNoUnitsSVG,
|
||||
_pacedTestLists.lengthPx,
|
||||
_pacedTestLists.lengthPxSVG,
|
||||
_pacedTestLists.lengthPctSVG,
|
||||
_pacedTestLists.lengthPxPctSVG)),
|
||||
// XXXdholbert TODO: test 'stroke-dasharray' once we support animating it
|
||||
|
@ -58,16 +58,16 @@ function main()
|
||||
verifyStyle(rect, "stroke-width", "5px");
|
||||
svg.setCurrentTime(1);
|
||||
verifyStyle(text, "font-size", "20px");
|
||||
verifyStyle(rect, "stroke-width", "20px");
|
||||
verifyStyle(rect, "stroke-width", "20");
|
||||
svg.setCurrentTime(1.5);
|
||||
verifyStyle(text, "font-size", "30px");
|
||||
verifyStyle(rect, "stroke-width", "30px");
|
||||
verifyStyle(rect, "stroke-width", "30");
|
||||
svg.setCurrentTime(2);
|
||||
verifyStyle(text, "font-size", "40px");
|
||||
verifyStyle(rect, "stroke-width", "40px");
|
||||
verifyStyle(rect, "stroke-width", "40");
|
||||
svg.setCurrentTime(3);
|
||||
verifyStyle(text, "font-size", "40px");
|
||||
verifyStyle(rect, "stroke-width", "40px");
|
||||
verifyStyle(rect, "stroke-width", "40");
|
||||
} catch (e) {
|
||||
// If anything goes wrong, make sure we restore textZoom before bubbling
|
||||
// the exception upwards, so that we don't mess up subsequent tests.
|
||||
|
@ -13,7 +13,6 @@ interface SVGPathElement : SVGGraphicsElement {
|
||||
|
||||
readonly attribute SVGAnimatedNumber pathLength;
|
||||
|
||||
[Throws]
|
||||
float getTotalLength();
|
||||
[NewObject, Throws]
|
||||
SVGPoint getPointAtLength(float distance);
|
||||
|
@ -525,11 +525,17 @@ public:
|
||||
// Inversely scale the offset by the resolution (when you're zoomed further in,
|
||||
// the same swipe should move you a shorter distance).
|
||||
CSSPoint cssOffset = offset / aFrameMetrics.GetZoom();
|
||||
|
||||
// Ordinarily we might need to do a ScheduleComposite if either of
|
||||
// the following AdjustDisplacement calls returns true, but this
|
||||
// is already running as part of a FlingAnimation, so we'll be compositing
|
||||
// per frame of animation anyway.
|
||||
CSSPoint overscroll;
|
||||
aFrameMetrics.ScrollBy(CSSPoint(
|
||||
mApzc.mX.AdjustDisplacement(cssOffset.x, overscroll.x),
|
||||
mApzc.mY.AdjustDisplacement(cssOffset.y, overscroll.y)
|
||||
));
|
||||
CSSPoint adjustedOffset;
|
||||
mApzc.mX.AdjustDisplacement(cssOffset.x, adjustedOffset.x, overscroll.x);
|
||||
mApzc.mY.AdjustDisplacement(cssOffset.y, adjustedOffset.y, overscroll.y);
|
||||
|
||||
aFrameMetrics.ScrollBy(adjustedOffset);
|
||||
|
||||
// The fling may have caused us to reach the end of our scroll range.
|
||||
if (!IsZero(overscroll)) {
|
||||
@ -1613,14 +1619,17 @@ bool AsyncPanZoomController::AttemptScroll(const ScreenPoint& aStartPoint,
|
||||
// the same swipe should move you a shorter distance).
|
||||
CSSPoint cssDisplacement = displacement / zoom;
|
||||
|
||||
CSSPoint allowedDisplacement(mX.AdjustDisplacement(cssDisplacement.x,
|
||||
cssOverscroll.x),
|
||||
mY.AdjustDisplacement(cssDisplacement.y,
|
||||
cssOverscroll.y));
|
||||
CSSPoint adjustedDisplacement;
|
||||
bool xChanged = mX.AdjustDisplacement(cssDisplacement.x, adjustedDisplacement.x, cssOverscroll.x);
|
||||
bool yChanged = mY.AdjustDisplacement(cssDisplacement.y, adjustedDisplacement.y, cssOverscroll.y);
|
||||
if (xChanged || yChanged) {
|
||||
ScheduleComposite();
|
||||
}
|
||||
|
||||
overscroll = cssOverscroll * zoom;
|
||||
|
||||
if (!IsZero(allowedDisplacement)) {
|
||||
ScrollBy(allowedDisplacement);
|
||||
if (!IsZero(adjustedDisplacement)) {
|
||||
ScrollBy(adjustedDisplacement);
|
||||
ScheduleCompositeAndMaybeRepaint();
|
||||
UpdateSharedCompositorFrameMetrics();
|
||||
}
|
||||
@ -1802,8 +1811,17 @@ CalculateDisplayPortSize(const CSSSize& aCompositionSize,
|
||||
float yMultiplier = fabsf(aVelocity.y) < gfxPrefs::APZMinSkateSpeed()
|
||||
? gfxPrefs::APZYStationarySizeMultiplier()
|
||||
: gfxPrefs::APZYSkateSizeMultiplier();
|
||||
return CSSSize(aCompositionSize.width * xMultiplier,
|
||||
aCompositionSize.height * yMultiplier);
|
||||
|
||||
// Ensure that it is at least as large as the visible area inflated by the
|
||||
// danger zone. If this is not the case then the "AboutToCheckerboard"
|
||||
// function in TiledContentClient.cpp will return true even in the stable
|
||||
// state.
|
||||
float xSize = std::max(aCompositionSize.width * xMultiplier,
|
||||
aCompositionSize.width + (2 * gfxPrefs::APZDangerZoneX()));
|
||||
float ySize = std::max(aCompositionSize.height * yMultiplier,
|
||||
aCompositionSize.height + (2 * gfxPrefs::APZDangerZoneY()));
|
||||
|
||||
return CSSSize(xSize, ySize);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -62,24 +62,27 @@ void Axis::StartTouch(int32_t aPos, uint32_t aTimestampMs) {
|
||||
mAxisLocked = false;
|
||||
}
|
||||
|
||||
float Axis::AdjustDisplacement(float aDisplacement, float& aOverscrollAmountOut) {
|
||||
bool Axis::AdjustDisplacement(float aDisplacement,
|
||||
float& aDisplacementOut,
|
||||
float& aOverscrollAmountOut)
|
||||
{
|
||||
if (mAxisLocked) {
|
||||
aOverscrollAmountOut = 0;
|
||||
return 0;
|
||||
aDisplacementOut = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
float displacement = aDisplacement;
|
||||
|
||||
// First consume any overscroll in the opposite direction along this axis.
|
||||
float consumedOverscroll = 0;
|
||||
if (mOverscroll > 0 && aDisplacement < 0) {
|
||||
float consumedOverscroll = std::min(mOverscroll, -aDisplacement);
|
||||
consumedOverscroll = std::min(mOverscroll, -aDisplacement);
|
||||
} else if (mOverscroll < 0 && aDisplacement > 0) {
|
||||
consumedOverscroll = 0 - std::min(-mOverscroll, aDisplacement);
|
||||
}
|
||||
mOverscroll -= consumedOverscroll;
|
||||
displacement += consumedOverscroll;
|
||||
} else if (mOverscroll < 0 && aDisplacement > 0) {
|
||||
float consumedOverscroll = std::min(-mOverscroll, aDisplacement);
|
||||
mOverscroll += consumedOverscroll;
|
||||
displacement -= consumedOverscroll;
|
||||
}
|
||||
|
||||
// Split the requested displacement into an allowed displacement that does
|
||||
// not overscroll, and an overscroll amount.
|
||||
@ -90,7 +93,8 @@ float Axis::AdjustDisplacement(float aDisplacement, float& aOverscrollAmountOut)
|
||||
aOverscrollAmountOut = DisplacementWillOverscrollAmount(displacement);
|
||||
displacement -= aOverscrollAmountOut;
|
||||
}
|
||||
return displacement;
|
||||
aDisplacementOut = displacement;
|
||||
return fabsf(consumedOverscroll) > EPSILON;
|
||||
}
|
||||
|
||||
float Axis::ApplyResistance(float aRequestedOverscroll) const {
|
||||
|
@ -83,9 +83,13 @@ public:
|
||||
* to prevent the viewport from overscrolling the page rect), and axis locking
|
||||
* (which might prevent any displacement from happening). If overscroll
|
||||
* ocurred, its amount is written to |aOverscrollAmountOut|.
|
||||
* The adjusted displacement is returned.
|
||||
* The |aDisplacementOut| parameter is set to the adjusted
|
||||
* displacement, and the function returns true iff internal overscroll amounts
|
||||
* were changed.
|
||||
*/
|
||||
float AdjustDisplacement(float aDisplacement, float& aOverscrollAmountOut);
|
||||
bool AdjustDisplacement(float aDisplacement,
|
||||
float& aDisplacementOut,
|
||||
float& aOverscrollAmountOut);
|
||||
|
||||
/**
|
||||
* Overscrolls this axis by the requested amount in the requested direction.
|
||||
|
@ -192,6 +192,7 @@ SharedFrameMetricsHelper::UpdateFromCompositorFrameMetrics(
|
||||
if (aLowPrecision && !mLastProgressiveUpdateWasLowPrecision) {
|
||||
// Skip low precision rendering until we're at risk of checkerboarding.
|
||||
if (!mProgressiveUpdateWasInDanger) {
|
||||
TILING_PRLOG(("TILING: Aborting low-precision rendering because not at risk of checkerboarding\n"));
|
||||
return true;
|
||||
}
|
||||
mProgressiveUpdateWasInDanger = false;
|
||||
@ -201,6 +202,8 @@ SharedFrameMetricsHelper::UpdateFromCompositorFrameMetrics(
|
||||
// Always abort updates if the resolution has changed. There's no use
|
||||
// in drawing at the incorrect resolution.
|
||||
if (!FuzzyEquals(compositorMetrics.GetZoom().scale, contentMetrics.GetZoom().scale)) {
|
||||
TILING_PRLOG(("TILING: Aborting because resolution changed from %f to %f\n",
|
||||
contentMetrics.GetZoom().scale, compositorMetrics.GetZoom().scale));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -239,6 +242,7 @@ SharedFrameMetricsHelper::UpdateFromCompositorFrameMetrics(
|
||||
// Abort drawing stale low-precision content if there's a more recent
|
||||
// display-port in the pipeline.
|
||||
if (aLowPrecision && !aHasPendingNewThebesContent) {
|
||||
TILING_PRLOG(("TILING: Aborting low-precision because of new pending content\n"));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -272,7 +276,14 @@ SharedFrameMetricsHelper::AboutToCheckerboard(const FrameMetrics& aContentMetric
|
||||
painted = painted.Intersect(aContentMetrics.mScrollableRect);
|
||||
showing = showing.Intersect(aContentMetrics.mScrollableRect);
|
||||
|
||||
return !painted.Contains(showing);
|
||||
if (!painted.Contains(showing)) {
|
||||
TILING_PRLOG_OBJ(("TILING: About to checkerboard; content %s\n", tmpstr.get()), aContentMetrics);
|
||||
TILING_PRLOG_OBJ(("TILING: About to checkerboard; painted %s\n", tmpstr.get()), painted);
|
||||
TILING_PRLOG_OBJ(("TILING: About to checkerboard; compositor %s\n", tmpstr.get()), aCompositorMetrics);
|
||||
TILING_PRLOG_OBJ(("TILING: About to checkerboard; showing %s\n", tmpstr.get()), showing);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ClientTiledLayerBuffer::ClientTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer,
|
||||
|
@ -197,10 +197,40 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount, DecodeStrategy
|
||||
if (!aCount || !mCurLine)
|
||||
return;
|
||||
|
||||
// This code assumes that mRawBuf == WIN_V3_INTERNAL_BIH_LENGTH
|
||||
// and that sizeof(mRawBuf) >= BFH_INTERNAL_LENGTH
|
||||
MOZ_ASSERT(sizeof(mRawBuf) == WIN_V3_INTERNAL_BIH_LENGTH);
|
||||
MOZ_ASSERT(sizeof(mRawBuf) >= BFH_INTERNAL_LENGTH);
|
||||
MOZ_ASSERT(OS2_INTERNAL_BIH_LENGTH < WIN_V3_INTERNAL_BIH_LENGTH);
|
||||
// This code also assumes it's working with a byte array
|
||||
MOZ_ASSERT(sizeof(mRawBuf[0]) == 1);
|
||||
|
||||
if (mPos < BFH_INTERNAL_LENGTH) { /* In BITMAPFILEHEADER */
|
||||
// BFH_INTERNAL_LENGTH < sizeof(mRawBuf)
|
||||
// mPos < BFH_INTERNAL_LENGTH
|
||||
// BFH_INTERNAL_LENGTH - mPos < sizeof(mRawBuf)
|
||||
// so toCopy <= BFH_INTERNAL_LENGTH
|
||||
// so toCopy < sizeof(mRawBuf)
|
||||
// so toCopy > 0 && toCopy <= BFH_INTERNAL_LENGTH
|
||||
uint32_t toCopy = BFH_INTERNAL_LENGTH - mPos;
|
||||
if (toCopy > aCount)
|
||||
toCopy = aCount;
|
||||
|
||||
// mRawBuf is a byte array of size WIN_V3_INTERNAL_BIH_LENGTH (verified above)
|
||||
// mPos is < BFH_INTERNAL_LENGTH
|
||||
// BFH_INTERNAL_LENGTH < WIN_V3_INTERNAL_BIH_LENGTH
|
||||
// so mPos < sizeof(mRawBuf)
|
||||
//
|
||||
// Therefore this assert should hold
|
||||
MOZ_ASSERT(mPos < sizeof(mRawBuf));
|
||||
|
||||
// toCopy <= BFH_INTERNAL_LENGTH
|
||||
// mPos >= 0 && mPos < BFH_INTERNAL_LENGTH
|
||||
// sizeof(mRawBuf) >= BFH_INTERNAL_LENGTH (verified above)
|
||||
//
|
||||
// Therefore this assert should hold
|
||||
MOZ_ASSERT(mPos + toCopy <= sizeof(mRawBuf));
|
||||
|
||||
memcpy(mRawBuf + mPos, aBuffer, toCopy);
|
||||
mPos += toCopy;
|
||||
aCount -= toCopy;
|
||||
@ -216,15 +246,74 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount, DecodeStrategy
|
||||
mLOH = OS2_HEADER_LENGTH;
|
||||
}
|
||||
if (mPos >= BFH_INTERNAL_LENGTH && mPos < mLOH) { /* In BITMAPINFOHEADER */
|
||||
// mLOH == WIN_V3_HEADER_LENGTH || mLOH == OS2_HEADER_LENGTH
|
||||
// OS2_HEADER_LENGTH < WIN_V3_HEADER_LENGTH
|
||||
// BFH_INTERNAL_LENGTH < OS2_HEADER_LENGTH
|
||||
// BFH_INTERNAL_LENGTH < WIN_V3_HEADER_LENGTH
|
||||
//
|
||||
// So toCopy is in the range
|
||||
// 1 to (WIN_V3_HEADER_LENGTH - BFH_INTERNAL_LENGTH)
|
||||
// or 1 to (OS2_HEADER_LENGTH - BFH_INTERNAL_LENGTH)
|
||||
//
|
||||
// But WIN_V3_HEADER_LENGTH = BFH_INTERNAL_LENGTH + WIN_V3_INTERNAL_BIH_LENGTH
|
||||
// and OS2_HEADER_LENGTH = BFH_INTERNAL_LENGTH + OS2_INTERNAL_BIH_LENGTH
|
||||
//
|
||||
// So toCopy is in the range
|
||||
//
|
||||
// 1 to WIN_V3_INTERNAL_BIH_LENGTH
|
||||
// or 1 to OS2_INTERNAL_BIH_LENGTH
|
||||
// and OS2_INTERNAL_BIH_LENGTH < WIN_V3_INTERNAL_BIH_LENGTH
|
||||
//
|
||||
// sizeof(mRawBuf) = WIN_V3_INTERNAL_BIH_LENGTH
|
||||
// so toCopy <= sizeof(mRawBuf)
|
||||
uint32_t toCopy = mLOH - mPos;
|
||||
if (toCopy > aCount)
|
||||
toCopy = aCount;
|
||||
memcpy(mRawBuf + (mPos - BFH_INTERNAL_LENGTH), aBuffer, toCopy);
|
||||
|
||||
// mPos is in the range
|
||||
// BFH_INTERNAL_LENGTH to (WIN_V3_HEADER_LENGTH - 1)
|
||||
//
|
||||
// offset is then in the range (see toCopy comments for more details)
|
||||
// 0 to (WIN_V3_INTERNAL_BIH_LENGTH - 1)
|
||||
//
|
||||
// sizeof(mRawBuf) is WIN_V3_INTERNAL_BIH_LENGTH so this
|
||||
// offset stays within bounds and this assert should hold
|
||||
const uint32_t offset = mPos - BFH_INTERNAL_LENGTH;
|
||||
MOZ_ASSERT(offset < sizeof(mRawBuf));
|
||||
|
||||
// Two cases:
|
||||
// mPos = BFH_INTERNAL_LENGTH
|
||||
// mLOH = WIN_V3_HEADER_LENGTH
|
||||
//
|
||||
// offset = 0
|
||||
// toCopy = WIN_V3_INTERNAL_BIH_LENGTH
|
||||
//
|
||||
// This will be in the bounds of sizeof(mRawBuf)
|
||||
//
|
||||
// Second Case:
|
||||
// mPos = WIN_V3_HEADER_LENGTH - 1
|
||||
// mLOH = WIN_V3_HEADER_LENGTH
|
||||
//
|
||||
// offset = WIN_V3_INTERNAL_BIH_LENGTH - 1
|
||||
// toCopy = 1
|
||||
//
|
||||
// This will be in the bounds of sizeof(mRawBuf)
|
||||
//
|
||||
// As sizeof(mRawBuf) == WIN_V3_INTERNAL_BIH_LENGTH (verified above)
|
||||
// and WIN_V3_HEADER_LENGTH is the largest range of values. If mLOH
|
||||
// was equal to OS2_HEADER_LENGTH then the ranges are smaller.
|
||||
MOZ_ASSERT(offset + toCopy <= sizeof(mRawBuf));
|
||||
|
||||
memcpy(mRawBuf + offset, aBuffer, toCopy);
|
||||
mPos += toCopy;
|
||||
aCount -= toCopy;
|
||||
aBuffer += toCopy;
|
||||
}
|
||||
|
||||
// At this point mPos should be >= mLOH unless aBuffer did not have enough
|
||||
// data. In the latter case aCount should be 0.
|
||||
MOZ_ASSERT(mPos >= mLOH || aCount == 0);
|
||||
|
||||
// HasSize is called to ensure that if at this point mPos == mLOH but
|
||||
// we have no data left to process, the next time WriteInternal is called
|
||||
// we won't enter this condition again.
|
||||
@ -376,12 +465,62 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount, DecodeStrategy
|
||||
}
|
||||
}
|
||||
else if (aCount && mBIH.compression == BI_BITFIELDS && mPos < (WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH)) {
|
||||
// If compression is used, this is a windows bitmap, hence we can
|
||||
// use WIN_HEADER_LENGTH instead of mLOH
|
||||
// If compression is used, this is a windows bitmap (compression can't be used with OS/2 bitmaps),
|
||||
// hence we can use WIN_V3_HEADER_LENGTH instead of mLOH.
|
||||
// (verified below)
|
||||
|
||||
// If aCount != 0 then mPos should be >= mLOH due to the if statements
|
||||
// at the beginning of the function
|
||||
MOZ_ASSERT(mPos >= mLOH);
|
||||
MOZ_ASSERT(mLOH == WIN_V3_HEADER_LENGTH);
|
||||
|
||||
// mLOH == WIN_V3_HEADER_LENGTH (verified above)
|
||||
// mPos >= mLOH (verified above)
|
||||
// mPos < WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH
|
||||
//
|
||||
// So toCopy is in the range
|
||||
// 0 to (BITFIELD_LENGTH - 1)
|
||||
uint32_t toCopy = (WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH) - mPos;
|
||||
if (toCopy > aCount)
|
||||
toCopy = aCount;
|
||||
memcpy(mRawBuf + (mPos - WIN_V3_HEADER_LENGTH), aBuffer, toCopy);
|
||||
|
||||
// mPos >= WIN_V3_HEADER_LENGTH
|
||||
// mPos < WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH
|
||||
//
|
||||
// offset is in the range
|
||||
// 0 to (BITFIELD_LENGTH - 1)
|
||||
//
|
||||
// BITFIELD_LENGTH < WIN_V3_INTERNAL_BIH_LENGTH
|
||||
// and sizeof(mRawBuf) == WIN_V3_INTERNAL_BIH_LENGTH (verified at top of function)
|
||||
//
|
||||
// Therefore this assert should hold
|
||||
const uint32_t offset = mPos - WIN_V3_HEADER_LENGTH;
|
||||
MOZ_ASSERT(offset < sizeof(mRawBuf));
|
||||
|
||||
// Two cases:
|
||||
// mPos = WIN_V3_HEADER_LENGTH
|
||||
//
|
||||
// offset = 0
|
||||
// toCopy = BITFIELD_LENGTH
|
||||
//
|
||||
// This will be in the bounds of sizeof(mRawBuf)
|
||||
//
|
||||
// Second case:
|
||||
//
|
||||
// mPos = WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH - 1
|
||||
//
|
||||
// offset = BITFIELD_LENGTH - 1
|
||||
// toCopy = 1
|
||||
//
|
||||
// This will be in the bounds of sizeof(mRawBuf)
|
||||
//
|
||||
// As BITFIELD_LENGTH < WIN_V3_INTERNAL_BIH_LENGTH and
|
||||
// sizeof(mRawBuf) == WIN_V3_INTERNAL_BIH_LENGTH
|
||||
//
|
||||
// Therefore this assert should hold
|
||||
MOZ_ASSERT(offset + toCopy <= sizeof(mRawBuf));
|
||||
|
||||
memcpy(mRawBuf + offset, aBuffer, toCopy);
|
||||
mPos += toCopy;
|
||||
aBuffer += toCopy;
|
||||
aCount -= toCopy;
|
||||
|
@ -54,11 +54,11 @@ private:
|
||||
* the bitmasks from mBitFields */
|
||||
NS_METHOD CalcBitShift();
|
||||
|
||||
uint32_t mPos;
|
||||
uint32_t mPos; ///< Number of bytes read from aBuffer in WriteInternal()
|
||||
|
||||
BMPFILEHEADER mBFH;
|
||||
BITMAPV5HEADER mBIH;
|
||||
char mRawBuf[WIN_V3_INTERNAL_BIH_LENGTH];
|
||||
char mRawBuf[WIN_V3_INTERNAL_BIH_LENGTH]; ///< If this is changed, WriteInternal() MUST be updated
|
||||
|
||||
uint32_t mLOH; ///< Length of the header
|
||||
|
||||
|
@ -880,8 +880,23 @@ static bool
|
||||
SaveStack(JSContext *cx, unsigned argc, jsval *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
unsigned maxFrameCount = 0;
|
||||
if (args.length() >= 1) {
|
||||
double d;
|
||||
if (!ToNumber(cx, args[0], &d))
|
||||
return false;
|
||||
if (d < 0) {
|
||||
js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
|
||||
JSDVG_SEARCH_STACK, args[0], JS::NullPtr(),
|
||||
"not a valid maximum frame count", NULL);
|
||||
return false;
|
||||
}
|
||||
maxFrameCount = d;
|
||||
}
|
||||
|
||||
Rooted<JSObject*> stack(cx);
|
||||
if (!JS::CaptureCurrentStack(cx, &stack))
|
||||
if (!JS::CaptureCurrentStack(cx, &stack, maxFrameCount))
|
||||
return false;
|
||||
args.rval().setObjectOrNull(stack);
|
||||
return true;
|
||||
|
@ -98,7 +98,9 @@ assertThrowsValue(function() { f(8,2.4) }, 2.4+36);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'var identity=imp.identity; function g(x) { x=+x; return +identity(x) } return g'), null, imp)(13.37), 13.37);
|
||||
|
||||
// Test asm.js => ion paths
|
||||
setJitCompilerOption("ion.usecount.trigger", 20);
|
||||
setJitCompilerOption("ion.usecount.trigger", 10);
|
||||
setJitCompilerOption("baseline.usecount.trigger", 0);
|
||||
setJitCompilerOption("offthread-compilation.enable", 0);
|
||||
|
||||
// In registers on x64 and ARM, on the stack for x86
|
||||
function ffiIntFew(a,b,c,d) { return d+1 }
|
||||
@ -109,32 +111,32 @@ for (var i = 0; i < 40; i++)
|
||||
// Stack and registers for x64 and ARM, stack for x86
|
||||
function ffiIntMany(a,b,c,d,e,f,g,h,i,j) { return j+1 }
|
||||
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; return ffi(i|0,(i+1)|0,(i+2)|0,(i+3)|0,(i+4)|0,(i+5)|0,(i+6)|0,(i+7)|0,(i+8)|0,(i+9)|0)|0 } return f'), null, {ffi:ffiIntMany});
|
||||
for (var i = 0; i < 40; i++)
|
||||
for (var i = 0; i < 15; i++)
|
||||
assertEq(f(i), i+10);
|
||||
|
||||
// In registers on x64 and ARM, on the stack for x86
|
||||
function ffiDoubleFew(a,b,c,d) { return d+1 }
|
||||
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=+i; return +ffi(i,i+1.0,i+2.0,i+3.0) } return f'), null, {ffi:ffiDoubleFew});
|
||||
for (var i = 0; i < 40; i++)
|
||||
for (var i = 0; i < 15; i++)
|
||||
assertEq(f(i), i+4);
|
||||
|
||||
// Stack and registers for x64 and ARM, stack for x86
|
||||
function ffiDoubleMany(a,b,c,d,e,f,g,h,i,j) { return j+1 }
|
||||
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=+i; return +ffi(i,i+1.0,i+2.0,i+3.0,i+4.0,i+5.0,i+6.0,i+7.0,i+8.0,i+9.0) } return f'), null, {ffi:ffiDoubleMany});
|
||||
for (var i = 0; i < 40; i++)
|
||||
for (var i = 0; i < 15; i++)
|
||||
assertEq(f(i), i+10);
|
||||
|
||||
// Test the throw path
|
||||
function ffiThrow(n) { if (n == 38) throw 'yolo'; }
|
||||
function ffiThrow(n) { if (n == 14) throw 'yolo'; }
|
||||
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; ffi(i >> 0); } return f'), null, {ffi:ffiThrow});
|
||||
var i = 0;
|
||||
try {
|
||||
for (; i < 40; i++)
|
||||
for (; i < 15; i++)
|
||||
f(i);
|
||||
throw 'assume unreachable';
|
||||
} catch (e) {
|
||||
assertEq(e, 'yolo');
|
||||
assertEq(i, 38);
|
||||
assertEq(i, 14);
|
||||
}
|
||||
|
||||
// OOL conversion paths
|
||||
|
@ -17,10 +17,14 @@ function dumpStack()
|
||||
stack = new Error().stack
|
||||
}
|
||||
|
||||
setJitCompilerOption("ion.usecount.trigger", 10);
|
||||
setJitCompilerOption("baseline.usecount.trigger", 0);
|
||||
setJitCompilerOption("offthread-compilation.enable", 0);
|
||||
|
||||
var callFFI = asmCompile('global', 'ffis', USE_ASM + "var ffi=ffis.ffi; function f() { return ffi()|0 } return f");
|
||||
|
||||
var f = asmLink(callFFI, null, {ffi:dumpStack});
|
||||
for (var i = 0; i < 5000; i++) {
|
||||
for (var i = 0; i < 15; i++) {
|
||||
stack = null;
|
||||
f();
|
||||
matchStack(stack, ['dumpStack', 'f']);
|
||||
@ -42,7 +46,7 @@ matchStack(stack, ["dumpStack", "f", "middle", "f"]);
|
||||
|
||||
function returnStackDumper() { return { valueOf:function() { stack = new Error().stack } } }
|
||||
var f = asmLink(callFFI, null, {ffi:returnStackDumper});
|
||||
for (var i = 0; i < 5000; i++) {
|
||||
for (var i = 0; i < 15; i++) {
|
||||
stack = null;
|
||||
f();
|
||||
matchStack(stack, ['valueOf', 'f']);
|
||||
|
42
js/src/jit-test/tests/saved-stacks/max-frame-count.js
Normal file
42
js/src/jit-test/tests/saved-stacks/max-frame-count.js
Normal file
@ -0,0 +1,42 @@
|
||||
// Test that we can capture only the N newest frames.
|
||||
// This is the maxFrameCount argument to JS::CaptureCurrentStack.
|
||||
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
function recur(n, limit) {
|
||||
if (n > 0)
|
||||
return recur(n - 1, limit);
|
||||
return saveStack(limit);
|
||||
}
|
||||
|
||||
// Negative values are rejected.
|
||||
assertThrowsInstanceOf(() => saveStack(-1), TypeError);
|
||||
|
||||
// Zero means 'no limit'.
|
||||
assertEq(saveStack(0).parent, null);
|
||||
assertEq(recur(0, 0).parent !== null, true);
|
||||
assertEq(recur(0, 0).parent.parent, null);
|
||||
assertEq(recur(1, 0).parent.parent.parent, null);
|
||||
assertEq(recur(2, 0).parent.parent.parent.parent, null);
|
||||
assertEq(recur(3, 0).parent.parent.parent.parent.parent, null);
|
||||
|
||||
// limit of 1
|
||||
assertEq(saveStack(1).parent, null);
|
||||
assertEq(recur(0, 1).parent, null);
|
||||
assertEq(recur(0, 1).parent, null);
|
||||
assertEq(recur(1, 1).parent, null);
|
||||
assertEq(recur(2, 1).parent, null);
|
||||
|
||||
// limit of 2
|
||||
assertEq(saveStack(2).parent, null);
|
||||
assertEq(recur(0, 2).parent !== null, true);
|
||||
assertEq(recur(0, 2).parent.parent, null);
|
||||
assertEq(recur(1, 2).parent.parent, null);
|
||||
assertEq(recur(2, 2).parent.parent, null);
|
||||
|
||||
// limit of 3
|
||||
assertEq(saveStack(3).parent, null);
|
||||
assertEq(recur(0, 3).parent !== null, true);
|
||||
assertEq(recur(0, 3).parent.parent, null);
|
||||
assertEq(recur(1, 3).parent.parent.parent, null);
|
||||
assertEq(recur(2, 3).parent.parent.parent, null);
|
@ -16,7 +16,6 @@
|
||||
#include "jsprf.h"
|
||||
#include "prmjtime.h"
|
||||
|
||||
#include "assembler/assembler/MacroAssembler.h"
|
||||
#include "frontend/Parser.h"
|
||||
#include "jit/AsmJSLink.h"
|
||||
#include "jit/AsmJSModule.h"
|
||||
@ -1409,9 +1408,6 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
return false;
|
||||
return exits_.add(p, Move(exitDescriptor), *exitIndex);
|
||||
}
|
||||
bool addFunctionName(PropertyName *name, uint32_t *index) {
|
||||
return module_->addFunctionName(name, index);
|
||||
}
|
||||
|
||||
// Note a constraint on the minimum size of the heap. The heap size is
|
||||
// constrained when linking to be at least the maximum of all such constraints.
|
||||
@ -1443,6 +1439,11 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
bool finishGeneratingFunction(Func &func, MIRGenerator &mir, CodeGenerator &codegen) {
|
||||
JS_ASSERT(func.defined() && func.code()->bound());
|
||||
|
||||
uint32_t beginOffset = func.code()->offset();
|
||||
uint32_t endOffset = masm_.currentOffset();
|
||||
if (!module_->addFunctionCodeRange(func.name(), beginOffset, endOffset))
|
||||
return false;
|
||||
|
||||
jit::IonScriptCounts *counts = codegen.extractScriptCounts();
|
||||
if (counts && !module_->addFunctionCounts(counts)) {
|
||||
js_delete(counts);
|
||||
@ -1480,15 +1481,19 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
module_->finishFunctionBodies(masm_.currentOffset());
|
||||
}
|
||||
|
||||
void startGeneratingEntry(unsigned exportIndex) {
|
||||
module_->exportedFunction(exportIndex).initCodeOffset(masm_.currentOffset());
|
||||
}
|
||||
bool finishGeneratingEntry(unsigned exportIndex) {
|
||||
return module_->addEntryCodeRange(exportIndex, masm_.currentOffset());
|
||||
}
|
||||
|
||||
void setInterpExitOffset(unsigned exitIndex) {
|
||||
module_->exit(exitIndex).initInterpOffset(masm_.currentOffset());
|
||||
}
|
||||
void setIonExitOffset(unsigned exitIndex) {
|
||||
module_->exit(exitIndex).initIonOffset(masm_.currentOffset());
|
||||
}
|
||||
void setEntryOffset(unsigned exportIndex) {
|
||||
module_->exportedFunction(exportIndex).initCodeOffset(masm_.currentOffset());
|
||||
}
|
||||
|
||||
void buildCompilationTimeReport(bool storedInCache, ScopedJSFreePtr<char> *out) {
|
||||
ScopedJSFreePtr<char> slowFuns;
|
||||
@ -1808,7 +1813,6 @@ class FunctionCompiler
|
||||
ModuleCompiler & m_;
|
||||
LifoAlloc & lifo_;
|
||||
ParseNode * fn_;
|
||||
uint32_t functionNameIndex_;
|
||||
|
||||
LocalMap locals_;
|
||||
VarInitializerVector varInitializers_;
|
||||
@ -1829,15 +1833,11 @@ class FunctionCompiler
|
||||
LabeledBlockMap labeledBreaks_;
|
||||
LabeledBlockMap labeledContinues_;
|
||||
|
||||
static const uint32_t NO_FUNCTION_NAME_INDEX = UINT32_MAX;
|
||||
JS_STATIC_ASSERT(NO_FUNCTION_NAME_INDEX > CallSiteDesc::FUNCTION_NAME_INDEX_MAX);
|
||||
|
||||
public:
|
||||
FunctionCompiler(ModuleCompiler &m, ParseNode *fn, LifoAlloc &lifo)
|
||||
: m_(m),
|
||||
lifo_(lifo),
|
||||
fn_(fn),
|
||||
functionNameIndex_(NO_FUNCTION_NAME_INDEX),
|
||||
locals_(m.cx()),
|
||||
varInitializers_(m.cx()),
|
||||
alloc_(nullptr),
|
||||
@ -2279,12 +2279,7 @@ class FunctionCompiler
|
||||
uint32_t line, column;
|
||||
m_.tokenStream().srcCoords.lineNumAndColumnIndex(call.node_->pn_pos.begin, &line, &column);
|
||||
|
||||
if (functionNameIndex_ == NO_FUNCTION_NAME_INDEX) {
|
||||
if (!m_.addFunctionName(FunctionName(fn_), &functionNameIndex_))
|
||||
return false;
|
||||
}
|
||||
|
||||
CallSiteDesc desc(line, column, functionNameIndex_);
|
||||
CallSiteDesc desc(line, column);
|
||||
MAsmJSCall *ins = MAsmJSCall::New(alloc(), desc, callee, call.regArgs_, returnType,
|
||||
call.spIncrement_);
|
||||
if (!ins)
|
||||
@ -5955,7 +5950,7 @@ GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFu
|
||||
// PushRegsInMask(NonVolatileRegs).
|
||||
masm.setFramePushed(0);
|
||||
|
||||
// See AsmJSFrameSize comment in Assembler-*.h.
|
||||
// See AsmJSFrameSize comment in Assembler-shared.h.
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
masm.push(lr);
|
||||
#endif // JS_CODEGEN_ARM
|
||||
@ -6030,7 +6025,7 @@ GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFu
|
||||
|
||||
// Call into the real function.
|
||||
AssertStackAlignment(masm);
|
||||
masm.call(CallSiteDesc::Entry(), func.code());
|
||||
masm.call(func.code());
|
||||
|
||||
// Pop the stack and recover the original 'argv' argument passed to the
|
||||
// trampoline (which was pushed on the stack).
|
||||
@ -6214,14 +6209,18 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
|
||||
m.setInterpExitOffset(exitIndex);
|
||||
masm.setFramePushed(0);
|
||||
|
||||
// See AsmJSFrameSize comment in Assembler-*.h.
|
||||
// See AsmJSFrameSize comment in Assembler-shared.h.
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
masm.push(lr);
|
||||
#endif
|
||||
#if defined(JS_CODEGEN_MIPS)
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
masm.push(ra);
|
||||
#endif
|
||||
|
||||
// Store the frame pointer in AsmJSActivation::exitFP for stack unwinding.
|
||||
Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
|
||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP()));
|
||||
|
||||
MIRType typeArray[] = { MIRType_Pointer, // cx
|
||||
MIRType_Pointer, // exitDatum
|
||||
MIRType_Int32, // argc
|
||||
@ -6240,16 +6239,11 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
|
||||
|
||||
// Fill the argument array.
|
||||
unsigned offsetToCallerStackArgs = AsmJSFrameSize + masm.framePushed();
|
||||
Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
|
||||
Register scratch = ABIArgGenerator::NonArgReturnVolatileReg1;
|
||||
FillArgumentArray(m, exit.sig().args(), offsetToArgv, offsetToCallerStackArgs, scratch);
|
||||
|
||||
// Prepare the arguments for the call to InvokeFromAsmJS_*.
|
||||
ABIArgMIRTypeIter i(invokeArgTypes);
|
||||
Register activation = ABIArgGenerator::NonArgReturnVolatileReg1;
|
||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||
|
||||
// Record sp in the AsmJSActivation for stack-walking.
|
||||
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitSP()));
|
||||
|
||||
// argument 0: cx
|
||||
if (i->kind() == ABIArg::GPR) {
|
||||
@ -6290,16 +6284,16 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
|
||||
AssertStackAlignment(masm);
|
||||
switch (exit.sig().retType().which()) {
|
||||
case RetType::Void:
|
||||
masm.callExit(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_Ignore), i.stackBytesConsumedSoFar());
|
||||
masm.call(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_Ignore));
|
||||
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
|
||||
break;
|
||||
case RetType::Signed:
|
||||
masm.callExit(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToInt32), i.stackBytesConsumedSoFar());
|
||||
masm.call(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToInt32));
|
||||
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
|
||||
masm.unboxInt32(argv, ReturnReg);
|
||||
break;
|
||||
case RetType::Double:
|
||||
masm.callExit(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToNumber), i.stackBytesConsumedSoFar());
|
||||
masm.call(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToNumber));
|
||||
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
|
||||
masm.loadDouble(argv, ReturnDoubleReg);
|
||||
break;
|
||||
@ -6311,6 +6305,11 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
|
||||
// Note: the caller is IonMonkey code which means there are no non-volatile
|
||||
// registers to restore.
|
||||
masm.freeStack(stackDec);
|
||||
|
||||
// Clear exitFP before the frame is destroyed.
|
||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||
masm.storePtr(ImmWord(0), Address(activation, AsmJSActivation::offsetOfExitFP()));
|
||||
|
||||
masm.ret();
|
||||
}
|
||||
|
||||
@ -6335,9 +6334,6 @@ GenerateOOLConvert(ModuleCompiler &m, RetType retType, Label *throwLabel)
|
||||
Register activation = ABIArgGenerator::NonArgReturnVolatileReg1;
|
||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||
|
||||
// Record sp in the AsmJSActivation for stack-walking.
|
||||
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitSP()));
|
||||
|
||||
// Store real arguments
|
||||
ABIArgMIRTypeIter i(callArgTypes);
|
||||
|
||||
@ -6365,12 +6361,12 @@ GenerateOOLConvert(ModuleCompiler &m, RetType retType, Label *throwLabel)
|
||||
AssertStackAlignment(masm);
|
||||
switch (retType.which()) {
|
||||
case RetType::Signed:
|
||||
masm.callExit(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToInt32), i.stackBytesConsumedSoFar());
|
||||
masm.call(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToInt32));
|
||||
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
|
||||
masm.unboxInt32(Address(StackPointer, offsetToArgv), ReturnReg);
|
||||
break;
|
||||
case RetType::Double:
|
||||
masm.callExit(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToNumber), i.stackBytesConsumedSoFar());
|
||||
masm.call(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToNumber));
|
||||
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
|
||||
masm.loadDouble(Address(StackPointer, offsetToArgv), ReturnDoubleReg);
|
||||
break;
|
||||
@ -6388,19 +6384,22 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
|
||||
m.setIonExitOffset(exitIndex);
|
||||
masm.setFramePushed(0);
|
||||
|
||||
// See AsmJSFrameSize comment in Assembler-*.h.
|
||||
#if defined(JS_CODEGEN_X64)
|
||||
masm.Push(HeapReg);
|
||||
#elif defined(JS_CODEGEN_ARM)
|
||||
// See AsmJSFrameSize comment in Assembler-shared.h.
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
masm.push(lr);
|
||||
|
||||
// The GlobalReg (r10) and HeapReg (r11) also need to be restored before
|
||||
// returning to asm.js code.
|
||||
// The NANReg also needs to be restored, but is a constant and is reloaded before
|
||||
// returning to asm.js code.
|
||||
masm.PushRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
masm.push(ra);
|
||||
#endif
|
||||
|
||||
// Store the frame pointer in AsmJSActivation::exitFP for stack unwinding.
|
||||
Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
|
||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP()));
|
||||
|
||||
// Ion does not preserve nonvolatile registers, so we have to preserve them.
|
||||
#if defined(JS_CODEGEN_X64)
|
||||
masm.Push(HeapReg);
|
||||
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
|
||||
masm.PushRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
|
||||
#endif
|
||||
|
||||
@ -6498,19 +6497,6 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
|
||||
Register reg2 = AsmJSIonExitRegE2;
|
||||
Register reg3 = AsmJSIonExitRegE3;
|
||||
|
||||
LoadAsmJSActivationIntoRegister(masm, reg0);
|
||||
|
||||
// Record sp in the AsmJSActivation for stack-walking.
|
||||
#if defined(JS_CODEGEN_MIPS)
|
||||
// Add a flag to indicate to AsmJSFrameIterator that we are calling
|
||||
// into Ion, since the offset from SP to the return address is
|
||||
// different when calling Ion vs. the native ABI.
|
||||
masm.ma_or(reg1, StackPointer, Imm32(0x1));
|
||||
masm.storePtr(reg1, Address(reg0, AsmJSActivation::offsetOfExitSP()));
|
||||
#else
|
||||
masm.storePtr(StackPointer, Address(reg0, AsmJSActivation::offsetOfExitSP()));
|
||||
#endif
|
||||
|
||||
// The following is inlined:
|
||||
// JSContext *cx = activation->cx();
|
||||
// Activation *act = cx->mainThread().activation();
|
||||
@ -6524,6 +6510,7 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
|
||||
size_t offsetOfJitTop = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, jitTop);
|
||||
size_t offsetOfJitJSContext = offsetof(JSRuntime, mainThread) +
|
||||
offsetof(PerThreadData, jitJSContext);
|
||||
LoadAsmJSActivationIntoRegister(masm, reg0);
|
||||
masm.loadPtr(Address(reg0, AsmJSActivation::offsetOfContext()), reg3);
|
||||
masm.loadPtr(Address(reg3, JSContext::offsetOfRuntime()), reg0);
|
||||
masm.loadPtr(Address(reg0, offsetOfActivation), reg1);
|
||||
@ -6595,13 +6582,19 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
|
||||
|
||||
masm.bind(&done);
|
||||
masm.freeStack(stackDec);
|
||||
|
||||
// Restore non-volatile registers saved in the prologue.
|
||||
#if defined(JS_CODEGEN_X64)
|
||||
masm.Pop(HeapReg);
|
||||
#endif
|
||||
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
|
||||
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
|
||||
masm.loadConstantDouble(GenericNaN(), NANReg);
|
||||
masm.PopRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
|
||||
#endif
|
||||
|
||||
// Clear exitFP before the frame is destroyed.
|
||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||
masm.storePtr(ImmWord(0), Address(activation, AsmJSActivation::offsetOfExitFP()));
|
||||
|
||||
masm.ret();
|
||||
JS_ASSERT(masm.framePushed() == 0);
|
||||
|
||||
@ -6642,18 +6635,20 @@ GenerateStackOverflowExit(ModuleCompiler &m, Label *throwLabel)
|
||||
masm.align(CodeAlignment);
|
||||
masm.bind(&m.stackOverflowLabel());
|
||||
|
||||
// The stack-overflow is checked before bumping the stack.
|
||||
masm.setFramePushed(0);
|
||||
|
||||
// Store the frame pointer in AsmJSActivation::exitFP for stack unwinding.
|
||||
Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
|
||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP()));
|
||||
|
||||
MIRTypeVector argTypes(m.cx());
|
||||
argTypes.infallibleAppend(MIRType_Pointer); // cx
|
||||
|
||||
unsigned stackDec = StackDecrementForCall(masm, argTypes, MaybeRetAddr);
|
||||
masm.reserveStack(stackDec);
|
||||
|
||||
Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
|
||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||
|
||||
// Record sp in the AsmJSActivation for stack-walking.
|
||||
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitSP()));
|
||||
|
||||
ABIArgMIRTypeIter i(argTypes);
|
||||
|
||||
// argument 0: cx
|
||||
@ -6668,7 +6663,11 @@ GenerateStackOverflowExit(ModuleCompiler &m, Label *throwLabel)
|
||||
JS_ASSERT(i.done());
|
||||
|
||||
AssertStackAlignment(masm);
|
||||
masm.callExit(AsmJSImmPtr(AsmJSImm_ReportOverRecursed), i.stackBytesConsumedSoFar());
|
||||
masm.call(AsmJSImmPtr(AsmJSImm_ReportOverRecursed));
|
||||
|
||||
// Clear exitFP before the frame is destroyed.
|
||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||
masm.storePtr(ImmWord(0), Address(activation, AsmJSActivation::offsetOfExitFP()));
|
||||
|
||||
// Don't worry about restoring the stack; throwLabel will pop everything.
|
||||
masm.jump(throwLabel);
|
||||
@ -6867,10 +6866,10 @@ static bool
|
||||
GenerateStubs(ModuleCompiler &m)
|
||||
{
|
||||
for (unsigned i = 0; i < m.module().numExportedFunctions(); i++) {
|
||||
m.setEntryOffset(i);
|
||||
m.startGeneratingEntry(i);
|
||||
if (!GenerateEntry(m, m.module().exportedFunction(i)))
|
||||
return false;
|
||||
if (m.masm().oom())
|
||||
if (m.masm().oom() || !m.finishGeneratingEntry(i))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
75
js/src/jit/AsmJSFrameIterator.cpp
Normal file
75
js/src/jit/AsmJSFrameIterator.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jit/AsmJSFrameIterator.h"
|
||||
|
||||
#include "jit/AsmJS.h"
|
||||
#include "jit/AsmJSModule.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
static void *
|
||||
ReturnAddressFromFP(uint8_t *fp)
|
||||
{
|
||||
// In asm.js code, the "frame" consists of a single word: the saved
|
||||
// return address of the caller.
|
||||
static_assert(AsmJSFrameSize == sizeof(void*), "Frame size mismatch");
|
||||
return *(uint8_t**)fp;
|
||||
}
|
||||
|
||||
AsmJSFrameIterator::AsmJSFrameIterator(const AsmJSActivation &activation)
|
||||
: module_(&activation.module()),
|
||||
fp_(activation.exitFP())
|
||||
{
|
||||
if (!fp_)
|
||||
return;
|
||||
settle(ReturnAddressFromFP(fp_));
|
||||
}
|
||||
|
||||
void
|
||||
AsmJSFrameIterator::operator++()
|
||||
{
|
||||
JS_ASSERT(!done());
|
||||
fp_ += callsite_->stackDepth();
|
||||
settle(ReturnAddressFromFP(fp_));
|
||||
}
|
||||
|
||||
void
|
||||
AsmJSFrameIterator::settle(void *returnAddress)
|
||||
{
|
||||
const AsmJSModule::CodeRange *codeRange = module_->lookupCodeRange(ReturnAddressFromFP(fp_));
|
||||
JS_ASSERT(codeRange);
|
||||
codeRange_ = codeRange;
|
||||
|
||||
switch (codeRange->kind()) {
|
||||
case AsmJSModule::CodeRange::Entry:
|
||||
fp_ = nullptr;
|
||||
JS_ASSERT(done());
|
||||
return;
|
||||
case AsmJSModule::CodeRange::Function:
|
||||
callsite_ = module_->lookupCallSite(returnAddress);
|
||||
JS_ASSERT(callsite_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
JSAtom *
|
||||
AsmJSFrameIterator::functionDisplayAtom() const
|
||||
{
|
||||
JS_ASSERT(!done());
|
||||
return reinterpret_cast<const AsmJSModule::CodeRange*>(codeRange_)->functionName(*module_);
|
||||
}
|
||||
|
||||
unsigned
|
||||
AsmJSFrameIterator::computeLine(uint32_t *column) const
|
||||
{
|
||||
JS_ASSERT(!done());
|
||||
if (column)
|
||||
*column = callsite_->column();
|
||||
return callsite_->line();
|
||||
}
|
||||
|
46
js/src/jit/AsmJSFrameIterator.h
Normal file
46
js/src/jit/AsmJSFrameIterator.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef jit_AsmJSFrameIterator_h
|
||||
#define jit_AsmJSFrameIterator_h
|
||||
|
||||
#include "mozilla/NullPtr.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class JSAtom;
|
||||
|
||||
namespace js {
|
||||
|
||||
class AsmJSActivation;
|
||||
class AsmJSModule;
|
||||
namespace jit { struct CallSite; }
|
||||
|
||||
// Iterates over the frames of a single AsmJSActivation.
|
||||
class AsmJSFrameIterator
|
||||
{
|
||||
const AsmJSModule *module_;
|
||||
const jit::CallSite *callsite_;
|
||||
uint8_t *fp_;
|
||||
|
||||
// Really, a const AsmJSModule::CodeRange*, but no forward declarations of
|
||||
// nested classes, so use void* to avoid pulling in all of AsmJSModule.h.
|
||||
const void *codeRange_;
|
||||
|
||||
void settle(void *returnAddress);
|
||||
|
||||
public:
|
||||
explicit AsmJSFrameIterator() : module_(nullptr) {}
|
||||
explicit AsmJSFrameIterator(const AsmJSActivation &activation);
|
||||
void operator++();
|
||||
bool done() const { return !fp_; }
|
||||
JSAtom *functionDisplayAtom() const;
|
||||
unsigned computeLine(uint32_t *column) const;
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // jit_AsmJSFrameIterator_h
|
@ -34,101 +34,6 @@ using namespace js::jit;
|
||||
using mozilla::IsNaN;
|
||||
using mozilla::PodZero;
|
||||
|
||||
static uint8_t *
|
||||
ReturnAddressForExitCall(uint8_t **psp)
|
||||
{
|
||||
uint8_t *sp = *psp;
|
||||
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
|
||||
// For calls to Ion/C++ on x86/x64, the exitSP is the SP right before the call
|
||||
// to C++. Since the call instruction pushes the return address, we know
|
||||
// that the return address is 1 word below exitSP.
|
||||
return *(uint8_t**)(sp - sizeof(void*));
|
||||
#elif defined(JS_CODEGEN_ARM)
|
||||
// For calls to Ion/C++ on ARM, the *caller* pushes the return address on
|
||||
// the stack. For Ion, this is just part of the ABI. For C++, the return
|
||||
// address is explicitly pushed before the call since we cannot expect the
|
||||
// callee to immediately push lr. This means that exitSP points to the
|
||||
// return address.
|
||||
return *(uint8_t**)sp;
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
// On MIPS we have two cases: an exit to C++ will store the return address
|
||||
// at ShadowStackSpace above sp; an exit to Ion will store the return
|
||||
// address at sp. To distinguish the two cases, the low bit of sp (which is
|
||||
// aligned and therefore zero) is set for Ion exits.
|
||||
if (uintptr_t(sp) & 0x1) {
|
||||
sp = *psp -= 0x1; // Clear the low bit
|
||||
return *(uint8_t**)sp;
|
||||
}
|
||||
return *(uint8_t**)(sp + ShadowStackSpace);
|
||||
#else
|
||||
# error "Unknown architecture!"
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint8_t *
|
||||
ReturnAddressForJitCall(uint8_t *sp)
|
||||
{
|
||||
// Once inside JIT code, sp always points to the word before the return
|
||||
// address.
|
||||
return *(uint8_t**)(sp - sizeof(void*));
|
||||
}
|
||||
|
||||
AsmJSFrameIterator::AsmJSFrameIterator(const AsmJSActivation *activation)
|
||||
: module_(nullptr)
|
||||
{
|
||||
if (!activation || activation->isInterruptedSP())
|
||||
return;
|
||||
|
||||
module_ = &activation->module();
|
||||
sp_ = activation->exitSP();
|
||||
|
||||
settle(ReturnAddressForExitCall(&sp_));
|
||||
}
|
||||
|
||||
void
|
||||
AsmJSFrameIterator::operator++()
|
||||
{
|
||||
settle(ReturnAddressForJitCall(sp_));
|
||||
}
|
||||
|
||||
void
|
||||
AsmJSFrameIterator::settle(uint8_t *returnAddress)
|
||||
{
|
||||
callsite_ = module_->lookupCallSite(returnAddress);
|
||||
if (!callsite_ || callsite_->isEntry()) {
|
||||
module_ = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (callsite_->isEntry()) {
|
||||
module_ = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
sp_ += callsite_->stackDepth();
|
||||
|
||||
if (callsite_->isExit())
|
||||
return settle(ReturnAddressForJitCall(sp_));
|
||||
|
||||
JS_ASSERT(callsite_->isNormal());
|
||||
}
|
||||
|
||||
JSAtom *
|
||||
AsmJSFrameIterator::functionDisplayAtom() const
|
||||
{
|
||||
JS_ASSERT(!done());
|
||||
return module_->functionName(callsite_->functionNameIndex());
|
||||
}
|
||||
|
||||
unsigned
|
||||
AsmJSFrameIterator::computeLine(uint32_t *column) const
|
||||
{
|
||||
JS_ASSERT(!done());
|
||||
if (column)
|
||||
*column = callsite_->column();
|
||||
return callsite_->line();
|
||||
}
|
||||
|
||||
static bool
|
||||
CloneModule(JSContext *cx, MutableHandle<AsmJSModuleObject*> moduleObj)
|
||||
{
|
||||
|
@ -9,31 +9,8 @@
|
||||
|
||||
#include "NamespaceImports.h"
|
||||
|
||||
class JSAtom;
|
||||
|
||||
namespace js {
|
||||
|
||||
class AsmJSActivation;
|
||||
class AsmJSModule;
|
||||
namespace jit { struct CallSite; }
|
||||
|
||||
// Iterates over the frames of a single AsmJSActivation.
|
||||
class AsmJSFrameIterator
|
||||
{
|
||||
const AsmJSModule *module_;
|
||||
const jit::CallSite *callsite_;
|
||||
uint8_t *sp_;
|
||||
|
||||
void settle(uint8_t *returnAddress);
|
||||
|
||||
public:
|
||||
explicit AsmJSFrameIterator(const AsmJSActivation *activation);
|
||||
void operator++();
|
||||
bool done() const { return !module_; }
|
||||
JSAtom *functionDisplayAtom() const;
|
||||
unsigned computeLine(uint32_t *column) const;
|
||||
};
|
||||
|
||||
#ifdef JS_ION
|
||||
|
||||
// Create a new JSFunction to replace originalFun as the representation of the
|
||||
|
@ -167,6 +167,7 @@ AsmJSModule::addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t *asmJSModu
|
||||
exits_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
exports_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
callSites_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
codeRanges_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
functionNames_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
heapAccesses_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
functionCounts_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
@ -189,11 +190,11 @@ struct CallSiteRetAddrOffset
|
||||
};
|
||||
|
||||
const CallSite *
|
||||
AsmJSModule::lookupCallSite(uint8_t *returnAddress) const
|
||||
AsmJSModule::lookupCallSite(void *returnAddress) const
|
||||
{
|
||||
JS_ASSERT(isFinished());
|
||||
|
||||
uint32_t target = returnAddress - code_;
|
||||
uint32_t target = ((uint8_t*)returnAddress) - code_;
|
||||
size_t lowerBound = 0;
|
||||
size_t upperBound = callSites_.length();
|
||||
|
||||
@ -204,6 +205,45 @@ AsmJSModule::lookupCallSite(uint8_t *returnAddress) const
|
||||
return &callSites_[match];
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
// Create an ordering on CodeRange and pc offsets suitable for BinarySearch.
|
||||
// Stick these in the same namespace as AsmJSModule so that argument-dependent
|
||||
// lookup will find it.
|
||||
bool
|
||||
operator==(size_t pcOffset, const AsmJSModule::CodeRange &rhs)
|
||||
{
|
||||
return pcOffset >= rhs.begin() && pcOffset < rhs.end();
|
||||
}
|
||||
bool
|
||||
operator<=(const AsmJSModule::CodeRange &lhs, const AsmJSModule::CodeRange &rhs)
|
||||
{
|
||||
return lhs.begin() <= rhs.begin();
|
||||
}
|
||||
bool
|
||||
operator<(size_t pcOffset, const AsmJSModule::CodeRange &rhs)
|
||||
{
|
||||
return pcOffset < rhs.begin();
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
const AsmJSModule::CodeRange *
|
||||
AsmJSModule::lookupCodeRange(void *pc) const
|
||||
{
|
||||
JS_ASSERT(isFinished());
|
||||
|
||||
uint32_t target = ((uint8_t*)pc) - code_;
|
||||
size_t lowerBound = 0;
|
||||
size_t upperBound = codeRanges_.length();
|
||||
|
||||
size_t match;
|
||||
if (!BinarySearch(codeRanges_, lowerBound, upperBound, target, &match))
|
||||
return nullptr;
|
||||
|
||||
return &codeRanges_[match];
|
||||
}
|
||||
|
||||
struct HeapAccessOffset
|
||||
{
|
||||
const AsmJSHeapAccessVector &accesses;
|
||||
@ -214,12 +254,12 @@ struct HeapAccessOffset
|
||||
};
|
||||
|
||||
const AsmJSHeapAccess *
|
||||
AsmJSModule::lookupHeapAccess(uint8_t *pc) const
|
||||
AsmJSModule::lookupHeapAccess(void *pc) const
|
||||
{
|
||||
JS_ASSERT(isFinished());
|
||||
JS_ASSERT(containsPC(pc));
|
||||
|
||||
uint32_t target = pc - code_;
|
||||
uint32_t target = ((uint8_t*)pc) - code_;
|
||||
size_t lowerBound = 0;
|
||||
size_t upperBound = heapAccesses_.length();
|
||||
|
||||
@ -293,6 +333,11 @@ AsmJSModule::finish(ExclusiveContext *cx, TokenStream &tokenStream, MacroAssembl
|
||||
CallSite &c = callSites_[i];
|
||||
c.setReturnAddressOffset(masm.actualOffset(c.returnAddressOffset()));
|
||||
}
|
||||
for (size_t i = 0; i < codeRanges_.length(); i++) {
|
||||
CodeRange &c = codeRanges_[i];
|
||||
c.begin_ = masm.actualOffset(c.begin_);
|
||||
c.end_ = masm.actualOffset(c.end_);
|
||||
}
|
||||
#endif
|
||||
JS_ASSERT(pod.functionBytes_ % AsmJSPageSize == 0);
|
||||
|
||||
@ -1084,6 +1129,7 @@ AsmJSModule::serializedSize() const
|
||||
SerializedVectorSize(exits_) +
|
||||
SerializedVectorSize(exports_) +
|
||||
SerializedPodVectorSize(callSites_) +
|
||||
SerializedPodVectorSize(codeRanges_) +
|
||||
SerializedVectorSize(functionNames_) +
|
||||
SerializedPodVectorSize(heapAccesses_) +
|
||||
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
|
||||
@ -1104,6 +1150,7 @@ AsmJSModule::serialize(uint8_t *cursor) const
|
||||
cursor = SerializeVector(cursor, exits_);
|
||||
cursor = SerializeVector(cursor, exports_);
|
||||
cursor = SerializePodVector(cursor, callSites_);
|
||||
cursor = SerializePodVector(cursor, codeRanges_);
|
||||
cursor = SerializeVector(cursor, functionNames_);
|
||||
cursor = SerializePodVector(cursor, heapAccesses_);
|
||||
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
|
||||
@ -1130,6 +1177,7 @@ AsmJSModule::deserialize(ExclusiveContext *cx, const uint8_t *cursor)
|
||||
(cursor = DeserializeVector(cx, cursor, &exits_)) &&
|
||||
(cursor = DeserializeVector(cx, cursor, &exports_)) &&
|
||||
(cursor = DeserializePodVector(cx, cursor, &callSites_)) &&
|
||||
(cursor = DeserializePodVector(cx, cursor, &codeRanges_)) &&
|
||||
(cursor = DeserializeVector(cx, cursor, &functionNames_)) &&
|
||||
(cursor = DeserializePodVector(cx, cursor, &heapAccesses_)) &&
|
||||
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
|
||||
@ -1200,6 +1248,7 @@ AsmJSModule::clone(JSContext *cx, ScopedJSDeletePtr<AsmJSModule> *moduleOut) con
|
||||
!CloneVector(cx, exits_, &out.exits_) ||
|
||||
!CloneVector(cx, exports_, &out.exports_) ||
|
||||
!ClonePodVector(cx, callSites_, &out.callSites_) ||
|
||||
!ClonePodVector(cx, codeRanges_, &out.codeRanges_) ||
|
||||
!CloneVector(cx, functionNames_, &out.functionNames_) ||
|
||||
!ClonePodVector(cx, heapAccesses_, &out.heapAccesses_) ||
|
||||
!staticLinkData_.clone(cx, &out.staticLinkData_))
|
||||
|
@ -313,6 +313,33 @@ class AsmJSModule
|
||||
bool clone(ExclusiveContext *cx, ExportedFunction *out) const;
|
||||
};
|
||||
|
||||
class CodeRange
|
||||
{
|
||||
public:
|
||||
enum Kind { Entry, Function };
|
||||
|
||||
private:
|
||||
Kind kind_;
|
||||
uint32_t begin_;
|
||||
uint32_t end_;
|
||||
uint32_t functionNameIndex_;
|
||||
|
||||
friend class AsmJSModule;
|
||||
CodeRange(Kind k, uint32_t begin, uint32_t end, uint32_t functionNameIndex)
|
||||
: kind_(k), begin_(begin), end_(end), functionNameIndex_(functionNameIndex)
|
||||
{}
|
||||
|
||||
public:
|
||||
CodeRange() {}
|
||||
Kind kind() const { return kind_; }
|
||||
uint32_t begin() const { return begin_; }
|
||||
uint32_t end() const { return end_; }
|
||||
PropertyName *functionName(const AsmJSModule &module) const {
|
||||
JS_ASSERT(kind_ == Function);
|
||||
return module.functionNames_[functionNameIndex_].name();
|
||||
}
|
||||
};
|
||||
|
||||
class Name
|
||||
{
|
||||
PropertyName *name_;
|
||||
@ -479,6 +506,7 @@ class AsmJSModule
|
||||
Vector<Exit, 0, SystemAllocPolicy> exits_;
|
||||
Vector<ExportedFunction, 0, SystemAllocPolicy> exports_;
|
||||
Vector<jit::CallSite, 0, SystemAllocPolicy> callSites_;
|
||||
Vector<CodeRange, 0, SystemAllocPolicy> codeRanges_;
|
||||
Vector<Name, 0, SystemAllocPolicy> functionNames_;
|
||||
Vector<jit::AsmJSHeapAccess, 0, SystemAllocPolicy> heapAccesses_;
|
||||
Vector<jit::IonScriptCounts*, 0, SystemAllocPolicy> functionCounts_;
|
||||
@ -666,17 +694,20 @@ class AsmJSModule
|
||||
if (len > pod.minHeapLength_)
|
||||
pod.minHeapLength_ = len;
|
||||
}
|
||||
bool addFunctionName(PropertyName *name, uint32_t *nameIndex) {
|
||||
bool addFunctionCodeRange(PropertyName *name, uint32_t begin, uint32_t end) {
|
||||
JS_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
|
||||
JS_ASSERT(name->isTenured());
|
||||
if (functionNames_.length() > jit::CallSiteDesc::FUNCTION_NAME_INDEX_MAX)
|
||||
JS_ASSERT(begin <= end);
|
||||
JS_ASSERT_IF(!codeRanges_.empty(), codeRanges_.back().end() <= begin);
|
||||
if (functionNames_.length() >= UINT32_MAX)
|
||||
return false;
|
||||
*nameIndex = functionNames_.length();
|
||||
return functionNames_.append(name);
|
||||
CodeRange codeRange(CodeRange::Function, begin, end, functionNames_.length());
|
||||
return functionNames_.append(name) && codeRanges_.append(codeRange);
|
||||
}
|
||||
PropertyName *functionName(uint32_t i) const {
|
||||
JS_ASSERT(isFinished());
|
||||
return functionNames_[i].name();
|
||||
bool addEntryCodeRange(unsigned exportIndex, uint32_t end) {
|
||||
uint32_t begin = exports_[exportIndex].pod.codeOffset_;
|
||||
CodeRange codeRange(CodeRange::Entry, begin, end, UINT32_MAX);
|
||||
return codeRanges_.append(codeRange);
|
||||
}
|
||||
bool addExit(unsigned ffiIndex, unsigned *exitIndex) {
|
||||
JS_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
|
||||
@ -852,11 +883,15 @@ class AsmJSModule
|
||||
|
||||
// Lookup a callsite by the return pc (from the callee to the caller).
|
||||
// Return null if no callsite was found.
|
||||
const jit::CallSite *lookupCallSite(uint8_t *returnAddress) const;
|
||||
const jit::CallSite *lookupCallSite(void *returnAddress) const;
|
||||
|
||||
// Lookup the name the code range containing the given pc. Return null if no
|
||||
// code range was found.
|
||||
const CodeRange *lookupCodeRange(void *pc) const;
|
||||
|
||||
// Lookup a heap access site by the pc which performs the access. Return
|
||||
// null if no heap access was found.
|
||||
const jit::AsmJSHeapAccess *lookupHeapAccess(uint8_t *pc) const;
|
||||
const jit::AsmJSHeapAccess *lookupHeapAccess(void *pc) const;
|
||||
|
||||
// The global data section is placed after the executable code (i.e., at
|
||||
// offset codeBytes_) in the module's linear allocation. The global data
|
||||
|
@ -356,7 +356,7 @@ HandleSimulatorInterrupt(JSRuntime *rt, AsmJSActivation *activation, void *fault
|
||||
if (module.containsPC((void *)rt->mainThread.simulator()->get_pc()) &&
|
||||
module.containsPC(faultingAddress))
|
||||
{
|
||||
activation->setInterrupted(nullptr);
|
||||
activation->setResumePC(nullptr);
|
||||
int32_t nextpc = int32_t(module.interruptExit());
|
||||
rt->mainThread.simulator()->set_resume_pc(nextpc);
|
||||
return true;
|
||||
@ -465,7 +465,7 @@ HandleException(PEXCEPTION_POINTERS exception)
|
||||
// The trampoline will jump to activation->resumePC if execution isn't
|
||||
// interrupted.
|
||||
if (module.containsPC(faultingAddress)) {
|
||||
activation->setInterrupted(pc);
|
||||
activation->setResumePC(pc);
|
||||
*ppc = module.interruptExit();
|
||||
|
||||
JSRuntime::AutoLockForInterrupt lock(rt);
|
||||
@ -668,7 +668,7 @@ HandleMachException(JSRuntime *rt, const ExceptionRequest &request)
|
||||
// The trampoline will jump to activation->resumePC if execution isn't
|
||||
// interrupted.
|
||||
if (module.containsPC(faultingAddress)) {
|
||||
activation->setInterrupted(pc);
|
||||
activation->setResumePC(pc);
|
||||
*ppc = module.interruptExit();
|
||||
|
||||
JSRuntime::AutoLockForInterrupt lock(rt);
|
||||
@ -918,7 +918,7 @@ HandleSignal(int signum, siginfo_t *info, void *ctx)
|
||||
// The trampoline will jump to activation->resumePC if execution isn't
|
||||
// interrupted.
|
||||
if (module.containsPC(faultingAddress)) {
|
||||
activation->setInterrupted(pc);
|
||||
activation->setResumePC(pc);
|
||||
*ppc = module.interruptExit();
|
||||
|
||||
JSRuntime::AutoLockForInterrupt lock(rt);
|
||||
|
@ -8583,7 +8583,7 @@ CodeGenerator::visitAsmJSCall(LAsmJSCall *ins)
|
||||
masm.call(mir->desc(), ToRegister(ins->getOperand(mir->dynamicCalleeOperandIndex())));
|
||||
break;
|
||||
case MAsmJSCall::Callee::Builtin:
|
||||
masm.call(mir->desc(), AsmJSImmPtr(callee.builtin()));
|
||||
masm.call(AsmJSImmPtr(callee.builtin()));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -140,12 +140,6 @@ static const uint32_t StackAlignment = 8;
|
||||
static const uint32_t CodeAlignment = 8;
|
||||
static const bool StackKeptAligned = true;
|
||||
|
||||
// As an invariant across architectures, within asm.js code:
|
||||
// $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment
|
||||
// To achieve this on ARM, the first instruction of the asm.js prologue pushes
|
||||
// lr without incrementing masm.framePushed.
|
||||
static const uint32_t AsmJSFrameSize = sizeof(void*);
|
||||
|
||||
static const Scale ScalePointer = TimesFour;
|
||||
|
||||
class Instruction;
|
||||
|
@ -53,7 +53,7 @@ CodeGeneratorARM::generateAsmJSPrologue(Label *stackOverflowLabel)
|
||||
{
|
||||
JS_ASSERT(gen->compilingAsmJS());
|
||||
|
||||
// See comment in Assembler-arm.h about AsmJSFrameSize.
|
||||
// See comment in Assembler-shared.h about AsmJSFrameSize.
|
||||
masm.push(lr);
|
||||
|
||||
// The asm.js over-recursed handler wants to be able to assume that SP
|
||||
|
@ -1791,6 +1791,17 @@ MacroAssemblerARMCompat::callIon(Register callee)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::callIonFromAsmJS(Register callee)
|
||||
{
|
||||
ma_callIonNoPush(callee);
|
||||
|
||||
// The Ion ABI has the callee pop the return address off the stack.
|
||||
// The asm.js caller assumes that the call leaves sp unchanged, so bump
|
||||
// the stack.
|
||||
subPtr(Imm32(sizeof(void*)), sp);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::reserveStack(uint32_t amount)
|
||||
{
|
||||
@ -3626,19 +3637,6 @@ MacroAssemblerARM::ma_call(ImmPtr dest)
|
||||
as_blx(CallReg);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARM::ma_callAndStoreRet(const Register r, uint32_t stackArgBytes)
|
||||
{
|
||||
// Note: this function stores the return address to sp[0]. The caller must
|
||||
// anticipate this by pushing additional space on the stack. The ABI does
|
||||
// not provide space for a return address so this function may only be
|
||||
// called if no argument are passed.
|
||||
JS_ASSERT(stackArgBytes == 0);
|
||||
AutoForbidPools afp(this);
|
||||
as_dtr(IsStore, 32, Offset, pc, DTRAddr(sp, DtrOffImm(0)));
|
||||
as_blx(r);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::breakpoint()
|
||||
{
|
||||
|
@ -398,9 +398,6 @@ class MacroAssemblerARM : public Assembler
|
||||
|
||||
void ma_call(ImmPtr dest);
|
||||
|
||||
// calls reg, storing the return address into sp[0]
|
||||
void ma_callAndStoreRet(const Register reg, uint32_t stackArgBytes);
|
||||
|
||||
// Float registers can only be loaded/stored in continuous runs
|
||||
// when using vstm/vldm.
|
||||
// This function breaks set into continuous runs and loads/stores
|
||||
@ -567,38 +564,13 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
ma_movPatchable(ImmPtr(c->raw()), ScratchRegister, Always, rs);
|
||||
ma_callIonHalfPush(ScratchRegister);
|
||||
}
|
||||
|
||||
void appendCallSite(const CallSiteDesc &desc) {
|
||||
// Add an extra sizeof(void*) to include the return address that was
|
||||
// pushed by the call instruction (see CallSite::stackDepth).
|
||||
enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_ + AsmJSFrameSize));
|
||||
}
|
||||
|
||||
void call(const CallSiteDesc &desc, const Register reg) {
|
||||
call(reg);
|
||||
appendCallSite(desc);
|
||||
enoughMemory_ &= append(desc, currentOffset(), framePushed_);
|
||||
}
|
||||
void call(const CallSiteDesc &desc, Label *label) {
|
||||
call(label);
|
||||
appendCallSite(desc);
|
||||
}
|
||||
void call(const CallSiteDesc &desc, AsmJSImmPtr imm) {
|
||||
call(imm);
|
||||
appendCallSite(desc);
|
||||
}
|
||||
void callExit(AsmJSImmPtr imm, uint32_t stackArgBytes) {
|
||||
movePtr(imm, CallReg);
|
||||
ma_callAndStoreRet(CallReg, stackArgBytes);
|
||||
appendCallSite(CallSiteDesc::Exit());
|
||||
}
|
||||
void callIonFromAsmJS(const Register reg) {
|
||||
ma_callIonNoPush(reg);
|
||||
appendCallSite(CallSiteDesc::Exit());
|
||||
|
||||
// The Ion ABI has the callee pop the return address off the stack.
|
||||
// The asm.js caller assumes that the call leaves sp unchanged, so bump
|
||||
// the stack.
|
||||
subPtr(Imm32(sizeof(void*)), sp);
|
||||
enoughMemory_ &= append(desc, currentOffset(), framePushed_);
|
||||
}
|
||||
|
||||
void branch(JitCode *c) {
|
||||
@ -1280,6 +1252,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
// Makes an Ion call using the only two methods that it is sane for
|
||||
// indep code to make a call
|
||||
void callIon(Register callee);
|
||||
void callIonFromAsmJS(Register callee);
|
||||
|
||||
void reserveStack(uint32_t amount);
|
||||
void freeStack(uint32_t amount);
|
||||
|
@ -4070,7 +4070,7 @@ Simulator::execute()
|
||||
int32_t rpc = resume_pc_;
|
||||
if (MOZ_UNLIKELY(rpc != 0)) {
|
||||
// AsmJS signal handler ran and we have to adjust the pc.
|
||||
activation->setInterrupted((void *)get_pc());
|
||||
activation->setResumePC((void *)get_pc());
|
||||
set_pc(rpc);
|
||||
resume_pc_ = 0;
|
||||
}
|
||||
|
@ -152,12 +152,6 @@ static const uint32_t StackAlignment = 8;
|
||||
static const uint32_t CodeAlignment = 4;
|
||||
static const bool StackKeptAligned = true;
|
||||
|
||||
// As an invariant across architectures, within asm.js code:
|
||||
// $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment
|
||||
// To achieve this on MIPS, the first instruction of the asm.js prologue pushes
|
||||
// ra without incrementing masm.framePushed.
|
||||
static const uint32_t AsmJSFrameSize = sizeof(void*);
|
||||
|
||||
static const Scale ScalePointer = TimesFour;
|
||||
|
||||
// MIPS instruction types
|
||||
|
@ -52,7 +52,7 @@ CodeGeneratorMIPS::generateAsmJSPrologue(Label *stackOverflowLabel)
|
||||
{
|
||||
JS_ASSERT(gen->compilingAsmJS());
|
||||
|
||||
// See comment in Assembler-mips.h about AsmJSFrameSize.
|
||||
// See comment in Assembler-shared.h about AsmJSFrameSize.
|
||||
masm.push(ra);
|
||||
|
||||
// The asm.js over-recursed handler wants to be able to assume that SP
|
||||
|
@ -1523,6 +1523,16 @@ MacroAssemblerMIPSCompat::callIon(Register callee)
|
||||
ma_callIon(callee);
|
||||
}
|
||||
}
|
||||
void
|
||||
MacroAssemblerMIPSCompat::callIonFromAsmJS(Register callee)
|
||||
{
|
||||
ma_callIonNoPush(reg);
|
||||
|
||||
// The Ion ABI has the callee pop the return address off the stack.
|
||||
// The asm.js caller assumes that the call leaves sp unchanged, so bump
|
||||
// the stack.
|
||||
subPtr(Imm32(sizeof(void*)), StackPointer);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::reserveStack(uint32_t amount)
|
||||
@ -3024,21 +3034,6 @@ MacroAssemblerMIPS::ma_callIonHalfPush(const Register r)
|
||||
as_sw(ra, StackPointer, 0);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPS::ma_callAndStoreRet(const Register r, uint32_t stackArgBytes)
|
||||
{
|
||||
// Note: this function stores the return address to sp[16]. The caller
|
||||
// must anticipate this by reserving additional space on the stack.
|
||||
// The ABI does not provide space for a return address so this function
|
||||
// stores 'ra' before any ABI arguments.
|
||||
// This function may only be called if there are 4 or less arguments.
|
||||
JS_ASSERT(stackArgBytes == 4 * sizeof(uintptr_t));
|
||||
|
||||
// This is a MIPS hack to push return address during jalr delay slot.
|
||||
as_jalr(r);
|
||||
as_sw(ra, StackPointer, 4 * sizeof(uintptr_t));
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPS::ma_call(ImmPtr dest)
|
||||
{
|
||||
|
@ -301,9 +301,6 @@ class MacroAssemblerMIPS : public Assembler
|
||||
// calls an ion function, assuming that the stack is currently not 8 byte aligned
|
||||
void ma_callIonHalfPush(const Register reg);
|
||||
|
||||
// calls reg, storing the return address into sp[stackArgBytes]
|
||||
void ma_callAndStoreRet(const Register reg, uint32_t stackArgBytes);
|
||||
|
||||
void ma_call(ImmPtr dest);
|
||||
|
||||
void ma_jump(ImmPtr dest);
|
||||
@ -415,38 +412,13 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS
|
||||
ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw()));
|
||||
ma_callIonHalfPush(ScratchRegister);
|
||||
}
|
||||
|
||||
void appendCallSite(const CallSiteDesc &desc) {
|
||||
// Add an extra sizeof(void*) to include the return address that was
|
||||
// pushed by the call instruction (see CallSite::stackDepth).
|
||||
enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_ + AsmJSFrameSize));
|
||||
}
|
||||
|
||||
void call(const CallSiteDesc &desc, const Register reg) {
|
||||
call(reg);
|
||||
appendCallSite(desc);
|
||||
enoughMemory_ &= append(desc, currentOffset(), framePushed_);
|
||||
}
|
||||
void call(const CallSiteDesc &desc, Label *label) {
|
||||
call(label);
|
||||
appendCallSite(desc);
|
||||
}
|
||||
void call(const CallSiteDesc &desc, AsmJSImmPtr imm) {
|
||||
call(imm);
|
||||
appendCallSite(desc);
|
||||
}
|
||||
void callExit(AsmJSImmPtr imm, uint32_t stackArgBytes) {
|
||||
movePtr(imm, CallReg);
|
||||
ma_callAndStoreRet(CallReg, stackArgBytes);
|
||||
appendCallSite(CallSiteDesc::Exit());
|
||||
}
|
||||
void callIonFromAsmJS(const Register reg) {
|
||||
ma_callIonNoPush(reg);
|
||||
appendCallSite(CallSiteDesc::Exit());
|
||||
|
||||
// The Ion ABI has the callee pop the return address off the stack.
|
||||
// The asm.js caller assumes that the call leaves sp unchanged, so bump
|
||||
// the stack.
|
||||
subPtr(Imm32(sizeof(void*)), StackPointer);
|
||||
enoughMemory_ &= append(desc, currentOffset(), framePushed_);
|
||||
}
|
||||
|
||||
void branch(JitCode *c) {
|
||||
@ -1002,6 +974,7 @@ public:
|
||||
// Makes an Ion call using the only two methods that it is sane for
|
||||
// indep code to make a call
|
||||
void callIon(Register callee);
|
||||
void callIonFromAsmJS(Register callee);
|
||||
|
||||
void reserveStack(uint32_t amount);
|
||||
void freeStack(uint32_t amount);
|
||||
|
@ -577,48 +577,19 @@ class CodeLocationLabel
|
||||
}
|
||||
};
|
||||
|
||||
// Describes the user-visible properties of a callsite.
|
||||
//
|
||||
// A few general notes about the stack-walking supported by CallSite(Desc):
|
||||
// - This information facilitates stack-walking performed by FrameIter which
|
||||
// is used by Error.stack and other user-visible stack-walking functions.
|
||||
// - Ion/asm.js calling conventions do not maintain a frame-pointer so
|
||||
// stack-walking must lookup the stack depth based on the PC.
|
||||
// - Stack-walking only occurs from C++ after a synchronous calls (JS-to-JS and
|
||||
// JS-to-C++). Thus, we do not need to map arbitrary PCs to stack-depths,
|
||||
// just the return address at callsites.
|
||||
// - An exception to the above rule is the interrupt callback which can happen
|
||||
// at arbitrary PCs. In such cases, we drop frames from the stack-walk. In
|
||||
// the future when a full PC->stack-depth map is maintained, we handle this
|
||||
// case.
|
||||
// While the frame-pointer chain allows the stack to be unwound without
|
||||
// metadata, Error.stack still needs to know the line/column of every call in
|
||||
// the chain. A CallSiteDesc describes the line/column of a single callsite.
|
||||
// A CallSiteDesc is created by callers of MacroAssembler.
|
||||
class CallSiteDesc
|
||||
{
|
||||
uint32_t line_;
|
||||
uint32_t column_;
|
||||
uint32_t functionNameIndex_;
|
||||
|
||||
static const uint32_t sEntryTrampoline = UINT32_MAX;
|
||||
static const uint32_t sExit = UINT32_MAX - 1;
|
||||
|
||||
public:
|
||||
static const uint32_t FUNCTION_NAME_INDEX_MAX = UINT32_MAX - 2;
|
||||
|
||||
CallSiteDesc() {}
|
||||
|
||||
CallSiteDesc(uint32_t line, uint32_t column, uint32_t functionNameIndex)
|
||||
: line_(line), column_(column), functionNameIndex_(functionNameIndex)
|
||||
{}
|
||||
|
||||
static CallSiteDesc Entry() { return CallSiteDesc(0, 0, sEntryTrampoline); }
|
||||
static CallSiteDesc Exit() { return CallSiteDesc(0, 0, sExit); }
|
||||
|
||||
bool isEntry() const { return functionNameIndex_ == sEntryTrampoline; }
|
||||
bool isExit() const { return functionNameIndex_ == sExit; }
|
||||
bool isNormal() const { return !(isEntry() || isExit()); }
|
||||
|
||||
uint32_t line() const { JS_ASSERT(isNormal()); return line_; }
|
||||
uint32_t column() const { JS_ASSERT(isNormal()); return column_; }
|
||||
uint32_t functionNameIndex() const { JS_ASSERT(isNormal()); return functionNameIndex_; }
|
||||
CallSiteDesc(uint32_t line, uint32_t column) : line_(line), column_(column) {}
|
||||
uint32_t line() const { return line_; }
|
||||
uint32_t column() const { return column_; }
|
||||
};
|
||||
|
||||
// Adds to CallSiteDesc the metadata necessary to walk the stack given an
|
||||
@ -641,13 +612,21 @@ struct CallSite : public CallSiteDesc
|
||||
uint32_t returnAddressOffset() const { return returnAddressOffset_; }
|
||||
|
||||
// The stackDepth measures the amount of stack space pushed since the
|
||||
// function was called. In particular, this includes the word pushed by the
|
||||
// call instruction on x86/x64.
|
||||
uint32_t stackDepth() const { JS_ASSERT(!isEntry()); return stackDepth_; }
|
||||
// function was called. In particular, this includes the pushed return
|
||||
// address on all archs (whether or not the call instruction pushes the
|
||||
// return address (x86/x64) or the prologue does (ARM/MIPS).
|
||||
uint32_t stackDepth() const { return stackDepth_; }
|
||||
};
|
||||
|
||||
typedef Vector<CallSite, 0, SystemAllocPolicy> CallSiteVector;
|
||||
|
||||
// As an invariant across architectures, within asm.js code:
|
||||
// $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment
|
||||
// AsmJSFrameSize is 1 word, for the return address pushed by the call (or, in
|
||||
// the case of ARM/MIPS, by the first instruction of the prologue). This means
|
||||
// masm.framePushed never includes the pushed return address.
|
||||
static const uint32_t AsmJSFrameSize = sizeof(void*);
|
||||
|
||||
// Summarizes a heap access made by asm.js code that needs to be patched later
|
||||
// and/or looked up by the asm.js signal handlers. Different architectures need
|
||||
// to know different things (x64: offset and length, ARM: where to patch in
|
||||
@ -821,7 +800,11 @@ class AssemblerShared
|
||||
return !enoughMemory_;
|
||||
}
|
||||
|
||||
bool append(CallSite callsite) { return callsites_.append(callsite); }
|
||||
bool append(const CallSiteDesc &desc, size_t currentOffset, size_t framePushed) {
|
||||
// framePushed does not include AsmJSFrameSize, so add it in here (see
|
||||
// CallSite::stackDepth).
|
||||
return callsites_.append(CallSite(desc, currentOffset, framePushed + AsmJSFrameSize));
|
||||
}
|
||||
CallSiteVector &&extractCallSites() { return Move(callsites_); }
|
||||
|
||||
bool append(AsmJSHeapAccess access) { return asmJSHeapAccesses_.append(access); }
|
||||
|
@ -667,26 +667,23 @@ class MacroAssemblerX86Shared : public Assembler
|
||||
bool buildFakeExitFrame(Register scratch, uint32_t *offset);
|
||||
void callWithExitFrame(JitCode *target);
|
||||
|
||||
void callIon(Register callee) {
|
||||
call(callee);
|
||||
}
|
||||
|
||||
void appendCallSite(const CallSiteDesc &desc) {
|
||||
// Add an extra sizeof(void*) to include the return address that was
|
||||
// pushed by the call instruction (see CallSite::stackDepth).
|
||||
enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_ + AsmJSFrameSize));
|
||||
}
|
||||
|
||||
void call(const CallSiteDesc &desc, Label *label) {
|
||||
call(label);
|
||||
appendCallSite(desc);
|
||||
enoughMemory_ &= append(desc, currentOffset(), framePushed_);
|
||||
}
|
||||
void call(const CallSiteDesc &desc, Register reg) {
|
||||
call(reg);
|
||||
appendCallSite(desc);
|
||||
enoughMemory_ &= append(desc, currentOffset(), framePushed_);
|
||||
}
|
||||
void callIonFromAsmJS(Register reg) {
|
||||
call(CallSiteDesc::Exit(), reg);
|
||||
void callIon(Register callee) {
|
||||
call(callee);
|
||||
}
|
||||
void callIonFromAsmJS(Register callee) {
|
||||
call(callee);
|
||||
}
|
||||
void call(AsmJSImmPtr target) {
|
||||
mov(target, eax);
|
||||
call(eax);
|
||||
}
|
||||
|
||||
void checkStackAlignment() {
|
||||
|
@ -185,13 +185,6 @@ static const uint32_t StackAlignment = 16;
|
||||
static const bool StackKeptAligned = false;
|
||||
static const uint32_t CodeAlignment = 8;
|
||||
|
||||
// As an invariant across architectures, within asm.js code:
|
||||
// $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment
|
||||
// On x64, this naturally falls out of the fact that the 'call' instruction
|
||||
// pushes the return address on the stack and masm.framePushed = 0 at the first
|
||||
// instruction of the prologue.
|
||||
static const uint32_t AsmJSFrameSize = sizeof(void*);
|
||||
|
||||
static const Scale ScalePointer = TimesEight;
|
||||
|
||||
} // namespace jit
|
||||
|
@ -100,18 +100,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
||||
void call(ImmPtr target) {
|
||||
call(ImmWord(uintptr_t(target.value)));
|
||||
}
|
||||
void call(AsmJSImmPtr target) {
|
||||
mov(target, rax);
|
||||
call(rax);
|
||||
}
|
||||
|
||||
void call(const CallSiteDesc &desc, AsmJSImmPtr target) {
|
||||
call(target);
|
||||
appendCallSite(desc);
|
||||
}
|
||||
void callExit(AsmJSImmPtr target, uint32_t stackArgBytes) {
|
||||
call(CallSiteDesc::Exit(), target);
|
||||
}
|
||||
|
||||
// Refers to the upper 32 bits of a 64-bit Value operand.
|
||||
// On x86_64, the upper 32 bits do not necessarily only contain the type.
|
||||
|
@ -113,13 +113,6 @@ static const uint32_t StackAlignment = 4;
|
||||
static const bool StackKeptAligned = false;
|
||||
static const uint32_t CodeAlignment = 8;
|
||||
|
||||
// As an invariant across architectures, within asm.js code:
|
||||
// $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment
|
||||
// On x86, this naturally falls out of the fact that the 'call' instruction
|
||||
// pushes the return address on the stack and masm.framePushed = 0 at the first
|
||||
// instruction of the prologue.
|
||||
static const uint32_t AsmJSFrameSize = sizeof(void*);
|
||||
|
||||
struct ImmTag : public Imm32
|
||||
{
|
||||
ImmTag(JSValueTag mask)
|
||||
@ -382,13 +375,6 @@ class Assembler : public AssemblerX86Shared
|
||||
JmpSrc src = masm.call();
|
||||
addPendingJump(src, target, Relocation::HARDCODED);
|
||||
}
|
||||
void call(AsmJSImmPtr target) {
|
||||
// Moving to a register is suboptimal. To fix (use a single
|
||||
// call-immediate instruction) we'll need to distinguish a new type of
|
||||
// relative patch to an absolute address in AsmJSAbsoluteLink.
|
||||
mov(target, eax);
|
||||
call(eax);
|
||||
}
|
||||
|
||||
// Emit a CALL or CMP (nop) instruction. ToggleCall can be used to patch
|
||||
// this instruction.
|
||||
|
@ -1120,13 +1120,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
||||
Push(dynStack);
|
||||
call(target);
|
||||
}
|
||||
void call(const CallSiteDesc &desc, AsmJSImmPtr target) {
|
||||
call(target);
|
||||
appendCallSite(desc);
|
||||
}
|
||||
void callExit(AsmJSImmPtr target, uint32_t stackArgBytes) {
|
||||
call(CallSiteDesc::Exit(), target);
|
||||
}
|
||||
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label *label);
|
||||
|
@ -6589,12 +6589,12 @@ JS::SetOutOfMemoryCallback(JSRuntime *rt, OutOfMemoryCallback cb, void *data)
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::CaptureCurrentStack(JSContext *cx, JS::MutableHandleObject stackp)
|
||||
JS::CaptureCurrentStack(JSContext *cx, JS::MutableHandleObject stackp, unsigned maxFrameCount)
|
||||
{
|
||||
JSCompartment *compartment = cx->compartment();
|
||||
JS_ASSERT(compartment);
|
||||
Rooted<SavedFrame *> frame(cx);
|
||||
if (!compartment->savedStacks().saveCurrentStack(cx, &frame))
|
||||
if (!compartment->savedStacks().saveCurrentStack(cx, &frame, maxFrameCount))
|
||||
return false;
|
||||
stackp.set(frame.get());
|
||||
return true;
|
||||
|
@ -5194,8 +5194,14 @@ typedef void
|
||||
extern JS_PUBLIC_API(void)
|
||||
SetOutOfMemoryCallback(JSRuntime *rt, OutOfMemoryCallback cb, void *data);
|
||||
|
||||
|
||||
/*
|
||||
* Capture the current call stack as a chain of SavedFrame objects, and set
|
||||
* |stackp| to the SavedFrame for the newest stack frame. If |maxFrameCount| is
|
||||
* non-zero, capture at most the youngest |maxFrameCount| frames.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
CaptureCurrentStack(JSContext *cx, MutableHandleObject stackp);
|
||||
CaptureCurrentStack(JSContext *cx, MutableHandleObject stackp, unsigned maxFrameCount = 0);
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
|
@ -800,7 +800,7 @@ js::FindBody(JSContext *cx, HandleFunction fun, HandleLinearString src, size_t *
|
||||
*bodyStart = ts.currentToken().pos.begin;
|
||||
if (braced)
|
||||
*bodyStart += 1;
|
||||
RangedPtr<const jschar> end = srcChars.end();
|
||||
mozilla::RangedPtr<const jschar> end = srcChars.end();
|
||||
if (end[-1] == '}') {
|
||||
end--;
|
||||
} else {
|
||||
|
@ -27,7 +27,6 @@
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsarray.h"
|
||||
@ -1170,20 +1169,10 @@ FirstCharMatcher8bit(const char *text, uint32_t n, const char pat)
|
||||
static const jschar *
|
||||
FirstCharMatcher16bit(const jschar *text, uint32_t n, const jschar pat)
|
||||
{
|
||||
/* Some platforms define wchar_t as signed and others not. */
|
||||
#if (WCHAR_MIN == 0 && WCHAR_MAX == UINT16_MAX) || (WCHAR_MIN == INT16_MIN && WCHAR_MAX == INT16_MAX)
|
||||
#if defined(XP_DARWIN) || defined(XP_WIN)
|
||||
/*
|
||||
* Wmemchr works the best.
|
||||
* But only possible to use this when,
|
||||
* size of jschar = size of wchar_t.
|
||||
*/
|
||||
const wchar_t *wtext = (const wchar_t *) text;
|
||||
const wchar_t wpat = (const wchar_t) pat;
|
||||
return (jschar *) (wmemchr(wtext, wpat, n));
|
||||
#elif defined(__clang__)
|
||||
/*
|
||||
* Performance under memchr is horrible in clang.
|
||||
* Hence it is best to use UnrolledMatcher in this case
|
||||
* Performance of memchr is horrible in OSX. Windows is better,
|
||||
* but it is still better to use UnrolledMatcher.
|
||||
*/
|
||||
return FirstCharMatcherUnrolled<jschar, jschar>(text, n, pat);
|
||||
#else
|
||||
|
@ -248,6 +248,7 @@ if CONFIG['ENABLE_ION']:
|
||||
'irregexp/NativeRegExpMacroAssembler.cpp',
|
||||
'jit/AliasAnalysis.cpp',
|
||||
'jit/AsmJS.cpp',
|
||||
'jit/AsmJSFrameIterator.cpp',
|
||||
'jit/AsmJSLink.cpp',
|
||||
'jit/AsmJSModule.cpp',
|
||||
'jit/AsmJSSignalHandlers.cpp',
|
||||
|
@ -396,13 +396,13 @@ SavedStacks::init()
|
||||
}
|
||||
|
||||
bool
|
||||
SavedStacks::saveCurrentStack(JSContext *cx, MutableHandleSavedFrame frame)
|
||||
SavedStacks::saveCurrentStack(JSContext *cx, MutableHandleSavedFrame frame, unsigned maxFrameCount)
|
||||
{
|
||||
JS_ASSERT(initialized());
|
||||
JS_ASSERT(&cx->compartment()->savedStacks() == this);
|
||||
|
||||
ScriptFrameIter iter(cx);
|
||||
return insertFrames(cx, iter, frame);
|
||||
return insertFrames(cx, iter, frame, maxFrameCount);
|
||||
}
|
||||
|
||||
void
|
||||
@ -476,7 +476,8 @@ SavedStacks::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
|
||||
}
|
||||
|
||||
bool
|
||||
SavedStacks::insertFrames(JSContext *cx, ScriptFrameIter &iter, MutableHandleSavedFrame frame)
|
||||
SavedStacks::insertFrames(JSContext *cx, ScriptFrameIter &iter, MutableHandleSavedFrame frame,
|
||||
unsigned maxFrameCount)
|
||||
{
|
||||
if (iter.done()) {
|
||||
frame.set(nullptr);
|
||||
@ -497,8 +498,20 @@ SavedStacks::insertFrames(JSContext *cx, ScriptFrameIter &iter, MutableHandleSav
|
||||
// script and callee should keep compartment alive.
|
||||
JSCompartment *compartment = iter.compartment();
|
||||
RootedSavedFrame parentFrame(cx);
|
||||
if (!insertFrames(cx, ++iter, &parentFrame))
|
||||
|
||||
// If maxFrameCount is zero, then there's no limit on the number of frames.
|
||||
if (maxFrameCount == 0) {
|
||||
if (!insertFrames(cx, ++iter, &parentFrame, 0))
|
||||
return false;
|
||||
} else if (maxFrameCount == 1) {
|
||||
// Since we were only asked to save one frame, the SavedFrame we're
|
||||
// building here should have no parent, even if there are older frames
|
||||
// on the stack.
|
||||
parentFrame = nullptr;
|
||||
} else {
|
||||
if (!insertFrames(cx, ++iter, &parentFrame, maxFrameCount - 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
AutoLocationValueRooter location(cx);
|
||||
if (!getLocation(cx, script, pc, &location))
|
||||
|
@ -104,7 +104,7 @@ class SavedStacks {
|
||||
|
||||
bool init();
|
||||
bool initialized() const { return frames.initialized(); }
|
||||
bool saveCurrentStack(JSContext *cx, MutableHandleSavedFrame frame);
|
||||
bool saveCurrentStack(JSContext *cx, MutableHandleSavedFrame frame, unsigned maxFrameCount = 0);
|
||||
void sweep(JSRuntime *rt);
|
||||
void trace(JSTracer *trc);
|
||||
uint32_t count();
|
||||
@ -116,7 +116,8 @@ class SavedStacks {
|
||||
SavedFrame::Set frames;
|
||||
JSObject *savedFrameProto;
|
||||
|
||||
bool insertFrames(JSContext *cx, ScriptFrameIter &iter, MutableHandleSavedFrame frame);
|
||||
bool insertFrames(JSContext *cx, ScriptFrameIter &iter, MutableHandleSavedFrame frame,
|
||||
unsigned maxFrameCount = 0);
|
||||
SavedFrame *getOrCreateSavedFrame(JSContext *cx, const SavedFrame::Lookup &lookup);
|
||||
// |SavedFrame.prototype| is created lazily and held weakly. It should only
|
||||
// be accessed through this method.
|
||||
|
@ -587,7 +587,7 @@ FrameIter::settleOnActivation()
|
||||
}
|
||||
|
||||
if (activation->isAsmJS()) {
|
||||
data_.asmJSFrames_ = AsmJSFrameIterator(data_.activations_->asAsmJS());
|
||||
data_.asmJSFrames_ = AsmJSFrameIterator(*data_.activations_->asAsmJS());
|
||||
|
||||
if (data_.asmJSFrames_.done()) {
|
||||
++data_.activations_;
|
||||
@ -639,7 +639,7 @@ FrameIter::Data::Data(ThreadSafeContext *cx, SavedOption savedOption,
|
||||
#ifdef JS_ION
|
||||
, jitFrames_((uint8_t *)nullptr, SequentialExecution)
|
||||
, ionInlineFrameNo_(0)
|
||||
, asmJSFrames_(nullptr)
|
||||
, asmJSFrames_()
|
||||
#endif
|
||||
{
|
||||
}
|
||||
@ -1688,7 +1688,7 @@ AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module)
|
||||
errorRejoinSP_(nullptr),
|
||||
profiler_(nullptr),
|
||||
resumePC_(nullptr),
|
||||
exitSP_(nullptr)
|
||||
exitFP_(nullptr)
|
||||
{
|
||||
if (cx->runtime()->spsProfiler.enabled()) {
|
||||
// Use a profiler string that matches jsMatch regex in
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "jsfun.h"
|
||||
#include "jsscript.h"
|
||||
|
||||
#include "jit/AsmJSLink.h"
|
||||
#include "jit/AsmJSFrameIterator.h"
|
||||
#include "jit/JitFrameIterator.h"
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
#include "jit/Registers.h" // for RegisterDump
|
||||
@ -1511,9 +1511,7 @@ class AsmJSActivation : public Activation
|
||||
void *errorRejoinSP_;
|
||||
SPSProfiler *profiler_;
|
||||
void *resumePC_;
|
||||
uint8_t *exitSP_;
|
||||
|
||||
static const intptr_t InterruptedSP = -1;
|
||||
uint8_t *exitFP_;
|
||||
|
||||
public:
|
||||
AsmJSActivation(JSContext *cx, AsmJSModule &module);
|
||||
@ -1529,16 +1527,18 @@ class AsmJSActivation : public Activation
|
||||
|
||||
// Initialized by JIT code:
|
||||
static unsigned offsetOfErrorRejoinSP() { return offsetof(AsmJSActivation, errorRejoinSP_); }
|
||||
static unsigned offsetOfExitSP() { return offsetof(AsmJSActivation, exitSP_); }
|
||||
static unsigned offsetOfExitFP() { return offsetof(AsmJSActivation, exitFP_); }
|
||||
|
||||
// Set from SIGSEGV handler:
|
||||
void setInterrupted(void *pc) { resumePC_ = pc; exitSP_ = (uint8_t*)InterruptedSP; }
|
||||
bool isInterruptedSP() const { return exitSP_ == (uint8_t*)InterruptedSP; }
|
||||
void setResumePC(void *pc) { resumePC_ = pc; }
|
||||
|
||||
// Note: exitSP is the sp right before the call instruction. On x86, this
|
||||
// means before the return address is pushed on the stack, on ARM, this
|
||||
// means after.
|
||||
uint8_t *exitSP() const { JS_ASSERT(!isInterruptedSP()); return exitSP_; }
|
||||
// If pc is in C++/Ion code, exitFP points to the innermost asm.js frame
|
||||
// (the one that called into C++). While in asm.js code, exitFP is either
|
||||
// null or points to the innermost asm.js frame. Thus, it is always valid to
|
||||
// unwind a non-null exitFP. The only way C++ can observe a null exitFP is
|
||||
// asychronous interruption of asm.js execution (viz., via the profiler,
|
||||
// a signal handler, or the interrupt exit).
|
||||
uint8_t *exitFP() const { return exitFP_; }
|
||||
};
|
||||
|
||||
// A FrameIter walks over the runtime's stack of JS script activations,
|
||||
|
@ -79,7 +79,8 @@ StackScopedCloneRead(JSContext *cx, JSStructuredCloneReader *reader, uint32_t ta
|
||||
if (!JS_WrapObject(cx, &obj))
|
||||
return nullptr;
|
||||
|
||||
if (!xpc::NewFunctionForwarder(cx, obj, true, &functionValue))
|
||||
FunctionForwarderOptions forwarderOptions(cx);
|
||||
if (!xpc::NewFunctionForwarder(cx, JSID_VOIDHANDLE, obj, forwarderOptions, &functionValue))
|
||||
return nullptr;
|
||||
|
||||
return &functionValue.toObject();
|
||||
@ -139,9 +140,14 @@ StackScopedCloneWrite(JSContext *cx, JSStructuredCloneWriter *writer,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cloneData->mOptions->cloneFunctions && JS_ObjectIsCallable(cx, obj)) {
|
||||
if (JS_ObjectIsCallable(cx, obj)) {
|
||||
if (cloneData->mOptions->cloneFunctions) {
|
||||
cloneData->mFunctions.append(obj);
|
||||
return JS_WriteUint32Pair(writer, SCTAG_FUNCTION, cloneData->mFunctions.length() - 1);
|
||||
} else {
|
||||
JS_ReportError(cx, "Permission denied to pass a Function via structured clone");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
JS_ReportError(cx, "Encountered unsupported value type writing stack-scoped structured clone");
|
||||
@ -201,17 +207,30 @@ CloningFunctionForwarder(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
RootedValue v(cx, js::GetFunctionNativeReserved(&args.callee(), 0));
|
||||
NS_ASSERTION(v.isObject(), "weird function");
|
||||
RootedObject origFunObj(cx, UncheckedUnwrap(&v.toObject()));
|
||||
// Grab the options from the reserved slot.
|
||||
RootedObject optionsObj(cx, &js::GetFunctionNativeReserved(&args.callee(), 1).toObject());
|
||||
FunctionForwarderOptions options(cx, optionsObj);
|
||||
if (!options.Parse())
|
||||
return false;
|
||||
|
||||
// Grab and unwrap the underlying callable.
|
||||
RootedObject forwarderObj(cx, &js::GetFunctionNativeReserved(&args.callee(), 0).toObject());
|
||||
RootedObject origFunObj(cx, UncheckedUnwrap(forwarderObj));
|
||||
{
|
||||
JSAutoCompartment ac(cx, origFunObj);
|
||||
// Note: only the arguments are cloned not the |this| or the |callee|.
|
||||
// Function forwarder does not use those.
|
||||
StackScopedCloneOptions options;
|
||||
options.wrapReflectors = true;
|
||||
StackScopedCloneOptions cloneOptions;
|
||||
cloneOptions.wrapReflectors = true;
|
||||
for (unsigned i = 0; i < args.length(); i++) {
|
||||
if (!StackScopedClone(cx, options, args[i])) {
|
||||
RootedObject argObj(cx, args[i].isObject() ? &args[i].toObject() : nullptr);
|
||||
if (options.allowCallbacks && argObj && JS_ObjectIsCallable(cx, argObj)) {
|
||||
FunctionForwarderOptions innerOptions(cx);
|
||||
if (!JS_WrapObject(cx, &argObj))
|
||||
return false;
|
||||
if (!xpc::NewFunctionForwarder(cx, JSID_VOIDHANDLE, argObj, innerOptions, args[i]))
|
||||
return nullptr;
|
||||
} else if (!StackScopedClone(cx, cloneOptions, args[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -243,13 +262,39 @@ NonCloningFunctionForwarder(JSContext *cx, unsigned argc, Value *vp)
|
||||
return JS_CallFunctionValue(cx, obj, v, args, args.rval());
|
||||
}
|
||||
bool
|
||||
NewFunctionForwarder(JSContext *cx, HandleId id, HandleObject callable, bool doclone,
|
||||
NewFunctionForwarder(JSContext *cx, HandleId idArg, HandleObject callable,
|
||||
FunctionForwarderOptions &options, MutableHandleValue vp)
|
||||
{
|
||||
RootedId id(cx, idArg);
|
||||
if (id == JSID_VOIDHANDLE)
|
||||
id = GetRTIdByIndex(cx, XPCJSRuntime::IDX_EMPTYSTRING);
|
||||
|
||||
JSFunction *fun = js::NewFunctionByIdWithReserved(cx, CloningFunctionForwarder, 0,0,
|
||||
JS::CurrentGlobalOrNull(cx), id);
|
||||
if (!fun)
|
||||
return false;
|
||||
|
||||
// Stash the callable in slot 0.
|
||||
AssertSameCompartment(cx, callable);
|
||||
RootedObject funObj(cx, JS_GetFunctionObject(fun));
|
||||
js::SetFunctionNativeReserved(funObj, 0, ObjectValue(*callable));
|
||||
|
||||
// Stash the options in slot 1.
|
||||
RootedObject optionsObj(cx, options.ToJSObject(cx));
|
||||
if (!optionsObj)
|
||||
return false;
|
||||
js::SetFunctionNativeReserved(funObj, 1, ObjectValue(*optionsObj));
|
||||
|
||||
vp.setObject(*funObj);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
NewNonCloningFunctionForwarder(JSContext *cx, HandleId id, HandleObject callable,
|
||||
MutableHandleValue vp)
|
||||
{
|
||||
JSFunction *fun = js::NewFunctionByIdWithReserved(cx, doclone ? CloningFunctionForwarder :
|
||||
NonCloningFunctionForwarder,
|
||||
JSFunction *fun = js::NewFunctionByIdWithReserved(cx, NonCloningFunctionForwarder,
|
||||
0,0, JS::CurrentGlobalOrNull(cx), id);
|
||||
|
||||
if (!fun)
|
||||
return false;
|
||||
|
||||
@ -259,18 +304,6 @@ NewFunctionForwarder(JSContext *cx, HandleId id, HandleObject callable, bool doc
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
NewFunctionForwarder(JSContext *cx, HandleObject callable, bool doclone,
|
||||
MutableHandleValue vp)
|
||||
{
|
||||
RootedId emptyId(cx);
|
||||
RootedValue emptyStringValue(cx, JS_GetEmptyStringValue(cx));
|
||||
if (!JS_ValueToId(cx, emptyStringValue, &emptyId))
|
||||
return false;
|
||||
|
||||
return NewFunctionForwarder(cx, emptyId, callable, doclone, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
ExportFunction(JSContext *cx, HandleValue vfunction, HandleValue vscope, HandleValue voptions,
|
||||
MutableHandleValue rval)
|
||||
@ -283,7 +316,7 @@ ExportFunction(JSContext *cx, HandleValue vfunction, HandleValue vscope, HandleV
|
||||
|
||||
RootedObject funObj(cx, &vfunction.toObject());
|
||||
RootedObject targetScope(cx, &vscope.toObject());
|
||||
ExportOptions options(cx, hasOptions ? &voptions.toObject() : nullptr);
|
||||
ExportFunctionOptions options(cx, hasOptions ? &voptions.toObject() : nullptr);
|
||||
if (hasOptions && !options.Parse())
|
||||
return false;
|
||||
|
||||
@ -334,7 +367,9 @@ ExportFunction(JSContext *cx, HandleValue vfunction, HandleValue vscope, HandleV
|
||||
|
||||
// And now, let's create the forwarder function in the target compartment
|
||||
// for the function the be exported.
|
||||
if (!NewFunctionForwarder(cx, id, funObj, /* doclone = */ true, rval)) {
|
||||
FunctionForwarderOptions forwarderOptions(cx);
|
||||
forwarderOptions.allowCallbacks = options.allowCallbacks;
|
||||
if (!NewFunctionForwarder(cx, id, funObj, forwarderOptions, rval)) {
|
||||
JS_ReportError(cx, "Exporting function failed");
|
||||
return false;
|
||||
}
|
||||
|
@ -3084,7 +3084,7 @@ nsXPCComponents_Utils::MakeObjectPropsNormal(HandleValue vobj, JSContext *cx)
|
||||
if (!js::IsWrapper(propobj) || !JS_ObjectIsCallable(cx, propobj))
|
||||
continue;
|
||||
|
||||
if (!NewFunctionForwarder(cx, id, propobj, /* doclone = */ false, &v) ||
|
||||
if (!NewNonCloningFunctionForwarder(cx, id, propobj, &v) ||
|
||||
!JS_SetPropertyById(cx, obj, id, v))
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -85,6 +85,7 @@ const char* const XPCJSRuntime::mStrings[] = {
|
||||
"length", // IDX_LENGTH
|
||||
"name", // IDX_NAME
|
||||
"undefined", // IDX_UNDEFINED
|
||||
"", // IDX_EMPTYSTRING
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
@ -481,6 +481,7 @@ public:
|
||||
IDX_LENGTH ,
|
||||
IDX_NAME ,
|
||||
IDX_UNDEFINED ,
|
||||
IDX_EMPTYSTRING ,
|
||||
IDX_TOTAL_COUNT // just a count of the above
|
||||
};
|
||||
|
||||
@ -3280,17 +3281,23 @@ Atob(JSContext *cx, unsigned argc, jsval *vp);
|
||||
bool
|
||||
Btoa(JSContext *cx, unsigned argc, jsval *vp);
|
||||
|
||||
class FunctionForwarderOptions;
|
||||
|
||||
// Helper function that creates a JSFunction that wraps a native function that
|
||||
// forwards the call to the original 'callable'. If the 'doclone' argument is
|
||||
// set, it also structure clones non-native arguments for extra security.
|
||||
// forwards the call to the original 'callable'. For improved security, any
|
||||
// object-valued arguments are cloned at call time, unless either:
|
||||
//
|
||||
// * The object is a function and FunctionForwarderOptions::allowCallbacks is set
|
||||
// * The object is a reflector, in which case it is wrapped.
|
||||
bool
|
||||
NewFunctionForwarder(JSContext *cx, JS::HandleId id, JS::HandleObject callable,
|
||||
bool doclone, JS::MutableHandleValue vp);
|
||||
FunctionForwarderOptions &options, JS::MutableHandleValue vp);
|
||||
|
||||
// Old-style function forwarding without structured-cloning for arguments. This
|
||||
// is deprecated.
|
||||
bool
|
||||
NewFunctionForwarder(JSContext *cx, JS::HandleObject callable,
|
||||
bool doclone, JS::MutableHandleValue vp);
|
||||
NewNonCloningFunctionForwarder(JSContext *cx, JS::HandleId id,
|
||||
JS::HandleObject callable, JS::MutableHandleValue vp);
|
||||
|
||||
// Old fashioned xpc error reporter. Try to use JS_ReportError instead.
|
||||
nsresult
|
||||
@ -3395,17 +3402,22 @@ public:
|
||||
JS::RootedId defineAs;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS ExportOptions : public OptionsBase {
|
||||
class MOZ_STACK_CLASS ExportFunctionOptions : public OptionsBase {
|
||||
public:
|
||||
ExportOptions(JSContext *cx = xpc_GetSafeJSContext(),
|
||||
ExportFunctionOptions(JSContext *cx = xpc_GetSafeJSContext(),
|
||||
JSObject* options = nullptr)
|
||||
: OptionsBase(cx, options)
|
||||
, defineAs(cx, JSID_VOID)
|
||||
, allowCallbacks(false)
|
||||
{ }
|
||||
|
||||
virtual bool Parse() { return ParseId("defineAs", &defineAs); };
|
||||
virtual bool Parse() {
|
||||
return ParseId("defineAs", &defineAs) &&
|
||||
ParseBoolean("allowCallbacks", &allowCallbacks);
|
||||
};
|
||||
|
||||
JS::RootedId defineAs;
|
||||
bool allowCallbacks;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS StackScopedCloneOptions : public OptionsBase {
|
||||
@ -3422,10 +3434,51 @@ public:
|
||||
ParseBoolean("cloneFunctions", &cloneFunctions);
|
||||
};
|
||||
|
||||
// When a reflector is encountered, wrap it rather than aborting the clone.
|
||||
bool wrapReflectors;
|
||||
|
||||
// When a function is encountered, clone it (exportFunction-style) rather than
|
||||
// aborting the clone.
|
||||
bool cloneFunctions;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS FunctionForwarderOptions : public OptionsBase {
|
||||
public:
|
||||
FunctionForwarderOptions(JSContext *cx = xpc_GetSafeJSContext(),
|
||||
JSObject* options = nullptr)
|
||||
: OptionsBase(cx, options)
|
||||
, allowCallbacks(false)
|
||||
{ }
|
||||
|
||||
JSObject *ToJSObject(JSContext *cx) {
|
||||
JS::RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
|
||||
JS::RootedObject obj(cx, JS_NewObjectWithGivenProto(cx, nullptr, JS::NullPtr(), global));
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
JS::RootedValue val(cx);
|
||||
unsigned attrs = JSPROP_READONLY | JSPROP_PERMANENT;
|
||||
val = JS::BooleanValue(allowCallbacks);
|
||||
if (!JS_DefineProperty(cx, obj, "allowCallbacks", val, attrs))
|
||||
return nullptr;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
virtual bool Parse() {
|
||||
return ParseBoolean("allowCallbacks", &allowCallbacks);
|
||||
};
|
||||
|
||||
// Allow callback arguments. This is similar to setting cloneFunctions in
|
||||
// StackScopedCloneOptions, except that cloneFunctions will clone any Function
|
||||
// encountered in the object graph, whereas this option only allows the base
|
||||
// object to be supported.
|
||||
//
|
||||
// So invoking: |forwardedFunction(callback)| will work, but
|
||||
// |forwardedFunction({ cb: callback })| will not.
|
||||
bool allowCallbacks;
|
||||
};
|
||||
|
||||
JSObject *
|
||||
CreateGlobalObject(JSContext *cx, const JSClass *clasp, nsIPrincipal *principal,
|
||||
JS::CompartmentOptions& aOptions);
|
||||
|
@ -10,6 +10,7 @@ function run_test() {
|
||||
epsb.do_check_true = do_check_true;
|
||||
epsb.do_check_eq = do_check_eq;
|
||||
epsb.do_check_neq = do_check_neq;
|
||||
subsb.do_check_true = do_check_true;
|
||||
|
||||
// Exporting should work if prinicipal of the source sandbox
|
||||
// subsumes the principal of the target sandbox.
|
||||
@ -17,7 +18,7 @@ function run_test() {
|
||||
Object.prototype.protoProp = "common";
|
||||
var wasCalled = false;
|
||||
var _this = this;
|
||||
this.funToExport = function(a, obj, native, mixed) {
|
||||
this.funToExport = function(a, obj, native, mixed, callback) {
|
||||
do_check_eq(a, 42);
|
||||
do_check_neq(obj, subsb.tobecloned);
|
||||
do_check_eq(obj.cloned, "cloned");
|
||||
@ -26,13 +27,18 @@ function run_test() {
|
||||
do_check_eq(_this, this);
|
||||
do_check_eq(mixed.xrayed, subsb.xrayed);
|
||||
do_check_eq(mixed.xrayed2, subsb.xrayed2);
|
||||
if (typeof callback == 'function') {
|
||||
do_check_eq(typeof subsb.callback, 'function');
|
||||
do_check_neq(callback, subsb.callback);
|
||||
callback();
|
||||
}
|
||||
wasCalled = true;
|
||||
};
|
||||
this.checkIfCalled = function() {
|
||||
do_check_true(wasCalled);
|
||||
wasCalled = false;
|
||||
}
|
||||
exportFunction(funToExport, subsb, { defineAs: "imported" });
|
||||
exportFunction(funToExport, subsb, { defineAs: "imported", allowCallbacks: true });
|
||||
}.toSource() + ")()", epsb);
|
||||
|
||||
subsb.xrayed = Cu.evalInSandbox("(" + function () {
|
||||
@ -47,7 +53,17 @@ function run_test() {
|
||||
xrayed2 = XPCNativeWrapper(new XMLHttpRequest());
|
||||
mixed = { xrayed: xrayed, xrayed2: xrayed2 };
|
||||
tobecloned = { cloned: "cloned" };
|
||||
imported(42,tobecloned, native, mixed);
|
||||
invokedCallback = false;
|
||||
callback = function() { invokedCallback = true; };
|
||||
imported(42, tobecloned, native, mixed, callback);
|
||||
do_check_true(invokedCallback);
|
||||
try {
|
||||
// Callbacks must be functions, not objects leading to functions.
|
||||
imported(42, tobecloned, native, mixed, { cb: callback });
|
||||
do_check_true(false);
|
||||
} catch (e) {
|
||||
do_check_true(/denied/.test(e) && /Function/.test(e));
|
||||
}
|
||||
}.toSource() + ")()", subsb);
|
||||
|
||||
// Invoking an exported function with cross-origin arguments should throw.
|
||||
@ -114,6 +130,16 @@ function run_test() {
|
||||
imported2(42, tobecloned, native, mixed);
|
||||
}.toSource() + ")()", subsb);
|
||||
|
||||
// Make sure that functions may not be passed when allowCallbacks is not set.
|
||||
try {
|
||||
Cu.evalInSandbox("(" + function () {
|
||||
imported2(42, tobecloned, native, mixed, callback);
|
||||
}.toSource() + ")()", subsb);
|
||||
do_check_true(false);
|
||||
} catch (e) {
|
||||
do_check_true(/denied/.test(e) && /Function/.test(e));
|
||||
}
|
||||
|
||||
Cu.evalInSandbox("(" + function() {
|
||||
checkIfCalled();
|
||||
}.toSource() + ")()", epsb);
|
||||
|
@ -2013,33 +2013,37 @@ ContainerState::PopThebesLayerData()
|
||||
ThebesLayerData* containingThebesLayerData =
|
||||
mLayerBuilder->GetContainingThebesLayerData();
|
||||
if (containingThebesLayerData) {
|
||||
if (!data->mDispatchToContentHitRegion.GetBounds().IsEmpty()) {
|
||||
nsRect rect = nsLayoutUtils::TransformFrameRectToAncestor(
|
||||
mContainerReferenceFrame,
|
||||
data->mDispatchToContentHitRegion.GetBounds(),
|
||||
containingThebesLayerData->mReferenceFrame);
|
||||
containingThebesLayerData->mDispatchToContentHitRegion.Or(
|
||||
containingThebesLayerData->mDispatchToContentHitRegion, rect);
|
||||
|
||||
rect = nsLayoutUtils::TransformFrameRectToAncestor(
|
||||
}
|
||||
if (!data->mMaybeHitRegion.GetBounds().IsEmpty()) {
|
||||
nsRect rect = nsLayoutUtils::TransformFrameRectToAncestor(
|
||||
mContainerReferenceFrame,
|
||||
data->mMaybeHitRegion.GetBounds(),
|
||||
containingThebesLayerData->mReferenceFrame);
|
||||
containingThebesLayerData->mMaybeHitRegion.Or(
|
||||
containingThebesLayerData->mMaybeHitRegion, rect);
|
||||
|
||||
}
|
||||
if (!data->mHitRegion.GetBounds().IsEmpty()) {
|
||||
// Our definitely-hit region must go to the maybe-hit-region since
|
||||
// this function is an approximation.
|
||||
gfx3DMatrix matrix = nsLayoutUtils::GetTransformToAncestor(
|
||||
mContainerReferenceFrame, containingThebesLayerData->mReferenceFrame);
|
||||
gfxMatrix matrix2D;
|
||||
bool isPrecise = matrix.Is2D(&matrix2D) && !matrix2D.HasNonAxisAlignedTransform();
|
||||
rect = nsLayoutUtils::TransformFrameRectToAncestor(
|
||||
nsRect rect = nsLayoutUtils::TransformFrameRectToAncestor(
|
||||
mContainerReferenceFrame,
|
||||
data->mHitRegion.GetBounds(),
|
||||
containingThebesLayerData->mReferenceFrame);
|
||||
nsRegion* dest = isPrecise ? &containingThebesLayerData->mHitRegion
|
||||
: &containingThebesLayerData->mMaybeHitRegion;
|
||||
dest->Or(*dest, rect);
|
||||
}
|
||||
} else {
|
||||
EventRegions regions;
|
||||
regions.mHitRegion = ScaleRegionToOutsidePixels(data->mHitRegion);
|
||||
|
@ -2619,7 +2619,13 @@ CalculateFrameMetricsForDisplayPort(nsIFrame* aScrollFrame,
|
||||
nsIPresShell* presShell = presContext->PresShell();
|
||||
CSSToLayoutDeviceScale deviceScale(float(nsPresContext::AppUnitsPerCSSPixel())
|
||||
/ presContext->AppUnitsPerDevPixel());
|
||||
ParentLayerToLayerScale resolution(presShell->GetResolution().width);
|
||||
ParentLayerToLayerScale resolution;
|
||||
if (aScrollFrame == presShell->GetRootScrollFrame()) {
|
||||
// Only the root scrollable frame for a given presShell should pick up
|
||||
// the presShell's resolution. All the other frames are 1.0.
|
||||
resolution = ParentLayerToLayerScale(presShell->GetXResolution(),
|
||||
presShell->GetYResolution());
|
||||
}
|
||||
LayoutDeviceToLayerScale cumulativeResolution(presShell->GetCumulativeResolution().width);
|
||||
|
||||
metrics.mDevPixelsPerCSSPixel = deviceScale;
|
||||
|
@ -3326,9 +3326,20 @@ StyleAnimationValue::ExtractComputedValue(nsCSSProperty aProperty,
|
||||
return false;
|
||||
};
|
||||
return true;
|
||||
case eStyleAnimType_Coord:
|
||||
return StyleCoordToValue(*static_cast<const nsStyleCoord*>(
|
||||
StyleDataAtOffset(styleStruct, ssOffset)), aComputedValue);
|
||||
case eStyleAnimType_Coord: {
|
||||
const nsStyleCoord& coord = *static_cast<const nsStyleCoord*>(
|
||||
StyleDataAtOffset(styleStruct, ssOffset));
|
||||
if (nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_NUMBERS_ARE_PIXELS) &&
|
||||
coord.GetUnit() == eStyleUnit_Coord) {
|
||||
// For SVG properties where number means the same thing as length,
|
||||
// we want to animate them the same way. Normalize both to number
|
||||
// since it has more accuracy (float vs nscoord).
|
||||
aComputedValue.SetFloatValue(nsPresContext::
|
||||
AppUnitsToFloatCSSPixels(coord.GetCoordValue()));
|
||||
return true;
|
||||
}
|
||||
return StyleCoordToValue(coord, aComputedValue);
|
||||
}
|
||||
case eStyleAnimType_Sides_Top:
|
||||
case eStyleAnimType_Sides_Right:
|
||||
case eStyleAnimType_Sides_Bottom:
|
||||
|
@ -3817,7 +3817,8 @@ CSS_PROP_SVG(
|
||||
stroke_dasharray,
|
||||
StrokeDasharray,
|
||||
CSS_PROPERTY_PARSE_FUNCTION |
|
||||
CSS_PROPERTY_VALUE_LIST_USES_COMMAS,
|
||||
CSS_PROPERTY_VALUE_LIST_USES_COMMAS |
|
||||
CSS_PROPERTY_NUMBERS_ARE_PIXELS,
|
||||
// NOTE: Internal values have range restrictions.
|
||||
"",
|
||||
0,
|
||||
@ -3828,7 +3829,8 @@ CSS_PROP_SVG(
|
||||
stroke-dashoffset,
|
||||
stroke_dashoffset,
|
||||
StrokeDashoffset,
|
||||
CSS_PROPERTY_PARSE_VALUE,
|
||||
CSS_PROPERTY_PARSE_VALUE |
|
||||
CSS_PROPERTY_NUMBERS_ARE_PIXELS,
|
||||
"",
|
||||
VARIANT_HLPN | VARIANT_OPENTYPE_SVG_KEYWORD,
|
||||
kStrokeContextValueKTable,
|
||||
@ -3880,7 +3882,8 @@ CSS_PROP_SVG(
|
||||
stroke_width,
|
||||
StrokeWidth,
|
||||
CSS_PROPERTY_PARSE_VALUE |
|
||||
CSS_PROPERTY_VALUE_NONNEGATIVE,
|
||||
CSS_PROPERTY_VALUE_NONNEGATIVE |
|
||||
CSS_PROPERTY_NUMBERS_ARE_PIXELS,
|
||||
"",
|
||||
VARIANT_HLPN | VARIANT_OPENTYPE_SVG_KEYWORD,
|
||||
kStrokeContextValueKTable,
|
||||
|
@ -213,6 +213,9 @@ static_assert((CSS_PROPERTY_PARSE_PROPERTY_MASK &
|
||||
// aliases.
|
||||
#define CSS_PROPERTY_ALWAYS_ENABLED_IN_CHROME_OR_CERTIFIED_APP (1<<23)
|
||||
|
||||
// This property's unitless values are pixels.
|
||||
#define CSS_PROPERTY_NUMBERS_ARE_PIXELS (1<<24)
|
||||
|
||||
/**
|
||||
* Types of animatable values.
|
||||
*/
|
||||
|
@ -218,8 +218,8 @@ var supported_properties = {
|
||||
"stroke-dasharray": [ test_dasharray_transition ],
|
||||
// NOTE: when calc() is supported on 'stroke-dashoffset', we should
|
||||
// add test_length_percent_calc_transition.
|
||||
"stroke-dashoffset": [ test_length_transition, test_percent_transition,
|
||||
test_length_unclamped, test_percent_unclamped ],
|
||||
"stroke-dashoffset": [ test_length_transition_svg, test_percent_transition,
|
||||
test_length_unclamped_svg, test_percent_unclamped ],
|
||||
"stroke-miterlimit": [ test_float_aboveOne_transition,
|
||||
test_float_aboveOne_clamped ],
|
||||
"stroke-opacity" : [ test_float_zeroToOne_transition,
|
||||
@ -228,8 +228,8 @@ var supported_properties = {
|
||||
test_float_zeroToOne_clamped ],
|
||||
// NOTE: when calc() is supported on 'stroke-width', we should add
|
||||
// test_length_percent_calc_transition.
|
||||
"stroke-width": [ test_length_transition, test_percent_transition,
|
||||
test_length_clamped, test_percent_clamped ],
|
||||
"stroke-width": [ test_length_transition_svg, test_percent_transition,
|
||||
test_length_clamped_svg, test_percent_clamped ],
|
||||
"text-indent": [ test_length_transition, test_percent_transition,
|
||||
test_length_percent_calc_transition,
|
||||
test_length_unclamped, test_percent_unclamped ],
|
||||
@ -872,27 +872,43 @@ function check_distance(prop, start, quarter, end)
|
||||
ok(Math.abs((qe * 4 - se * 3) / se) < 0.0001, "property '" + prop + "': distance " + qe + " from quarter '" + quarter + "' to end '" + end + "' should be three quarters distance " + se + " from start '" + start + "' to end '" + end + "'");
|
||||
}
|
||||
|
||||
function test_length_transition(prop) {
|
||||
function test_length_transition_svg_or_units(prop, numbers_are_pixels) {
|
||||
div.style.setProperty("transition-property", "none", "");
|
||||
div.style.setProperty(prop, "4px", "");
|
||||
is(cs.getPropertyValue(prop), "4px",
|
||||
"length-valued property " + prop + ": computed value before transition");
|
||||
div.style.setProperty("transition-property", prop, "");
|
||||
div.style.setProperty(prop, "12px", "");
|
||||
is(cs.getPropertyValue(prop), "6px",
|
||||
is(cs.getPropertyValue(prop), numbers_are_pixels ? "6" : "6px",
|
||||
"length-valued property " + prop + ": interpolation of lengths");
|
||||
check_distance(prop, "4px", "6px", "12px");
|
||||
}
|
||||
|
||||
function test_length_transition(prop) {
|
||||
test_length_transition_svg_or_units(prop, false);
|
||||
}
|
||||
|
||||
function test_length_transition_svg(prop) {
|
||||
test_length_transition_svg_or_units(prop, true);
|
||||
}
|
||||
|
||||
function test_length_clamped(prop) {
|
||||
test_length_clamped_or_unclamped(prop, true);
|
||||
test_length_clamped_or_unclamped(prop, true, false);
|
||||
}
|
||||
|
||||
function test_length_unclamped(prop) {
|
||||
test_length_clamped_or_unclamped(prop, false);
|
||||
test_length_clamped_or_unclamped(prop, false, false);
|
||||
}
|
||||
|
||||
function test_length_clamped_or_unclamped(prop, is_clamped) {
|
||||
function test_length_clamped_svg(prop) {
|
||||
test_length_clamped_or_unclamped(prop, true, true);
|
||||
}
|
||||
|
||||
function test_length_unclamped_svg(prop) {
|
||||
test_length_clamped_or_unclamped(prop, false, true);
|
||||
}
|
||||
|
||||
function test_length_clamped_or_unclamped(prop, is_clamped, numbers_are_pixels) {
|
||||
div.style.setProperty("transition-timing-function", FUNC_NEGATIVE, "");
|
||||
div.style.setProperty("transition-property", "none", "");
|
||||
div.style.setProperty(prop, "0px", "");
|
||||
@ -900,7 +916,8 @@ function test_length_clamped_or_unclamped(prop, is_clamped) {
|
||||
"length-valued property " + prop + ": flush before clamping test");
|
||||
div.style.setProperty("transition-property", prop, "");
|
||||
div.style.setProperty(prop, "100px", "");
|
||||
(is_clamped ? is : isnot)(cs.getPropertyValue(prop), "0px",
|
||||
(is_clamped ? is : isnot)(cs.getPropertyValue(prop),
|
||||
numbers_are_pixels ? "0" : "0px",
|
||||
"length-valued property " + prop + ": clamping of negatives");
|
||||
div.style.setProperty("transition-timing-function", "linear", "");
|
||||
}
|
||||
|
@ -41,7 +41,10 @@ BinarySearch(const Container& aContainer, size_t aBegin, size_t aEnd,
|
||||
size_t high = aEnd;
|
||||
while (low != high) {
|
||||
size_t middle = low + (high - low) / 2;
|
||||
const T& middleValue = aContainer[middle];
|
||||
|
||||
// Allow any intermediate type so long as it provides a suitable ordering
|
||||
// relation.
|
||||
const auto& middleValue = aContainer[middle];
|
||||
|
||||
MOZ_ASSERT(aContainer[low] <= aContainer[middle]);
|
||||
MOZ_ASSERT(aContainer[middle] <= aContainer[high - 1]);
|
||||
|
@ -3702,7 +3702,12 @@ pref("canvas.image.cache.limit", 0);
|
||||
pref("image.onload.decode.limit", 0);
|
||||
|
||||
// WebGL prefs
|
||||
#ifdef ANDROID
|
||||
// Disable MSAA on mobile.
|
||||
pref("gl.msaa-level", 0);
|
||||
#else
|
||||
pref("gl.msaa-level", 2);
|
||||
#endif
|
||||
pref("webgl.force-enabled", false);
|
||||
pref("webgl.disabled", false);
|
||||
pref("webgl.shader_validator", true);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
@ -60,26 +60,39 @@ nsTemporaryFileInputStream::ReadSegments(nsWriteSegmentFun writer,
|
||||
mozilla::MutexAutoLock lock(mFileDescOwner->FileMutex());
|
||||
PR_Seek64(mFileDescOwner->mFD, mStartPos, PR_SEEK_SET);
|
||||
|
||||
// Limit requested count to the amount remaining in our section of the file.
|
||||
count = std::min(count, uint32_t(mEndPos - mStartPos));
|
||||
uint32_t remainBufCount = count;
|
||||
|
||||
char buf[4096];
|
||||
while (remainBufCount > 0) {
|
||||
uint32_t bufCount = std::min(remainBufCount, (uint32_t)sizeof(buf));
|
||||
int32_t read_result = PR_Read(mFileDescOwner->mFD, buf, bufCount);
|
||||
if (read_result < 0) {
|
||||
while (*result < count) {
|
||||
uint32_t bufCount = std::min(count - *result, (uint32_t) sizeof(buf));
|
||||
int32_t bytesRead = PR_Read(mFileDescOwner->mFD, buf, bufCount);
|
||||
if (bytesRead < 0) {
|
||||
return NS_ErrorAccordingToNSPR();
|
||||
}
|
||||
uint32_t write_result = 0;
|
||||
nsresult rv = writer(this, closure, buf,
|
||||
count - remainBufCount, bufCount, &write_result);
|
||||
remainBufCount -= bufCount;
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ASSERTION(write_result <= bufCount,
|
||||
"writer should not write more than we asked it to write");
|
||||
mStartPos += bufCount;
|
||||
|
||||
int32_t bytesWritten = 0;
|
||||
while (bytesWritten < bytesRead) {
|
||||
uint32_t writerCount = 0;
|
||||
nsresult rv = writer(this, closure, buf + bytesWritten, *result,
|
||||
bytesRead - bytesWritten, &writerCount);
|
||||
if (NS_FAILED(rv) || writerCount == 0) {
|
||||
// nsIInputStream::ReadSegments' contract specifies that errors
|
||||
// from writer are not propagated to ReadSegments' caller.
|
||||
//
|
||||
// If writer fails, leaving bytes still in buf, that's okay: we
|
||||
// only update mStartPos to reflect successful writes, so the call
|
||||
// to PR_Seek64 at the top will restart us at the right spot.
|
||||
return NS_OK;
|
||||
}
|
||||
*result = count;
|
||||
NS_ASSERTION(writerCount <= (uint32_t) (bytesRead - bytesWritten),
|
||||
"writer should not write more than we asked it to write");
|
||||
bytesWritten += writerCount;
|
||||
*result += writerCount;
|
||||
mStartPos += writerCount;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -123,10 +123,18 @@ static const char kGOOGLE_PIN_AlphaSSL_G2Fingerprint[] =
|
||||
static const char kGOOGLE_PIN_CryptoCat1Fingerprint[] =
|
||||
"vKaqtTLWmVuXPVJE+0OqN5sRc4VCcSQHI/W3XTDVR24=";
|
||||
|
||||
/* GOOGLE_PIN_EntrustRootEC1 */
|
||||
static const char kGOOGLE_PIN_EntrustRootEC1Fingerprint[] =
|
||||
"/qK31kX7pz11PB7Jp4cMQOH3sMVh6Se5hb9xGGbjbyI=";
|
||||
|
||||
/* GOOGLE_PIN_Entrust_G2 */
|
||||
static const char kGOOGLE_PIN_Entrust_G2Fingerprint[] =
|
||||
"du6FkDdMcVQ3u8prumAo6t3i3G27uMP2EOhR8R0at/U=";
|
||||
|
||||
/* GOOGLE_PIN_GoDaddySecure */
|
||||
static const char kGOOGLE_PIN_GoDaddySecureFingerprint[] =
|
||||
"MrZLZnJ6IGPkBm87lYywqu5Xal7O/ZUzmbuIdHMdlYc=";
|
||||
|
||||
/* GOOGLE_PIN_Libertylavabitcom */
|
||||
static const char kGOOGLE_PIN_LibertylavabitcomFingerprint[] =
|
||||
"WnKzsDXgqPtS1KvtImrhQPqcxfpmfssuI2cSJt4LMks=";
|
||||
@ -658,6 +666,33 @@ static const StaticPinset kPinset_lavabit = {
|
||||
&kPinset_lavabit_sha256
|
||||
};
|
||||
|
||||
static const char* kPinset_dropbox_sha256_Data[] = {
|
||||
kGOOGLE_PIN_EntrustRootEC1Fingerprint,
|
||||
kThawte_Premium_Server_CAFingerprint,
|
||||
kthawte_Primary_Root_CA___G3Fingerprint,
|
||||
kthawte_Primary_Root_CAFingerprint,
|
||||
kEntrust_net_Premium_2048_Secure_Server_CAFingerprint,
|
||||
kDigiCert_Assured_ID_Root_CAFingerprint,
|
||||
kGo_Daddy_Root_Certificate_Authority___G2Fingerprint,
|
||||
kGOOGLE_PIN_GoDaddySecureFingerprint,
|
||||
kGeoTrust_Primary_Certification_AuthorityFingerprint,
|
||||
kGo_Daddy_Class_2_CAFingerprint,
|
||||
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
|
||||
kthawte_Primary_Root_CA___G2Fingerprint,
|
||||
kEntrust_Root_Certification_AuthorityFingerprint,
|
||||
kGOOGLE_PIN_Entrust_G2Fingerprint,
|
||||
kGeoTrust_Global_CAFingerprint,
|
||||
kGeoTrust_Primary_Certification_Authority___G3Fingerprint,
|
||||
kDigiCert_Global_Root_CAFingerprint,
|
||||
kGeoTrust_Primary_Certification_Authority___G2Fingerprint,
|
||||
};
|
||||
static const StaticFingerprints kPinset_dropbox_sha256 = { 18, kPinset_dropbox_sha256_Data };
|
||||
|
||||
static const StaticPinset kPinset_dropbox = {
|
||||
nullptr,
|
||||
&kPinset_dropbox_sha256
|
||||
};
|
||||
|
||||
/* Domainlist */
|
||||
struct TransportSecurityPreload {
|
||||
const char* mHost;
|
||||
@ -676,6 +711,7 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
|
||||
{ "addons.mozilla.org", true, false, true, 1, &kPinset_mozilla },
|
||||
{ "admin.google.com", true, false, false, -1, &kPinset_google_root_pems },
|
||||
{ "android.com", true, false, false, -1, &kPinset_google_root_pems },
|
||||
{ "api.accounts.firefox.com", true, true, false, 5, &kPinset_mozilla_fxa },
|
||||
{ "api.twitter.com", true, false, false, -1, &kPinset_twitterCDN },
|
||||
{ "apis.google.com", true, false, false, -1, &kPinset_google_root_pems },
|
||||
{ "appengine.google.com", true, false, false, -1, &kPinset_google_root_pems },
|
||||
@ -702,6 +738,7 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
|
||||
{ "docs.google.com", true, false, false, -1, &kPinset_google_root_pems },
|
||||
{ "doubleclick.net", true, false, false, -1, &kPinset_google_root_pems },
|
||||
{ "drive.google.com", true, false, false, -1, &kPinset_google_root_pems },
|
||||
{ "dropbox.com", false, true, false, -1, &kPinset_dropbox },
|
||||
{ "encrypted.google.com", true, false, false, -1, &kPinset_google_root_pems },
|
||||
{ "exclude-subdomains.pinning.example.com", false, false, false, 0, &kPinset_mozilla_test },
|
||||
{ "g.co", true, false, false, -1, &kPinset_google_root_pems },
|
||||
|
@ -190,6 +190,8 @@
|
||||
"pins": "mozilla", "test_mode": true, "id": 3 },
|
||||
{ "name": "accounts.firefox.com", "include_subdomains": true,
|
||||
"pins": "mozilla_fxa", "test_mode": true, "id": 4 },
|
||||
{ "name": "api.accounts.firefox.com", "include_subdomains": true,
|
||||
"pins": "mozilla_fxa", "test_mode": true, "id": 5 },
|
||||
{ "name": "cdn.mozilla.net", "include_subdomains": true,
|
||||
"pins": "mozilla", "test_mode": false },
|
||||
{ "name": "cdn.mozilla.org", "include_subdomains": true,
|
||||
|
@ -2,7 +2,7 @@ import os
|
||||
from setuptools import setup, find_packages
|
||||
import sys
|
||||
|
||||
version = '0.7.10'
|
||||
version = '0.7.11'
|
||||
|
||||
# dependencies
|
||||
with open('requirements.txt') as f:
|
||||
|
@ -617,10 +617,10 @@ private:
|
||||
continue;
|
||||
}
|
||||
scanned = fscanf(sizeFile, "%" SCNu64, &size);
|
||||
fclose(sizeFile);
|
||||
if (NS_WARN_IF(scanned != 1)) {
|
||||
continue;
|
||||
}
|
||||
fclose(sizeFile);
|
||||
|
||||
// Read mapped regions; format described below.
|
||||
uint64_t freeSize = size;
|
||||
|
Loading…
Reference in New Issue
Block a user