зеркало из https://github.com/mozilla/gecko-dev.git
merge m-c to fx-team
This commit is contained in:
Коммит
81e1cddebf
|
@ -1339,8 +1339,8 @@ nsIEProfileMigrator::CopyFavorites(bool aReplace)
|
|||
do_GetService(NS_NAVBOOKMARKSSERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool batchAction = aReplace ? BATCH_ACTION_BOOKMARKS_REPLACE
|
||||
: BATCH_ACTION_BOOKMARKS;
|
||||
PRUint8 batchAction = aReplace ? BATCH_ACTION_BOOKMARKS_REPLACE
|
||||
: BATCH_ACTION_BOOKMARKS;
|
||||
nsCOMPtr<nsISupportsPRUint8> supports =
|
||||
do_CreateInstance(NS_SUPPORTS_PRUINT8_CONTRACTID);
|
||||
NS_ENSURE_TRUE(supports, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
|
|
@ -418,10 +418,6 @@ user_pref("javascript.options.showInConsole", true);
|
|||
user_pref("devtools.errorconsole.enabled", true);
|
||||
user_pref("layout.debug.enable_data_xbl", true);
|
||||
user_pref("browser.EULA.override", true);
|
||||
user_pref("javascript.options.tracejit.content", true);
|
||||
user_pref("javascript.options.methodjit.content", true);
|
||||
user_pref("javascript.options.jitprofiling.content", true);
|
||||
user_pref("javascript.options.methodjit_always", false);
|
||||
user_pref("gfx.color_management.force_srgb", true);
|
||||
user_pref("network.manage-offline-status", false);
|
||||
user_pref("test.mousescroll", true);
|
||||
|
|
|
@ -6,7 +6,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=391728
|
|||
<head>
|
||||
<title>Test for Bug 391728</title>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/PluginUtils.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -527,14 +527,14 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
|
|||
height = 1;
|
||||
}
|
||||
|
||||
// If we already have a gl context, then we just need to resize
|
||||
// FB0.
|
||||
if (gl &&
|
||||
gl->ResizeOffscreen(gfxIntSize(width, height)))
|
||||
{
|
||||
// If we already have a gl context, then we just need to resize it
|
||||
if (gl) {
|
||||
gl->ResizeOffscreen(gfxIntSize(width, height)); // Doesn't matter if it succeeds (soft-fail)
|
||||
// It's unlikely that we'll get a proper-sized context if we recreate if we didn't on resize
|
||||
|
||||
// everything's good, we're done here
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mWidth = gl->OffscreenActualSize().width;
|
||||
mHeight = gl->OffscreenActualSize().height;
|
||||
mResetLayer = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -601,6 +601,11 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
|
|||
format.minAlpha = 0;
|
||||
}
|
||||
|
||||
if (mOptions.antialias) {
|
||||
PRUint32 msaaLevel = Preferences::GetUint("webgl.msaa-level", 2);
|
||||
format.samples = msaaLevel*msaaLevel;
|
||||
}
|
||||
|
||||
if (PR_GetEnv("MOZ_WEBGL_PREFER_EGL")) {
|
||||
preferEGL = true;
|
||||
}
|
||||
|
@ -898,7 +903,7 @@ WebGLContext::GetContextAttributes(jsval *aResult)
|
|||
NULL, NULL, JSPROP_ENUMERATE) ||
|
||||
!JS_DefineProperty(cx, obj, "stencil", cf.stencil > 0 ? JSVAL_TRUE : JSVAL_FALSE,
|
||||
NULL, NULL, JSPROP_ENUMERATE) ||
|
||||
!JS_DefineProperty(cx, obj, "antialias", JSVAL_FALSE,
|
||||
!JS_DefineProperty(cx, obj, "antialias", cf.samples > 0 ? JSVAL_TRUE : JSVAL_FALSE,
|
||||
NULL, NULL, JSPROP_ENUMERATE) ||
|
||||
!JS_DefineProperty(cx, obj, "premultipliedAlpha",
|
||||
mOptions.premultipliedAlpha ? JSVAL_TRUE : JSVAL_FALSE,
|
||||
|
|
|
@ -310,7 +310,7 @@ struct WebGLContextOptions {
|
|||
// these are defaults
|
||||
WebGLContextOptions()
|
||||
: alpha(true), depth(true), stencil(false),
|
||||
premultipliedAlpha(true), antialias(false),
|
||||
premultipliedAlpha(true), antialias(true),
|
||||
preserveDrawingBuffer(false)
|
||||
{ }
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
conformance/canvas/drawingbuffer-static-canvas-test.html
|
||||
conformance/canvas/drawingbuffer-test.html
|
||||
conformance/context/premultiplyalpha-test.html
|
||||
conformance/glsl/misc/glsl-long-variable-names.html
|
||||
conformance/glsl/misc/shader-with-256-character-identifier.frag.html
|
||||
|
@ -8,7 +6,6 @@ conformance/misc/uninitialized-test.html
|
|||
conformance/programs/gl-get-active-attribute.html
|
||||
conformance/reading/read-pixels-test.html
|
||||
conformance/renderbuffers/framebuffer-object-attachment.html
|
||||
conformance/renderbuffers/renderbuffer-initialization.html
|
||||
conformance/textures/texture-mips.html
|
||||
conformance/uniforms/gl-uniform-bool.html
|
||||
conformance/more/functions/copyTexImage2D.html
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
conformance/canvas/buffer-preserve-test.html
|
||||
conformance/canvas/drawingbuffer-static-canvas-test.html
|
||||
conformance/canvas/drawingbuffer-test.html
|
||||
conformance/context/context-attributes-alpha-depth-stencil-antialias.html
|
||||
conformance/context/premultiplyalpha-test.html
|
||||
conformance/glsl/misc/glsl-function-nodes.html
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
conformance/canvas/buffer-preserve-test.html
|
||||
conformance/canvas/drawingbuffer-static-canvas-test.html
|
||||
conformance/canvas/drawingbuffer-test.html
|
||||
conformance/context/premultiplyalpha-test.html
|
||||
conformance/glsl/functions/glsl-function-atan.html
|
||||
conformance/glsl/functions/glsl-function-atan-xy.html
|
||||
|
|
|
@ -1675,7 +1675,8 @@ nsEventStateManager::DispatchCrossProcessEvent(nsEvent* aEvent, nsIFrameLoader*
|
|||
bool
|
||||
nsEventStateManager::IsRemoteTarget(nsIContent* target) {
|
||||
return target &&
|
||||
target->Tag() == nsGkAtoms::browser &&
|
||||
(target->Tag() == nsGkAtoms::browser ||
|
||||
target->Tag() == nsGkAtoms::iframe) &&
|
||||
target->IsXUL() &&
|
||||
target->AttrValueIs(kNameSpaceID_None, nsGkAtoms::Remote,
|
||||
nsGkAtoms::_true, eIgnoreCase);
|
||||
|
|
|
@ -166,4 +166,10 @@ void ScaleDisplayByAspectRatio(nsIntSize& aDisplay, float aAspectRatio);
|
|||
#define MEDIA_THREAD_STACK_SIZE nsIThreadManager::DEFAULT_STACK_SIZE
|
||||
#endif
|
||||
|
||||
// Android's audio backend is not available in content processes, so audio must
|
||||
// be remoted to the parent chrome process.
|
||||
#if defined(ANDROID)
|
||||
#define REMOTE_AUDIO 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -66,12 +66,6 @@ using namespace mozilla;
|
|||
#define SA_PER_STREAM_VOLUME 1
|
||||
#endif
|
||||
|
||||
// Android's audio backend is not available in content processes, so audio must
|
||||
// be remoted to the parent chrome process.
|
||||
#if defined(ANDROID)
|
||||
#define REMOTE_AUDIO 1
|
||||
#endif
|
||||
|
||||
using mozilla::TimeStamp;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
|
@ -80,6 +74,9 @@ PRLogModuleInfo* gAudioStreamLog = nsnull;
|
|||
|
||||
static const PRUint32 FAKE_BUFFER_SIZE = 176400;
|
||||
|
||||
// Number of milliseconds per second.
|
||||
static const PRInt64 MS_PER_S = 1000;
|
||||
|
||||
class nsNativeAudioStream : public nsAudioStream
|
||||
{
|
||||
public:
|
||||
|
@ -752,9 +749,9 @@ nsRemotedAudioStream::GetPositionInFrames()
|
|||
return 0;
|
||||
|
||||
PRInt64 time = mAudioChild->GetLastKnownPositionTimestamp();
|
||||
PRInt64 result = position + (mRate * (PR_IntervalNow() - time) / USECS_PER_S);
|
||||
PRInt64 dt = PR_IntervalToMilliseconds(PR_IntervalNow() - time);
|
||||
|
||||
return result;
|
||||
return position + (mRate * dt / MS_PER_S);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -635,6 +635,29 @@ void nsBuiltinDecoderStateMachine::AudioLoop()
|
|||
NS_WARNING("Int overflow calculating audio end time");
|
||||
break;
|
||||
}
|
||||
|
||||
// The remoted audio stream does not block writes when the other end's buffers
|
||||
// are full, so this sleep is necessary to stop the audio thread spinning its
|
||||
// wheels. When bug 695612 is fixed, this block of code can be removed.
|
||||
#if defined(REMOTE_AUDIO)
|
||||
PRInt64 audioAhead = mAudioEndTime - GetMediaTime();
|
||||
if (audioAhead > AMPLE_AUDIO_USECS &&
|
||||
framesWritten > minWriteFrames)
|
||||
{
|
||||
// We've pushed enough audio onto the hardware that we've queued up a
|
||||
// significant amount ahead of the playback position. The decode
|
||||
// thread will be going to sleep, so we won't get any new audio
|
||||
// anyway, so sleep until we need to push to the hardware again.
|
||||
Wait(AMPLE_AUDIO_USECS / 2);
|
||||
// Kick the decode thread; since above we only do a NotifyAll when
|
||||
// we pop an audio chunk of the queue, the decoder won't wake up if
|
||||
// we've got no more decoded chunks to push to the hardware. We can
|
||||
// hit this condition if the last frame in the stream doesn't have
|
||||
// it's EOS flag set, and the decode thread sleeps just after decoding
|
||||
// that packet, but before realising there's no more packets.
|
||||
mon.NotifyAll();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (mReader->mAudioQueue.AtEndOfStream() &&
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
#include "imgIContainer.h"
|
||||
#include "imgIDecoderObserver.h"
|
||||
#include "gfxContext.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
@ -168,28 +167,6 @@ nsSVGImageElement::LoadSVGImage(bool aForce, bool aNotify)
|
|||
//----------------------------------------------------------------------
|
||||
// nsIContent methods:
|
||||
|
||||
nsresult
|
||||
nsSVGImageElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
|
||||
const nsAString* aValue, bool aNotify)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_XLink && aName == nsGkAtoms::href) {
|
||||
// If caller is not chrome and dom.disable_image_src_set is true,
|
||||
// prevent setting image.src by exiting early
|
||||
if (Preferences::GetBool("dom.disable_image_src_set") &&
|
||||
!nsContentUtils::IsCallerChrome()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aValue) {
|
||||
LoadSVGImage(true, aNotify);
|
||||
} else {
|
||||
CancelImageRequests(aNotify);
|
||||
}
|
||||
}
|
||||
return nsSVGImageElementBase::AfterSetAttr(aNamespaceID, aName,
|
||||
aValue, aNotify);
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGImageElement::MaybeLoadSVGImage()
|
||||
{
|
||||
|
@ -281,17 +258,6 @@ nsSVGImageElement::GetStringInfo()
|
|||
ArrayLength(sStringInfo));
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGImageElement::DidAnimateString(PRUint8 aAttrEnum)
|
||||
{
|
||||
if (aAttrEnum == HREF) {
|
||||
LoadSVGImage(true, false);
|
||||
return;
|
||||
}
|
||||
|
||||
nsSVGImageElementBase::DidAnimateString(aAttrEnum);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGImageElement::CopyInnerTo(nsGenericElement* aDest) const
|
||||
{
|
||||
|
|
|
@ -77,8 +77,6 @@ public:
|
|||
NS_FORWARD_NSIDOMSVGELEMENT(nsSVGImageElementBase::)
|
||||
|
||||
// nsIContent interface
|
||||
virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
|
||||
const nsAString* aValue, bool aNotify);
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers);
|
||||
|
@ -103,7 +101,6 @@ protected:
|
|||
virtual LengthAttributesInfo GetLengthInfo();
|
||||
virtual SVGAnimatedPreserveAspectRatio *GetPreserveAspectRatio();
|
||||
virtual StringAttributesInfo GetStringInfo();
|
||||
virtual void DidAnimateString(PRUint8 aAttrEnum);
|
||||
|
||||
enum { X, Y, WIDTH, HEIGHT };
|
||||
nsSVGLength2 mLengthAttributes[4];
|
||||
|
|
|
@ -342,7 +342,6 @@ function finish() {
|
|||
// If the test changed the value of max_total_viewers via a call to
|
||||
// enableBFCache(), then restore it now.
|
||||
if (typeof(gOrigMaxTotalViewers) != "undefined") {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch);
|
||||
prefs.setIntPref("browser.sessionhistory.max_total_viewers",
|
||||
|
@ -425,7 +424,6 @@ function waitForTrue(fn, onWaitComplete, timeout) {
|
|||
* to 0 (disabled), if a number, set it to that specific number
|
||||
*/
|
||||
function enableBFCache(enable) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch);
|
||||
|
||||
|
|
|
@ -2980,7 +2980,8 @@ nsFocusManager::GetRootForFocus(nsPIDOMWindow* aWindow,
|
|||
TabParent*
|
||||
nsFocusManager::GetRemoteForContent(nsIContent* aContent) {
|
||||
if (!aContent ||
|
||||
aContent->Tag() != nsGkAtoms::browser ||
|
||||
(aContent->Tag() != nsGkAtoms::browser &&
|
||||
aContent->Tag() != nsGkAtoms::iframe) ||
|
||||
!aContent->IsXUL() ||
|
||||
!aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::Remote,
|
||||
nsGkAtoms::_true, eIgnoreCase))
|
||||
|
|
|
@ -86,7 +86,7 @@ public:
|
|||
the protocol.
|
||||
*/
|
||||
template<class Toplevel>
|
||||
static void CreateCrashReporter(Toplevel* actor);
|
||||
static bool CreateCrashReporter(Toplevel* actor);
|
||||
#endif
|
||||
/* Initialize this reporter with data from the child process */
|
||||
void
|
||||
|
@ -176,7 +176,7 @@ CrashReporterParent::GenerateCrashReport(Toplevel* t,
|
|||
}
|
||||
|
||||
template<class Toplevel>
|
||||
/* static */ void
|
||||
/* static */ bool
|
||||
CrashReporterParent::CreateCrashReporter(Toplevel* actor)
|
||||
{
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
|
@ -189,7 +189,9 @@ CrashReporterParent::CreateCrashReporter(Toplevel* actor)
|
|||
} else {
|
||||
NS_ERROR("Error creating crash reporter actor");
|
||||
}
|
||||
return !!p;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "AndroidBridge.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "gfxContext.h"
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
|
||||
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
|
||||
#define ASSIGN(obj, name) (obj)->name = anp_surface_##name
|
||||
|
@ -51,17 +52,11 @@
|
|||
static struct ANPSurfaceInterfaceJavaGlue {
|
||||
bool initialized;
|
||||
jclass geckoAppShellClass;
|
||||
jclass lockInfoCls;
|
||||
jmethodID lockSurfaceANP;
|
||||
jmethodID jUnlockSurfaceANP;
|
||||
jfieldID jDirtyTop;
|
||||
jfieldID jDirtyLeft;
|
||||
jfieldID jDirtyBottom;
|
||||
jfieldID jDirtyRight;
|
||||
jclass surfaceInfoCls;
|
||||
jmethodID getSurfaceInfo;
|
||||
jfieldID jFormat;
|
||||
jfieldID jWidth ;
|
||||
jfieldID jHeight;
|
||||
jfieldID jBuffer;
|
||||
} gSurfaceJavaGlue;
|
||||
|
||||
#define getClassGlobalRef(env, cname) \
|
||||
|
@ -74,23 +69,16 @@ static void init(JNIEnv* env) {
|
|||
gSurfaceJavaGlue.geckoAppShellClass = mozilla::AndroidBridge::GetGeckoAppShellClass();
|
||||
|
||||
jmethodID getClass = env->GetStaticMethodID(gSurfaceJavaGlue.geckoAppShellClass,
|
||||
"getSurfaceLockInfoClass",
|
||||
"getSurfaceInfoClass",
|
||||
"()Ljava/lang/Class;");
|
||||
|
||||
gSurfaceJavaGlue.lockInfoCls = (jclass) env->NewGlobalRef(env->CallStaticObjectMethod(gSurfaceJavaGlue.geckoAppShellClass, getClass));
|
||||
gSurfaceJavaGlue.surfaceInfoCls = (jclass) env->NewGlobalRef(env->CallStaticObjectMethod(gSurfaceJavaGlue.geckoAppShellClass, getClass));
|
||||
|
||||
gSurfaceJavaGlue.jDirtyTop = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "dirtyTop", "I");
|
||||
gSurfaceJavaGlue.jDirtyLeft = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "dirtyLeft", "I");
|
||||
gSurfaceJavaGlue.jDirtyBottom = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "dirtyBottom", "I");
|
||||
gSurfaceJavaGlue.jDirtyRight = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "dirtyRight", "I");
|
||||
gSurfaceJavaGlue.jFormat = env->GetFieldID(gSurfaceJavaGlue.surfaceInfoCls, "format", "I");
|
||||
gSurfaceJavaGlue.jWidth = env->GetFieldID(gSurfaceJavaGlue.surfaceInfoCls, "width", "I");
|
||||
gSurfaceJavaGlue.jHeight = env->GetFieldID(gSurfaceJavaGlue.surfaceInfoCls, "height", "I");
|
||||
|
||||
gSurfaceJavaGlue.jFormat = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "format", "I");
|
||||
gSurfaceJavaGlue.jWidth = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "width", "I");
|
||||
gSurfaceJavaGlue.jHeight = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "height", "I");
|
||||
|
||||
gSurfaceJavaGlue.jBuffer = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "buffer", "Ljava/nio/Buffer;");
|
||||
gSurfaceJavaGlue.lockSurfaceANP = env->GetStaticMethodID(gSurfaceJavaGlue.geckoAppShellClass, "lockSurfaceANP", "(Landroid/view/SurfaceView;IIII)Lorg/mozilla/gecko/SurfaceLockInfo;");
|
||||
gSurfaceJavaGlue.jUnlockSurfaceANP = env->GetStaticMethodID(gSurfaceJavaGlue.geckoAppShellClass, "unlockSurfaceANP", "(Landroid/view/SurfaceView;)V");
|
||||
gSurfaceJavaGlue.getSurfaceInfo = env->GetStaticMethodID(gSurfaceJavaGlue.geckoAppShellClass, "getSurfaceInfo", "(Landroid/view/SurfaceView;)Lorg/mozilla/gecko/SurfaceInfo;");
|
||||
gSurfaceJavaGlue.initialized = true;
|
||||
}
|
||||
|
||||
|
@ -103,62 +91,68 @@ static bool anp_lock(JNIEnv* env, jobject surfaceView, ANPBitmap* bitmap, ANPRec
|
|||
|
||||
init(env);
|
||||
|
||||
jvalue args[5];
|
||||
args[0].l = surfaceView;
|
||||
if (dirtyRect) {
|
||||
args[1].i = dirtyRect->top;
|
||||
args[2].i = dirtyRect->left;
|
||||
args[3].i = dirtyRect->bottom;
|
||||
args[4].i = dirtyRect->right;
|
||||
LOG("dirty rect: %d, %d, %d, %d", dirtyRect->top, dirtyRect->left, dirtyRect->bottom, dirtyRect->right);
|
||||
} else {
|
||||
args[1].i = args[2].i = args[3].i = args[4].i = 0;
|
||||
}
|
||||
|
||||
jobject info = env->CallStaticObjectMethod(gSurfaceJavaGlue.geckoAppShellClass,
|
||||
gSurfaceJavaGlue.lockSurfaceANP,
|
||||
surfaceView, args[1].i, args[2].i, args[3].i, args[4].i);
|
||||
gSurfaceJavaGlue.getSurfaceInfo, surfaceView);
|
||||
|
||||
LOG("info: %p", info);
|
||||
if (!info)
|
||||
return false;
|
||||
|
||||
// the surface may have expanded the dirty region so we must to pass that
|
||||
// information back to the plugin.
|
||||
if (dirtyRect) {
|
||||
dirtyRect->left = env->GetIntField(info, gSurfaceJavaGlue.jDirtyLeft);
|
||||
dirtyRect->right = env->GetIntField(info, gSurfaceJavaGlue.jDirtyRight);
|
||||
dirtyRect->top = env->GetIntField(info, gSurfaceJavaGlue.jDirtyTop);
|
||||
dirtyRect->bottom = env->GetIntField(info, gSurfaceJavaGlue.jDirtyBottom);
|
||||
LOG("dirty rect: %d, %d, %d, %d", dirtyRect->top, dirtyRect->left, dirtyRect->bottom, dirtyRect->right);
|
||||
}
|
||||
|
||||
bitmap->width = env->GetIntField(info, gSurfaceJavaGlue.jWidth);
|
||||
bitmap->height = env->GetIntField(info, gSurfaceJavaGlue.jHeight);
|
||||
|
||||
if (bitmap->width <= 0 || bitmap->height <= 0)
|
||||
return false;
|
||||
|
||||
int format = env->GetIntField(info, gSurfaceJavaGlue.jFormat);
|
||||
gfxImageFormat targetFormat;
|
||||
|
||||
// format is PixelFormat
|
||||
if (format & 0x00000001) {
|
||||
/*
|
||||
bitmap->format = kRGBA_8888_ANPBitmapFormat;
|
||||
bitmap->rowBytes = bitmap->width * 4;
|
||||
}
|
||||
else if (format & 0x00000004) {
|
||||
targetFormat = gfxASurface::ImageFormatARGB32;
|
||||
*/
|
||||
|
||||
// We actually can't handle this right now because gfxImageSurface
|
||||
// doesn't support RGBA32.
|
||||
LOG("Unable to handle 32bit pixel format");
|
||||
return false;
|
||||
} else if (format & 0x00000004) {
|
||||
bitmap->format = kRGB_565_ANPBitmapFormat;
|
||||
bitmap->rowBytes = bitmap->width * 2;
|
||||
}
|
||||
else {
|
||||
targetFormat = gfxASurface::ImageFormatRGB16_565;
|
||||
} else {
|
||||
LOG("format from glue is unknown %d\n", format);
|
||||
return false;
|
||||
}
|
||||
|
||||
jobject buf = env->GetObjectField(info, gSurfaceJavaGlue.jBuffer);
|
||||
bitmap->baseAddr = env->GetDirectBufferAddress(buf);
|
||||
nsNPAPIPluginInstance* pinst = nsNPAPIPluginInstance::FindByJavaSurface((void*)surfaceView);
|
||||
if (!pinst) {
|
||||
LOG("Failed to get plugin instance");
|
||||
return false;
|
||||
}
|
||||
|
||||
NPRect lockRect;
|
||||
if (dirtyRect) {
|
||||
lockRect.top = dirtyRect->top;
|
||||
lockRect.left = dirtyRect->left;
|
||||
lockRect.right = dirtyRect->right;
|
||||
lockRect.bottom = dirtyRect->bottom;
|
||||
} else {
|
||||
// No dirty rect, use the whole bitmap
|
||||
lockRect.top = lockRect.left = 0;
|
||||
lockRect.right = bitmap->width;
|
||||
lockRect.bottom = bitmap->height;
|
||||
}
|
||||
|
||||
LOG("format: %d, width: %d, height: %d", bitmap->format, bitmap->width, bitmap->height);
|
||||
gfxImageSurface* target = pinst->LockTargetSurface(bitmap->width, bitmap->height, targetFormat, &lockRect);
|
||||
bitmap->baseAddr = target->Data();
|
||||
|
||||
env->DeleteLocalRef(info);
|
||||
env->DeleteLocalRef(buf);
|
||||
return ( bitmap->width > 0 && bitmap->height > 0 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void anp_unlock(JNIEnv* env, jobject surfaceView) {
|
||||
|
@ -169,10 +163,13 @@ static void anp_unlock(JNIEnv* env, jobject surfaceView) {
|
|||
return;
|
||||
}
|
||||
|
||||
init(env);
|
||||
env->CallStaticVoidMethod(gSurfaceJavaGlue.geckoAppShellClass, gSurfaceJavaGlue.jUnlockSurfaceANP, surfaceView);
|
||||
LOG("returning from %s", __PRETTY_FUNCTION__);
|
||||
|
||||
nsNPAPIPluginInstance* pinst = nsNPAPIPluginInstance::FindByJavaSurface((void*)surfaceView);
|
||||
if (!pinst) {
|
||||
LOG("Could not find plugin instance!");
|
||||
return;
|
||||
}
|
||||
|
||||
pinst->UnlockTargetSurface(true /* invalidate the locked area */);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -578,6 +578,29 @@ nsNPAPIPlugin::Shutdown()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsNPAPIPlugin::RetainStream(NPStream *pstream, nsISupports **aRetainedPeer)
|
||||
{
|
||||
if (!aRetainedPeer)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
*aRetainedPeer = NULL;
|
||||
|
||||
if (!pstream || !pstream->ndata)
|
||||
return NPERR_INVALID_PARAM;
|
||||
|
||||
nsNPAPIPluginStreamListener* listener =
|
||||
static_cast<nsNPAPIPluginStreamListener*>(pstream->ndata);
|
||||
nsPluginStreamListenerPeer* peer = listener->GetStreamListenerPeer();
|
||||
|
||||
if (!peer)
|
||||
return NPERR_GENERIC_ERROR;
|
||||
|
||||
*aRetainedPeer = (nsISupports*) peer;
|
||||
NS_ADDREF(*aRetainedPeer);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Create a new NPP GET or POST (given in the type argument) url
|
||||
// stream that may have a notify callback
|
||||
NPError
|
||||
|
|
|
@ -106,6 +106,8 @@ public:
|
|||
nsresult CreatePluginInstance(nsNPAPIPluginInstance **aResult);
|
||||
nsresult Shutdown();
|
||||
|
||||
static nsresult RetainStream(NPStream *pstream, nsISupports **aRetainedPeer);
|
||||
|
||||
protected:
|
||||
NPPluginFuncs mPluginFuncs;
|
||||
PluginLibrary* mLibrary;
|
||||
|
|
|
@ -65,7 +65,6 @@
|
|||
#include "ANPBase.h"
|
||||
#include <android/log.h>
|
||||
#include "android_npapi.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/CondVar.h"
|
||||
#include "AndroidBridge.h"
|
||||
#endif
|
||||
|
@ -73,6 +72,11 @@
|
|||
using namespace mozilla;
|
||||
using namespace mozilla::plugins::parent;
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <map>
|
||||
static std::map<void*, nsNPAPIPluginInstance*> sSurfaceMap;
|
||||
#endif
|
||||
|
||||
static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID);
|
||||
static NS_DEFINE_IID(kIPluginStreamListenerIID, NS_IPLUGINSTREAMLISTENER_IID);
|
||||
|
||||
|
@ -89,6 +93,7 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance(nsNPAPIPlugin* plugin)
|
|||
#endif
|
||||
#ifdef ANDROID
|
||||
mSurface(nsnull),
|
||||
mTargetSurface(nsnull),
|
||||
mDrawingModel(0),
|
||||
#endif
|
||||
mRunning(NOT_STARTED),
|
||||
|
@ -122,6 +127,10 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance(nsNPAPIPlugin* plugin)
|
|||
mUsePluginLayersPref = useLayersPref;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
mTargetSurfaceLock = new Mutex("nsNPAPIPluginInstance::SurfaceLock");
|
||||
#endif
|
||||
|
||||
PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance ctor: this=%p\n",this));
|
||||
}
|
||||
|
||||
|
@ -133,6 +142,22 @@ nsNPAPIPluginInstance::~nsNPAPIPluginInstance()
|
|||
PR_Free((void *)mMIMEType);
|
||||
mMIMEType = nsnull;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
if (mSurface) {
|
||||
sSurfaceMap.erase(mSurface);
|
||||
}
|
||||
|
||||
if (mTargetSurface) {
|
||||
delete mTargetSurface;
|
||||
mTargetSurface = nsnull;
|
||||
}
|
||||
|
||||
if (mTargetSurfaceLock) {
|
||||
delete mTargetSurfaceLock;
|
||||
mTargetSurfaceLock = nsnull;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -338,7 +363,12 @@ nsNPAPIPluginInstance::InitializePlugin()
|
|||
const char* const* pnames = nsnull;
|
||||
const char* const* pvalues = nsnull;
|
||||
if (NS_SUCCEEDED(GetParameters(pcount, pnames, pvalues))) {
|
||||
// Android expects an empty string as the separator instead of null
|
||||
#ifdef ANDROID
|
||||
NS_ASSERTION(PL_strcmp(values[count], "") == 0, "attribute/parameter array not setup correctly for Android NPAPI plugins");
|
||||
#else
|
||||
NS_ASSERTION(!values[count], "attribute/parameter array not setup correctly for NPAPI plugins");
|
||||
#endif
|
||||
if (pcount)
|
||||
count += ++pcount; // if it's all setup correctly, then all we need is to
|
||||
// change the count (attrs + PARAM/blank + params)
|
||||
|
@ -770,9 +800,61 @@ void* nsNPAPIPluginInstance::GetJavaSurface()
|
|||
|
||||
nsCOMPtr<SurfaceGetter> sg = new SurfaceGetter(mPlugin->PluginFuncs(), mNPP);
|
||||
mSurface = sg->GetSurface();
|
||||
sSurfaceMap[mSurface] = this;
|
||||
return mSurface;
|
||||
}
|
||||
|
||||
gfxImageSurface*
|
||||
nsNPAPIPluginInstance::LockTargetSurface()
|
||||
{
|
||||
mTargetSurfaceLock->Lock();
|
||||
return mTargetSurface;
|
||||
}
|
||||
|
||||
gfxImageSurface*
|
||||
nsNPAPIPluginInstance::LockTargetSurface(PRUint32 aWidth, PRUint32 aHeight, gfxImageFormat aFormat,
|
||||
NPRect* aRect)
|
||||
{
|
||||
mTargetSurfaceLock->Lock();
|
||||
if (!mTargetSurface ||
|
||||
mTargetSurface->Width() != aWidth ||
|
||||
mTargetSurface->Height() != aHeight ||
|
||||
mTargetSurface->Format() != aFormat) {
|
||||
|
||||
if (mTargetSurface) {
|
||||
delete mTargetSurface;
|
||||
}
|
||||
|
||||
mTargetSurface = new gfxImageSurface(gfxIntSize(aWidth, aHeight), aFormat);
|
||||
}
|
||||
|
||||
mTargetLockRect = *aRect;
|
||||
|
||||
return mTargetSurface;
|
||||
}
|
||||
|
||||
void
|
||||
nsNPAPIPluginInstance::InvalidateTargetRect()
|
||||
{
|
||||
InvalidateRect(&mTargetLockRect);
|
||||
}
|
||||
|
||||
void
|
||||
nsNPAPIPluginInstance::UnlockTargetSurface(bool aInvalidate)
|
||||
{
|
||||
mTargetSurfaceLock->Unlock();
|
||||
|
||||
if (aInvalidate) {
|
||||
NS_DispatchToMainThread(NS_NewRunnableMethod(this, &nsNPAPIPluginInstance::InvalidateTargetRect));
|
||||
}
|
||||
}
|
||||
|
||||
nsNPAPIPluginInstance*
|
||||
nsNPAPIPluginInstance::FindByJavaSurface(void* aJavaSurface)
|
||||
{
|
||||
return sSurfaceMap[aJavaSurface];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
nsresult nsNPAPIPluginInstance::GetDrawingModel(PRInt32* aModel)
|
||||
|
|
|
@ -50,9 +50,16 @@
|
|||
#include "nsInterfaceHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
#include "gfxASurface.h"
|
||||
#include "gfxImageSurface.h"
|
||||
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/PluginLibrary.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
#include "mozilla/Mutex.h"
|
||||
#endif
|
||||
|
||||
struct JSObject;
|
||||
|
||||
class nsPluginStreamListenerPeer; // browser-initiated stream class
|
||||
|
@ -148,6 +155,13 @@ public:
|
|||
#ifdef ANDROID
|
||||
void SetDrawingModel(PRUint32 aModel);
|
||||
void* GetJavaSurface();
|
||||
|
||||
gfxImageSurface* LockTargetSurface();
|
||||
gfxImageSurface* LockTargetSurface(PRUint32 aWidth, PRUint32 aHeight, gfxASurface::gfxImageFormat aFormat,
|
||||
NPRect* aRect);
|
||||
void UnlockTargetSurface(bool aInvalidate);
|
||||
|
||||
static nsNPAPIPluginInstance* FindByJavaSurface(void* aJavaSurface);
|
||||
#endif
|
||||
|
||||
nsresult NewStreamListener(const char* aURL, void* notifyData,
|
||||
|
@ -264,7 +278,12 @@ private:
|
|||
|
||||
bool mUsePluginLayersPref;
|
||||
#ifdef ANDROID
|
||||
void InvalidateTargetRect();
|
||||
|
||||
void* mSurface;
|
||||
gfxImageSurface *mTargetSurface;
|
||||
mozilla::Mutex* mTargetSurfaceLock;
|
||||
NPRect mTargetLockRect;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -1233,12 +1233,9 @@ nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays()
|
|||
// Set to the next slot to fill in name and value cache arrays.
|
||||
PRUint32 nextAttrParamIndex = 0;
|
||||
|
||||
// Potentially add WMODE attribute.
|
||||
if (!wmodeType.IsEmpty()) {
|
||||
mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("wmode"));
|
||||
mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(wmodeType));
|
||||
nextAttrParamIndex++;
|
||||
}
|
||||
// Whether or not we force the wmode below while traversing
|
||||
// the name/value pairs.
|
||||
bool wmodeSet = false;
|
||||
|
||||
// Add attribute name/value pairs.
|
||||
for (PRInt32 index = start; index != end; index += increment) {
|
||||
|
@ -1252,7 +1249,25 @@ nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays()
|
|||
FixUpURLS(name, value);
|
||||
|
||||
mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(name);
|
||||
mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(value);
|
||||
if (!wmodeType.IsEmpty() &&
|
||||
0 == PL_strcasecmp(mCachedAttrParamNames[nextAttrParamIndex], "wmode")) {
|
||||
mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(wmodeType));
|
||||
|
||||
if (!wmodeSet) {
|
||||
// We allocated space to add a wmode attr, but we don't need it now.
|
||||
mNumCachedAttrs--;
|
||||
wmodeSet = true;
|
||||
}
|
||||
} else {
|
||||
mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(value);
|
||||
}
|
||||
nextAttrParamIndex++;
|
||||
}
|
||||
|
||||
// Potentially add WMODE attribute.
|
||||
if (!wmodeType.IsEmpty() && !wmodeSet) {
|
||||
mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("wmode"));
|
||||
mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(wmodeType));
|
||||
nextAttrParamIndex++;
|
||||
}
|
||||
|
||||
|
@ -1656,6 +1671,27 @@ void nsPluginInstanceOwner::ScrollPositionDidChange(nscoord aX, nscoord aY)
|
|||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
void nsPluginInstanceOwner::AddPluginView(const gfxRect& aRect)
|
||||
{
|
||||
void* javaSurface = mInstance->GetJavaSurface();
|
||||
|
||||
if (!javaSurface)
|
||||
return;
|
||||
|
||||
JNIEnv* env = GetJNIForThread();
|
||||
jclass cls = env->FindClass("org/mozilla/gecko/GeckoAppShell");
|
||||
jmethodID method = env->GetStaticMethodID(cls,
|
||||
"addPluginView",
|
||||
"(Landroid/view/View;DDDD)V");
|
||||
env->CallStaticVoidMethod(cls,
|
||||
method,
|
||||
javaSurface,
|
||||
aRect.x,
|
||||
aRect.y,
|
||||
aRect.width,
|
||||
aRect.height);
|
||||
}
|
||||
|
||||
void nsPluginInstanceOwner::RemovePluginView()
|
||||
{
|
||||
if (mInstance && mObjectFrame) {
|
||||
|
@ -2797,45 +2833,6 @@ void nsPluginInstanceOwner::Paint(const nsRect& aDirtyRect, HPS aHPS)
|
|||
|
||||
#ifdef ANDROID
|
||||
|
||||
class AndroidPaintEventRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
AndroidPaintEventRunnable(void* aSurface, nsNPAPIPluginInstance* inst, const gfxRect& aFrameRect)
|
||||
: mSurface(aSurface), mInstance(inst), mFrameRect(aFrameRect) {
|
||||
}
|
||||
|
||||
~AndroidPaintEventRunnable() {
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
LOG("%p - AndroidPaintEventRunnable::Run\n", this);
|
||||
|
||||
if (!mInstance || !mSurface)
|
||||
return NS_OK;
|
||||
|
||||
// This needs to happen on the gecko main thread.
|
||||
JNIEnv* env = GetJNIForThread();
|
||||
jclass cls = env->FindClass("org/mozilla/gecko/GeckoAppShell");
|
||||
jmethodID method = env->GetStaticMethodID(cls,
|
||||
"addPluginView",
|
||||
"(Landroid/view/View;DDDD)V");
|
||||
env->CallStaticVoidMethod(cls,
|
||||
method,
|
||||
mSurface,
|
||||
mFrameRect.x,
|
||||
mFrameRect.y,
|
||||
mFrameRect.width,
|
||||
mFrameRect.height);
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
void* mSurface;
|
||||
nsCOMPtr<nsNPAPIPluginInstance> mInstance;
|
||||
gfxRect mFrameRect;
|
||||
};
|
||||
|
||||
|
||||
void nsPluginInstanceOwner::Paint(gfxContext* aContext,
|
||||
const gfxRect& aFrameRect,
|
||||
const gfxRect& aDirtyRect)
|
||||
|
@ -2847,33 +2844,20 @@ void nsPluginInstanceOwner::Paint(gfxContext* aContext,
|
|||
mInstance->GetDrawingModel(&model);
|
||||
|
||||
if (model == kSurface_ANPDrawingModel) {
|
||||
AddPluginView(aFrameRect);
|
||||
|
||||
{
|
||||
ANPEvent event;
|
||||
event.inSize = sizeof(ANPEvent);
|
||||
event.eventType = kLifecycle_ANPEventType;
|
||||
event.data.lifecycle.action = kOnScreen_ANPLifecycleAction;
|
||||
mInstance->HandleEvent(&event, nsnull);
|
||||
gfxImageSurface* pluginSurface = mInstance->LockTargetSurface();
|
||||
if (!pluginSurface) {
|
||||
mInstance->UnlockTargetSurface(false);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
gfxMatrix currentMatrix = aContext->CurrentMatrix();
|
||||
gfxSize scale = currentMatrix.ScaleFactors(true);
|
||||
printf_stderr("!!!!!!!! scale!!: %f x %f\n", scale.width, scale.height);
|
||||
*/
|
||||
aContext->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
aContext->SetSource(pluginSurface, gfxPoint(aFrameRect.x, aFrameRect.y));
|
||||
aContext->Clip(aDirtyRect);
|
||||
aContext->Paint();
|
||||
|
||||
JNIEnv* env = GetJNIForThread();
|
||||
jclass cls = env->FindClass("org/mozilla/gecko/GeckoAppShell");
|
||||
jmethodID method = env->GetStaticMethodID(cls,
|
||||
"addPluginView",
|
||||
"(Landroid/view/View;DDDD)V");
|
||||
env->CallStaticVoidMethod(cls,
|
||||
method,
|
||||
mInstance->GetJavaSurface(),
|
||||
aFrameRect.x,
|
||||
aFrameRect.y,
|
||||
aFrameRect.width,
|
||||
aFrameRect.height);
|
||||
mInstance->UnlockTargetSurface(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -309,6 +309,7 @@ private:
|
|||
|
||||
void FixUpURLS(const nsString &name, nsAString &value);
|
||||
#ifdef ANDROID
|
||||
void AddPluginView(const gfxRect& aRect);
|
||||
void RemovePluginView();
|
||||
#endif
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ BrowserStreamChild::BrowserStreamChild(PluginInstanceChild* instance,
|
|||
, mStreamStatus(kStreamOpen)
|
||||
, mDestroyPending(NOT_DESTROYED)
|
||||
, mNotifyPending(false)
|
||||
, mStreamAsFilePending(false)
|
||||
, mInstanceDying(false)
|
||||
, mState(CONSTRUCTING)
|
||||
, mURL(url)
|
||||
|
@ -140,7 +141,7 @@ BrowserStreamChild::RecvWrite(const int32_t& offset,
|
|||
}
|
||||
|
||||
bool
|
||||
BrowserStreamChild::AnswerNPP_StreamAsFile(const nsCString& fname)
|
||||
BrowserStreamChild::RecvNPP_StreamAsFile(const nsCString& fname)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG(("%s (fname=%s)", FULLFUNCTION, fname.get()));
|
||||
|
||||
|
@ -152,8 +153,10 @@ BrowserStreamChild::AnswerNPP_StreamAsFile(const nsCString& fname)
|
|||
if (kStreamOpen != mStreamStatus)
|
||||
return true;
|
||||
|
||||
mInstance->mPluginIface->asfile(&mInstance->mData, &mStream,
|
||||
fname.get());
|
||||
mStreamAsFilePending = true;
|
||||
mStreamAsFileName = fname;
|
||||
EnsureDeliveryPending();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -238,6 +241,19 @@ BrowserStreamChild::Deliver()
|
|||
"Exit out of the data-delivery loop with pending data");
|
||||
mPendingData.Clear();
|
||||
|
||||
// NPP_StreamAsFile() is documented (at MDN) to be called "when the stream
|
||||
// is complete" -- i.e. after all calls to NPP_WriteReady() and NPP_Write()
|
||||
// have finished. We make these calls asynchronously (from
|
||||
// DeliverPendingData()). So we need to make sure all the "pending data"
|
||||
// has been "delivered" before calling NPP_StreamAsFile() (also
|
||||
// asynchronously). Doing this resolves bug 687610, bug 670036 and possibly
|
||||
// also other bugs.
|
||||
if (mStreamAsFilePending) {
|
||||
mInstance->mPluginIface->asfile(&mInstance->mData, &mStream,
|
||||
mStreamAsFileName.get());
|
||||
mStreamAsFilePending = false;
|
||||
}
|
||||
|
||||
if (DESTROY_PENDING == mDestroyPending) {
|
||||
mDestroyPending = DESTROYED;
|
||||
if (mState != DYING)
|
||||
|
|
|
@ -72,7 +72,7 @@ public:
|
|||
virtual bool RecvWrite(const int32_t& offset,
|
||||
const Buffer& data,
|
||||
const uint32_t& newsize);
|
||||
virtual bool AnswerNPP_StreamAsFile(const nsCString& fname);
|
||||
virtual bool RecvNPP_StreamAsFile(const nsCString& fname);
|
||||
virtual bool RecvNPP_DestroyStream(const NPReason& reason);
|
||||
virtual bool Recv__delete__();
|
||||
|
||||
|
@ -166,6 +166,8 @@ private:
|
|||
DESTROYED // NPP_DestroyStream delivered, NPP_URLNotify may still be pending
|
||||
} mDestroyPending;
|
||||
bool mNotifyPending;
|
||||
bool mStreamAsFilePending;
|
||||
nsCString mStreamAsFileName;
|
||||
|
||||
// When NPP_Destroy is called for our instance (manager), this flag is set
|
||||
// cancels the stream and avoids sending StreamDestroyed.
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "BrowserStreamParent.h"
|
||||
#include "PluginInstanceParent.h"
|
||||
#include "nsNPAPIPlugin.h"
|
||||
|
||||
#include "mozilla/unused.h"
|
||||
|
||||
|
@ -97,6 +98,8 @@ BrowserStreamParent::RecvStreamDestroyed()
|
|||
return false;
|
||||
}
|
||||
|
||||
mStreamPeer = NULL;
|
||||
|
||||
mState = DELETING;
|
||||
return Send__delete__(this);
|
||||
}
|
||||
|
@ -134,7 +137,15 @@ BrowserStreamParent::StreamAsFile(const char* fname)
|
|||
NS_ASSERTION(ALIVE == mState,
|
||||
"Calling streamasfile after NPP_DestroyStream?");
|
||||
|
||||
unused << CallNPP_StreamAsFile(nsCString(fname));
|
||||
// Make sure our stream survives until the plugin process tells us we've
|
||||
// been destroyed (until RecvStreamDestroyed() is called). Since we retain
|
||||
// mStreamPeer at most once, we won't get in trouble if StreamAsFile() is
|
||||
// called more than once.
|
||||
if (!mStreamPeer) {
|
||||
nsNPAPIPlugin::RetainStream(mStream, getter_AddRefs(mStreamPeer));
|
||||
}
|
||||
|
||||
unused << SendNPP_StreamAsFile(nsCString(fname));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -76,6 +76,7 @@ private:
|
|||
|
||||
PluginInstanceParent* mNPP;
|
||||
NPStream* mStream;
|
||||
nsCOMPtr<nsISupports> mStreamPeer;
|
||||
|
||||
enum {
|
||||
ALIVE,
|
||||
|
|
|
@ -59,7 +59,7 @@ rpc protocol PBrowserStream
|
|||
child:
|
||||
async Write(int32_t offset, Buffer data,
|
||||
uint32_t newlength);
|
||||
rpc NPP_StreamAsFile(nsCString fname);
|
||||
async NPP_StreamAsFile(nsCString fname);
|
||||
|
||||
/**
|
||||
* NPP_DestroyStream may race with other messages: the child acknowledges
|
||||
|
|
|
@ -116,7 +116,11 @@ PluginModuleParent::LoadModule(const char* aFilePath)
|
|||
TimeoutChanged(kChildTimeoutPref, parent);
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
CrashReporterParent::CreateCrashReporter(parent.get());
|
||||
// If this fails, we're having IPC troubles, and we're doomed anyways.
|
||||
if (!CrashReporterParent::CreateCrashReporter(parent.get())) {
|
||||
parent->mShutdown = true;
|
||||
return nsnull;
|
||||
}
|
||||
#endif
|
||||
|
||||
return parent.forget();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<head>
|
||||
<title>NPAPI ClearSiteData/GetSitesWithData Functionality</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/PluginUtils.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
|
||||
|
|
|
@ -1355,10 +1355,7 @@ public class GeckoAppShell
|
|||
(int)y);
|
||||
|
||||
if (GeckoApp.mainLayout.indexOfChild(view) == -1) {
|
||||
view.setWillNotDraw(false);
|
||||
if(view instanceof SurfaceView)
|
||||
((SurfaceView)view).setZOrderOnTop(true);
|
||||
|
||||
view.setWillNotDraw(true);
|
||||
GeckoApp.mainLayout.addView(view, lp);
|
||||
}
|
||||
else
|
||||
|
@ -1412,16 +1409,9 @@ public class GeckoAppShell
|
|||
return null;
|
||||
}
|
||||
|
||||
static HashMap<SurfaceView, SurfaceLockInfo> sSufaceMap = new HashMap<SurfaceView, SurfaceLockInfo>();
|
||||
|
||||
public static void lockSurfaceANP()
|
||||
public static SurfaceInfo getSurfaceInfo(SurfaceView sview)
|
||||
{
|
||||
Log.i("GeckoAppShell", "other lockSurfaceANP");
|
||||
}
|
||||
|
||||
public static org.mozilla.gecko.SurfaceLockInfo lockSurfaceANP(android.view.SurfaceView sview, int top, int left, int bottom, int right)
|
||||
{
|
||||
Log.i("GeckoAppShell", "real lockSurfaceANP " + sview + ", " + top + ", " + left + ", " + bottom + ", " + right);
|
||||
Log.i("GeckoAppShell", "getSurfaceInfo " + sview);
|
||||
if (sview == null)
|
||||
return null;
|
||||
|
||||
|
@ -1435,80 +1425,28 @@ public class GeckoAppShell
|
|||
}
|
||||
|
||||
int n = 0;
|
||||
if (format == PixelFormat.RGB_565)
|
||||
if (format == PixelFormat.RGB_565) {
|
||||
n = 2;
|
||||
else if (format == PixelFormat.RGBA_8888)
|
||||
} else if (format == PixelFormat.RGBA_8888) {
|
||||
n = 4;
|
||||
|
||||
if (n == 0)
|
||||
} else {
|
||||
Log.i("GeckoAppShell", "Unknown pixel format: " + format);
|
||||
return null;
|
||||
|
||||
SurfaceLockInfo info = sSufaceMap.get(sview);
|
||||
if (info == null) {
|
||||
info = new SurfaceLockInfo();
|
||||
sSufaceMap.put(sview, info);
|
||||
}
|
||||
|
||||
Rect r = new Rect(left, top, right, bottom);
|
||||
|
||||
info.canvas = sview.getHolder().lockCanvas(r);
|
||||
int bufSizeRequired = info.canvas.getWidth() * info.canvas.getHeight() * n;
|
||||
Log.i("GeckoAppShell", "lockSurfaceANP - bufSizeRequired: " + n + " " + info.canvas.getHeight() + " " + info.canvas.getWidth());
|
||||
|
||||
if (info.width != info.canvas.getWidth() || info.height != info.canvas.getHeight() || info.buffer == null || info.buffer.capacity() < bufSizeRequired) {
|
||||
info.width = info.canvas.getWidth();
|
||||
info.height = info.canvas.getHeight();
|
||||
|
||||
// XXX Bitmaps instead of ByteBuffer
|
||||
info.buffer = ByteBuffer.allocateDirect(bufSizeRequired); //leak
|
||||
Log.i("GeckoAppShell", "!!!!!!!!!!! lockSurfaceANP - Allocating buffer! " + bufSizeRequired);
|
||||
|
||||
}
|
||||
|
||||
info.canvas.drawColor(Color.WHITE, PorterDuff.Mode.CLEAR);
|
||||
SurfaceInfo info = new SurfaceInfo();
|
||||
|
||||
Rect r = sview.getHolder().getSurfaceFrame();
|
||||
info.width = r.right;
|
||||
info.height = r.bottom;
|
||||
info.format = format;
|
||||
info.dirtyTop = top;
|
||||
info.dirtyBottom = bottom;
|
||||
info.dirtyLeft = left;
|
||||
info.dirtyRight = right;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public static void unlockSurfaceANP(SurfaceView sview) {
|
||||
SurfaceLockInfo info = sSufaceMap.get(sview);
|
||||
|
||||
int n = 0;
|
||||
Bitmap.Config config;
|
||||
if (info.format == PixelFormat.RGB_565) {
|
||||
n = 2;
|
||||
config = Bitmap.Config.RGB_565;
|
||||
} else {
|
||||
n = 4;
|
||||
config = Bitmap.Config.ARGB_8888;
|
||||
}
|
||||
|
||||
Log.i("GeckoAppShell", "unlockSurfaceANP: " + (info.width * info.height * n));
|
||||
|
||||
Bitmap bm = Bitmap.createBitmap(info.width, info.height, config);
|
||||
bm.copyPixelsFromBuffer(info.buffer);
|
||||
info.canvas.drawBitmap(bm, 0, 0, null);
|
||||
sview.getHolder().unlockCanvasAndPost(info.canvas);
|
||||
}
|
||||
|
||||
public static Class getSurfaceLockInfoClass() {
|
||||
Log.i("GeckoAppShell", "class name: " + SurfaceLockInfo.class.getName());
|
||||
return SurfaceLockInfo.class;
|
||||
}
|
||||
|
||||
public static Method getSurfaceLockMethod() {
|
||||
Method[] m = GeckoAppShell.class.getMethods();
|
||||
for (int i = 0; i < m.length; i++) {
|
||||
if (m[i].getName().equals("lockSurfaceANP"))
|
||||
return m[i];
|
||||
}
|
||||
return null;
|
||||
public static Class getSurfaceInfoClass() {
|
||||
Log.i("GeckoAppShell", "class name: " + SurfaceInfo.class.getName());
|
||||
return SurfaceInfo.class;
|
||||
}
|
||||
|
||||
static native void executeNextRunnable();
|
||||
|
|
|
@ -53,7 +53,7 @@ JAVAFILES = \
|
|||
GeckoSurfaceView.java \
|
||||
GeckoInputConnection.java \
|
||||
AlertNotification.java \
|
||||
SurfaceLockInfo.java \
|
||||
SurfaceInfo.java \
|
||||
$(NULL)
|
||||
|
||||
PROCESSEDJAVAFILES = \
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package org.mozilla.gecko;
|
||||
|
||||
public class SurfaceInfo {
|
||||
public int format;
|
||||
public int width;
|
||||
public int height;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package org.mozilla.gecko;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import java.nio.Buffer;
|
||||
|
||||
public class SurfaceLockInfo {
|
||||
public int dirtyTop;
|
||||
public int dirtyLeft;
|
||||
public int dirtyRight;
|
||||
public int dirtyBottom;
|
||||
|
||||
public int bpr;
|
||||
public int format;
|
||||
public int width;
|
||||
public int height;
|
||||
public Buffer buffer;
|
||||
public Canvas canvas;
|
||||
}
|
|
@ -11,6 +11,7 @@ In this order:
|
|||
angle-limit-identifiers-to-250-chars.patch - see bug 675625
|
||||
angle-use-xmalloc.patch - see bug 680840. Can drop this patch whenever the new preprocessor lands.
|
||||
angle-mCurrentValueOffsets-size_t.patch - ANGLE bug 220 - compile fix on win64
|
||||
angle-pool_allocator-assignable.patch - ANGLE r798
|
||||
|
||||
In addition to these patches, the Makefile.in files are ours, they're not present in upsteam ANGLE.
|
||||
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
diff --git a/gfx/angle/src/compiler/PoolAlloc.h b/gfx/angle/src/compiler/PoolAlloc.h
|
||||
--- a/gfx/angle/src/compiler/PoolAlloc.h
|
||||
+++ b/gfx/angle/src/compiler/PoolAlloc.h
|
||||
@@ -248,22 +248,28 @@ public:
|
||||
|
||||
template<class Other>
|
||||
struct rebind {
|
||||
typedef pool_allocator<Other> other;
|
||||
};
|
||||
pointer address(reference x) const { return &x; }
|
||||
const_pointer address(const_reference x) const { return &x; }
|
||||
|
||||
- pool_allocator() : allocator(GlobalPoolAllocator) { }
|
||||
- pool_allocator(TPoolAllocator& a) : allocator(a) { }
|
||||
+ pool_allocator() : allocator(&GlobalPoolAllocator) { }
|
||||
+ pool_allocator(TPoolAllocator& a) : allocator(&a) { }
|
||||
pool_allocator(const pool_allocator<T>& p) : allocator(p.allocator) { }
|
||||
|
||||
+ template <class Other>
|
||||
+ pool_allocator<T>& operator=(const pool_allocator<Other>& p) {
|
||||
+ allocator = p.allocator;
|
||||
+ return *this;
|
||||
+ }
|
||||
+
|
||||
template<class Other>
|
||||
- pool_allocator(const pool_allocator<Other>& p) : allocator(p.getAllocator()) { }
|
||||
+ pool_allocator(const pool_allocator<Other>& p) : allocator(&p.getAllocator()) { }
|
||||
|
||||
#if defined(__SUNPRO_CC) && !defined(_RWSTD_ALLOCATOR)
|
||||
// libCStd on some platforms have a different allocate/deallocate interface.
|
||||
// Caller pre-bakes sizeof(T) into 'n' which is the number of bytes to be
|
||||
// allocated, not the number of elements.
|
||||
void* allocate(size_type n) {
|
||||
return getAllocator().allocate(n);
|
||||
}
|
||||
@@ -285,16 +291,16 @@ public:
|
||||
void destroy(pointer p) { p->T::~T(); }
|
||||
|
||||
bool operator==(const pool_allocator& rhs) const { return &getAllocator() == &rhs.getAllocator(); }
|
||||
bool operator!=(const pool_allocator& rhs) const { return &getAllocator() != &rhs.getAllocator(); }
|
||||
|
||||
size_type max_size() const { return static_cast<size_type>(-1) / sizeof(T); }
|
||||
size_type max_size(int size) const { return static_cast<size_type>(-1) / size; }
|
||||
|
||||
- void setAllocator(TPoolAllocator* a) { allocator = *a; }
|
||||
- TPoolAllocator& getAllocator() const { return allocator; }
|
||||
+ void setAllocator(TPoolAllocator* a) { allocator = a; }
|
||||
+ TPoolAllocator& getAllocator() const { return *allocator; }
|
||||
|
||||
protected:
|
||||
- TPoolAllocator& allocator;
|
||||
+ TPoolAllocator* allocator;
|
||||
};
|
||||
|
||||
#endif // _POOLALLOC_INCLUDED_
|
|
@ -253,12 +253,18 @@ public:
|
|||
pointer address(reference x) const { return &x; }
|
||||
const_pointer address(const_reference x) const { return &x; }
|
||||
|
||||
pool_allocator() : allocator(GlobalPoolAllocator) { }
|
||||
pool_allocator(TPoolAllocator& a) : allocator(a) { }
|
||||
pool_allocator() : allocator(&GlobalPoolAllocator) { }
|
||||
pool_allocator(TPoolAllocator& a) : allocator(&a) { }
|
||||
pool_allocator(const pool_allocator<T>& p) : allocator(p.allocator) { }
|
||||
|
||||
template <class Other>
|
||||
pool_allocator<T>& operator=(const pool_allocator<Other>& p) {
|
||||
allocator = p.allocator;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Other>
|
||||
pool_allocator(const pool_allocator<Other>& p) : allocator(p.getAllocator()) { }
|
||||
pool_allocator(const pool_allocator<Other>& p) : allocator(&p.getAllocator()) { }
|
||||
|
||||
#if defined(__SUNPRO_CC) && !defined(_RWSTD_ALLOCATOR)
|
||||
// libCStd on some platforms have a different allocate/deallocate interface.
|
||||
|
@ -290,11 +296,11 @@ public:
|
|||
size_type max_size() const { return static_cast<size_type>(-1) / sizeof(T); }
|
||||
size_type max_size(int size) const { return static_cast<size_type>(-1) / size; }
|
||||
|
||||
void setAllocator(TPoolAllocator* a) { allocator = *a; }
|
||||
TPoolAllocator& getAllocator() const { return allocator; }
|
||||
void setAllocator(TPoolAllocator* a) { allocator = a; }
|
||||
TPoolAllocator& getAllocator() const { return *allocator; }
|
||||
|
||||
protected:
|
||||
TPoolAllocator& allocator;
|
||||
TPoolAllocator* allocator;
|
||||
};
|
||||
|
||||
#endif // _POOLALLOC_INCLUDED_
|
||||
|
|
|
@ -1111,7 +1111,7 @@ BasicCanvasLayer::UpdateSurface(gfxASurface* aDestSurface)
|
|||
mGLContext->MakeCurrent();
|
||||
|
||||
#if defined (MOZ_X11) && defined (MOZ_EGL_XRENDER_COMPOSITE)
|
||||
mGLContext->fFinish();
|
||||
mGLContext->Finish();
|
||||
gfxASurface* offscreenSurface = mGLContext->GetOffscreenPixmapSurface();
|
||||
|
||||
// XRender can only blend premuliplied alpha, so only allow xrender
|
||||
|
|
|
@ -172,6 +172,10 @@ CanvasLayerOGL::UpdateSurface()
|
|||
}
|
||||
#endif
|
||||
|
||||
if (mCanvasGLContext) {
|
||||
mCanvasGLContext->MakeCurrent();
|
||||
mCanvasGLContext->fFinish();
|
||||
}
|
||||
mOGLManager->MakeCurrent();
|
||||
|
||||
if (mCanvasGLContext &&
|
||||
|
|
|
@ -377,6 +377,33 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
|||
(mSymbols.fMapBuffer && mSymbols.fUnmapBuffer),
|
||||
"ARB_pixel_buffer_object supported without glMapBuffer/UnmapBuffer being available!");
|
||||
|
||||
// Check for aux symbols based on extensions
|
||||
if (IsExtensionSupported(GLContext::ANGLE_framebuffer_blit) ||
|
||||
IsExtensionSupported(GLContext::EXT_framebuffer_blit)) {
|
||||
SymLoadStruct auxSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fBlitFramebuffer, { "BlitFramebuffer", "BlitFramebufferEXT", "BlitFramebufferANGLE", NULL } },
|
||||
{ NULL, { NULL } },
|
||||
};
|
||||
if (!LoadSymbols(&auxSymbols[0], trygl, prefix)) {
|
||||
NS_RUNTIMEABORT("GL supports framebuffer_blit without supplying glBlitFramebuffer");
|
||||
mInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsExtensionSupported(GLContext::ANGLE_framebuffer_multisample) ||
|
||||
IsExtensionSupported(GLContext::EXT_framebuffer_multisample)) {
|
||||
SymLoadStruct auxSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fRenderbufferStorageMultisample, { "RenderbufferStorageMultisample", "RenderbufferStorageMultisampleEXT", "RenderbufferStorageMultisampleANGLE", NULL } },
|
||||
{ NULL, { NULL } },
|
||||
};
|
||||
if (!LoadSymbols(&auxSymbols[0], trygl, prefix)) {
|
||||
NS_RUNTIMEABORT("GL supports framebuffer_multisample without supplying glRenderbufferStorageMultisample");
|
||||
mInitialized = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mInitialized) {
|
||||
GLint v[4];
|
||||
|
||||
fGetIntegerv(LOCAL_GL_SCISSOR_BOX, v);
|
||||
|
@ -438,6 +465,11 @@ static const char *sExtensionNames[] = {
|
|||
"GL_ARB_texture_float",
|
||||
"GL_EXT_unpack_subimage",
|
||||
"GL_OES_standard_derivatives",
|
||||
"GL_EXT_framebuffer_blit",
|
||||
"GL_ANGLE_framebuffer_blit",
|
||||
"GL_EXT_framebuffer_multisample",
|
||||
"GL_ANGLE_framebuffer_multisample",
|
||||
"GL_OES_rgb8_rgba8",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -986,107 +1018,155 @@ PRUint32 TiledTextureImage::GetTileCount()
|
|||
}
|
||||
|
||||
bool
|
||||
GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
|
||||
GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize, const bool aUseReadFBO, const bool aDisableAA)
|
||||
{
|
||||
if (!IsOffscreenSizeAllowed(aSize))
|
||||
return false;
|
||||
|
||||
MakeCurrent();
|
||||
|
||||
bool alpha = mCreationFormat.alpha > 0;
|
||||
int depth = mCreationFormat.depth;
|
||||
int stencil = mCreationFormat.stencil;
|
||||
const bool alpha = mCreationFormat.alpha > 0;
|
||||
const int depth = mCreationFormat.depth;
|
||||
const int stencil = mCreationFormat.stencil;
|
||||
int samples = mCreationFormat.samples;
|
||||
|
||||
bool firstTime = (mOffscreenFBO == 0);
|
||||
const bool useDrawMSFBO = (samples > 0) && SupportsFramebufferMultisample();
|
||||
|
||||
GLuint curBoundTexture = 0;
|
||||
if (!useDrawMSFBO && !aUseReadFBO)
|
||||
return true;
|
||||
|
||||
if (!useDrawMSFBO || aDisableAA)
|
||||
samples = 0;
|
||||
|
||||
const bool firstTime = (mOffscreenDrawFBO == 0 && mOffscreenReadFBO == 0);
|
||||
|
||||
GLuint curBoundFramebufferDraw = 0;
|
||||
GLuint curBoundFramebufferRead = 0;
|
||||
GLuint curBoundRenderbuffer = 0;
|
||||
GLuint curBoundFramebuffer = 0;
|
||||
GLuint curBoundTexture = 0;
|
||||
|
||||
GLint viewport[4];
|
||||
|
||||
bool useDepthStencil =
|
||||
!mIsGLES2 || IsExtensionSupported(OES_packed_depth_stencil);
|
||||
const bool useDepthStencil =
|
||||
!mIsGLES2 || IsExtensionSupported(OES_packed_depth_stencil);
|
||||
|
||||
// save a few things for later restoring
|
||||
fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, (GLint*) &curBoundTexture);
|
||||
fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*) &curBoundFramebuffer);
|
||||
curBoundFramebufferDraw = GetBoundDrawFBO();
|
||||
curBoundFramebufferRead = GetBoundReadFBO();
|
||||
fGetIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, (GLint*) &curBoundRenderbuffer);
|
||||
fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, (GLint*) &curBoundTexture);
|
||||
fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
|
||||
|
||||
// the context format of what we're defining;
|
||||
// for some reason, UpdateActualFormat isn't working with a bound FBO.
|
||||
ContextFormat cf;
|
||||
// the context format of what we're defining
|
||||
// This becomes mActualFormat on success
|
||||
ContextFormat cf(mCreationFormat);
|
||||
|
||||
// If this is the first time we're going through this, we need
|
||||
// to create the objects we'll use. Otherwise, just bind them.
|
||||
if (firstTime) {
|
||||
fGenTextures(1, &mOffscreenTexture);
|
||||
fBindTexture(LOCAL_GL_TEXTURE_2D, mOffscreenTexture);
|
||||
fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
|
||||
fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
|
||||
// Create everything we need for the resize, so if it fails, we haven't broken anything
|
||||
// If successful, these new resized objects will replace their associated member vars in GLContext
|
||||
GLuint newOffscreenDrawFBO = 0;
|
||||
GLuint newOffscreenReadFBO = 0;
|
||||
GLuint newOffscreenTexture = 0;
|
||||
GLuint newOffscreenColorRB = 0;
|
||||
GLuint newOffscreenDepthRB = 0;
|
||||
GLuint newOffscreenStencilRB = 0;
|
||||
|
||||
fGenFramebuffers(1, &mOffscreenFBO);
|
||||
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mOffscreenFBO);
|
||||
|
||||
if (depth && stencil && useDepthStencil) {
|
||||
fGenRenderbuffers(1, &mOffscreenDepthRB);
|
||||
} else {
|
||||
if (depth) {
|
||||
fGenRenderbuffers(1, &mOffscreenDepthRB);
|
||||
}
|
||||
|
||||
if (stencil) {
|
||||
fGenRenderbuffers(1, &mOffscreenStencilRB);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fBindTexture(LOCAL_GL_TEXTURE_2D, mOffscreenTexture);
|
||||
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mOffscreenFBO);
|
||||
// Create the buffers and texture
|
||||
if (aUseReadFBO) {
|
||||
fGenFramebuffers(1, &newOffscreenReadFBO);
|
||||
fGenTextures(1, &newOffscreenTexture);
|
||||
}
|
||||
|
||||
// resize the FBO components
|
||||
if (alpha) {
|
||||
fTexImage2D(LOCAL_GL_TEXTURE_2D,
|
||||
0,
|
||||
LOCAL_GL_RGBA,
|
||||
aSize.width, aSize.height,
|
||||
0,
|
||||
LOCAL_GL_RGBA,
|
||||
LOCAL_GL_UNSIGNED_BYTE,
|
||||
NULL);
|
||||
|
||||
cf.red = cf.green = cf.blue = cf.alpha = 8;
|
||||
if (useDrawMSFBO) {
|
||||
fGenFramebuffers(1, &newOffscreenDrawFBO);
|
||||
fGenRenderbuffers(1, &newOffscreenColorRB);
|
||||
} else {
|
||||
fTexImage2D(LOCAL_GL_TEXTURE_2D,
|
||||
0,
|
||||
LOCAL_GL_RGB,
|
||||
aSize.width, aSize.height,
|
||||
0,
|
||||
LOCAL_GL_RGB,
|
||||
#ifdef XP_WIN
|
||||
LOCAL_GL_UNSIGNED_BYTE,
|
||||
#else
|
||||
mIsGLES2 ? LOCAL_GL_UNSIGNED_SHORT_5_6_5
|
||||
: LOCAL_GL_UNSIGNED_BYTE,
|
||||
#endif
|
||||
NULL);
|
||||
|
||||
#ifdef XP_WIN
|
||||
cf.red = cf.green = cf.blue = 8;
|
||||
#else
|
||||
cf.red = 5;
|
||||
cf.green = 6;
|
||||
cf.blue = 5;
|
||||
#endif
|
||||
cf.alpha = 0;
|
||||
newOffscreenDrawFBO = newOffscreenReadFBO;
|
||||
}
|
||||
|
||||
if (depth && stencil && useDepthStencil) {
|
||||
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOffscreenDepthRB);
|
||||
fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
|
||||
LOCAL_GL_DEPTH24_STENCIL8,
|
||||
aSize.width, aSize.height);
|
||||
fGenRenderbuffers(1, &newOffscreenDepthRB);
|
||||
} else {
|
||||
if (depth) {
|
||||
fGenRenderbuffers(1, &newOffscreenDepthRB);
|
||||
}
|
||||
|
||||
if (stencil) {
|
||||
fGenRenderbuffers(1, &newOffscreenStencilRB);
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate texture
|
||||
if (aUseReadFBO) {
|
||||
fBindTexture(LOCAL_GL_TEXTURE_2D, newOffscreenTexture);
|
||||
fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
|
||||
fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
|
||||
|
||||
if (alpha) {
|
||||
fTexImage2D(LOCAL_GL_TEXTURE_2D,
|
||||
0,
|
||||
LOCAL_GL_RGBA,
|
||||
aSize.width, aSize.height,
|
||||
0,
|
||||
LOCAL_GL_RGBA,
|
||||
LOCAL_GL_UNSIGNED_BYTE,
|
||||
NULL);
|
||||
|
||||
cf.red = cf.green = cf.blue = cf.alpha = 8;
|
||||
} else {
|
||||
fTexImage2D(LOCAL_GL_TEXTURE_2D,
|
||||
0,
|
||||
LOCAL_GL_RGB,
|
||||
aSize.width, aSize.height,
|
||||
0,
|
||||
LOCAL_GL_RGB,
|
||||
#ifdef XP_WIN
|
||||
LOCAL_GL_UNSIGNED_BYTE,
|
||||
#else
|
||||
mIsGLES2 ? LOCAL_GL_UNSIGNED_SHORT_5_6_5
|
||||
: LOCAL_GL_UNSIGNED_BYTE,
|
||||
#endif
|
||||
NULL);
|
||||
|
||||
#ifdef XP_WIN
|
||||
cf.red = cf.green = cf.blue = 8;
|
||||
#else
|
||||
cf.red = 5;
|
||||
cf.green = 6;
|
||||
cf.blue = 5;
|
||||
#endif
|
||||
cf.alpha = 0;
|
||||
}
|
||||
}
|
||||
cf.samples = samples;
|
||||
|
||||
// Allocate color buffer
|
||||
if (useDrawMSFBO) {
|
||||
GLenum colorFormat;
|
||||
if (!mIsGLES2 || IsExtensionSupported(OES_rgb8_rgba8))
|
||||
colorFormat = alpha ? LOCAL_GL_RGBA8 : LOCAL_GL_RGB8;
|
||||
else
|
||||
colorFormat = alpha ? LOCAL_GL_RGBA4 : LOCAL_GL_RGB565;
|
||||
|
||||
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, newOffscreenColorRB);
|
||||
fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER,
|
||||
samples,
|
||||
colorFormat,
|
||||
aSize.width, aSize.height);
|
||||
}
|
||||
|
||||
// Allocate depth and stencil buffers
|
||||
if (depth && stencil && useDepthStencil) {
|
||||
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, newOffscreenDepthRB);
|
||||
if (useDrawMSFBO) {
|
||||
fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER,
|
||||
samples,
|
||||
LOCAL_GL_DEPTH24_STENCIL8,
|
||||
aSize.width, aSize.height);
|
||||
} else {
|
||||
fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
|
||||
LOCAL_GL_DEPTH24_STENCIL8,
|
||||
aSize.width, aSize.height);
|
||||
}
|
||||
cf.depth = 24;
|
||||
cf.stencil = 8;
|
||||
} else {
|
||||
|
@ -1108,77 +1188,167 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
|
|||
cf.depth = 24;
|
||||
}
|
||||
|
||||
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOffscreenDepthRB);
|
||||
fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, depthType,
|
||||
aSize.width, aSize.height);
|
||||
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, newOffscreenDepthRB);
|
||||
if (useDrawMSFBO) {
|
||||
fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER,
|
||||
samples,
|
||||
depthType,
|
||||
aSize.width, aSize.height);
|
||||
} else {
|
||||
fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
|
||||
depthType,
|
||||
aSize.width, aSize.height);
|
||||
}
|
||||
}
|
||||
|
||||
if (stencil) {
|
||||
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOffscreenStencilRB);
|
||||
fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
|
||||
LOCAL_GL_STENCIL_INDEX8,
|
||||
aSize.width, aSize.height);
|
||||
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, newOffscreenStencilRB);
|
||||
if (useDrawMSFBO) {
|
||||
fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER,
|
||||
samples,
|
||||
LOCAL_GL_STENCIL_INDEX8,
|
||||
aSize.width, aSize.height);
|
||||
} else {
|
||||
fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
|
||||
LOCAL_GL_STENCIL_INDEX8,
|
||||
aSize.width, aSize.height);
|
||||
}
|
||||
cf.stencil = 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Now assemble the FBO, if we're creating one
|
||||
// for the first time.
|
||||
if (firstTime) {
|
||||
fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_COLOR_ATTACHMENT0,
|
||||
LOCAL_GL_TEXTURE_2D,
|
||||
mOffscreenTexture,
|
||||
0);
|
||||
// Now assemble the FBO
|
||||
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, newOffscreenDrawFBO); // If we're not using a separate draw FBO, this will be the read FBO
|
||||
if (useDrawMSFBO) {
|
||||
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_COLOR_ATTACHMENT0,
|
||||
LOCAL_GL_RENDERBUFFER,
|
||||
newOffscreenColorRB);
|
||||
}
|
||||
|
||||
if (depth && stencil && useDepthStencil) {
|
||||
if (depth && stencil && useDepthStencil) {
|
||||
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_DEPTH_ATTACHMENT,
|
||||
LOCAL_GL_RENDERBUFFER,
|
||||
newOffscreenDepthRB);
|
||||
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_STENCIL_ATTACHMENT,
|
||||
LOCAL_GL_RENDERBUFFER,
|
||||
newOffscreenDepthRB);
|
||||
} else {
|
||||
if (depth) {
|
||||
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_DEPTH_ATTACHMENT,
|
||||
LOCAL_GL_RENDERBUFFER,
|
||||
mOffscreenDepthRB);
|
||||
newOffscreenDepthRB);
|
||||
}
|
||||
|
||||
if (stencil) {
|
||||
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_STENCIL_ATTACHMENT,
|
||||
LOCAL_GL_RENDERBUFFER,
|
||||
mOffscreenDepthRB);
|
||||
} else {
|
||||
if (depth) {
|
||||
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_DEPTH_ATTACHMENT,
|
||||
LOCAL_GL_RENDERBUFFER,
|
||||
mOffscreenDepthRB);
|
||||
}
|
||||
|
||||
if (stencil) {
|
||||
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_STENCIL_ATTACHMENT,
|
||||
LOCAL_GL_RENDERBUFFER,
|
||||
mOffscreenStencilRB);
|
||||
}
|
||||
newOffscreenStencilRB);
|
||||
}
|
||||
}
|
||||
|
||||
if (aUseReadFBO) {
|
||||
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, newOffscreenReadFBO);
|
||||
fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_COLOR_ATTACHMENT0,
|
||||
LOCAL_GL_TEXTURE_2D,
|
||||
newOffscreenTexture,
|
||||
0);
|
||||
}
|
||||
|
||||
// We should be all resized. Check for framebuffer completeness.
|
||||
GLenum status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
|
||||
GLenum status;
|
||||
bool framebuffersComplete = true;
|
||||
|
||||
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, newOffscreenDrawFBO);
|
||||
status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
|
||||
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
||||
NS_WARNING("Error resizing offscreen framebuffer -- framebuffer not complete");
|
||||
NS_WARNING("DrawFBO: Incomplete");
|
||||
#ifdef DEBUG
|
||||
printf_stderr("Framebuffer status: %X\n", status);
|
||||
#endif
|
||||
framebuffersComplete = false;
|
||||
}
|
||||
|
||||
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, newOffscreenReadFBO);
|
||||
status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
|
||||
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
||||
NS_WARNING("ReadFBO: Incomplete");
|
||||
#ifdef DEBUG
|
||||
printf_stderr("Framebuffer status: %X\n", status);
|
||||
#endif
|
||||
framebuffersComplete = false;
|
||||
}
|
||||
|
||||
if (!framebuffersComplete) {
|
||||
NS_WARNING("Error resizing offscreen framebuffer -- framebuffer(s) not complete");
|
||||
|
||||
// Clean up the mess
|
||||
fDeleteFramebuffers(1, &newOffscreenDrawFBO);
|
||||
fDeleteFramebuffers(1, &newOffscreenReadFBO);
|
||||
fDeleteTextures(1, &newOffscreenTexture);
|
||||
fDeleteRenderbuffers(1, &newOffscreenColorRB);
|
||||
fDeleteRenderbuffers(1, &newOffscreenDepthRB);
|
||||
fDeleteRenderbuffers(1, &newOffscreenStencilRB);
|
||||
|
||||
BindReadFBO(curBoundFramebufferRead);
|
||||
BindDrawFBO(curBoundFramebufferDraw);
|
||||
fBindTexture(LOCAL_GL_TEXTURE_2D, curBoundTexture);
|
||||
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, curBoundRenderbuffer);
|
||||
fViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Success, so delete the old and busted
|
||||
fDeleteFramebuffers(1, &mOffscreenDrawFBO);
|
||||
fDeleteFramebuffers(1, &mOffscreenReadFBO);
|
||||
fDeleteTextures(1, &mOffscreenTexture);
|
||||
fDeleteRenderbuffers(1, &mOffscreenColorRB);
|
||||
fDeleteRenderbuffers(1, &mOffscreenDepthRB);
|
||||
fDeleteRenderbuffers(1, &mOffscreenStencilRB);
|
||||
|
||||
// Update currently bound references if we're changing what they were point to
|
||||
// This way we don't rebind to old buffers when we're done here
|
||||
if (curBoundFramebufferDraw == mOffscreenDrawFBO)
|
||||
curBoundFramebufferDraw = newOffscreenDrawFBO;
|
||||
if (curBoundFramebufferRead == mOffscreenReadFBO)
|
||||
curBoundFramebufferRead = newOffscreenReadFBO;
|
||||
if (curBoundTexture == mOffscreenTexture)
|
||||
curBoundTexture = newOffscreenTexture;
|
||||
if (curBoundRenderbuffer == mOffscreenColorRB)
|
||||
curBoundRenderbuffer = newOffscreenColorRB;
|
||||
else if (curBoundRenderbuffer == mOffscreenDepthRB)
|
||||
curBoundRenderbuffer = newOffscreenDepthRB;
|
||||
else if (curBoundRenderbuffer == mOffscreenStencilRB)
|
||||
curBoundRenderbuffer = newOffscreenStencilRB;
|
||||
|
||||
// Replace with the new hotness
|
||||
mOffscreenDrawFBO = newOffscreenDrawFBO;
|
||||
mOffscreenReadFBO = newOffscreenReadFBO;
|
||||
mOffscreenTexture = newOffscreenTexture;
|
||||
mOffscreenColorRB = newOffscreenColorRB;
|
||||
mOffscreenDepthRB = newOffscreenDepthRB;
|
||||
mOffscreenStencilRB = newOffscreenStencilRB;
|
||||
|
||||
mOffscreenSize = aSize;
|
||||
mOffscreenActualSize = aSize;
|
||||
|
||||
if (firstTime) {
|
||||
// UpdateActualFormat() doesn't work for some reason, with a
|
||||
// FBO bound, even though it should.
|
||||
//UpdateActualFormat();
|
||||
mActualFormat = cf;
|
||||
mActualFormat = cf;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf_stderr("Created offscreen FBO: r: %d g: %d b: %d a: %d depth: %d stencil: %d\n",
|
||||
if (mDebugMode) {
|
||||
printf_stderr("%s %dx%d offscreen FBO: r: %d g: %d b: %d a: %d depth: %d stencil: %d samples: %d\n",
|
||||
firstTime ? "Created" : "Resized",
|
||||
mOffscreenActualSize.width, mOffscreenActualSize.height,
|
||||
mActualFormat.red, mActualFormat.green, mActualFormat.blue, mActualFormat.alpha,
|
||||
mActualFormat.depth, mActualFormat.stencil);
|
||||
#endif
|
||||
mActualFormat.depth, mActualFormat.stencil, mActualFormat.samples);
|
||||
}
|
||||
#endif
|
||||
|
||||
// We're good, and the framebuffer is already attached, so let's
|
||||
// clear out our new framebuffer; otherwise we'll end up displaying
|
||||
|
@ -1186,13 +1356,18 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
|
|||
// can restore them.
|
||||
fViewport(0, 0, aSize.width, aSize.height);
|
||||
|
||||
// Make sure we know that the buffers are new and thus dirty:
|
||||
ForceDirtyFBOs();
|
||||
|
||||
// Clear the new framebuffer with the full viewport
|
||||
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, GetOffscreenFBO());
|
||||
ClearSafely();
|
||||
|
||||
// Ok, now restore the GL state back to what it was before the resize took place.
|
||||
BindDrawFBO(curBoundFramebufferDraw);
|
||||
BindReadFBO(curBoundFramebufferRead);
|
||||
fBindTexture(LOCAL_GL_TEXTURE_2D, curBoundTexture);
|
||||
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, curBoundRenderbuffer);
|
||||
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, curBoundFramebuffer);
|
||||
|
||||
// -don't- restore the viewport the first time through this, since
|
||||
// the previous one isn't valid.
|
||||
|
@ -1205,13 +1380,17 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
|
|||
void
|
||||
GLContext::DeleteOffscreenFBO()
|
||||
{
|
||||
fDeleteFramebuffers(1, &mOffscreenFBO);
|
||||
fDeleteFramebuffers(1, &mOffscreenDrawFBO);
|
||||
fDeleteFramebuffers(1, &mOffscreenReadFBO);
|
||||
fDeleteTextures(1, &mOffscreenTexture);
|
||||
fDeleteRenderbuffers(1, &mOffscreenColorRB);
|
||||
fDeleteRenderbuffers(1, &mOffscreenDepthRB);
|
||||
fDeleteRenderbuffers(1, &mOffscreenStencilRB);
|
||||
|
||||
mOffscreenFBO = 0;
|
||||
mOffscreenDrawFBO = 0;
|
||||
mOffscreenReadFBO = 0;
|
||||
mOffscreenTexture = 0;
|
||||
mOffscreenColorRB = 0;
|
||||
mOffscreenDepthRB = 0;
|
||||
mOffscreenStencilRB = 0;
|
||||
}
|
||||
|
|
|
@ -476,11 +476,11 @@ struct THEBES_API ContextFormat
|
|||
};
|
||||
|
||||
ContextFormat() {
|
||||
memset(this, 0, sizeof(*this));
|
||||
memset(this, 0, sizeof(ContextFormat));
|
||||
}
|
||||
|
||||
ContextFormat(const StandardContextFormat cf) {
|
||||
memset(this, 0, sizeof(*this));
|
||||
memset(this, 0, sizeof(ContextFormat));
|
||||
switch (cf) {
|
||||
case BasicRGBA32:
|
||||
red = green = blue = alpha = 8;
|
||||
|
@ -519,6 +519,7 @@ struct THEBES_API ContextFormat
|
|||
int green, minGreen;
|
||||
int blue, minBlue;
|
||||
int alpha, minAlpha;
|
||||
int samples;
|
||||
|
||||
int colorBits() const { return red + green + blue; }
|
||||
};
|
||||
|
@ -547,7 +548,10 @@ public:
|
|||
mFlipped(false),
|
||||
mBlitProgram(0),
|
||||
mBlitFramebuffer(0),
|
||||
mOffscreenFBO(0),
|
||||
mOffscreenDrawFBO(0),
|
||||
mOffscreenReadFBO(0),
|
||||
mOffscreenFBOsDirty(false),
|
||||
mOffscreenColorRB(0),
|
||||
mOffscreenDepthRB(0),
|
||||
mOffscreenStencilRB(0)
|
||||
#ifdef DEBUG
|
||||
|
@ -719,7 +723,7 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!aOffscreen->mOffscreenFBO) {
|
||||
if (!aOffscreen->mOffscreenDrawFBO && !aOffscreen->mOffscreenReadFBO) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -749,8 +753,8 @@ public:
|
|||
* Only valid if IsOffscreen() returns true.
|
||||
*/
|
||||
virtual bool ResizeOffscreen(const gfxIntSize& aNewSize) {
|
||||
if (mOffscreenFBO)
|
||||
return ResizeOffscreenFBO(aNewSize);
|
||||
if (mOffscreenDrawFBO || mOffscreenReadFBO)
|
||||
return ResizeOffscreenFBO(aNewSize, mOffscreenReadFBO != 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -781,12 +785,232 @@ public:
|
|||
* Only valid if IsOffscreen() returns true.
|
||||
*/
|
||||
GLuint GetOffscreenFBO() {
|
||||
return mOffscreenFBO;
|
||||
// 0 is interpreted as (off)screen, whether for read or draw operations
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLuint GetOffscreenTexture() {
|
||||
return mOffscreenTexture;
|
||||
}
|
||||
|
||||
virtual bool SupportsFramebufferMultisample() {
|
||||
return IsExtensionSupported(EXT_framebuffer_multisample) || IsExtensionSupported(ANGLE_framebuffer_multisample);
|
||||
}
|
||||
|
||||
virtual bool SupportsOffscreenSplit() {
|
||||
return IsExtensionSupported(EXT_framebuffer_blit) || IsExtensionSupported(ANGLE_framebuffer_blit);
|
||||
}
|
||||
|
||||
GLuint GetBoundDrawFBO() {
|
||||
GLint ret = 0;
|
||||
if (SupportsOffscreenSplit())
|
||||
fGetIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, &ret);
|
||||
else
|
||||
fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
GLuint GetBoundReadFBO() {
|
||||
GLint ret = 0;
|
||||
if (SupportsOffscreenSplit())
|
||||
fGetIntegerv(LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT, &ret);
|
||||
else
|
||||
fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void BindDrawFBO(GLuint name) {
|
||||
if (SupportsOffscreenSplit())
|
||||
fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, name);
|
||||
else
|
||||
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, name);
|
||||
}
|
||||
|
||||
void BindReadFBO(GLuint name) {
|
||||
if (SupportsOffscreenSplit())
|
||||
fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, name);
|
||||
else
|
||||
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, name);
|
||||
}
|
||||
|
||||
GLuint SwapBoundDrawFBO(GLuint name) {
|
||||
GLuint prev = GetBoundDrawFBO();
|
||||
BindDrawFBO(name);
|
||||
return prev;
|
||||
}
|
||||
|
||||
GLuint SwapBoundReadFBO(GLuint name) {
|
||||
GLuint prev = GetBoundReadFBO();
|
||||
BindReadFBO(name);
|
||||
return prev;
|
||||
}
|
||||
|
||||
void BindOffscreenDrawBuffer() {
|
||||
BindDrawFBO(mOffscreenDrawFBO);
|
||||
}
|
||||
|
||||
void BindOffscreenReadBuffer() {
|
||||
BindReadFBO(mOffscreenReadFBO);
|
||||
}
|
||||
|
||||
void BindOffscreenBuffers() {
|
||||
BindOffscreenDrawBuffer();
|
||||
BindOffscreenReadBuffer();
|
||||
}
|
||||
|
||||
private:
|
||||
GLuint mPrevDrawFBOBinding;
|
||||
GLuint mPrevReadFBOBinding;
|
||||
bool mOffscreenFBOsDirty;
|
||||
|
||||
void BeforeGLDrawCall() {
|
||||
// Record and rebind if necessary
|
||||
mPrevDrawFBOBinding = GetBoundDrawFBO();
|
||||
if (mPrevDrawFBOBinding == 0) {
|
||||
BindDrawFBO(mOffscreenDrawFBO);
|
||||
} else if (mPrevDrawFBOBinding != mOffscreenDrawFBO)
|
||||
return;
|
||||
|
||||
// Must be after binding the proper FBO
|
||||
if (mOffscreenDrawFBO == mOffscreenReadFBO)
|
||||
return;
|
||||
|
||||
// If we're already dirty, no need to set it again
|
||||
if (mOffscreenFBOsDirty)
|
||||
return;
|
||||
|
||||
mOffscreenFBOsDirty = true;
|
||||
}
|
||||
|
||||
void AfterGLDrawCall() {
|
||||
if (mPrevDrawFBOBinding == 0) {
|
||||
BindDrawFBO(0);
|
||||
}
|
||||
}
|
||||
|
||||
void BeforeGLReadCall() {
|
||||
// Record and rebind if necessary
|
||||
mPrevReadFBOBinding = GetBoundReadFBO();
|
||||
if (mPrevReadFBOBinding == 0) {
|
||||
BindReadFBO(mOffscreenReadFBO);
|
||||
} else if (mPrevReadFBOBinding != mOffscreenReadFBO)
|
||||
return;
|
||||
|
||||
// Must be after binding the proper FBO
|
||||
if (mOffscreenDrawFBO == mOffscreenReadFBO)
|
||||
return;
|
||||
|
||||
// If we're not dirty, there's no need to blit
|
||||
if (!mOffscreenFBOsDirty)
|
||||
return;
|
||||
|
||||
const bool scissor = fIsEnabled(LOCAL_GL_SCISSOR_TEST);
|
||||
if (scissor)
|
||||
fDisable(LOCAL_GL_SCISSOR_TEST);
|
||||
|
||||
// flip read/draw for blitting
|
||||
GLuint prevDraw = SwapBoundDrawFBO(mOffscreenReadFBO);
|
||||
BindReadFBO(mOffscreenDrawFBO); // We know that Read must already be mOffscreenRead, so no need to write that down
|
||||
|
||||
GLint width = mOffscreenActualSize.width;
|
||||
GLint height = mOffscreenActualSize.height;
|
||||
raw_fBlitFramebuffer(0, 0, width, height,
|
||||
0, 0, width, height,
|
||||
LOCAL_GL_COLOR_BUFFER_BIT,
|
||||
LOCAL_GL_NEAREST);
|
||||
|
||||
BindDrawFBO(prevDraw);
|
||||
BindReadFBO(mOffscreenReadFBO);
|
||||
|
||||
if (scissor)
|
||||
fEnable(LOCAL_GL_SCISSOR_TEST);
|
||||
|
||||
mOffscreenFBOsDirty = false;
|
||||
}
|
||||
|
||||
void AfterGLReadCall() {
|
||||
if (mPrevReadFBOBinding == 0) {
|
||||
BindReadFBO(0);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// Draw call hooks:
|
||||
void fClear(GLbitfield mask) {
|
||||
BeforeGLDrawCall();
|
||||
raw_fClear(mask);
|
||||
AfterGLDrawCall();
|
||||
}
|
||||
|
||||
void fDrawArrays(GLenum mode, GLint first, GLsizei count) {
|
||||
BeforeGLDrawCall();
|
||||
raw_fDrawArrays(mode, first, count);
|
||||
AfterGLDrawCall();
|
||||
}
|
||||
|
||||
void fDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) {
|
||||
BeforeGLDrawCall();
|
||||
raw_fDrawElements(mode, count, type, indices);
|
||||
AfterGLDrawCall();
|
||||
}
|
||||
|
||||
// Read call hooks:
|
||||
void fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) {
|
||||
BeforeGLReadCall();
|
||||
raw_fReadPixels(x, y, width, height, format, type, pixels);
|
||||
AfterGLReadCall();
|
||||
}
|
||||
|
||||
void fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
|
||||
BeforeGLReadCall();
|
||||
raw_fCopyTexImage2D(target, level, internalformat,
|
||||
x, y, width, height, border);
|
||||
AfterGLReadCall();
|
||||
}
|
||||
|
||||
void fCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
BeforeGLReadCall();
|
||||
raw_fCopyTexSubImage2D(target, level, xoffset, yoffset,
|
||||
x, y, width, height);
|
||||
AfterGLReadCall();
|
||||
}
|
||||
|
||||
void ForceDirtyFBOs() {
|
||||
GLuint draw = SwapBoundReadFBO(mOffscreenDrawFBO);
|
||||
|
||||
BeforeGLDrawCall();
|
||||
// no-op; just pretend we did something
|
||||
AfterGLDrawCall();
|
||||
|
||||
BindDrawFBO(draw);
|
||||
}
|
||||
|
||||
void BlitDirtyFBOs() {
|
||||
GLuint read = SwapBoundReadFBO(mOffscreenReadFBO);
|
||||
|
||||
BeforeGLReadCall();
|
||||
// no-op; we just want to make sure the Read FBO is updated if it needs to be
|
||||
AfterGLReadCall();
|
||||
|
||||
BindReadFBO(read);
|
||||
}
|
||||
|
||||
// Before reads from offscreen texture
|
||||
void fFinish() {
|
||||
BeforeGLReadCall();
|
||||
raw_fFinish();
|
||||
AfterGLReadCall();
|
||||
}
|
||||
|
||||
// Draw/Read
|
||||
void fBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
|
||||
BeforeGLDrawCall();
|
||||
BeforeGLReadCall();
|
||||
raw_fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||
AfterGLReadCall();
|
||||
AfterGLDrawCall();
|
||||
}
|
||||
|
||||
#if defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE)
|
||||
virtual gfxASurface* GetOffscreenPixmapSurface()
|
||||
{
|
||||
|
@ -1013,6 +1237,11 @@ public:
|
|||
ARB_texture_float,
|
||||
EXT_unpack_subimage,
|
||||
OES_standard_derivatives,
|
||||
EXT_framebuffer_blit,
|
||||
ANGLE_framebuffer_blit,
|
||||
EXT_framebuffer_multisample,
|
||||
ANGLE_framebuffer_multisample,
|
||||
OES_rgb8_rgba8,
|
||||
Extensions_Max
|
||||
};
|
||||
|
||||
|
@ -1092,9 +1321,20 @@ protected:
|
|||
|
||||
// helper to create/resize an offscreen FBO,
|
||||
// for offscreen implementations that use FBOs.
|
||||
bool ResizeOffscreenFBO(const gfxIntSize& aSize);
|
||||
bool ResizeOffscreenFBO(const gfxIntSize& aSize, const bool aUseReadFBO, const bool aDisableAA);
|
||||
bool ResizeOffscreenFBO(const gfxIntSize& aSize, const bool aUseReadFBO) {
|
||||
if (ResizeOffscreenFBO(aSize, aUseReadFBO, false))
|
||||
return true;
|
||||
|
||||
if (!mCreationFormat.samples)
|
||||
return false;
|
||||
printf("ResizeOffscreenFBO failed with AA, retrying without...\n");
|
||||
return ResizeOffscreenFBO(aSize, aUseReadFBO, true);
|
||||
}
|
||||
void DeleteOffscreenFBO();
|
||||
GLuint mOffscreenFBO;
|
||||
GLuint mOffscreenDrawFBO;
|
||||
GLuint mOffscreenReadFBO;
|
||||
GLuint mOffscreenColorRB;
|
||||
GLuint mOffscreenDepthRB;
|
||||
GLuint mOffscreenStencilRB;
|
||||
|
||||
|
@ -1454,7 +1694,7 @@ public:
|
|||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fClear(GLbitfield mask) {
|
||||
void raw_fClear(GLbitfield mask) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fClear(mask);
|
||||
AFTER_GL_CALL;
|
||||
|
@ -1514,13 +1754,13 @@ public:
|
|||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fDrawArrays(GLenum mode, GLint first, GLsizei count) {
|
||||
void raw_fDrawArrays(GLenum mode, GLint first, GLsizei count) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fDrawArrays(mode, first, count);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) {
|
||||
void raw_fDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fDrawElements(mode, count, type, indices);
|
||||
AFTER_GL_CALL;
|
||||
|
@ -1538,7 +1778,7 @@ public:
|
|||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fFinish() {
|
||||
void raw_fFinish() {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fFinish();
|
||||
AFTER_GL_CALL;
|
||||
|
@ -1756,7 +1996,7 @@ public:
|
|||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) {
|
||||
void raw_fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fReadPixels(x, y, width, height, format, type, pixels);
|
||||
AFTER_GL_CALL;
|
||||
|
@ -2002,7 +2242,7 @@ public:
|
|||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
|
||||
void raw_fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fCopyTexImage2D(target, level, internalformat,
|
||||
x, FixYValue(y, height),
|
||||
|
@ -2010,7 +2250,7 @@ public:
|
|||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
void raw_fCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fCopyTexSubImage2D(target, level, xoffset, yoffset,
|
||||
x, FixYValue(y, height),
|
||||
|
@ -2092,6 +2332,12 @@ public:
|
|||
return retval;
|
||||
}
|
||||
|
||||
void raw_fBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
realGLboolean fIsRenderbuffer (GLuint renderbuffer) {
|
||||
BEFORE_GL_CALL;
|
||||
realGLboolean retval = mSymbols.fIsRenderbuffer(renderbuffer);
|
||||
|
@ -2105,6 +2351,12 @@ public:
|
|||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fRenderbufferStorageMultisample(target, samples, internalFormat, width, height);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fDepthRange(GLclampf a, GLclampf b) {
|
||||
BEFORE_GL_CALL;
|
||||
if (mIsGLES2) {
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "gfxPlatform.h"
|
||||
#include "gfxFailure.h"
|
||||
#include "prenv.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
|
@ -263,6 +264,9 @@ GLContextCGL::UnbindTex2DOffscreen(GLContext *aOffscreen)
|
|||
bool
|
||||
GLContextCGL::ResizeOffscreen(const gfxIntSize& aNewSize)
|
||||
{
|
||||
if (!IsOffscreenSizeAllowed(aNewSize))
|
||||
return false;
|
||||
|
||||
if (mPBuffer) {
|
||||
NSOpenGLPixelBuffer *pb = [[NSOpenGLPixelBuffer alloc]
|
||||
initWithTextureTarget:LOCAL_GL_TEXTURE_2D
|
||||
|
@ -274,6 +278,10 @@ GLContextCGL::ResizeOffscreen(const gfxIntSize& aNewSize)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!ResizeOffscreenFBO(aNewSize, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
[mPBuffer release];
|
||||
mPBuffer = pb;
|
||||
|
||||
|
@ -289,7 +297,7 @@ GLContextCGL::ResizeOffscreen(const gfxIntSize& aNewSize)
|
|||
return true;
|
||||
}
|
||||
|
||||
return ResizeOffscreenFBO(aNewSize);
|
||||
return ResizeOffscreenFBO(aNewSize, true);
|
||||
}
|
||||
|
||||
class TextureImageCGL : public BasicTextureImage
|
||||
|
@ -528,8 +536,7 @@ CreateOffscreenPBufferContext(const gfxIntSize& aSize,
|
|||
}
|
||||
|
||||
static already_AddRefed<GLContextCGL>
|
||||
CreateOffscreenFBOContext(const gfxIntSize& aSize,
|
||||
const ContextFormat& aFormat,
|
||||
CreateOffscreenFBOContext(const ContextFormat& aFormat,
|
||||
bool aShare = true)
|
||||
{
|
||||
if (!sCGLLibrary.EnsureInitialized()) {
|
||||
|
@ -557,23 +564,34 @@ already_AddRefed<GLContext>
|
|||
GLContextProviderCGL::CreateOffscreen(const gfxIntSize& aSize,
|
||||
const ContextFormat& aFormat)
|
||||
{
|
||||
ContextFormat actualFormat(aFormat);
|
||||
actualFormat.samples = 0;
|
||||
|
||||
nsRefPtr<GLContextCGL> glContext;
|
||||
|
||||
glContext = CreateOffscreenPBufferContext(aSize, aFormat);
|
||||
if (glContext &&
|
||||
glContext->Init())
|
||||
|
||||
NS_ENSURE_TRUE(Preferences::GetRootBranch(), nsnull);
|
||||
const bool preferFBOs = Preferences::GetBool("cgl.prefer-fbo", false);
|
||||
if (!preferFBOs)
|
||||
{
|
||||
glContext->mOffscreenSize = aSize;
|
||||
glContext->mOffscreenActualSize = aSize;
|
||||
glContext = CreateOffscreenPBufferContext(aSize, actualFormat);
|
||||
if (glContext &&
|
||||
glContext->Init() &&
|
||||
glContext->ResizeOffscreenFBO(aSize, false))
|
||||
{
|
||||
glContext->mOffscreenSize = aSize;
|
||||
glContext->mOffscreenActualSize = aSize;
|
||||
|
||||
return glContext.forget();
|
||||
printf("GL Offscreen: CGL+PBuffer\n");
|
||||
|
||||
return glContext.forget();
|
||||
}
|
||||
}
|
||||
|
||||
// try a FBO as second choice
|
||||
glContext = CreateOffscreenFBOContext(aSize, aFormat);
|
||||
glContext = CreateOffscreenFBOContext(actualFormat);
|
||||
if (glContext &&
|
||||
glContext->Init() &&
|
||||
glContext->ResizeOffscreenFBO(aSize))
|
||||
glContext->ResizeOffscreenFBO(aSize, true))
|
||||
{
|
||||
return glContext.forget();
|
||||
}
|
||||
|
@ -602,8 +620,7 @@ GLContextProviderCGL::GetGlobalContext()
|
|||
// than 16x16 in size; also 16x16 is POT so that we can do
|
||||
// a FBO with it on older video cards. A FBO context for
|
||||
// sharing is preferred since it has no associated target.
|
||||
gGlobalContext = CreateOffscreenFBOContext(gfxIntSize(16, 16),
|
||||
ContextFormat(ContextFormat::BasicRGB24),
|
||||
gGlobalContext = CreateOffscreenFBOContext(ContextFormat(ContextFormat::BasicRGB24),
|
||||
false);
|
||||
if (!gGlobalContext || !static_cast<GLContextCGL*>(gGlobalContext.get())->Init()) {
|
||||
NS_WARNING("Couldn't init gGlobalContext.");
|
||||
|
|
|
@ -1054,6 +1054,9 @@ GLContextEGL::UnbindTex2DOffscreen(GLContext *aOffscreen)
|
|||
bool
|
||||
GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize)
|
||||
{
|
||||
if (!IsOffscreenSizeAllowed(aNewSize))
|
||||
return false;
|
||||
|
||||
if (mIsPBuffer) {
|
||||
gfxIntSize pbsize(aNewSize);
|
||||
|
||||
|
@ -1067,9 +1070,12 @@ GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize)
|
|||
pbsize);
|
||||
if (!surface) {
|
||||
NS_WARNING("Failed to resize pbuffer");
|
||||
return nsnull;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ResizeOffscreenFBO(pbsize, false))
|
||||
return false;
|
||||
|
||||
SetOffscreenSize(aNewSize, pbsize);
|
||||
|
||||
if (mSurface && !mPlatformContext) {
|
||||
|
@ -1114,6 +1120,9 @@ GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize)
|
|||
if (!config) {
|
||||
return false;
|
||||
}
|
||||
if (!ResizeOffscreenFBO(aNewSize, true))
|
||||
return false;
|
||||
|
||||
mThebesSurface = xsurface;
|
||||
|
||||
return true;
|
||||
|
@ -1121,10 +1130,13 @@ GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize)
|
|||
#endif
|
||||
|
||||
#if defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE)
|
||||
return ResizeOffscreenPixmapSurface(aNewSize);
|
||||
if (ResizeOffscreenPixmapSurface(aNewSize)) {
|
||||
if (ResizeOffscreenFBO(aNewSize, true))
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ResizeOffscreenFBO(aNewSize);
|
||||
return ResizeOffscreenFBO(aNewSize, true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1999,13 +2011,15 @@ GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& aSize,
|
|||
nsTArray<EGLint> attribs(32);
|
||||
int attribAttempt = 0;
|
||||
|
||||
int tryDepthSize = (aFormat.depth > 0) ? 24 : 0;
|
||||
|
||||
TRY_ATTRIBS_AGAIN:
|
||||
switch (attribAttempt) {
|
||||
case 0:
|
||||
FillPBufferAttribs(attribs, aFormat, configCanBindToTexture, 8, 24);
|
||||
FillPBufferAttribs(attribs, aFormat, configCanBindToTexture, 8, tryDepthSize);
|
||||
break;
|
||||
case 1:
|
||||
FillPBufferAttribs(attribs, aFormat, configCanBindToTexture, -1, 24);
|
||||
FillPBufferAttribs(attribs, aFormat, configCanBindToTexture, -1, tryDepthSize);
|
||||
break;
|
||||
case 2:
|
||||
FillPBufferAttribs(attribs, aFormat, configCanBindToTexture, -1, -1);
|
||||
|
@ -2237,14 +2251,38 @@ GLContextProviderEGL::CreateOffscreen(const gfxIntSize& aSize,
|
|||
if (!sEGLLibrary.EnsureInitialized()) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
ContextFormat actualFormat(aFormat);
|
||||
// actualFormat.samples = 0;
|
||||
|
||||
#if defined(ANDROID) || defined(XP_WIN)
|
||||
return GLContextEGL::CreateEGLPBufferOffscreenContext(aSize, aFormat);
|
||||
nsRefPtr<GLContextEGL> glContext =
|
||||
GLContextEGL::CreateEGLPBufferOffscreenContext(aSize, actualFormat);
|
||||
|
||||
if (!glContext)
|
||||
return nsnull;
|
||||
|
||||
if (!glContext->ResizeOffscreenFBO(glContext->OffscreenActualSize(), false))
|
||||
return nsnull;
|
||||
|
||||
printf("GL Offscreen: EGL+PBuffer\n");
|
||||
return glContext.forget();
|
||||
|
||||
#elif defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE)
|
||||
return GLContextEGL::CreateBasicEGLPixmapOffscreenContext(aSize, aFormat);
|
||||
nsRefPtr<GLContextEGL> glContext =
|
||||
GLContextEGL::CreateBasicEGLPixmapOffscreenContext(aSize, actualFormat);
|
||||
|
||||
if (!glContext)
|
||||
return nsnull;
|
||||
|
||||
if (!glContext->ResizeOffscreenFBO(glContext->OffscreenActualSize(), true))
|
||||
return nsnull;
|
||||
|
||||
printf("GL Offscreen: EGL+Pixmap\n");
|
||||
return glContext.forget();
|
||||
#elif defined(MOZ_X11)
|
||||
nsRefPtr<GLContextEGL> glContext =
|
||||
GLContextEGL::CreateEGLPixmapOffscreenContext(aSize, aFormat, true);
|
||||
GLContextEGL::CreateEGLPixmapOffscreenContext(aSize, actualFormat, true);
|
||||
|
||||
if (!glContext) {
|
||||
return nsnull;
|
||||
|
@ -2254,7 +2292,7 @@ GLContextProviderEGL::CreateOffscreen(const gfxIntSize& aSize,
|
|||
// render from this
|
||||
return nsnull;
|
||||
}
|
||||
if (!gUseBackingSurface && !glContext->ResizeOffscreenFBO(aSize)) {
|
||||
if (!gUseBackingSurface && !glContext->ResizeOffscreenFBO(glContext->OffscreenActualSize(), true)) {
|
||||
// we weren't able to create the initial
|
||||
// offscreen FBO, so this is dead
|
||||
return nsnull;
|
||||
|
|
|
@ -1237,9 +1237,11 @@ already_AddRefed<GLContext>
|
|||
GLContextProviderGLX::CreateOffscreen(const gfxIntSize& aSize,
|
||||
const ContextFormat& aFormat)
|
||||
{
|
||||
ContextFormat actualFormat(aFormat);
|
||||
// actualFormat.samples = 0;
|
||||
|
||||
nsRefPtr<GLContextGLX> glContext =
|
||||
CreateOffscreenPixmapContext(aSize, aFormat, true);
|
||||
CreateOffscreenPixmapContext(aSize, actualFormat, true);
|
||||
|
||||
if (!glContext) {
|
||||
return nsnull;
|
||||
|
@ -1251,7 +1253,7 @@ GLContextProviderGLX::CreateOffscreen(const gfxIntSize& aSize,
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
if (!glContext->ResizeOffscreenFBO(aSize)) {
|
||||
if (!glContext->ResizeOffscreenFBO(aSize, true)) {
|
||||
// we weren't able to create the initial
|
||||
// offscreen FBO, so this is dead
|
||||
return nsnull;
|
||||
|
|
|
@ -259,7 +259,10 @@ GLContextProviderOSMesa::CreateOffscreen(const gfxIntSize& aSize,
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
nsRefPtr<GLContextOSMesa> glContext = new GLContextOSMesa(aFormat);
|
||||
ContextFormat actualFormat(aFormat);
|
||||
actualFormat.samples = 0;
|
||||
|
||||
nsRefPtr<GLContextOSMesa> glContext = new GLContextOSMesa(actualFormat);
|
||||
|
||||
if (!glContext->Init(aSize))
|
||||
{
|
||||
|
|
|
@ -48,6 +48,8 @@
|
|||
|
||||
#include "prenv.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
|
||||
|
@ -398,10 +400,44 @@ GLContextWGL::UnbindTex2DOffscreen(GLContext *aOffscreen)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
GetMaxSize(HDC hDC, int format, gfxIntSize& size)
|
||||
{
|
||||
int query[] = {LOCAL_WGL_MAX_PBUFFER_WIDTH_ARB, LOCAL_WGL_MAX_PBUFFER_HEIGHT_ARB};
|
||||
int result[2];
|
||||
|
||||
// (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int* piAttributes, int *piValues)
|
||||
if (!sWGLLibrary.fGetPixelFormatAttribiv(hDC, format, 0, 2, query, result))
|
||||
return false;
|
||||
|
||||
size.width = result[0];
|
||||
size.height = result[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsValidSizeForFormat(HDC hDC, int format, const gfxIntSize& requested)
|
||||
{
|
||||
gfxIntSize max;
|
||||
if (!GetMaxSize(hDC, format, max))
|
||||
return true;
|
||||
|
||||
if (requested.width > max.width)
|
||||
return false;
|
||||
if (requested.height > max.height)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GLContextWGL::ResizeOffscreen(const gfxIntSize& aNewSize)
|
||||
{
|
||||
if (mPBuffer) {
|
||||
if (!IsValidSizeForFormat(gSharedWindowDC, mPixelFormat, aNewSize))
|
||||
return false;
|
||||
|
||||
int pbattrs[] = {
|
||||
LOCAL_WGL_TEXTURE_FORMAT_ARB,
|
||||
mCreationFormat.alpha > 0 ? LOCAL_WGL_TEXTURE_RGBA_ARB
|
||||
|
@ -433,10 +469,10 @@ GLContextWGL::ResizeOffscreen(const gfxIntSize& aNewSize)
|
|||
MakeCurrent();
|
||||
ClearSafely();
|
||||
|
||||
return true;
|
||||
return ResizeOffscreenFBO(aNewSize, false);
|
||||
}
|
||||
|
||||
return ResizeOffscreenFBO(aNewSize);
|
||||
return ResizeOffscreenFBO(aNewSize, true);
|
||||
}
|
||||
|
||||
static GLContextWGL *
|
||||
|
@ -543,6 +579,9 @@ CreatePBufferOffscreenContext(const gfxIntSize& aSize,
|
|||
// XXX add back the priority choosing code here
|
||||
int chosenFormat = formats[0];
|
||||
|
||||
if (!IsValidSizeForFormat(gSharedWindowDC, chosenFormat, aSize))
|
||||
return nsnull;
|
||||
|
||||
HANDLE pbuffer = sWGLLibrary.fCreatePbuffer(gSharedWindowDC, chosenFormat,
|
||||
aSize.width, aSize.height,
|
||||
pbattrs.Elements());
|
||||
|
@ -570,8 +609,7 @@ CreatePBufferOffscreenContext(const gfxIntSize& aSize,
|
|||
}
|
||||
|
||||
static already_AddRefed<GLContextWGL>
|
||||
CreateWindowOffscreenContext(const gfxIntSize& aSize,
|
||||
const ContextFormat& aFormat)
|
||||
CreateWindowOffscreenContext(const ContextFormat& aFormat)
|
||||
{
|
||||
// CreateWindowOffscreenContext must return a global-shared context
|
||||
GLContextWGL *shareContext = GetGlobalContextWGL();
|
||||
|
@ -612,19 +650,25 @@ GLContextProviderWGL::CreateOffscreen(const gfxIntSize& aSize,
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
ContextFormat actualFormat(aFormat);
|
||||
// actualFormat.samples = 0;
|
||||
|
||||
nsRefPtr<GLContextWGL> glContext;
|
||||
|
||||
// Always try to create a pbuffer context first, because we
|
||||
// want the context isolation.
|
||||
if (sWGLLibrary.fCreatePbuffer &&
|
||||
NS_ENSURE_TRUE(Preferences::GetRootBranch(), nsnull);
|
||||
const bool preferFBOs = Preferences::GetBool("wgl.prefer-fbo", false);
|
||||
if (!preferFBOs &&
|
||||
sWGLLibrary.fCreatePbuffer &&
|
||||
sWGLLibrary.fChoosePixelFormat)
|
||||
{
|
||||
glContext = CreatePBufferOffscreenContext(aSize, aFormat);
|
||||
glContext = CreatePBufferOffscreenContext(aSize, actualFormat);
|
||||
}
|
||||
|
||||
// If it failed, then create a window context and use a FBO.
|
||||
if (!glContext) {
|
||||
glContext = CreateWindowOffscreenContext(aSize, aFormat);
|
||||
glContext = CreateWindowOffscreenContext(actualFormat);
|
||||
}
|
||||
|
||||
if (!glContext ||
|
||||
|
@ -633,15 +677,12 @@ GLContextProviderWGL::CreateOffscreen(const gfxIntSize& aSize,
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
if (!glContext->ResizeOffscreenFBO(aSize, !glContext->mPBuffer))
|
||||
return nsnull;
|
||||
|
||||
glContext->mOffscreenSize = aSize;
|
||||
glContext->mOffscreenActualSize = aSize;
|
||||
|
||||
if (!glContext->mPBuffer &&
|
||||
!glContext->ResizeOffscreenFBO(aSize))
|
||||
{
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
return glContext.forget();
|
||||
}
|
||||
|
||||
|
|
|
@ -307,6 +307,11 @@ struct GLContextSymbols
|
|||
typedef void (GLAPIENTRY * PFNGLRENDERBUFFERSTORAGE) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height);
|
||||
PFNGLRENDERBUFFERSTORAGE fRenderbufferStorage;
|
||||
|
||||
typedef void (GLAPIENTRY * PFNGLBLITFRAMEBUFFER) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
||||
PFNGLBLITFRAMEBUFFER fBlitFramebuffer;
|
||||
typedef void (GLAPIENTRY * PFNGLRENDERBUFFERSTORAGEMULTISAMPLE) (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height);
|
||||
PFNGLRENDERBUFFERSTORAGEMULTISAMPLE fRenderbufferStorageMultisample;
|
||||
|
||||
|
||||
/* These are different between GLES2 and desktop GL; we hide those differences, use the GL
|
||||
* names, but the most limited data type.
|
||||
|
|
|
@ -560,6 +560,7 @@ Vector<T,N,AP>::calculateNewCapacity(size_t curLength, size_t lengthInc,
|
|||
size_t &newCap)
|
||||
{
|
||||
size_t newMinCap = curLength + lengthInc;
|
||||
size_t newMinSize = newMinCap * sizeof(T);
|
||||
|
||||
/*
|
||||
* Check for overflow in the above addition, below CEILING_LOG2, and later
|
||||
|
@ -571,8 +572,14 @@ Vector<T,N,AP>::calculateNewCapacity(size_t curLength, size_t lengthInc,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Round up to next power of 2. */
|
||||
newCap = RoundUpPow2(newMinCap);
|
||||
/*
|
||||
* It's best to request 2^N sized chunks because they are unlikely to be
|
||||
* rounded up by the allocator. (Asking for a 2^N number of elements isn't
|
||||
* as good, because if sizeof(T) is not a power-of-two that would result in
|
||||
* a non-2^N request size, which can cause waste.)
|
||||
*/
|
||||
size_t newSize = RoundUpPow2(newMinSize);
|
||||
newCap = newSize / sizeof(T);
|
||||
|
||||
/*
|
||||
* Do not allow a buffer large enough that the expression ((char *)end() -
|
||||
|
|
|
@ -48,25 +48,28 @@
|
|||
|
||||
#include "jsinferinlines.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::frontend;
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* Compile a top-level script.
|
||||
*/
|
||||
Compiler::Compiler(JSContext *cx, JSPrincipals *prin, StackFrame *cfp)
|
||||
BytecodeCompiler::BytecodeCompiler(JSContext *cx, JSPrincipals *prin, StackFrame *cfp)
|
||||
: parser(cx, prin, cfp), globalScope(NULL)
|
||||
{}
|
||||
|
||||
JSScript *
|
||||
Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerFrame,
|
||||
JSPrincipals *principals, uint32 tcflags,
|
||||
const jschar *chars, size_t length,
|
||||
const char *filename, uintN lineno, JSVersion version,
|
||||
JSString *source /* = NULL */,
|
||||
uintN staticLevel /* = 0 */)
|
||||
BytecodeCompiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerFrame,
|
||||
JSPrincipals *principals, uint32 tcflags,
|
||||
const jschar *chars, size_t length,
|
||||
const char *filename, uintN lineno, JSVersion version,
|
||||
JSString *source /* = NULL */,
|
||||
uintN staticLevel /* = 0 */)
|
||||
{
|
||||
TokenKind tt;
|
||||
JSParseNode *pn;
|
||||
ParseNode *pn;
|
||||
JSScript *script;
|
||||
bool inDirectivePrologue;
|
||||
|
||||
|
@ -80,15 +83,15 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF
|
|||
JS_ASSERT_IF(callerFrame, tcflags & TCF_COMPILE_N_GO);
|
||||
JS_ASSERT_IF(staticLevel != 0, callerFrame);
|
||||
|
||||
Compiler compiler(cx, principals, callerFrame);
|
||||
BytecodeCompiler compiler(cx, principals, callerFrame);
|
||||
if (!compiler.init(chars, length, filename, lineno, version))
|
||||
return NULL;
|
||||
|
||||
Parser &parser = compiler.parser;
|
||||
TokenStream &tokenStream = parser.tokenStream;
|
||||
|
||||
JSCodeGenerator cg(&parser, tokenStream.getLineno());
|
||||
if (!cg.init(cx, JSTreeContext::USED_AS_TREE_CONTEXT))
|
||||
CodeGenerator cg(&parser, tokenStream.getLineno());
|
||||
if (!cg.init(cx, TreeContext::USED_AS_TREE_CONTEXT))
|
||||
return NULL;
|
||||
|
||||
Probes::compileScriptBegin(cx, filename, lineno);
|
||||
|
@ -143,7 +146,7 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF
|
|||
* function captured in case it refers to an upvar, and someone
|
||||
* wishes to decompile it while it's running.
|
||||
*/
|
||||
JSObjectBox *funbox = parser.newObjectBox(callerFrame->fun());
|
||||
ObjectBox *funbox = parser.newObjectBox(callerFrame->fun());
|
||||
if (!funbox)
|
||||
goto out;
|
||||
funbox->emitLink = cg.objectList.lastbox;
|
||||
|
@ -189,21 +192,21 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF
|
|||
if (inDirectivePrologue && !parser.recognizeDirectivePrologue(pn, &inDirectivePrologue))
|
||||
goto out;
|
||||
|
||||
if (!js_FoldConstants(cx, pn, &cg))
|
||||
if (!FoldConstants(cx, pn, &cg))
|
||||
goto out;
|
||||
|
||||
if (!parser.analyzeFunctions(&cg))
|
||||
goto out;
|
||||
cg.functionList = NULL;
|
||||
|
||||
if (!js_EmitTree(cx, &cg, pn))
|
||||
if (!EmitTree(cx, &cg, pn))
|
||||
goto out;
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
if (!pn->isKind(TOK_SEMI) || !pn->pn_kid || !TreeTypeIsXML(pn->pn_kid->getKind()))
|
||||
onlyXML = false;
|
||||
#endif
|
||||
RecycleTree(pn, &cg);
|
||||
cg.freeTree(pn);
|
||||
}
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
|
@ -257,7 +260,7 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF
|
|||
* Nowadays the threaded interpreter needs a stop instruction, so we
|
||||
* do have to emit that here.
|
||||
*/
|
||||
if (js_Emit1(cx, &cg, JSOP_STOP) < 0)
|
||||
if (Emit1(cx, &cg, JSOP_STOP) < 0)
|
||||
goto out;
|
||||
|
||||
JS_ASSERT(cg.version() == version);
|
||||
|
@ -282,7 +285,7 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF
|
|||
}
|
||||
|
||||
bool
|
||||
Compiler::defineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *script)
|
||||
BytecodeCompiler::defineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *script)
|
||||
{
|
||||
JSObject *globalObj = globalScope.globalObj;
|
||||
|
||||
|
@ -325,7 +328,7 @@ Compiler::defineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *scrip
|
|||
def.knownSlot = shape->slot;
|
||||
}
|
||||
|
||||
js::Vector<JSScript *, 16> worklist(cx);
|
||||
Vector<JSScript *, 16> worklist(cx);
|
||||
if (!worklist.append(script))
|
||||
return false;
|
||||
|
||||
|
@ -388,11 +391,11 @@ Compiler::defineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *scrip
|
|||
* handler attribute in an HTML <INPUT> tag.
|
||||
*/
|
||||
bool
|
||||
Compiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *principals,
|
||||
Bindings *bindings, const jschar *chars, size_t length,
|
||||
const char *filename, uintN lineno, JSVersion version)
|
||||
BytecodeCompiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *principals,
|
||||
Bindings *bindings, const jschar *chars, size_t length,
|
||||
const char *filename, uintN lineno, JSVersion version)
|
||||
{
|
||||
Compiler compiler(cx, principals);
|
||||
BytecodeCompiler compiler(cx, principals);
|
||||
|
||||
if (!compiler.init(chars, length, filename, lineno, version))
|
||||
return false;
|
||||
|
@ -400,8 +403,8 @@ Compiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *prin
|
|||
Parser &parser = compiler.parser;
|
||||
TokenStream &tokenStream = parser.tokenStream;
|
||||
|
||||
JSCodeGenerator funcg(&parser, tokenStream.getLineno());
|
||||
if (!funcg.init(cx, JSTreeContext::USED_AS_TREE_CONTEXT))
|
||||
CodeGenerator funcg(&parser, tokenStream.getLineno());
|
||||
if (!funcg.init(cx, TreeContext::USED_AS_TREE_CONTEXT))
|
||||
return false;
|
||||
|
||||
funcg.flags |= TCF_IN_FUNCTION;
|
||||
|
@ -413,7 +416,7 @@ Compiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *prin
|
|||
|
||||
/* FIXME: make Function format the source for a function definition. */
|
||||
tokenStream.mungeCurrentToken(TOK_NAME);
|
||||
JSParseNode *fn = FunctionNode::create(&funcg);
|
||||
ParseNode *fn = FunctionNode::create(&funcg);
|
||||
if (fn) {
|
||||
fn->pn_body = NULL;
|
||||
fn->pn_cookie.makeFree();
|
||||
|
@ -439,21 +442,22 @@ Compiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *prin
|
|||
}
|
||||
|
||||
/*
|
||||
* Farble the body so that it looks like a block statement to js_EmitTree,
|
||||
* which is called from js_EmitFunctionBody (see jsemit.cpp). After we're
|
||||
* done parsing, we must fold constants, analyze any nested functions, and
|
||||
* generate code for this function, including a stop opcode at the end.
|
||||
* Farble the body so that it looks like a block statement to EmitTree,
|
||||
* which is called from EmitFunctionBody (see BytecodeGenerator.cpp).
|
||||
* After we're done parsing, we must fold constants, analyze any nested
|
||||
* functions, and generate code for this function, including a stop opcode
|
||||
* at the end.
|
||||
*/
|
||||
tokenStream.mungeCurrentToken(TOK_LC);
|
||||
JSParseNode *pn = fn ? parser.functionBody() : NULL;
|
||||
ParseNode *pn = fn ? parser.functionBody() : NULL;
|
||||
if (pn) {
|
||||
if (!CheckStrictParameters(cx, &funcg)) {
|
||||
pn = NULL;
|
||||
} else if (!tokenStream.matchToken(TOK_EOF)) {
|
||||
parser.reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
|
||||
pn = NULL;
|
||||
} else if (!js_FoldConstants(cx, pn, &funcg)) {
|
||||
/* js_FoldConstants reported the error already. */
|
||||
} else if (!FoldConstants(cx, pn, &funcg)) {
|
||||
/* FoldConstants reported the error already. */
|
||||
pn = NULL;
|
||||
} else if (!parser.analyzeFunctions(&funcg)) {
|
||||
pn = NULL;
|
||||
|
@ -465,7 +469,7 @@ Compiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *prin
|
|||
pn = fn->pn_body;
|
||||
}
|
||||
|
||||
if (!js_EmitFunctionScript(cx, &funcg, pn))
|
||||
if (!EmitFunctionScript(cx, &funcg, pn))
|
||||
pn = NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,12 +45,12 @@
|
|||
|
||||
namespace js {
|
||||
|
||||
struct Compiler
|
||||
struct BytecodeCompiler
|
||||
{
|
||||
Parser parser;
|
||||
GlobalScope *globalScope;
|
||||
|
||||
Compiler(JSContext *cx, JSPrincipals *prin = NULL, StackFrame *cfp = NULL);
|
||||
BytecodeCompiler(JSContext *cx, JSPrincipals *prin = NULL, StackFrame *cfp = NULL);
|
||||
|
||||
JSContext *context() {
|
||||
return parser.context;
|
||||
|
@ -63,7 +63,7 @@ struct Compiler
|
|||
|
||||
static bool
|
||||
compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *principals,
|
||||
js::Bindings *bindings, const jschar *chars, size_t length,
|
||||
Bindings *bindings, const jschar *chars, size_t length,
|
||||
const char *filename, uintN lineno, JSVersion version);
|
||||
|
||||
static JSScript *
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -56,7 +56,7 @@
|
|||
|
||||
#include "jsatominlines.h"
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* NB: If you add enumerators for scope statements, add them between STMT_WITH
|
||||
|
@ -64,9 +64,10 @@ JS_BEGIN_EXTERN_C
|
|||
* non-looping statement enumerators, add them before STMT_DO_LOOP or you will
|
||||
* break the STMT_TYPE_IS_LOOP macro.
|
||||
*
|
||||
* Also remember to keep the statementName array in jsemit.c in sync.
|
||||
* Also remember to keep the statementName array in BytecodeGenerator.cpp in
|
||||
* sync.
|
||||
*/
|
||||
typedef enum JSStmtType {
|
||||
enum StmtType {
|
||||
STMT_LABEL, /* labeled statement: L: s */
|
||||
STMT_IF, /* if (then) statement */
|
||||
STMT_ELSE, /* else clause of if statement */
|
||||
|
@ -83,12 +84,12 @@ typedef enum JSStmtType {
|
|||
STMT_FOR_IN_LOOP, /* for/in loop statement */
|
||||
STMT_WHILE_LOOP, /* while loop statement */
|
||||
STMT_LIMIT
|
||||
} JSStmtType;
|
||||
};
|
||||
|
||||
#define STMT_TYPE_IN_RANGE(t,b,e) ((uint)((t) - (b)) <= (uintN)((e) - (b)))
|
||||
|
||||
/*
|
||||
* A comment on the encoding of the JSStmtType enum and type-testing macros:
|
||||
* A comment on the encoding of the js::StmtType enum and type-testing macros:
|
||||
*
|
||||
* STMT_TYPE_MAYBE_SCOPE tells whether a statement type is always, or may
|
||||
* become, a lexical scope. It therefore includes block and switch (the two
|
||||
|
@ -96,7 +97,7 @@ typedef enum JSStmtType {
|
|||
* pending the "reformed with" in ES4/JS2). It includes all try-catch-finally
|
||||
* types, which are high-numbered maybe-scope types.
|
||||
*
|
||||
* STMT_TYPE_LINKS_SCOPE tells whether a JSStmtInfo of the given type eagerly
|
||||
* STMT_TYPE_LINKS_SCOPE tells whether a js::StmtInfo of the given type eagerly
|
||||
* links to other scoping statement info records. It excludes the two early
|
||||
* "maybe" types, block and switch, as well as the try and both finally types,
|
||||
* since try and the other trailing maybe-scope types don't need block scope
|
||||
|
@ -124,9 +125,7 @@ typedef enum JSStmtType {
|
|||
#define STMT_IS_TRYING(stmt) STMT_TYPE_IS_TRYING((stmt)->type)
|
||||
#define STMT_IS_LOOP(stmt) STMT_TYPE_IS_LOOP((stmt)->type)
|
||||
|
||||
typedef struct JSStmtInfo JSStmtInfo;
|
||||
|
||||
struct JSStmtInfo {
|
||||
struct StmtInfo {
|
||||
uint16 type; /* statement type */
|
||||
uint16 flags; /* flags, see below */
|
||||
uint32 blockid; /* for simplified dominance computation */
|
||||
|
@ -135,10 +134,10 @@ struct JSStmtInfo {
|
|||
ptrdiff_t continues; /* offset of last continue in loop */
|
||||
union {
|
||||
JSAtom *label; /* name of LABEL */
|
||||
JSObjectBox *blockBox; /* block scope object */
|
||||
ObjectBox *blockBox; /* block scope object */
|
||||
};
|
||||
JSStmtInfo *down; /* info for enclosing statement */
|
||||
JSStmtInfo *downScope; /* next enclosing lexical scope */
|
||||
StmtInfo *down; /* info for enclosing statement */
|
||||
StmtInfo *downScope; /* next enclosing lexical scope */
|
||||
};
|
||||
|
||||
#define SIF_SCOPE 0x0001 /* statement has its own lexical scope */
|
||||
|
@ -146,12 +145,12 @@ struct JSStmtInfo {
|
|||
#define SIF_FOR_BLOCK 0x0004 /* for (let ...) induced block scope */
|
||||
|
||||
/*
|
||||
* To reuse space in JSStmtInfo, rename breaks and continues for use during
|
||||
* To reuse space in StmtInfo, rename breaks and continues for use during
|
||||
* try/catch/finally code generation and backpatching. To match most common
|
||||
* use cases, the macro argument is a struct, not a struct pointer. Only a
|
||||
* loop, switch, or label statement info record can have breaks and continues,
|
||||
* and only a for loop has an update backpatch chain, so it's safe to overlay
|
||||
* these for the "trying" JSStmtTypes.
|
||||
* these for the "trying" StmtTypes.
|
||||
*/
|
||||
#define CATCHNOTE(stmt) ((stmt).update)
|
||||
#define GOSUBS(stmt) ((stmt).breaks)
|
||||
|
@ -160,7 +159,7 @@ struct JSStmtInfo {
|
|||
#define SET_STATEMENT_TOP(stmt, top) \
|
||||
((stmt)->update = (top), (stmt)->breaks = (stmt)->continues = (-1))
|
||||
|
||||
#define TCF_COMPILING 0x01 /* JSTreeContext is JSCodeGenerator */
|
||||
#define TCF_COMPILING 0x01 /* TreeContext is CodeGenerator */
|
||||
#define TCF_IN_FUNCTION 0x02 /* parsing inside function body */
|
||||
#define TCF_RETURN_EXPR 0x04 /* function has 'return expr;' */
|
||||
#define TCF_RETURN_VOID 0x08 /* function has 'return;' */
|
||||
|
@ -196,10 +195,10 @@ struct JSStmtInfo {
|
|||
#define TCF_DECL_DESTRUCTURING 0x10000
|
||||
|
||||
/*
|
||||
* A request flag passed to Compiler::compileScript and then down via
|
||||
* JSCodeGenerator to js_NewScriptFromCG, from script_compile_sub and any
|
||||
* kindred functions that need to make mutable scripts (even empty ones;
|
||||
* i.e., they can't share the const JSScript::emptyScript() singleton).
|
||||
* A request flag passed to BytecodeCompiler::compileScript and then down via
|
||||
* CodeGenerator to JSScript::NewScriptFromCG, from script_compile_sub and any
|
||||
* kindred functions that need to make mutable scripts (even empty ones; i.e.,
|
||||
* they can't share the const JSScript::emptyScript() singleton).
|
||||
*/
|
||||
#define TCF_NEED_MUTABLE_SCRIPT 0x20000
|
||||
|
||||
|
@ -299,7 +298,9 @@ struct JSStmtInfo {
|
|||
TCF_STRICT_MODE_CODE | \
|
||||
TCF_FUN_EXTENSIBLE_SCOPE)
|
||||
|
||||
struct JSTreeContext { /* tree context for semantic checks */
|
||||
struct CodeGenerator;
|
||||
|
||||
struct TreeContext { /* tree context for semantic checks */
|
||||
uint32 flags; /* statement state flags, see above */
|
||||
uint32 bodyid; /* block number of program/function body */
|
||||
uint32 blockidGen; /* preincremented block number generator */
|
||||
|
@ -309,19 +310,19 @@ struct JSTreeContext { /* tree context for semantic checks */
|
|||
non-zero depth in current paren tree */
|
||||
uint32 argumentsCount; /* number of |arguments| references encountered
|
||||
at non-zero depth in current paren tree */
|
||||
JSStmtInfo *topStmt; /* top of statement info stack */
|
||||
JSStmtInfo *topScopeStmt; /* top lexical scope statement */
|
||||
JSObjectBox *blockChainBox; /* compile time block scope chain (NB: one
|
||||
StmtInfo *topStmt; /* top of statement info stack */
|
||||
StmtInfo *topScopeStmt; /* top lexical scope statement */
|
||||
ObjectBox *blockChainBox; /* compile time block scope chain (NB: one
|
||||
deeper than the topScopeStmt/downScope
|
||||
chain when in head of let block/expr) */
|
||||
JSParseNode *blockNode; /* parse node for a block with let declarations
|
||||
ParseNode *blockNode; /* parse node for a block with let declarations
|
||||
(block with its own lexical scope) */
|
||||
js::AtomDecls decls; /* function, const, and var declarations */
|
||||
js::Parser *parser; /* ptr to common parsing and lexing data */
|
||||
JSParseNode *yieldNode; /* parse node for a yield expression that might
|
||||
AtomDecls decls; /* function, const, and var declarations */
|
||||
Parser *parser; /* ptr to common parsing and lexing data */
|
||||
ParseNode *yieldNode; /* parse node for a yield expression that might
|
||||
be an error if we turn out to be inside a
|
||||
generator expression */
|
||||
JSParseNode *argumentsNode; /* parse node for an arguments variable that
|
||||
ParseNode *argumentsNode; /* parse node for an arguments variable that
|
||||
might be an error if we turn out to be
|
||||
inside a generator expression */
|
||||
|
||||
|
@ -350,23 +351,23 @@ struct JSTreeContext { /* tree context for semantic checks */
|
|||
scopeChain_ = scopeChain;
|
||||
}
|
||||
|
||||
js::OwnedAtomDefnMapPtr lexdeps;/* unresolved lexical name dependencies */
|
||||
JSTreeContext *parent; /* enclosing function or global context */
|
||||
OwnedAtomDefnMapPtr lexdeps; /* unresolved lexical name dependencies */
|
||||
TreeContext *parent; /* enclosing function or global context */
|
||||
uintN staticLevel; /* static compilation unit nesting level */
|
||||
|
||||
JSFunctionBox *funbox; /* null or box for function we're compiling
|
||||
FunctionBox *funbox; /* null or box for function we're compiling
|
||||
if (flags & TCF_IN_FUNCTION) and not in
|
||||
Compiler::compileFunctionBody */
|
||||
JSFunctionBox *functionList;
|
||||
BytecodeCompiler::compileFunctionBody */
|
||||
FunctionBox *functionList;
|
||||
|
||||
JSParseNode *innermostWith; /* innermost WITH parse node */
|
||||
ParseNode *innermostWith; /* innermost WITH parse node */
|
||||
|
||||
js::Bindings bindings; /* bindings in this code, including
|
||||
Bindings bindings; /* bindings in this code, including
|
||||
arguments if we're compiling a function */
|
||||
|
||||
void trace(JSTracer *trc);
|
||||
|
||||
JSTreeContext(js::Parser *prs)
|
||||
TreeContext(Parser *prs)
|
||||
: flags(0), bodyid(0), blockidGen(0), parenDepth(0), yieldCount(0), argumentsCount(0),
|
||||
topStmt(NULL), topScopeStmt(NULL), blockChainBox(NULL), blockNode(NULL),
|
||||
decls(prs->context), parser(prs), yieldNode(NULL), argumentsNode(NULL), scopeChain_(NULL),
|
||||
|
@ -381,14 +382,14 @@ struct JSTreeContext { /* tree context for semantic checks */
|
|||
* time during code generation. To avoid a redundant stats update in such
|
||||
* cases, we store uint16(-1) in maxScopeDepth.
|
||||
*/
|
||||
~JSTreeContext() {
|
||||
~TreeContext() {
|
||||
parser->tc = this->parent;
|
||||
}
|
||||
|
||||
/*
|
||||
* JSCodeGenerator derives from JSTreeContext; however, only the top-level
|
||||
* JSCodeGenerators are actually used as full-fledged tree contexts (to
|
||||
* hold decls and lexdeps). We can avoid allocation overhead by making
|
||||
* js::CodeGenerator derives from js::TreeContext; however, only the
|
||||
* top-level CodeGenerators are actually used as full-fledged tree contexts
|
||||
* (to hold decls and lexdeps). We can avoid allocation overhead by making
|
||||
* this distinction explicit.
|
||||
*/
|
||||
enum InitBehavior {
|
||||
|
@ -419,7 +420,7 @@ struct JSTreeContext { /* tree context for semantic checks */
|
|||
bool atBodyLevel() { return !topStmt || (topStmt->flags & SIF_BODY_BLOCK); }
|
||||
|
||||
/* Test whether we're in a statement of given type. */
|
||||
bool inStatement(JSStmtType type);
|
||||
bool inStatement(StmtType type);
|
||||
|
||||
bool inStrictMode() const {
|
||||
return flags & TCF_STRICT_MODE_CODE;
|
||||
|
@ -434,7 +435,7 @@ struct JSTreeContext { /* tree context for semantic checks */
|
|||
int sharpSlotBase;
|
||||
bool ensureSharpSlots();
|
||||
|
||||
js::Compiler *compiler() { return (js::Compiler *)parser; }
|
||||
BytecodeCompiler *compiler() { return (BytecodeCompiler *) parser; }
|
||||
|
||||
// Return true there is a generator function within |skip| lexical scopes
|
||||
// (going upward) from this context's lexical scope. Always return true if
|
||||
|
@ -445,7 +446,7 @@ struct JSTreeContext { /* tree context for semantic checks */
|
|||
bool inFunction() const { return flags & TCF_IN_FUNCTION; }
|
||||
|
||||
bool compiling() const { return flags & TCF_COMPILING; }
|
||||
inline JSCodeGenerator *asCodeGenerator();
|
||||
inline CodeGenerator *asCodeGenerator();
|
||||
|
||||
bool usesArguments() const {
|
||||
return flags & TCF_FUN_USES_ARGUMENTS;
|
||||
|
@ -477,7 +478,7 @@ struct JSTreeContext { /* tree context for semantic checks */
|
|||
return flags & TCF_FUN_MUTATES_PARAMETER;
|
||||
}
|
||||
|
||||
void noteArgumentsUse(JSParseNode *pn) {
|
||||
void noteArgumentsUse(ParseNode *pn) {
|
||||
JS_ASSERT(inFunction());
|
||||
countArgumentsUse(pn);
|
||||
flags |= TCF_FUN_USES_ARGUMENTS;
|
||||
|
@ -485,7 +486,7 @@ struct JSTreeContext { /* tree context for semantic checks */
|
|||
funbox->node->pn_dflags |= PND_FUNARG;
|
||||
}
|
||||
|
||||
void countArgumentsUse(JSParseNode *pn) {
|
||||
void countArgumentsUse(ParseNode *pn) {
|
||||
JS_ASSERT(pn->pn_atom == parser->context->runtime->atomState.argumentsAtom);
|
||||
argumentsCount++;
|
||||
argumentsNode = pn;
|
||||
|
@ -502,38 +503,39 @@ struct JSTreeContext { /* tree context for semantic checks */
|
|||
bool hasExtensibleScope() const {
|
||||
return flags & TCF_FUN_EXTENSIBLE_SCOPE;
|
||||
}
|
||||
|
||||
ParseNode *freeTree(ParseNode *pn) { return parser->freeTree(pn); }
|
||||
};
|
||||
|
||||
/*
|
||||
* Return true if we need to check for conditions that elicit
|
||||
* JSOPTION_STRICT warnings or strict mode errors.
|
||||
*/
|
||||
inline bool JSTreeContext::needStrictChecks() {
|
||||
inline bool TreeContext::needStrictChecks() {
|
||||
return parser->context->hasStrictOption() || inStrictMode();
|
||||
}
|
||||
|
||||
namespace js {
|
||||
namespace frontend {
|
||||
|
||||
bool
|
||||
SetStaticLevel(JSTreeContext *tc, uintN staticLevel);
|
||||
SetStaticLevel(TreeContext *tc, uintN staticLevel);
|
||||
|
||||
bool
|
||||
GenerateBlockId(JSTreeContext *tc, uint32& blockid);
|
||||
GenerateBlockId(TreeContext *tc, uint32& blockid);
|
||||
|
||||
} /* namespace js */
|
||||
} /* namespace frontend */
|
||||
|
||||
struct JumpTarget;
|
||||
|
||||
/*
|
||||
* Span-dependent instructions are jumps whose span (from the jump bytecode to
|
||||
* the jump target) may require 2 or 4 bytes of immediate operand.
|
||||
*/
|
||||
typedef struct JSSpanDep JSSpanDep;
|
||||
typedef struct JSJumpTarget JSJumpTarget;
|
||||
|
||||
struct JSSpanDep {
|
||||
struct SpanDep {
|
||||
ptrdiff_t top; /* offset of first bytecode in an opcode */
|
||||
ptrdiff_t offset; /* offset - 1 within opcode of jump operand */
|
||||
ptrdiff_t before; /* original offset - 1 of jump operand */
|
||||
JSJumpTarget *target; /* tagged target pointer or backpatch delta */
|
||||
JumpTarget *target; /* tagged target pointer or backpatch delta */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -542,10 +544,10 @@ struct JSSpanDep {
|
|||
* instruction whose jump offset operand must be extended can be found quickly
|
||||
* and adjusted upward (toward higher offsets).
|
||||
*/
|
||||
struct JSJumpTarget {
|
||||
struct JumpTarget {
|
||||
ptrdiff_t offset; /* offset of span-dependent jump target */
|
||||
int balance; /* AVL tree balance number */
|
||||
JSJumpTarget *kids[2]; /* left and right AVL tree child pointers */
|
||||
JumpTarget *kids[2]; /* left and right AVL tree child pointers */
|
||||
};
|
||||
|
||||
#define JT_LEFT 0
|
||||
|
@ -555,20 +557,20 @@ struct JSJumpTarget {
|
|||
#define JT_DIR(imbalance) (((imbalance) + 1) >> 1)
|
||||
|
||||
/*
|
||||
* Backpatch deltas are encoded in JSSpanDep.target if JT_TAG_BIT is clear,
|
||||
* Backpatch deltas are encoded in js::SpanDep::target if JT_TAG_BIT is clear,
|
||||
* so we can maintain backpatch chains when using span dependency records to
|
||||
* hold jump offsets that overflow 16 bits.
|
||||
*/
|
||||
#define JT_TAG_BIT ((jsword) 1)
|
||||
#define JT_UNTAG_SHIFT 1
|
||||
#define JT_SET_TAG(jt) ((JSJumpTarget *)((jsword)(jt) | JT_TAG_BIT))
|
||||
#define JT_CLR_TAG(jt) ((JSJumpTarget *)((jsword)(jt) & ~JT_TAG_BIT))
|
||||
#define JT_SET_TAG(jt) ((JumpTarget *)((jsword)(jt) | JT_TAG_BIT))
|
||||
#define JT_CLR_TAG(jt) ((JumpTarget *)((jsword)(jt) & ~JT_TAG_BIT))
|
||||
#define JT_HAS_TAG(jt) ((jsword)(jt) & JT_TAG_BIT)
|
||||
|
||||
#define BITS_PER_PTRDIFF (sizeof(ptrdiff_t) * JS_BITS_PER_BYTE)
|
||||
#define BITS_PER_BPDELTA (BITS_PER_PTRDIFF - 1 - JT_UNTAG_SHIFT)
|
||||
#define BPDELTA_MAX (((ptrdiff_t)1 << BITS_PER_BPDELTA) - 1)
|
||||
#define BPDELTA_TO_JT(bp) ((JSJumpTarget *)((bp) << JT_UNTAG_SHIFT))
|
||||
#define BPDELTA_TO_JT(bp) ((JumpTarget *)((bp) << JT_UNTAG_SHIFT))
|
||||
#define JT_TO_BPDELTA(jt) ((ptrdiff_t)((jsword)(jt) >> JT_UNTAG_SHIFT))
|
||||
|
||||
#define SD_SET_TARGET(sd,jt) ((sd)->target = JT_SET_TAG(jt))
|
||||
|
@ -583,34 +585,31 @@ struct JSJumpTarget {
|
|||
? JT_CLR_TAG((sd)->target)->offset - (pivot) \
|
||||
: 0)
|
||||
|
||||
typedef struct JSTryNode JSTryNode;
|
||||
|
||||
struct JSTryNode {
|
||||
struct TryNode {
|
||||
JSTryNote note;
|
||||
JSTryNode *prev;
|
||||
TryNode *prev;
|
||||
};
|
||||
|
||||
struct JSCGObjectList {
|
||||
struct CGObjectList {
|
||||
uint32 length; /* number of emitted so far objects */
|
||||
JSObjectBox *lastbox; /* last emitted object */
|
||||
ObjectBox *lastbox; /* last emitted object */
|
||||
|
||||
JSCGObjectList() : length(0), lastbox(NULL) {}
|
||||
CGObjectList() : length(0), lastbox(NULL) {}
|
||||
|
||||
uintN index(JSObjectBox *objbox);
|
||||
uintN index(ObjectBox *objbox);
|
||||
void finish(JSObjectArray *array);
|
||||
};
|
||||
|
||||
class JSGCConstList {
|
||||
js::Vector<js::Value> list;
|
||||
class GCConstList {
|
||||
Vector<Value> list;
|
||||
public:
|
||||
JSGCConstList(JSContext *cx) : list(cx) {}
|
||||
bool append(js::Value v) { return list.append(v); }
|
||||
GCConstList(JSContext *cx) : list(cx) {}
|
||||
bool append(Value v) { return list.append(v); }
|
||||
size_t length() const { return list.length(); }
|
||||
void finish(JSConstArray *array);
|
||||
|
||||
};
|
||||
|
||||
struct JSCodeGenerator : public JSTreeContext
|
||||
struct CodeGenerator : public TreeContext
|
||||
{
|
||||
struct {
|
||||
jsbytecode *base; /* base of JS bytecode vector */
|
||||
|
@ -623,19 +622,19 @@ struct JSCodeGenerator : public JSTreeContext
|
|||
uintN currentLine; /* line number for tree-based srcnote gen */
|
||||
} prolog, main, *current;
|
||||
|
||||
js::OwnedAtomIndexMapPtr atomIndices; /* literals indexed for mapping */
|
||||
js::AtomDefnMapPtr roLexdeps;
|
||||
uintN firstLine; /* first line, for js_NewScriptFromCG */
|
||||
OwnedAtomIndexMapPtr atomIndices; /* literals indexed for mapping */
|
||||
AtomDefnMapPtr roLexdeps;
|
||||
uintN firstLine; /* first line, for JSScript::NewScriptFromCG */
|
||||
|
||||
intN stackDepth; /* current stack depth in script frame */
|
||||
uintN maxStackDepth; /* maximum stack depth so far */
|
||||
|
||||
uintN ntrynotes; /* number of allocated so far try notes */
|
||||
JSTryNode *lastTryNode; /* the last allocated try node */
|
||||
TryNode *lastTryNode; /* the last allocated try node */
|
||||
|
||||
JSSpanDep *spanDeps; /* span dependent instruction records */
|
||||
JSJumpTarget *jumpTargets; /* AVL tree of jump target offsets */
|
||||
JSJumpTarget *jtFreeList; /* JT_LEFT-linked list of free structs */
|
||||
SpanDep *spanDeps; /* span dependent instruction records */
|
||||
JumpTarget *jumpTargets; /* AVL tree of jump target offsets */
|
||||
JumpTarget *jtFreeList; /* JT_LEFT-linked list of free structs */
|
||||
uintN numSpanDeps; /* number of span dependencies */
|
||||
uintN numJumpTargets; /* number of jump targets */
|
||||
ptrdiff_t spanDepTodo; /* offset from main.base of potentially
|
||||
|
@ -643,36 +642,36 @@ struct JSCodeGenerator : public JSTreeContext
|
|||
|
||||
uintN arrayCompDepth; /* stack depth of array in comprehension */
|
||||
|
||||
uintN emitLevel; /* js_EmitTree recursion level */
|
||||
uintN emitLevel; /* js::frontend::EmitTree recursion level */
|
||||
|
||||
typedef js::HashMap<JSAtom *, js::Value> ConstMap;
|
||||
typedef HashMap<JSAtom *, Value> ConstMap;
|
||||
ConstMap constMap; /* compile time constants */
|
||||
|
||||
JSGCConstList constList; /* constants to be included with the script */
|
||||
GCConstList constList; /* constants to be included with the script */
|
||||
|
||||
JSCGObjectList objectList; /* list of emitted objects */
|
||||
JSCGObjectList regexpList; /* list of emitted regexp that will be
|
||||
CGObjectList objectList; /* list of emitted objects */
|
||||
CGObjectList regexpList; /* list of emitted regexp that will be
|
||||
cloned during execution */
|
||||
|
||||
js::OwnedAtomIndexMapPtr upvarIndices; /* map of atoms to upvar indexes */
|
||||
OwnedAtomIndexMapPtr upvarIndices; /* map of atoms to upvar indexes */
|
||||
|
||||
js::UpvarCookies upvarMap; /* indexed upvar slot locations */
|
||||
UpvarCookies upvarMap; /* indexed upvar slot locations */
|
||||
|
||||
typedef js::Vector<js::GlobalSlotArray::Entry, 16> GlobalUseVector;
|
||||
typedef Vector<GlobalSlotArray::Entry, 16> GlobalUseVector;
|
||||
|
||||
GlobalUseVector globalUses; /* per-script global uses */
|
||||
js::OwnedAtomIndexMapPtr globalMap; /* per-script map of global name to globalUses vector */
|
||||
OwnedAtomIndexMapPtr globalMap; /* per-script map of global name to globalUses vector */
|
||||
|
||||
/* Vectors of pn_cookie slot values. */
|
||||
typedef js::Vector<uint32, 8> SlotVector;
|
||||
typedef Vector<uint32, 8> SlotVector;
|
||||
SlotVector closedArgs;
|
||||
SlotVector closedVars;
|
||||
|
||||
uint16 traceIndex; /* index for the next JSOP_TRACE instruction */
|
||||
uint16 typesetCount; /* Number of JOF_TYPESET opcodes generated */
|
||||
|
||||
JSCodeGenerator(js::Parser *parser, uintN lineno);
|
||||
bool init(JSContext *cx, JSTreeContext::InitBehavior ib = USED_AS_CODE_GENERATOR);
|
||||
CodeGenerator(Parser *parser, uintN lineno);
|
||||
bool init(JSContext *cx, TreeContext::InitBehavior ib = USED_AS_CODE_GENERATOR);
|
||||
|
||||
JSContext *context() {
|
||||
return parser->context;
|
||||
|
@ -681,9 +680,9 @@ struct JSCodeGenerator : public JSTreeContext
|
|||
/*
|
||||
* Note that cgs are magic: they own the arena "top-of-stack" space above
|
||||
* their tempMark points. This means that you cannot alloc from tempPool
|
||||
* and save the pointer beyond the next JSCodeGenerator destructor call.
|
||||
* and save the pointer beyond the next CodeGenerator destructor call.
|
||||
*/
|
||||
~JSCodeGenerator();
|
||||
~CodeGenerator();
|
||||
|
||||
/*
|
||||
* Adds a use of a variable that is statically known to exist on the
|
||||
|
@ -699,7 +698,7 @@ struct JSCodeGenerator : public JSTreeContext
|
|||
* If the global use can be cached, |cookie| will be set to |slot|.
|
||||
* Otherwise, |cookie| is set to the free cookie value.
|
||||
*/
|
||||
bool addGlobalUse(JSAtom *atom, uint32 slot, js::UpvarCookie *cookie);
|
||||
bool addGlobalUse(JSAtom *atom, uint32 slot, UpvarCookie *cookie);
|
||||
|
||||
bool hasUpvarIndices() const {
|
||||
return upvarIndices.hasMap() && !upvarIndices->empty();
|
||||
|
@ -718,11 +717,11 @@ struct JSCodeGenerator : public JSTreeContext
|
|||
bool compilingForEval() const { return !!(flags & TCF_COMPILE_FOR_EVAL); }
|
||||
JSVersion version() const { return parser->versionWithFlags(); }
|
||||
|
||||
bool shouldNoteClosedName(JSParseNode *pn);
|
||||
bool shouldNoteClosedName(ParseNode *pn);
|
||||
|
||||
JS_ALWAYS_INLINE
|
||||
bool makeAtomIndex(JSAtom *atom, jsatomid *indexp) {
|
||||
js::AtomIndexAddPtr p = atomIndices->lookupForAdd(atom);
|
||||
AtomIndexAddPtr p = atomIndices->lookupForAdd(atom);
|
||||
if (p) {
|
||||
*indexp = p.value();
|
||||
return true;
|
||||
|
@ -739,7 +738,7 @@ struct JSCodeGenerator : public JSTreeContext
|
|||
bool checkSingletonContext() {
|
||||
if (!compileAndGo() || inFunction())
|
||||
return false;
|
||||
for (JSStmtInfo *stmt = topStmt; stmt; stmt = stmt->down) {
|
||||
for (StmtInfo *stmt = topStmt; stmt; stmt = stmt->down) {
|
||||
if (STMT_IS_LOOP(stmt))
|
||||
return false;
|
||||
}
|
||||
|
@ -771,51 +770,53 @@ struct JSCodeGenerator : public JSTreeContext
|
|||
#define CG_SWITCH_TO_MAIN(cg) ((cg)->current = &(cg)->main)
|
||||
#define CG_SWITCH_TO_PROLOG(cg) ((cg)->current = &(cg)->prolog)
|
||||
|
||||
inline JSCodeGenerator *
|
||||
JSTreeContext::asCodeGenerator()
|
||||
inline CodeGenerator *
|
||||
TreeContext::asCodeGenerator()
|
||||
{
|
||||
JS_ASSERT(compiling());
|
||||
return static_cast<JSCodeGenerator *>(this);
|
||||
return static_cast<CodeGenerator *>(this);
|
||||
}
|
||||
|
||||
namespace frontend {
|
||||
|
||||
/*
|
||||
* Emit one bytecode.
|
||||
*/
|
||||
extern ptrdiff_t
|
||||
js_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op);
|
||||
ptrdiff_t
|
||||
Emit1(JSContext *cx, CodeGenerator *cg, JSOp op);
|
||||
|
||||
/*
|
||||
* Emit two bytecodes, an opcode (op) with a byte of immediate operand (op1).
|
||||
*/
|
||||
extern ptrdiff_t
|
||||
js_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1);
|
||||
ptrdiff_t
|
||||
Emit2(JSContext *cx, CodeGenerator *cg, JSOp op, jsbytecode op1);
|
||||
|
||||
/*
|
||||
* Emit three bytecodes, an opcode with two bytes of immediate operands.
|
||||
*/
|
||||
extern ptrdiff_t
|
||||
js_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1,
|
||||
ptrdiff_t
|
||||
Emit3(JSContext *cx, CodeGenerator *cg, JSOp op, jsbytecode op1,
|
||||
jsbytecode op2);
|
||||
|
||||
/*
|
||||
* Emit five bytecodes, an opcode with two 16-bit immediates.
|
||||
*/
|
||||
extern ptrdiff_t
|
||||
js_Emit5(JSContext *cx, JSCodeGenerator *cg, JSOp op, uint16 op1,
|
||||
ptrdiff_t
|
||||
Emit5(JSContext *cx, CodeGenerator *cg, JSOp op, uint16 op1,
|
||||
uint16 op2);
|
||||
|
||||
/*
|
||||
* Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand.
|
||||
*/
|
||||
extern ptrdiff_t
|
||||
js_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra);
|
||||
ptrdiff_t
|
||||
EmitN(JSContext *cx, CodeGenerator *cg, JSOp op, size_t extra);
|
||||
|
||||
/*
|
||||
* Unsafe macro to call js_SetJumpOffset and return false if it does.
|
||||
* Unsafe macro to call SetJumpOffset and return false if it does.
|
||||
*/
|
||||
#define CHECK_AND_SET_JUMP_OFFSET_CUSTOM(cx,cg,pc,off,BAD_EXIT) \
|
||||
JS_BEGIN_MACRO \
|
||||
if (!js_SetJumpOffset(cx, cg, pc, off)) { \
|
||||
if (!SetJumpOffset(cx, cg, pc, off)) { \
|
||||
BAD_EXIT; \
|
||||
} \
|
||||
JS_END_MACRO
|
||||
|
@ -830,56 +831,52 @@ js_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra);
|
|||
#define CHECK_AND_SET_JUMP_OFFSET_AT(cx,cg,off) \
|
||||
CHECK_AND_SET_JUMP_OFFSET_AT_CUSTOM(cx, cg, off, return JS_FALSE)
|
||||
|
||||
extern JSBool
|
||||
js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc,
|
||||
ptrdiff_t off);
|
||||
JSBool
|
||||
SetJumpOffset(JSContext *cx, CodeGenerator *cg, jsbytecode *pc, ptrdiff_t off);
|
||||
|
||||
/*
|
||||
* Push the C-stack-allocated struct at stmt onto the stmtInfo stack.
|
||||
*/
|
||||
extern void
|
||||
js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type,
|
||||
ptrdiff_t top);
|
||||
void
|
||||
PushStatement(TreeContext *tc, StmtInfo *stmt, StmtType type, ptrdiff_t top);
|
||||
|
||||
/*
|
||||
* Push a block scope statement and link blockObj into tc->blockChain. To pop
|
||||
* this statement info record, use js_PopStatement as usual, or if appropriate
|
||||
* (if generating code), js_PopStatementCG.
|
||||
* this statement info record, use PopStatementTC as usual, or if appropriate
|
||||
* (if generating code), PopStatementCG.
|
||||
*/
|
||||
extern void
|
||||
js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObjectBox *blockBox,
|
||||
ptrdiff_t top);
|
||||
void
|
||||
PushBlockScope(TreeContext *tc, StmtInfo *stmt, ObjectBox *blockBox, ptrdiff_t top);
|
||||
|
||||
/*
|
||||
* Pop tc->topStmt. If the top JSStmtInfo struct is not stack-allocated, it
|
||||
* Pop tc->topStmt. If the top StmtInfo struct is not stack-allocated, it
|
||||
* is up to the caller to free it.
|
||||
*/
|
||||
extern void
|
||||
js_PopStatement(JSTreeContext *tc);
|
||||
void
|
||||
PopStatementTC(TreeContext *tc);
|
||||
|
||||
/*
|
||||
* Like js_PopStatement(cg), also patch breaks and continues unless the top
|
||||
* Like PopStatementTC(cg), also patch breaks and continues unless the top
|
||||
* statement info record represents a try-catch-finally suite. May fail if a
|
||||
* jump offset overflows.
|
||||
*/
|
||||
extern JSBool
|
||||
js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg);
|
||||
JSBool
|
||||
PopStatementCG(JSContext *cx, CodeGenerator *cg);
|
||||
|
||||
/*
|
||||
* Define and lookup a primitive jsval associated with the const named by atom.
|
||||
* js_DefineCompileTimeConstant analyzes the constant-folded initializer at pn
|
||||
* DefineCompileTimeConstant analyzes the constant-folded initializer at pn
|
||||
* and saves the const's value in cg->constList, if it can be used at compile
|
||||
* time. It returns true unless an error occurred.
|
||||
*
|
||||
* If the initializer's value could not be saved, js_DefineCompileTimeConstant
|
||||
* calls will return the undefined value. js_DefineCompileTimeConstant tries
|
||||
* If the initializer's value could not be saved, DefineCompileTimeConstant
|
||||
* calls will return the undefined value. DefineCompileTimeConstant tries
|
||||
* to find a const value memorized for atom, returning true with *vp set to a
|
||||
* value other than undefined if the constant was found, true with *vp set to
|
||||
* JSVAL_VOID if not found, and false on error.
|
||||
*/
|
||||
extern JSBool
|
||||
js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
|
||||
JSParseNode *pn);
|
||||
JSBool
|
||||
DefineCompileTimeConstant(JSContext *cx, CodeGenerator *cg, JSAtom *atom, ParseNode *pn);
|
||||
|
||||
/*
|
||||
* Find a lexically scoped variable (one declared by let, catch, or an array
|
||||
|
@ -890,26 +887,27 @@ js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
|
|||
* null, then if atom is found, set *slotp to its stack slot, otherwise to -1.
|
||||
* This means that if slotp is not null, all the block objects on the lexical
|
||||
* scope chain must have had their depth slots computed by the code generator,
|
||||
* so the caller must be under js_EmitTree.
|
||||
* so the caller must be under EmitTree.
|
||||
*
|
||||
* In any event, directly return the statement info record in which atom was
|
||||
* found. Otherwise return null.
|
||||
*/
|
||||
extern JSStmtInfo *
|
||||
js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp,
|
||||
JSStmtInfo *stmt = NULL);
|
||||
StmtInfo *
|
||||
LexicalLookup(TreeContext *tc, JSAtom *atom, jsint *slotp, StmtInfo *stmt = NULL);
|
||||
|
||||
/*
|
||||
* Emit code into cg for the tree rooted at pn.
|
||||
*/
|
||||
extern JSBool
|
||||
js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn);
|
||||
JSBool
|
||||
EmitTree(JSContext *cx, CodeGenerator *cg, ParseNode *pn);
|
||||
|
||||
/*
|
||||
* Emit function code using cg for the tree rooted at body.
|
||||
*/
|
||||
extern JSBool
|
||||
js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body);
|
||||
JSBool
|
||||
EmitFunctionScript(JSContext *cx, CodeGenerator *cg, ParseNode *body);
|
||||
|
||||
} /* namespace frontend */
|
||||
|
||||
/*
|
||||
* Source notes generated along with bytecode for decompiling and debugging.
|
||||
|
@ -927,13 +925,13 @@ js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body);
|
|||
* At most one "gettable" note (i.e., a note of type other than SRC_NEWLINE,
|
||||
* SRC_SETLINE, and SRC_XDELTA) applies to a given bytecode.
|
||||
*
|
||||
* NB: the js_SrcNoteSpec array in jsemit.c is indexed by this enum, so its
|
||||
* initializers need to match the order here.
|
||||
* NB: the js_SrcNoteSpec array in BytecodeGenerator.cpp is indexed by this
|
||||
* enum, so its initializers need to match the order here.
|
||||
*
|
||||
* Note on adding new source notes: every pair of bytecodes (A, B) where A and
|
||||
* B have disjoint sets of source notes that could apply to each bytecode may
|
||||
* reuse the same note type value for two notes (snA, snB) that have the same
|
||||
* arity, offsetBias, and isSpanDep initializers in js_SrcNoteSpec. This is
|
||||
* arity, offsetBias, and isSpanDep initializers in JSSrcNoteSpec. This is
|
||||
* why SRC_IF and SRC_INITPROP have the same value below. For bad historical
|
||||
* reasons, some bytecodes below that could be overlayed have not been, but
|
||||
* before using SRC_EXTENDED, consider compressing the existing note types.
|
||||
|
@ -941,7 +939,7 @@ js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body);
|
|||
* Don't forget to update JSXDR_BYTECODE_VERSION in jsxdrapi.h for all such
|
||||
* incompatible source note or other bytecode changes.
|
||||
*/
|
||||
typedef enum JSSrcNoteType {
|
||||
enum SrcNoteType {
|
||||
SRC_NULL = 0, /* terminates a note vector */
|
||||
SRC_IF = 1, /* JSOP_IFEQ bytecode is from an if-then */
|
||||
SRC_BREAK = 1, /* JSOP_GOTO is a break */
|
||||
|
@ -990,7 +988,7 @@ typedef enum JSSrcNoteType {
|
|||
SRC_NEWLINE = 22, /* bytecode follows a source newline */
|
||||
SRC_SETLINE = 23, /* a file-absolute source line number note */
|
||||
SRC_XDELTA = 24 /* 24-31 are for extended delta notes */
|
||||
} JSSrcNoteType;
|
||||
};
|
||||
|
||||
/*
|
||||
* Constants for the SRC_DECL source note. Note that span-dependent bytecode
|
||||
|
@ -1022,9 +1020,9 @@ typedef enum JSSrcNoteType {
|
|||
| ((d) & SN_XDELTA_MASK)))
|
||||
|
||||
#define SN_IS_XDELTA(sn) ((*(sn) >> SN_DELTA_BITS) >= SRC_XDELTA)
|
||||
#define SN_TYPE(sn) ((JSSrcNoteType)(SN_IS_XDELTA(sn) \
|
||||
? SRC_XDELTA \
|
||||
: *(sn) >> SN_DELTA_BITS))
|
||||
#define SN_TYPE(sn) ((js::SrcNoteType)(SN_IS_XDELTA(sn) \
|
||||
? SRC_XDELTA \
|
||||
: *(sn) >> SN_DELTA_BITS))
|
||||
#define SN_SET_TYPE(sn,type) SN_MAKE_NOTE(sn, type, SN_DELTA(sn))
|
||||
#define SN_IS_GETTABLE(sn) (SN_TYPE(sn) < SRC_NEWLINE)
|
||||
|
||||
|
@ -1046,17 +1044,6 @@ typedef enum JSSrcNoteType {
|
|||
#define SN_3BYTE_OFFSET_FLAG 0x80
|
||||
#define SN_3BYTE_OFFSET_MASK 0x7f
|
||||
|
||||
typedef struct JSSrcNoteSpec {
|
||||
const char *name; /* name for disassembly/debugging output */
|
||||
int8 arity; /* number of offset operands */
|
||||
uint8 offsetBias; /* bias of offset(s) from annotated pc */
|
||||
int8 isSpanDep; /* 1 or -1 if offsets could span extended ops,
|
||||
0 otherwise; sign tells span direction */
|
||||
} JSSrcNoteSpec;
|
||||
|
||||
extern JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[];
|
||||
extern JS_FRIEND_API(uintN) js_SrcNoteLength(jssrcnote *sn);
|
||||
|
||||
#define SN_LENGTH(sn) ((js_SrcNoteSpec[SN_TYPE(sn)].arity == 0) ? 1 \
|
||||
: js_SrcNoteLength(sn))
|
||||
#define SN_NEXT(sn) ((sn) + SN_LENGTH(sn))
|
||||
|
@ -1065,39 +1052,32 @@ extern JS_FRIEND_API(uintN) js_SrcNoteLength(jssrcnote *sn);
|
|||
#define SN_MAKE_TERMINATOR(sn) (*(sn) = SRC_NULL)
|
||||
#define SN_IS_TERMINATOR(sn) (*(sn) == SRC_NULL)
|
||||
|
||||
namespace frontend {
|
||||
|
||||
/*
|
||||
* Append a new source note of the given type (and therefore size) to cg's
|
||||
* notes dynamic array, updating cg->noteCount. Return the new note's index
|
||||
* within the array pointed at by cg->current->notes. Return -1 if out of
|
||||
* memory.
|
||||
*/
|
||||
extern intN
|
||||
js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type);
|
||||
intN
|
||||
NewSrcNote(JSContext *cx, CodeGenerator *cg, SrcNoteType type);
|
||||
|
||||
extern intN
|
||||
js_NewSrcNote2(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type,
|
||||
ptrdiff_t offset);
|
||||
intN
|
||||
NewSrcNote2(JSContext *cx, CodeGenerator *cg, SrcNoteType type, ptrdiff_t offset);
|
||||
|
||||
extern intN
|
||||
js_NewSrcNote3(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type,
|
||||
ptrdiff_t offset1, ptrdiff_t offset2);
|
||||
intN
|
||||
NewSrcNote3(JSContext *cx, CodeGenerator *cg, SrcNoteType type, ptrdiff_t offset1,
|
||||
ptrdiff_t offset2);
|
||||
|
||||
/*
|
||||
* NB: this function can add at most one extra extended delta note.
|
||||
*/
|
||||
extern jssrcnote *
|
||||
js_AddToSrcNoteDelta(JSContext *cx, JSCodeGenerator *cg, jssrcnote *sn,
|
||||
ptrdiff_t delta);
|
||||
jssrcnote *
|
||||
AddToSrcNoteDelta(JSContext *cx, CodeGenerator *cg, jssrcnote *sn, ptrdiff_t delta);
|
||||
|
||||
/*
|
||||
* Get and set the offset operand identified by which (0 for the first, etc.).
|
||||
*/
|
||||
extern JS_FRIEND_API(ptrdiff_t)
|
||||
js_GetSrcNoteOffset(jssrcnote *sn, uintN which);
|
||||
|
||||
extern JSBool
|
||||
js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index,
|
||||
uintN which, ptrdiff_t offset);
|
||||
JSBool
|
||||
SetSrcNoteOffset(JSContext *cx, CodeGenerator *cg, uintN index, uintN which, ptrdiff_t offset);
|
||||
|
||||
/*
|
||||
* Finish taking source notes in cx's notePool, copying final notes to the new
|
||||
|
@ -1106,8 +1086,8 @@ js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index,
|
|||
*
|
||||
* To compute the number of jssrcnotes to allocate and pass in via notes, use
|
||||
* the CG_COUNT_FINAL_SRCNOTES macro. This macro knows a lot about details of
|
||||
* js_FinishTakingSrcNotes, SO DON'T CHANGE jsemit.c's js_FinishTakingSrcNotes
|
||||
* FUNCTION WITHOUT CHECKING WHETHER THIS MACRO NEEDS CORRESPONDING CHANGES!
|
||||
* FinishTakingSrcNotes, so DON'T CHANGE js::frontend::FinishTakingSrcNotes
|
||||
* WITHOUT CHECKING WHETHER THIS MACRO NEEDS CORRESPONDING CHANGES!
|
||||
*/
|
||||
#define CG_COUNT_FINAL_SRCNOTES(cg, cnt) \
|
||||
JS_BEGIN_MACRO \
|
||||
|
@ -1130,12 +1110,30 @@ js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index,
|
|||
} \
|
||||
JS_END_MACRO
|
||||
|
||||
extern JSBool
|
||||
js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg, jssrcnote *notes);
|
||||
JSBool
|
||||
FinishTakingSrcNotes(JSContext *cx, CodeGenerator *cg, jssrcnote *notes);
|
||||
|
||||
extern void
|
||||
js_FinishTakingTryNotes(JSCodeGenerator *cg, JSTryNoteArray *array);
|
||||
void
|
||||
FinishTakingTryNotes(CodeGenerator *cg, JSTryNoteArray *array);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
} /* namespace frontend */
|
||||
} /* namespace js */
|
||||
|
||||
struct JSSrcNoteSpec {
|
||||
const char *name; /* name for disassembly/debugging output */
|
||||
int8 arity; /* number of offset operands */
|
||||
uint8 offsetBias; /* bias of offset(s) from annotated pc */
|
||||
int8 isSpanDep; /* 1 or -1 if offsets could span extended ops,
|
||||
0 otherwise; sign tells span direction */
|
||||
};
|
||||
|
||||
extern JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[];
|
||||
extern JS_FRIEND_API(uintN) js_SrcNoteLength(jssrcnote *sn);
|
||||
|
||||
/*
|
||||
* Get and set the offset operand identified by which (0 for the first, etc.).
|
||||
*/
|
||||
extern JS_FRIEND_API(ptrdiff_t)
|
||||
js_GetSrcNoteOffset(jssrcnote *sn, uintN which);
|
||||
|
||||
#endif /* BytecodeGenerator_h__ */
|
||||
|
|
|
@ -51,10 +51,10 @@
|
|||
|
||||
using namespace js;
|
||||
|
||||
static JSParseNode *
|
||||
ContainsStmt(JSParseNode *pn, TokenKind tt)
|
||||
static ParseNode *
|
||||
ContainsStmt(ParseNode *pn, TokenKind tt)
|
||||
{
|
||||
JSParseNode *pn2, *pnt;
|
||||
ParseNode *pn2, *pnt;
|
||||
|
||||
if (!pn)
|
||||
return NULL;
|
||||
|
@ -105,7 +105,7 @@ ContainsStmt(JSParseNode *pn, TokenKind tt)
|
|||
* XXX handles only strings and numbers for now
|
||||
*/
|
||||
static JSBool
|
||||
FoldType(JSContext *cx, JSParseNode *pn, TokenKind type)
|
||||
FoldType(JSContext *cx, ParseNode *pn, TokenKind type)
|
||||
{
|
||||
if (!pn->isKind(type)) {
|
||||
switch (type) {
|
||||
|
@ -145,8 +145,8 @@ FoldType(JSContext *cx, JSParseNode *pn, TokenKind type)
|
|||
* a successful call to this function.
|
||||
*/
|
||||
static JSBool
|
||||
FoldBinaryNumeric(JSContext *cx, JSOp op, JSParseNode *pn1, JSParseNode *pn2,
|
||||
JSParseNode *pn, JSTreeContext *tc)
|
||||
FoldBinaryNumeric(JSContext *cx, JSOp op, ParseNode *pn1, ParseNode *pn2,
|
||||
ParseNode *pn, TreeContext *tc)
|
||||
{
|
||||
jsdouble d, d2;
|
||||
int32 i, j;
|
||||
|
@ -213,9 +213,9 @@ FoldBinaryNumeric(JSContext *cx, JSOp op, JSParseNode *pn1, JSParseNode *pn2,
|
|||
|
||||
/* Take care to allow pn1 or pn2 to alias pn. */
|
||||
if (pn1 != pn)
|
||||
RecycleTree(pn1, tc);
|
||||
tc->freeTree(pn1);
|
||||
if (pn2 != pn)
|
||||
RecycleTree(pn2, tc);
|
||||
tc->freeTree(pn2);
|
||||
pn->setKind(TOK_NUMBER);
|
||||
pn->setOp(JSOP_DOUBLE);
|
||||
pn->setArity(PN_NULLARY);
|
||||
|
@ -226,10 +226,10 @@ FoldBinaryNumeric(JSContext *cx, JSOp op, JSParseNode *pn1, JSParseNode *pn2,
|
|||
#if JS_HAS_XML_SUPPORT
|
||||
|
||||
static JSBool
|
||||
FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
|
||||
FoldXMLConstants(JSContext *cx, ParseNode *pn, TreeContext *tc)
|
||||
{
|
||||
TokenKind tt;
|
||||
JSParseNode **pnp, *pn1, *pn2;
|
||||
ParseNode **pnp, *pn1, *pn2;
|
||||
JSString *accum, *str;
|
||||
uint32 i, j;
|
||||
|
||||
|
@ -303,7 +303,7 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
|
|||
#endif
|
||||
} else if (accum && pn1 != pn2) {
|
||||
while (pn1->pn_next != pn2) {
|
||||
pn1 = RecycleTree(pn1, tc);
|
||||
pn1 = tc->freeTree(pn1);
|
||||
--pn->pn_count;
|
||||
}
|
||||
pn1->setKind(TOK_XMLTEXT);
|
||||
|
@ -356,7 +356,7 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
|
|||
|
||||
JS_ASSERT(*pnp == pn1);
|
||||
while (pn1->pn_next) {
|
||||
pn1 = RecycleTree(pn1, tc);
|
||||
pn1 = tc->freeTree(pn1);
|
||||
--pn->pn_count;
|
||||
}
|
||||
pn1->setKind(TOK_XMLTEXT);
|
||||
|
@ -392,7 +392,7 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
|
|||
enum Truthiness { Truthy, Falsy, Unknown };
|
||||
|
||||
static Truthiness
|
||||
Boolish(JSParseNode *pn)
|
||||
Boolish(ParseNode *pn)
|
||||
{
|
||||
switch (pn->getOp()) {
|
||||
case JSOP_DOUBLE:
|
||||
|
@ -411,7 +411,7 @@ Boolish(JSParseNode *pn)
|
|||
*/
|
||||
if (pn->pn_count != 1)
|
||||
return Unknown;
|
||||
JSParseNode *pn2 = pn->pn_head;
|
||||
ParseNode *pn2 = pn->pn_head;
|
||||
if (!pn2->isKind(TOK_FUNCTION))
|
||||
return Unknown;
|
||||
if (!(pn2->pn_funbox->tcflags & TCF_GENEXP_LAMBDA))
|
||||
|
@ -434,23 +434,25 @@ Boolish(JSParseNode *pn)
|
|||
}
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
||||
{
|
||||
JSParseNode *pn1 = NULL, *pn2 = NULL, *pn3 = NULL;
|
||||
namespace js {
|
||||
|
||||
JS_CHECK_RECURSION(cx, return JS_FALSE);
|
||||
bool
|
||||
FoldConstants(JSContext *cx, ParseNode *pn, TreeContext *tc, bool inCond)
|
||||
{
|
||||
ParseNode *pn1 = NULL, *pn2 = NULL, *pn3 = NULL;
|
||||
|
||||
JS_CHECK_RECURSION(cx, return false);
|
||||
|
||||
switch (pn->getArity()) {
|
||||
case PN_FUNC:
|
||||
{
|
||||
uint32 oldflags = tc->flags;
|
||||
JSFunctionBox *oldlist = tc->functionList;
|
||||
FunctionBox *oldlist = tc->functionList;
|
||||
|
||||
tc->flags = pn->pn_funbox->tcflags;
|
||||
tc->functionList = pn->pn_funbox->kids;
|
||||
if (!js_FoldConstants(cx, pn->pn_body, tc))
|
||||
return JS_FALSE;
|
||||
if (!FoldConstants(cx, pn->pn_body, tc))
|
||||
return false;
|
||||
pn->pn_funbox->kids = tc->functionList;
|
||||
tc->flags = oldflags;
|
||||
tc->functionList = oldlist;
|
||||
|
@ -469,8 +471,8 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
|
||||
/* Save the list head in pn1 for later use. */
|
||||
for (; pn2; pn2 = pn2->pn_next) {
|
||||
if (!js_FoldConstants(cx, pn2, tc, cond))
|
||||
return JS_FALSE;
|
||||
if (!FoldConstants(cx, pn2, tc, cond))
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -480,18 +482,18 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
pn1 = pn->pn_kid1;
|
||||
pn2 = pn->pn_kid2;
|
||||
pn3 = pn->pn_kid3;
|
||||
if (pn1 && !js_FoldConstants(cx, pn1, tc, pn->isKind(TOK_IF)))
|
||||
return JS_FALSE;
|
||||
if (pn1 && !FoldConstants(cx, pn1, tc, pn->isKind(TOK_IF)))
|
||||
return false;
|
||||
if (pn2) {
|
||||
if (!js_FoldConstants(cx, pn2, tc, pn->isKind(TOK_FORHEAD)))
|
||||
return JS_FALSE;
|
||||
if (!FoldConstants(cx, pn2, tc, pn->isKind(TOK_FORHEAD)))
|
||||
return false;
|
||||
if (pn->isKind(TOK_FORHEAD) && pn2->isOp(JSOP_TRUE)) {
|
||||
RecycleTree(pn2, tc);
|
||||
tc->freeTree(pn2);
|
||||
pn->pn_kid2 = NULL;
|
||||
}
|
||||
}
|
||||
if (pn3 && !js_FoldConstants(cx, pn3, tc))
|
||||
return JS_FALSE;
|
||||
if (pn3 && !FoldConstants(cx, pn3, tc))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case PN_BINARY:
|
||||
|
@ -500,18 +502,18 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
|
||||
/* Propagate inCond through logical connectives. */
|
||||
if (pn->isKind(TOK_OR) || pn->isKind(TOK_AND)) {
|
||||
if (!js_FoldConstants(cx, pn1, tc, inCond))
|
||||
return JS_FALSE;
|
||||
if (!js_FoldConstants(cx, pn2, tc, inCond))
|
||||
return JS_FALSE;
|
||||
if (!FoldConstants(cx, pn1, tc, inCond))
|
||||
return false;
|
||||
if (!FoldConstants(cx, pn2, tc, inCond))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
/* First kid may be null (for default case in switch). */
|
||||
if (pn1 && !js_FoldConstants(cx, pn1, tc, pn->isKind(TOK_WHILE)))
|
||||
return JS_FALSE;
|
||||
if (!js_FoldConstants(cx, pn2, tc, pn->isKind(TOK_DO)))
|
||||
return JS_FALSE;
|
||||
if (pn1 && !FoldConstants(cx, pn1, tc, pn->isKind(TOK_WHILE)))
|
||||
return false;
|
||||
if (!FoldConstants(cx, pn2, tc, pn->isKind(TOK_DO)))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case PN_UNARY:
|
||||
|
@ -529,8 +531,8 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
if (pn->isOp(JSOP_TYPEOF) && !pn1->isKind(TOK_NAME))
|
||||
pn->setOp(JSOP_TYPEOFEXPR);
|
||||
|
||||
if (pn1 && !js_FoldConstants(cx, pn1, tc, pn->isOp(JSOP_NOT)))
|
||||
return JS_FALSE;
|
||||
if (pn1 && !FoldConstants(cx, pn1, tc, pn->isOp(JSOP_NOT)))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case PN_NAME:
|
||||
|
@ -544,15 +546,15 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
pn1 = pn->pn_expr;
|
||||
while (pn1 && pn1->isArity(PN_NAME) && !pn1->isUsed())
|
||||
pn1 = pn1->pn_expr;
|
||||
if (pn1 && !js_FoldConstants(cx, pn1, tc))
|
||||
return JS_FALSE;
|
||||
if (pn1 && !FoldConstants(cx, pn1, tc))
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case PN_NAMESET:
|
||||
pn1 = pn->pn_tree;
|
||||
if (!js_FoldConstants(cx, pn1, tc))
|
||||
return JS_FALSE;
|
||||
if (!FoldConstants(cx, pn1, tc))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case PN_NULLARY:
|
||||
|
@ -586,7 +588,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
/* FALL THROUGH */
|
||||
default:
|
||||
/* Early return to dodge common code that copies pn2 to pn. */
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
#if JS_HAS_GENERATOR_EXPRS
|
||||
|
@ -609,16 +611,16 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
pn->setArity(PN_LIST);
|
||||
pn->makeEmpty();
|
||||
}
|
||||
RecycleTree(pn2, tc);
|
||||
tc->freeTree(pn2);
|
||||
if (pn3 && pn3 != pn2)
|
||||
RecycleTree(pn3, tc);
|
||||
tc->freeTree(pn3);
|
||||
break;
|
||||
|
||||
case TOK_OR:
|
||||
case TOK_AND:
|
||||
if (inCond) {
|
||||
if (pn->isArity(PN_LIST)) {
|
||||
JSParseNode **pnp = &pn->pn_head;
|
||||
ParseNode **pnp = &pn->pn_head;
|
||||
JS_ASSERT(*pnp == pn1);
|
||||
do {
|
||||
Truthiness t = Boolish(pn1);
|
||||
|
@ -629,7 +631,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
if ((t == Truthy) == pn->isKind(TOK_OR)) {
|
||||
for (pn2 = pn1->pn_next; pn2; pn2 = pn3) {
|
||||
pn3 = pn2->pn_next;
|
||||
RecycleTree(pn2, tc);
|
||||
tc->freeTree(pn2);
|
||||
--pn->pn_count;
|
||||
}
|
||||
pn1->pn_next = NULL;
|
||||
|
@ -639,7 +641,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
if (pn->pn_count == 1)
|
||||
break;
|
||||
*pnp = pn1->pn_next;
|
||||
RecycleTree(pn1, tc);
|
||||
tc->freeTree(pn1);
|
||||
--pn->pn_count;
|
||||
} while ((pn1 = *pnp) != NULL);
|
||||
|
||||
|
@ -654,17 +656,17 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
pn->pn_right = pn2;
|
||||
} else if (pn->pn_count == 1) {
|
||||
pn->become(pn1);
|
||||
RecycleTree(pn1, tc);
|
||||
tc->freeTree(pn1);
|
||||
}
|
||||
} else {
|
||||
Truthiness t = Boolish(pn1);
|
||||
if (t != Unknown) {
|
||||
if ((t == Truthy) == pn->isKind(TOK_OR)) {
|
||||
RecycleTree(pn2, tc);
|
||||
tc->freeTree(pn2);
|
||||
pn->become(pn1);
|
||||
} else {
|
||||
JS_ASSERT((t == Truthy) == pn->isKind(TOK_AND));
|
||||
RecycleTree(pn1, tc);
|
||||
tc->freeTree(pn1);
|
||||
pn->become(pn2);
|
||||
}
|
||||
}
|
||||
|
@ -694,7 +696,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
*/
|
||||
JS_ASSERT(pn->pn_count > 2);
|
||||
if (pn->pn_xflags & PNX_CANTFOLD)
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
if (pn->pn_xflags != PNX_STRCAT)
|
||||
goto do_binary_op;
|
||||
|
||||
|
@ -702,26 +704,26 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
size_t length = 0;
|
||||
for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
|
||||
if (!FoldType(cx, pn2, TOK_STRING))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
/* XXX fold only if all operands convert to string */
|
||||
if (!pn2->isKind(TOK_STRING))
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
length += pn2->pn_atom->length();
|
||||
}
|
||||
|
||||
/* Allocate a new buffer and string descriptor for the result. */
|
||||
jschar *chars = (jschar *) cx->malloc_((length + 1) * sizeof(jschar));
|
||||
if (!chars)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
chars[length] = 0;
|
||||
JSString *str = js_NewString(cx, chars, length);
|
||||
if (!str) {
|
||||
cx->free_(chars);
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Fill the buffer, advancing chars and recycling kids as we go. */
|
||||
for (pn2 = pn1; pn2; pn2 = RecycleTree(pn2, tc)) {
|
||||
for (pn2 = pn1; pn2; pn2 = tc->freeTree(pn2)) {
|
||||
JSAtom *atom = pn2->pn_atom;
|
||||
size_t length2 = atom->length();
|
||||
js_strncpy(chars, atom->chars(), length2);
|
||||
|
@ -732,7 +734,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
/* Atomize the result string and mutate pn to refer to it. */
|
||||
pn->pn_atom = js_AtomizeString(cx, str);
|
||||
if (!pn->pn_atom)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
pn->setKind(TOK_STRING);
|
||||
pn->setOp(JSOP_STRING);
|
||||
pn->setArity(PN_NULLARY);
|
||||
|
@ -745,22 +747,22 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
JSString *left, *right, *str;
|
||||
|
||||
if (!FoldType(cx, !pn1->isKind(TOK_STRING) ? pn1 : pn2, TOK_STRING))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
if (!pn1->isKind(TOK_STRING) || !pn2->isKind(TOK_STRING))
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
left = pn1->pn_atom;
|
||||
right = pn2->pn_atom;
|
||||
str = js_ConcatStrings(cx, left, right);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
pn->pn_atom = js_AtomizeString(cx, str);
|
||||
if (!pn->pn_atom)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
pn->setKind(TOK_STRING);
|
||||
pn->setOp(JSOP_STRING);
|
||||
pn->setArity(PN_NULLARY);
|
||||
RecycleTree(pn1, tc);
|
||||
RecycleTree(pn2, tc);
|
||||
tc->freeTree(pn1);
|
||||
tc->freeTree(pn2);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -776,7 +778,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
JS_ASSERT(pn->pn_count > 2);
|
||||
for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
|
||||
if (!FoldType(cx, pn2, TOK_NUMBER))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
}
|
||||
for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
|
||||
/* XXX fold only if all operands convert to number */
|
||||
|
@ -789,22 +791,22 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
pn2 = pn1->pn_next;
|
||||
pn3 = pn2->pn_next;
|
||||
if (!FoldBinaryNumeric(cx, op, pn1, pn2, pn, tc))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
while ((pn2 = pn3) != NULL) {
|
||||
pn3 = pn2->pn_next;
|
||||
if (!FoldBinaryNumeric(cx, op, pn, pn2, pn, tc))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
JS_ASSERT(pn->isArity(PN_BINARY));
|
||||
if (!FoldType(cx, pn1, TOK_NUMBER) ||
|
||||
!FoldType(cx, pn2, TOK_NUMBER)) {
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
}
|
||||
if (pn1->isKind(TOK_NUMBER) && pn2->isKind(TOK_NUMBER)) {
|
||||
if (!FoldBinaryNumeric(cx, pn->getOp(), pn1, pn2, pn, tc))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -835,18 +837,18 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
|
||||
default:
|
||||
/* Return early to dodge the common TOK_NUMBER code. */
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
pn->setKind(TOK_NUMBER);
|
||||
pn->setOp(JSOP_DOUBLE);
|
||||
pn->setArity(PN_NULLARY);
|
||||
pn->pn_dval = d;
|
||||
RecycleTree(pn1, tc);
|
||||
tc->freeTree(pn1);
|
||||
} else if (pn1->isKind(TOK_PRIMARY)) {
|
||||
if (pn->isOp(JSOP_NOT) && (pn1->isOp(JSOP_TRUE) || pn1->isOp(JSOP_FALSE))) {
|
||||
pn->become(pn1);
|
||||
pn->setOp(pn->isOp(JSOP_TRUE) ? JSOP_FALSE : JSOP_TRUE);
|
||||
RecycleTree(pn1, tc);
|
||||
tc->freeTree(pn1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -861,28 +863,26 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
if (pn->isArity(PN_LIST)) {
|
||||
JS_ASSERT(pn->isKind(TOK_XMLLIST) || pn->pn_count != 0);
|
||||
if (!FoldXMLConstants(cx, pn, tc))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case TOK_AT:
|
||||
if (pn1->isKind(TOK_XMLNAME)) {
|
||||
JSObjectBox *xmlbox;
|
||||
|
||||
Value v = StringValue(pn1->pn_atom);
|
||||
if (!js_ToAttributeName(cx, &v))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
JS_ASSERT(v.isObject());
|
||||
|
||||
xmlbox = tc->parser->newObjectBox(&v.toObject());
|
||||
ObjectBox *xmlbox = tc->parser->newObjectBox(&v.toObject());
|
||||
if (!xmlbox)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
|
||||
pn->setKind(TOK_XMLNAME);
|
||||
pn->setOp(JSOP_OBJECT);
|
||||
pn->setArity(PN_NULLARY);
|
||||
pn->pn_objbox = xmlbox;
|
||||
RecycleTree(pn1, tc);
|
||||
tc->freeTree(pn1);
|
||||
}
|
||||
break;
|
||||
#endif /* JS_HAS_XML_SUPPORT */
|
||||
|
@ -899,12 +899,14 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
|
|||
* a method list corrupts the method list. However, methods are M's in
|
||||
* statements of the form 'this.foo = M;', which we never fold, so we're okay.
|
||||
*/
|
||||
PrepareNodeForMutation(pn, tc);
|
||||
tc->parser->allocator.prepareNodeForMutation(pn);
|
||||
pn->setKind(TOK_PRIMARY);
|
||||
pn->setOp(t == Truthy ? JSOP_TRUE : JSOP_FALSE);
|
||||
pn->setArity(PN_NULLARY);
|
||||
}
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
|
|
@ -43,12 +43,11 @@
|
|||
|
||||
#include "jsprvtd.h"
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
namespace js {
|
||||
|
||||
extern JSBool
|
||||
js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc,
|
||||
bool inCond = false);
|
||||
bool
|
||||
FoldConstants(JSContext *cx, ParseNode *pn, TreeContext *tc, bool inCond = false);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* FoldConstants_h__ */
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
#include "jscntxt.h"
|
||||
|
||||
#include "frontend/ParseNode.h" /* Need sizeof(JSDefinition). */
|
||||
#include "frontend/ParseNode.h" /* Need sizeof(js::Definition). */
|
||||
|
||||
#include "ParseMaps.h"
|
||||
|
||||
|
@ -81,7 +81,7 @@ ParseMapPool::allocate()
|
|||
return map;
|
||||
}
|
||||
|
||||
inline JSDefinition *
|
||||
inline Definition *
|
||||
AtomDecls::lookupFirst(JSAtom *atom)
|
||||
{
|
||||
JS_ASSERT(map);
|
||||
|
@ -101,7 +101,7 @@ AtomDecls::lookupMulti(JSAtom *atom)
|
|||
JS_ASSERT(map);
|
||||
AtomDOHPtr p = map->lookup(atom);
|
||||
if (!p)
|
||||
return MultiDeclRange((JSDefinition *) NULL);
|
||||
return MultiDeclRange((Definition *) NULL);
|
||||
|
||||
DefnOrHeader &doh = p.value();
|
||||
if (doh.isHeader())
|
||||
|
@ -110,7 +110,7 @@ AtomDecls::lookupMulti(JSAtom *atom)
|
|||
}
|
||||
|
||||
inline bool
|
||||
AtomDecls::addUnique(JSAtom *atom, JSDefinition *defn)
|
||||
AtomDecls::addUnique(JSAtom *atom, Definition *defn)
|
||||
{
|
||||
JS_ASSERT(map);
|
||||
AtomDOHAddPtr p = map->lookupForAdd(atom);
|
||||
|
|
|
@ -50,8 +50,8 @@ ParseMapPool::checkInvariants()
|
|||
* Having all values be of the same size permits us to easily reuse the
|
||||
* allocated space for each of the map types.
|
||||
*/
|
||||
JS_STATIC_ASSERT(sizeof(JSDefinition *) == sizeof(jsatomid));
|
||||
JS_STATIC_ASSERT(sizeof(JSDefinition *) == sizeof(DefnOrHeader));
|
||||
JS_STATIC_ASSERT(sizeof(Definition *) == sizeof(jsatomid));
|
||||
JS_STATIC_ASSERT(sizeof(Definition *) == sizeof(DefnOrHeader));
|
||||
JS_STATIC_ASSERT(sizeof(AtomDefnMap::Entry) == sizeof(AtomIndexMap::Entry));
|
||||
JS_STATIC_ASSERT(sizeof(AtomDefnMap::Entry) == sizeof(AtomDOHMap::Entry));
|
||||
JS_STATIC_ASSERT(sizeof(AtomMapT::Entry) == sizeof(AtomDOHMap::Entry));
|
||||
|
@ -124,7 +124,7 @@ DumpAtomDefnMap(const AtomDefnMapPtr &map)
|
|||
#endif
|
||||
|
||||
AtomDeclNode *
|
||||
AtomDecls::allocNode(JSDefinition *defn)
|
||||
AtomDecls::allocNode(Definition *defn)
|
||||
{
|
||||
AtomDeclNode *p = cx->tempLifoAlloc().new_<AtomDeclNode>(defn);
|
||||
if (!p) {
|
||||
|
@ -135,7 +135,7 @@ AtomDecls::allocNode(JSDefinition *defn)
|
|||
}
|
||||
|
||||
bool
|
||||
AtomDecls::addShadow(JSAtom *atom, JSDefinition *defn)
|
||||
AtomDecls::addShadow(JSAtom *atom, Definition *defn)
|
||||
{
|
||||
AtomDeclNode *node = allocNode(defn);
|
||||
if (!node)
|
||||
|
@ -177,7 +177,7 @@ AtomDecls::lastAsNode(DefnOrHeader *doh)
|
|||
}
|
||||
|
||||
bool
|
||||
AtomDecls::addHoist(JSAtom *atom, JSDefinition *defn)
|
||||
AtomDecls::addHoist(JSAtom *atom, Definition *defn)
|
||||
{
|
||||
AtomDeclNode *node = allocNode(defn);
|
||||
if (!node)
|
||||
|
|
|
@ -47,6 +47,8 @@
|
|||
|
||||
namespace js {
|
||||
|
||||
struct Definition;
|
||||
|
||||
/*
|
||||
* A pool that permits the reuse of the backing storage for the defn, index, or
|
||||
* defn-or-header (multi) maps.
|
||||
|
@ -126,7 +128,7 @@ class ParseMapPool
|
|||
}; /* ParseMapPool */
|
||||
|
||||
/*
|
||||
* N.B. This is a POD-type so that it can be included in the JSParseNode union.
|
||||
* N.B. This is a POD-type so that it can be included in the ParseNode union.
|
||||
* If possible, use the corresponding |OwnedAtomThingMapPtr| variant.
|
||||
*/
|
||||
template <class Map>
|
||||
|
@ -152,7 +154,7 @@ struct AtomThingMapPtr
|
|||
struct AtomDefnMapPtr : public AtomThingMapPtr<AtomDefnMap>
|
||||
{
|
||||
JS_ALWAYS_INLINE
|
||||
JSDefinition *lookupDefn(JSAtom *atom) {
|
||||
Definition *lookupDefn(JSAtom *atom) {
|
||||
AtomDefnMap::Ptr p = map_->lookup(atom);
|
||||
return p ? p.value() : NULL;
|
||||
}
|
||||
|
@ -185,22 +187,22 @@ typedef OwnedAtomThingMapPtr<AtomIndexMapPtr> OwnedAtomIndexMapPtr;
|
|||
/* Node structure for chaining in AtomDecls. */
|
||||
struct AtomDeclNode
|
||||
{
|
||||
JSDefinition *defn;
|
||||
Definition *defn;
|
||||
AtomDeclNode *next;
|
||||
|
||||
explicit AtomDeclNode(JSDefinition *defn)
|
||||
explicit AtomDeclNode(Definition *defn)
|
||||
: defn(defn), next(NULL)
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* Tagged union of a JSDefinition and an AtomDeclNode, for use in AtomDecl's
|
||||
* Tagged union of a Definition and an AtomDeclNode, for use in AtomDecl's
|
||||
* internal map.
|
||||
*/
|
||||
class DefnOrHeader
|
||||
{
|
||||
union {
|
||||
JSDefinition *defn;
|
||||
Definition *defn;
|
||||
AtomDeclNode *head;
|
||||
uintptr_t bits;
|
||||
} u;
|
||||
|
@ -210,7 +212,7 @@ class DefnOrHeader
|
|||
u.bits = 0;
|
||||
}
|
||||
|
||||
explicit DefnOrHeader(JSDefinition *defn) {
|
||||
explicit DefnOrHeader(Definition *defn) {
|
||||
u.defn = defn;
|
||||
JS_ASSERT(!isHeader());
|
||||
}
|
||||
|
@ -225,7 +227,7 @@ class DefnOrHeader
|
|||
return u.bits & 0x1;
|
||||
}
|
||||
|
||||
JSDefinition *defn() const {
|
||||
Definition *defn() const {
|
||||
JS_ASSERT(!isHeader());
|
||||
return u.defn;
|
||||
}
|
||||
|
@ -268,7 +270,7 @@ class AtomDecls
|
|||
AtomDecls(const AtomDecls &other);
|
||||
void operator=(const AtomDecls &other);
|
||||
|
||||
AtomDeclNode *allocNode(JSDefinition *defn);
|
||||
AtomDeclNode *allocNode(Definition *defn);
|
||||
|
||||
/*
|
||||
* Fallibly return the value in |doh| as a node.
|
||||
|
@ -290,18 +292,18 @@ class AtomDecls
|
|||
}
|
||||
|
||||
/* Return the definition at the head of the chain for |atom|. */
|
||||
inline JSDefinition *lookupFirst(JSAtom *atom);
|
||||
inline Definition *lookupFirst(JSAtom *atom);
|
||||
|
||||
/* Perform a lookup that can iterate over the definitions associated with |atom|. */
|
||||
inline MultiDeclRange lookupMulti(JSAtom *atom);
|
||||
|
||||
/* Add-or-update a known-unique definition for |atom|. */
|
||||
inline bool addUnique(JSAtom *atom, JSDefinition *defn);
|
||||
bool addShadow(JSAtom *atom, JSDefinition *defn);
|
||||
bool addHoist(JSAtom *atom, JSDefinition *defn);
|
||||
inline bool addUnique(JSAtom *atom, Definition *defn);
|
||||
bool addShadow(JSAtom *atom, Definition *defn);
|
||||
bool addHoist(JSAtom *atom, Definition *defn);
|
||||
|
||||
/* Updating the definition for an entry that is known to exist is infallible. */
|
||||
void updateFirst(JSAtom *atom, JSDefinition *defn) {
|
||||
void updateFirst(JSAtom *atom, Definition *defn) {
|
||||
JS_ASSERT(map);
|
||||
AtomDOHMap::Ptr p = map->lookup(atom);
|
||||
JS_ASSERT(p);
|
||||
|
@ -352,9 +354,9 @@ class MultiDeclRange
|
|||
friend class AtomDecls;
|
||||
|
||||
AtomDeclNode *node;
|
||||
JSDefinition *defn;
|
||||
Definition *defn;
|
||||
|
||||
explicit MultiDeclRange(JSDefinition *defn) : node(NULL), defn(defn) {}
|
||||
explicit MultiDeclRange(Definition *defn) : node(NULL), defn(defn) {}
|
||||
explicit MultiDeclRange(AtomDeclNode *node) : node(node), defn(node->defn) {}
|
||||
|
||||
public:
|
||||
|
@ -368,7 +370,7 @@ class MultiDeclRange
|
|||
defn = node ? node->defn : NULL;
|
||||
}
|
||||
|
||||
JSDefinition *front() {
|
||||
Definition *front() {
|
||||
JS_ASSERT(!empty());
|
||||
return defn;
|
||||
}
|
||||
|
@ -388,10 +390,10 @@ class AtomDeclsIter
|
|||
public:
|
||||
explicit AtomDeclsIter(AtomDecls *decls) : r(decls->all()), link(NULL) {}
|
||||
|
||||
JSDefinition *operator()() {
|
||||
Definition *operator()() {
|
||||
if (link) {
|
||||
JS_ASSERT(link != link->next);
|
||||
JSDefinition *result = link->defn;
|
||||
Definition *result = link->defn;
|
||||
link = link->next;
|
||||
JS_ASSERT(result);
|
||||
return result;
|
||||
|
|
|
@ -44,11 +44,11 @@
|
|||
#include "frontend/BytecodeGenerator.h"
|
||||
#include "frontend/TokenStream.h"
|
||||
|
||||
inline bool
|
||||
JSParseNode::isConstant()
|
||||
{
|
||||
using namespace js;
|
||||
namespace js {
|
||||
|
||||
inline bool
|
||||
ParseNode::isConstant()
|
||||
{
|
||||
switch (pn_type) {
|
||||
case TOK_NUMBER:
|
||||
case TOK_STRING:
|
||||
|
@ -70,10 +70,8 @@ JSParseNode::isConstant()
|
|||
}
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
inline void
|
||||
NameNode::initCommon(JSTreeContext *tc)
|
||||
NameNode::initCommon(TreeContext *tc)
|
||||
{
|
||||
pn_expr = NULL;
|
||||
pn_cookie.makeFree();
|
||||
|
|
|
@ -40,9 +40,6 @@
|
|||
|
||||
#include "frontend/ParseNode.h"
|
||||
|
||||
#include "frontend/BytecodeGenerator.h"
|
||||
#include "frontend/Parser.h"
|
||||
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
#include "frontend/ParseMaps-inl.h"
|
||||
|
@ -53,21 +50,23 @@ using namespace js;
|
|||
/*
|
||||
* Asserts to verify assumptions behind pn_ macros.
|
||||
*/
|
||||
#define pn_offsetof(m) offsetof(JSParseNode, m)
|
||||
#define pn_offsetof(m) offsetof(ParseNode, m)
|
||||
|
||||
JS_STATIC_ASSERT(pn_offsetof(pn_link) == pn_offsetof(dn_uses));
|
||||
|
||||
#undef pn_offsetof
|
||||
|
||||
namespace js {
|
||||
|
||||
void
|
||||
JSParseNode::become(JSParseNode *pn2)
|
||||
ParseNode::become(ParseNode *pn2)
|
||||
{
|
||||
JS_ASSERT(!pn_defn);
|
||||
JS_ASSERT(!pn2->isDefn());
|
||||
|
||||
JS_ASSERT(!pn_used);
|
||||
if (pn2->isUsed()) {
|
||||
JSParseNode **pnup = &pn2->pn_lexdef->dn_uses;
|
||||
ParseNode **pnup = &pn2->pn_lexdef->dn_uses;
|
||||
while (*pnup != pn2)
|
||||
pnup = &(*pnup)->pn_link;
|
||||
*pnup = this;
|
||||
|
@ -102,7 +101,7 @@ JSParseNode::become(JSParseNode *pn2)
|
|||
}
|
||||
|
||||
void
|
||||
JSParseNode::clear()
|
||||
ParseNode::clear()
|
||||
{
|
||||
pn_type = TOK_EOF;
|
||||
setOp(JSOP_NOP);
|
||||
|
@ -111,9 +110,8 @@ JSParseNode::clear()
|
|||
pn_parens = false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
JSFunctionBox::joinable() const
|
||||
FunctionBox::joinable() const
|
||||
{
|
||||
return function()->isNullClosure() &&
|
||||
(tcflags & (TCF_FUN_USES_ARGUMENTS |
|
||||
|
@ -122,9 +120,9 @@ JSFunctionBox::joinable() const
|
|||
}
|
||||
|
||||
bool
|
||||
JSFunctionBox::inAnyDynamicScope() const
|
||||
FunctionBox::inAnyDynamicScope() const
|
||||
{
|
||||
for (const JSFunctionBox *funbox = this; funbox; funbox = funbox->parent) {
|
||||
for (const FunctionBox *funbox = this; funbox; funbox = funbox->parent) {
|
||||
if (funbox->tcflags & (TCF_IN_WITH | TCF_FUN_EXTENSIBLE_SCOPE))
|
||||
return true;
|
||||
}
|
||||
|
@ -132,16 +130,16 @@ JSFunctionBox::inAnyDynamicScope() const
|
|||
}
|
||||
|
||||
bool
|
||||
JSFunctionBox::scopeIsExtensible() const
|
||||
FunctionBox::scopeIsExtensible() const
|
||||
{
|
||||
return tcflags & TCF_FUN_EXTENSIBLE_SCOPE;
|
||||
}
|
||||
|
||||
bool
|
||||
JSFunctionBox::shouldUnbrand(uintN methods, uintN slowMethods) const
|
||||
FunctionBox::shouldUnbrand(uintN methods, uintN slowMethods) const
|
||||
{
|
||||
if (slowMethods != 0) {
|
||||
for (const JSFunctionBox *funbox = this; funbox; funbox = funbox->parent) {
|
||||
for (const FunctionBox *funbox = this; funbox; funbox = funbox->parent) {
|
||||
if (!(funbox->tcflags & TCF_FUN_MODULE_PATTERN))
|
||||
return true;
|
||||
if (funbox->inLoop)
|
||||
|
@ -151,14 +149,12 @@ JSFunctionBox::shouldUnbrand(uintN methods, uintN slowMethods) const
|
|||
return false;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
/* Add |node| to |parser|'s free node list. */
|
||||
void
|
||||
AddNodeToFreeList(JSParseNode *pn, js::Parser *parser)
|
||||
ParseNodeAllocator::freeNode(ParseNode *pn)
|
||||
{
|
||||
/* Catch back-to-back dup recycles. */
|
||||
JS_ASSERT(pn != parser->nodeList);
|
||||
JS_ASSERT(pn != freelist);
|
||||
|
||||
/*
|
||||
* It's too hard to clear these nodes from the AtomDefnMaps, etc. that
|
||||
|
@ -170,19 +166,19 @@ AddNodeToFreeList(JSParseNode *pn, js::Parser *parser)
|
|||
JS_ASSERT(!pn->isDefn());
|
||||
|
||||
if (pn->isArity(PN_NAMESET) && pn->pn_names.hasMap())
|
||||
pn->pn_names.releaseMap(parser->context);
|
||||
pn->pn_names.releaseMap(cx);
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Poison the node, to catch attempts to use it without initializing it. */
|
||||
memset(pn, 0xab, sizeof(*pn));
|
||||
#endif
|
||||
|
||||
pn->pn_next = parser->nodeList;
|
||||
parser->nodeList = pn;
|
||||
pn->pn_next = freelist;
|
||||
freelist = pn;
|
||||
}
|
||||
|
||||
/*
|
||||
* A work pool of JSParseNodes. The work pool is a stack, chained together
|
||||
* A work pool of ParseNodes. The work pool is a stack, chained together
|
||||
* by nodes' pn_next fields. We use this to avoid creating deep C++ stacks
|
||||
* when recycling deep parse trees.
|
||||
*
|
||||
|
@ -194,59 +190,56 @@ class NodeStack {
|
|||
public:
|
||||
NodeStack() : top(NULL) { }
|
||||
bool empty() { return top == NULL; }
|
||||
void push(JSParseNode *pn) {
|
||||
void push(ParseNode *pn) {
|
||||
pn->pn_next = top;
|
||||
top = pn;
|
||||
}
|
||||
void pushUnlessNull(JSParseNode *pn) { if (pn) push(pn); }
|
||||
void pushUnlessNull(ParseNode *pn) { if (pn) push(pn); }
|
||||
/* Push the children of the PN_LIST node |pn| on the stack. */
|
||||
void pushList(JSParseNode *pn) {
|
||||
void pushList(ParseNode *pn) {
|
||||
/* This clobbers pn->pn_head if the list is empty; should be okay. */
|
||||
*pn->pn_tail = top;
|
||||
top = pn->pn_head;
|
||||
}
|
||||
JSParseNode *pop() {
|
||||
ParseNode *pop() {
|
||||
JS_ASSERT(!empty());
|
||||
JSParseNode *hold = top; /* my kingdom for a prog1 */
|
||||
ParseNode *hold = top; /* my kingdom for a prog1 */
|
||||
top = top->pn_next;
|
||||
return hold;
|
||||
}
|
||||
private:
|
||||
JSParseNode *top;
|
||||
ParseNode *top;
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
/*
|
||||
* Push the children of |pn| on |stack|. Return true if |pn| itself could be
|
||||
* safely recycled, or false if it must be cleaned later (pn_used and pn_defn
|
||||
* nodes, and all function nodes; see comments for
|
||||
* js::Parser::cleanFunctionList). Some callers want to free |pn|; others
|
||||
* (PrepareNodeForMutation) don't care about |pn|, and just need to take care of
|
||||
* its children.
|
||||
* (js::ParseNodeAllocator::prepareNodeForMutation) don't care about |pn|, and
|
||||
* just need to take care of its children.
|
||||
*/
|
||||
static bool
|
||||
PushNodeChildren(JSParseNode *pn, NodeStack *stack)
|
||||
PushNodeChildren(ParseNode *pn, NodeStack *stack)
|
||||
{
|
||||
switch (pn->getArity()) {
|
||||
case PN_FUNC:
|
||||
/*
|
||||
* Function nodes are linked into the function box tree, and may
|
||||
* appear on method lists. Both of those lists are singly-linked,
|
||||
* so trying to update them now could result in quadratic behavior
|
||||
* when recycling trees containing many functions; and the lists
|
||||
* can be very long. So we put off cleaning the lists up until just
|
||||
* before function analysis, when we call
|
||||
* js::Parser::cleanFunctionList.
|
||||
* Function nodes are linked into the function box tree, and may appear
|
||||
* on method lists. Both of those lists are singly-linked, so trying to
|
||||
* update them now could result in quadratic behavior when recycling
|
||||
* trees containing many functions; and the lists can be very long. So
|
||||
* we put off cleaning the lists up until just before function
|
||||
* analysis, when we call js::Parser::cleanFunctionList.
|
||||
*
|
||||
* In fact, we can't recycle the parse node yet, either: it may
|
||||
* appear on a method list, and reusing the node would corrupt
|
||||
* that. Instead, we clear its pn_funbox pointer to mark it as
|
||||
* deleted; js::Parser::cleanFunctionList recycles it as well.
|
||||
* In fact, we can't recycle the parse node yet, either: it may appear
|
||||
* on a method list, and reusing the node would corrupt that. Instead,
|
||||
* we clear its pn_funbox pointer to mark it as deleted;
|
||||
* js::Parser::cleanFunctionList recycles it as well.
|
||||
*
|
||||
* We do recycle the nodes around it, though, so we must clear
|
||||
* pointers to them to avoid leaving dangling references where
|
||||
* someone can find them.
|
||||
* We do recycle the nodes around it, though, so we must clear pointers
|
||||
* to them to avoid leaving dangling references where someone can find
|
||||
* them.
|
||||
*/
|
||||
pn->pn_funbox = NULL;
|
||||
stack->pushUnlessNull(pn->pn_body);
|
||||
|
@ -256,12 +249,11 @@ PushNodeChildren(JSParseNode *pn, NodeStack *stack)
|
|||
case PN_NAME:
|
||||
/*
|
||||
* Because used/defn nodes appear in AtomDefnMaps and elsewhere, we
|
||||
* don't recycle them. (We'll recover their storage when we free
|
||||
* the temporary arena.) However, we do recycle the nodes around
|
||||
* them, so clean up the pointers to avoid dangling references. The
|
||||
* top-level decls table carries references to them that later
|
||||
* iterations through the compileScript loop may find, so they need
|
||||
* to be neat.
|
||||
* don't recycle them. (We'll recover their storage when we free the
|
||||
* temporary arena.) However, we do recycle the nodes around them, so
|
||||
* clean up the pointers to avoid dangling references. The top-level
|
||||
* decls table carries references to them that later iterations through
|
||||
* the compileScript loop may find, so they need to be neat.
|
||||
*
|
||||
* pn_expr and pn_lexdef share storage; the latter isn't an owning
|
||||
* reference.
|
||||
|
@ -301,15 +293,13 @@ PushNodeChildren(JSParseNode *pn, NodeStack *stack)
|
|||
return true;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* Prepare |pn| to be mutated in place into a new kind of node. Recycle all
|
||||
* |pn|'s recyclable children (but not |pn| itself!), and disconnect it from
|
||||
* metadata structures (the function box tree).
|
||||
*/
|
||||
void
|
||||
PrepareNodeForMutation(JSParseNode *pn, JSTreeContext *tc)
|
||||
ParseNodeAllocator::prepareNodeForMutation(ParseNode *pn)
|
||||
{
|
||||
if (!pn->isArity(PN_NULLARY)) {
|
||||
if (pn->isArity(PN_FUNC)) {
|
||||
|
@ -340,7 +330,7 @@ PrepareNodeForMutation(JSParseNode *pn, JSTreeContext *tc)
|
|||
while (!stack.empty()) {
|
||||
pn = stack.pop();
|
||||
if (PushNodeChildren(pn, &stack))
|
||||
AddNodeToFreeList(pn, tc->parser);
|
||||
freeNode(pn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -355,18 +345,18 @@ PrepareNodeForMutation(JSParseNode *pn, JSTreeContext *tc)
|
|||
* recycle some part of it (unless you've updated |tc|->functionList, the
|
||||
* way js_FoldConstants does).
|
||||
*/
|
||||
JSParseNode *
|
||||
RecycleTree(JSParseNode *pn, JSTreeContext *tc)
|
||||
ParseNode *
|
||||
ParseNodeAllocator::freeTree(ParseNode *pn)
|
||||
{
|
||||
if (!pn)
|
||||
return NULL;
|
||||
|
||||
JSParseNode *savedNext = pn->pn_next;
|
||||
ParseNode *savedNext = pn->pn_next;
|
||||
|
||||
NodeStack stack;
|
||||
for (;;) {
|
||||
if (PushNodeChildren(pn, &stack))
|
||||
AddNodeToFreeList(pn, tc->parser);
|
||||
freeNode(pn);
|
||||
if (stack.empty())
|
||||
break;
|
||||
pn = stack.pop();
|
||||
|
@ -376,62 +366,37 @@ RecycleTree(JSParseNode *pn, JSTreeContext *tc)
|
|||
}
|
||||
|
||||
/*
|
||||
* Allocate a JSParseNode from tc's node freelist or, failing that, from
|
||||
* Allocate a ParseNode from parser's node freelist or, failing that, from
|
||||
* cx's temporary arena.
|
||||
*/
|
||||
JSParseNode *
|
||||
NewOrRecycledNode(JSTreeContext *tc)
|
||||
void *
|
||||
ParseNodeAllocator::allocNode()
|
||||
{
|
||||
JSParseNode *pn;
|
||||
|
||||
pn = tc->parser->nodeList;
|
||||
if (!pn) {
|
||||
JSContext *cx = tc->parser->context;
|
||||
pn = cx->tempLifoAlloc().new_<JSParseNode>();
|
||||
if (!pn)
|
||||
js_ReportOutOfMemory(cx);
|
||||
} else {
|
||||
tc->parser->nodeList = pn->pn_next;
|
||||
if (ParseNode *pn = freelist) {
|
||||
freelist = pn->pn_next;
|
||||
return pn;
|
||||
}
|
||||
|
||||
if (pn) {
|
||||
pn->setUsed(false);
|
||||
pn->setDefn(false);
|
||||
memset(&pn->pn_u, 0, sizeof pn->pn_u);
|
||||
pn->pn_next = NULL;
|
||||
}
|
||||
return pn;
|
||||
void *p = cx->tempLifoAlloc().alloc(sizeof (ParseNode));
|
||||
if (!p)
|
||||
js_ReportOutOfMemory(cx);
|
||||
return p;
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
/* used only by static create methods of subclasses */
|
||||
|
||||
JSParseNode *
|
||||
JSParseNode::create(JSParseNodeArity arity, JSTreeContext *tc)
|
||||
ParseNode *
|
||||
ParseNode::create(ParseNodeArity arity, TreeContext *tc)
|
||||
{
|
||||
const Token &tok = tc->parser->tokenStream.currentToken();
|
||||
return create(arity, tok.type, JSOP_NOP, tok.pos, tc);
|
||||
Parser *parser = tc->parser;
|
||||
const Token &tok = parser->tokenStream.currentToken();
|
||||
return parser->new_<ParseNode>(tok.type, JSOP_NOP, arity, tok.pos);
|
||||
}
|
||||
|
||||
JSParseNode *
|
||||
JSParseNode::create(JSParseNodeArity arity, TokenKind type, JSOp op, const TokenPos &pos,
|
||||
JSTreeContext *tc)
|
||||
ParseNode *
|
||||
ParseNode::newBinaryOrAppend(TokenKind tt, JSOp op, ParseNode *left, ParseNode *right,
|
||||
TreeContext *tc)
|
||||
{
|
||||
JSParseNode *pn = NewOrRecycledNode(tc);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->init(type, op, arity);
|
||||
pn->pn_pos = pos;
|
||||
return pn;
|
||||
}
|
||||
|
||||
JSParseNode *
|
||||
JSParseNode::newBinaryOrAppend(TokenKind tt, JSOp op, JSParseNode *left, JSParseNode *right,
|
||||
JSTreeContext *tc)
|
||||
{
|
||||
JSParseNode *pn, *pn1, *pn2;
|
||||
|
||||
if (!left || !right)
|
||||
return NULL;
|
||||
|
||||
|
@ -439,11 +404,9 @@ JSParseNode::newBinaryOrAppend(TokenKind tt, JSOp op, JSParseNode *left, JSParse
|
|||
* Flatten a left-associative (left-heavy) tree of a given operator into
|
||||
* a list, to reduce js_FoldConstants and js_EmitTree recursion.
|
||||
*/
|
||||
if (left->isKind(tt) &&
|
||||
left->isOp(op) &&
|
||||
(js_CodeSpec[op].format & JOF_LEFTASSOC)) {
|
||||
if (left->isKind(tt) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC)) {
|
||||
if (left->pn_arity != PN_LIST) {
|
||||
pn1 = left->pn_left, pn2 = left->pn_right;
|
||||
ParseNode *pn1 = left->pn_left, *pn2 = left->pn_right;
|
||||
left->setArity(PN_LIST);
|
||||
left->pn_parens = false;
|
||||
left->initList(pn1);
|
||||
|
@ -480,32 +443,21 @@ JSParseNode::newBinaryOrAppend(TokenKind tt, JSOp op, JSParseNode *left, JSParse
|
|||
if (tt == TOK_PLUS &&
|
||||
left->isKind(TOK_NUMBER) &&
|
||||
right->isKind(TOK_NUMBER) &&
|
||||
tc->parser->foldConstants) {
|
||||
tc->parser->foldConstants)
|
||||
{
|
||||
left->pn_dval += right->pn_dval;
|
||||
left->pn_pos.end = right->pn_pos.end;
|
||||
RecycleTree(right, tc);
|
||||
tc->freeTree(right);
|
||||
return left;
|
||||
}
|
||||
|
||||
pn = NewOrRecycledNode(tc);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->init(tt, op, PN_BINARY);
|
||||
pn->pn_pos.begin = left->pn_pos.begin;
|
||||
pn->pn_pos.end = right->pn_pos.end;
|
||||
pn->pn_left = left;
|
||||
pn->pn_right = right;
|
||||
return pn;
|
||||
return tc->parser->new_<BinaryNode>(tt, op, left, right);
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
NameNode *
|
||||
NameNode::create(JSAtom *atom, JSTreeContext *tc)
|
||||
NameNode::create(JSAtom *atom, TreeContext *tc)
|
||||
{
|
||||
JSParseNode *pn;
|
||||
|
||||
pn = JSParseNode::create(PN_NAME, tc);
|
||||
ParseNode *pn = ParseNode::create(PN_NAME, tc);
|
||||
if (pn) {
|
||||
pn->pn_atom = atom;
|
||||
((NameNode *)pn)->initCommon(tc);
|
||||
|
@ -519,8 +471,10 @@ const char js_argument_str[] = "argument";
|
|||
const char js_variable_str[] = "variable";
|
||||
const char js_unknown_str[] = "unknown";
|
||||
|
||||
namespace js {
|
||||
|
||||
const char *
|
||||
JSDefinition::kindString(Kind kind)
|
||||
Definition::kindString(Kind kind)
|
||||
{
|
||||
static const char *table[] = {
|
||||
js_var_str, js_const_str, js_let_str,
|
||||
|
@ -537,23 +491,18 @@ JSDefinition::kindString(Kind kind)
|
|||
* This function assumes the cloned tree is for use in the same statement and
|
||||
* binding context as the original tree.
|
||||
*/
|
||||
static JSParseNode *
|
||||
CloneParseTree(JSParseNode *opn, JSTreeContext *tc)
|
||||
static ParseNode *
|
||||
CloneParseTree(ParseNode *opn, TreeContext *tc)
|
||||
{
|
||||
JS_CHECK_RECURSION(tc->parser->context, return NULL);
|
||||
|
||||
JSParseNode *pn, *pn2, *opn2;
|
||||
|
||||
pn = NewOrRecycledNode(tc);
|
||||
ParseNode *pn = tc->parser->new_<ParseNode>(opn->getKind(), opn->getOp(), opn->getArity(),
|
||||
opn->pn_pos);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->setKind(opn->getKind());
|
||||
pn->setOp(opn->getOp());
|
||||
pn->setUsed(opn->isUsed());
|
||||
pn->setDefn(opn->isDefn());
|
||||
pn->setArity(opn->getArity());
|
||||
pn->setInParens(opn->isInParens());
|
||||
pn->pn_pos = opn->pn_pos;
|
||||
pn->setDefn(opn->isDefn());
|
||||
pn->setUsed(opn->isUsed());
|
||||
|
||||
switch (pn->getArity()) {
|
||||
#define NULLCHECK(e) JS_BEGIN_MACRO if (!(e)) return NULL; JS_END_MACRO
|
||||
|
@ -569,7 +518,8 @@ CloneParseTree(JSParseNode *opn, JSTreeContext *tc)
|
|||
|
||||
case PN_LIST:
|
||||
pn->makeEmpty();
|
||||
for (opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) {
|
||||
for (ParseNode *opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) {
|
||||
ParseNode *pn2;
|
||||
NULLCHECK(pn2 = CloneParseTree(opn2, tc));
|
||||
pn->append(pn2);
|
||||
}
|
||||
|
@ -606,7 +556,7 @@ CloneParseTree(JSParseNode *opn, JSTreeContext *tc)
|
|||
* The old name is a use of its pn_lexdef. Make the clone also be a
|
||||
* use of that definition.
|
||||
*/
|
||||
JSDefinition *dn = pn->pn_lexdef;
|
||||
Definition *dn = pn->pn_lexdef;
|
||||
|
||||
pn->pn_link = dn->dn_uses;
|
||||
dn->dn_uses = pn;
|
||||
|
@ -619,7 +569,7 @@ CloneParseTree(JSParseNode *opn, JSTreeContext *tc)
|
|||
*/
|
||||
if (opn->isDefn()) {
|
||||
opn->setDefn(false);
|
||||
LinkUseToDef(opn, (JSDefinition *) pn, tc);
|
||||
LinkUseToDef(opn, (Definition *) pn, tc);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -641,8 +591,6 @@ CloneParseTree(JSParseNode *opn, JSTreeContext *tc)
|
|||
|
||||
#endif /* JS_HAS_DESTRUCTURING */
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* Used by Parser::forStatement and comprehensionTail to clone the TARGET in
|
||||
* for (var/const/let TARGET in EXPR)
|
||||
|
@ -653,37 +601,35 @@ namespace js {
|
|||
* The cloned tree is for use only in the same statement and binding context as
|
||||
* the original tree.
|
||||
*/
|
||||
JSParseNode *
|
||||
CloneLeftHandSide(JSParseNode *opn, JSTreeContext *tc)
|
||||
ParseNode *
|
||||
CloneLeftHandSide(ParseNode *opn, TreeContext *tc)
|
||||
{
|
||||
JSParseNode *pn = NewOrRecycledNode(tc);
|
||||
ParseNode *pn = tc->parser->new_<ParseNode>(opn->getKind(), opn->getOp(), opn->getArity(),
|
||||
opn->pn_pos);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->setKind(opn->getKind());
|
||||
pn->setOp(opn->getOp());
|
||||
pn->setUsed(opn->isUsed());
|
||||
pn->setDefn(opn->isDefn());
|
||||
pn->setArity(opn->getArity());
|
||||
pn->setInParens(opn->isInParens());
|
||||
pn->pn_pos = opn->pn_pos;
|
||||
pn->setDefn(opn->isDefn());
|
||||
pn->setUsed(opn->isUsed());
|
||||
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
if (opn->isArity(PN_LIST)) {
|
||||
JS_ASSERT(opn->isKind(TOK_RB) || opn->isKind(TOK_RC));
|
||||
pn->makeEmpty();
|
||||
for (JSParseNode *opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) {
|
||||
JSParseNode *pn2;
|
||||
for (ParseNode *opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) {
|
||||
ParseNode *pn2;
|
||||
if (opn->isKind(TOK_RC)) {
|
||||
JS_ASSERT(opn2->isArity(PN_BINARY));
|
||||
JS_ASSERT(opn2->isKind(TOK_COLON));
|
||||
|
||||
JSParseNode *tag = CloneParseTree(opn2->pn_left, tc);
|
||||
ParseNode *tag = CloneParseTree(opn2->pn_left, tc);
|
||||
if (!tag)
|
||||
return NULL;
|
||||
JSParseNode *target = CloneLeftHandSide(opn2->pn_right, tc);
|
||||
ParseNode *target = CloneLeftHandSide(opn2->pn_right, tc);
|
||||
if (!target)
|
||||
return NULL;
|
||||
pn2 = BinaryNode::create(TOK_COLON, JSOP_INITPROP, opn2->pn_pos, tag, target, tc);
|
||||
|
||||
pn2 = tc->parser->new_<BinaryNode>(TOK_COLON, JSOP_INITPROP, opn2->pn_pos, tag, target);
|
||||
} else if (opn2->isArity(PN_NULLARY)) {
|
||||
JS_ASSERT(opn2->isKind(TOK_COMMA));
|
||||
pn2 = CloneParseTree(opn2, tc);
|
||||
|
@ -707,7 +653,7 @@ CloneLeftHandSide(JSParseNode *opn, JSTreeContext *tc)
|
|||
pn->pn_u.name = opn->pn_u.name;
|
||||
pn->setOp(JSOP_SETNAME);
|
||||
if (opn->isUsed()) {
|
||||
JSDefinition *dn = pn->pn_lexdef;
|
||||
Definition *dn = pn->pn_lexdef;
|
||||
|
||||
pn->pn_link = dn->dn_uses;
|
||||
dn->dn_uses = pn;
|
||||
|
@ -719,7 +665,7 @@ CloneLeftHandSide(JSParseNode *opn, JSTreeContext *tc)
|
|||
pn->pn_dflags &= ~PND_BOUND;
|
||||
pn->setDefn(false);
|
||||
|
||||
LinkUseToDef(pn, (JSDefinition *) opn, tc);
|
||||
LinkUseToDef(pn, (Definition *) opn, tc);
|
||||
}
|
||||
}
|
||||
return pn;
|
||||
|
|
|
@ -46,6 +46,8 @@
|
|||
#include "frontend/ParseMaps.h"
|
||||
#include "frontend/TokenStream.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* Parsing builds a tree of nodes that directs code generation. This tree is
|
||||
* not a concrete syntax tree in all respects (for example, || and && are left
|
||||
|
@ -57,7 +59,7 @@
|
|||
* Label Variant Members
|
||||
* ----- ------- -------
|
||||
* <Definitions>
|
||||
* TOK_FUNCTION name pn_funbox: ptr to JSFunctionBox holding function
|
||||
* TOK_FUNCTION name pn_funbox: ptr to js::FunctionBox holding function
|
||||
* object containing arg and var properties. We
|
||||
* create the function object at parse (not emit)
|
||||
* time to specialize arg and var bytecodes early.
|
||||
|
@ -74,7 +76,7 @@
|
|||
* TOK_ARGSBODY list list of formal parameters followed by TOK_LC node
|
||||
* for function body statements as final element
|
||||
* pn_count: 1 + number of formal parameters
|
||||
* TOK_UPVARS nameset pn_names: lexical dependencies (JSDefinitions)
|
||||
* TOK_UPVARS nameset pn_names: lexical dependencies (js::Definitions)
|
||||
* defined in enclosing scopes, or ultimately not
|
||||
* defined (free variables, either global property
|
||||
* references or reference errors).
|
||||
|
@ -281,7 +283,7 @@
|
|||
* Label Variant Members
|
||||
* ----- ------- -------
|
||||
* TOK_LEXICALSCOPE name pn_op: JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR
|
||||
* pn_objbox: block object in JSObjectBox holder
|
||||
* pn_objbox: block object in ObjectBox holder
|
||||
* pn_expr: block body
|
||||
* TOK_ARRAYCOMP list pn_count: 1
|
||||
* pn_head: list of 1 element, which is block
|
||||
|
@ -290,7 +292,7 @@
|
|||
* TOK_ARRAYPUSH unary pn_op: JSOP_ARRAYCOMP
|
||||
* pn_kid: array comprehension expression
|
||||
*/
|
||||
typedef enum JSParseNodeArity {
|
||||
enum ParseNodeArity {
|
||||
PN_NULLARY, /* 0 kids, only pn_atom/pn_dval/etc. */
|
||||
PN_UNARY, /* one kid, plus a couple of scalars */
|
||||
PN_BINARY, /* two kids, plus a couple of scalars */
|
||||
|
@ -298,65 +300,85 @@ typedef enum JSParseNodeArity {
|
|||
PN_FUNC, /* function definition node */
|
||||
PN_LIST, /* generic singly linked list */
|
||||
PN_NAME, /* name use or definition node */
|
||||
PN_NAMESET /* JSAtomDefnMapPtr + JSParseNode ptr */
|
||||
} JSParseNodeArity;
|
||||
PN_NAMESET /* AtomDefnMapPtr + ParseNode ptr */
|
||||
};
|
||||
|
||||
struct JSDefinition;
|
||||
struct Definition;
|
||||
|
||||
struct JSParseNode {
|
||||
struct ParseNode {
|
||||
private:
|
||||
uint32 pn_type : 16, /* TOK_* type, see frontend/TokenStream.h */
|
||||
pn_op : 8, /* see JSOp enum and jsopcode.tbl */
|
||||
pn_arity : 5, /* see JSParseNodeArity enum */
|
||||
pn_arity : 5, /* see ParseNodeArity enum */
|
||||
pn_parens : 1, /* this expr was enclosed in parens */
|
||||
pn_used : 1, /* name node is on a use-chain */
|
||||
pn_defn : 1; /* this node is a JSDefinition */
|
||||
pn_defn : 1; /* this node is a Definition */
|
||||
|
||||
public:
|
||||
ParseNode(TokenKind type, JSOp op, ParseNodeArity arity)
|
||||
: pn_type(type), pn_op(op), pn_arity(arity), pn_parens(0), pn_used(0), pn_defn(0),
|
||||
pn_offset(0), pn_next(NULL), pn_link(NULL)
|
||||
{
|
||||
pn_pos.begin.index = 0;
|
||||
pn_pos.begin.lineno = 0;
|
||||
pn_pos.end.index = 0;
|
||||
pn_pos.end.lineno = 0;
|
||||
memset(&pn_u, 0, sizeof pn_u);
|
||||
}
|
||||
|
||||
ParseNode(TokenKind type, JSOp op, ParseNodeArity arity, const TokenPos &pos)
|
||||
: pn_type(type), pn_op(op), pn_arity(arity), pn_parens(0), pn_used(0), pn_defn(0),
|
||||
pn_pos(pos), pn_offset(0), pn_next(NULL), pn_link(NULL)
|
||||
{
|
||||
memset(&pn_u, 0, sizeof pn_u);
|
||||
}
|
||||
|
||||
JSOp getOp() const { return JSOp(pn_op); }
|
||||
void setOp(JSOp op) { pn_op = op; }
|
||||
bool isOp(JSOp op) const { return getOp() == op; }
|
||||
js::TokenKind getKind() const { return js::TokenKind(pn_type); }
|
||||
void setKind(js::TokenKind kind) { pn_type = kind; }
|
||||
bool isKind(js::TokenKind kind) const { return getKind() == kind; }
|
||||
JSParseNodeArity getArity() const { return JSParseNodeArity(pn_arity); }
|
||||
bool isArity(JSParseNodeArity a) const { return getArity() == a; }
|
||||
void setArity(JSParseNodeArity a) { pn_arity = a; }
|
||||
TokenKind getKind() const { return TokenKind(pn_type); }
|
||||
void setKind(TokenKind kind) { pn_type = kind; }
|
||||
bool isKind(TokenKind kind) const { return getKind() == kind; }
|
||||
ParseNodeArity getArity() const { return ParseNodeArity(pn_arity); }
|
||||
bool isArity(ParseNodeArity a) const { return getArity() == a; }
|
||||
void setArity(ParseNodeArity a) { pn_arity = a; }
|
||||
|
||||
/* Boolean attributes. */
|
||||
bool isInParens() const { return pn_parens; }
|
||||
void setInParens(bool enabled) { pn_parens = enabled; }
|
||||
bool isDefn() const { return pn_defn; }
|
||||
void setDefn(bool enabled) { pn_defn = enabled; }
|
||||
bool isUsed() const { return pn_used; }
|
||||
void setUsed(bool enabled) { pn_used = enabled; }
|
||||
bool isDefn() const { return pn_defn; }
|
||||
void setDefn(bool enabled) { pn_defn = enabled; }
|
||||
|
||||
js::TokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */
|
||||
TokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */
|
||||
int32 pn_offset; /* first generated bytecode offset */
|
||||
JSParseNode *pn_next; /* intrinsic link in parent PN_LIST */
|
||||
JSParseNode *pn_link; /* def/use link (alignment freebie);
|
||||
also links JSFunctionBox::methods
|
||||
ParseNode *pn_next; /* intrinsic link in parent PN_LIST */
|
||||
ParseNode *pn_link; /* def/use link (alignment freebie);
|
||||
also links FunctionBox::methods
|
||||
lists of would-be |this| methods */
|
||||
|
||||
union {
|
||||
struct { /* list of next-linked nodes */
|
||||
JSParseNode *head; /* first node in list */
|
||||
JSParseNode **tail; /* ptr to ptr to last node in list */
|
||||
ParseNode *head; /* first node in list */
|
||||
ParseNode **tail; /* ptr to ptr to last node in list */
|
||||
uint32 count; /* number of nodes in list */
|
||||
uint32 xflags:12, /* extra flags, see below */
|
||||
blockid:20; /* see name variant below */
|
||||
} list;
|
||||
struct { /* ternary: if, for(;;), ?: */
|
||||
JSParseNode *kid1; /* condition, discriminant, etc. */
|
||||
JSParseNode *kid2; /* then-part, case list, etc. */
|
||||
JSParseNode *kid3; /* else-part, default case, etc. */
|
||||
ParseNode *kid1; /* condition, discriminant, etc. */
|
||||
ParseNode *kid2; /* then-part, case list, etc. */
|
||||
ParseNode *kid3; /* else-part, default case, etc. */
|
||||
} ternary;
|
||||
struct { /* two kids if binary */
|
||||
JSParseNode *left;
|
||||
JSParseNode *right;
|
||||
js::Value *pval; /* switch case value */
|
||||
ParseNode *left;
|
||||
ParseNode *right;
|
||||
Value *pval; /* switch case value */
|
||||
uintN iflags; /* JSITER_* flags for TOK_FOR node */
|
||||
} binary;
|
||||
struct { /* one kid if unary */
|
||||
JSParseNode *kid;
|
||||
ParseNode *kid;
|
||||
jsint num; /* -1 or sharp variable number */
|
||||
JSBool hidden; /* hidden genexp-induced JSOP_YIELD
|
||||
or directive prologue member (as
|
||||
|
@ -365,15 +387,15 @@ struct JSParseNode {
|
|||
struct { /* name, labeled statement, etc. */
|
||||
union {
|
||||
JSAtom *atom; /* lexical name or label atom */
|
||||
JSFunctionBox *funbox; /* function object */
|
||||
JSObjectBox *objbox; /* block or regexp object */
|
||||
FunctionBox *funbox; /* function object */
|
||||
ObjectBox *objbox; /* block or regexp object */
|
||||
};
|
||||
union {
|
||||
JSParseNode *expr; /* function body, var initializer, or
|
||||
ParseNode *expr; /* function body, var initializer, or
|
||||
base object of TOK_DOT */
|
||||
JSDefinition *lexdef; /* lexical definition for this use */
|
||||
Definition *lexdef; /* lexical definition for this use */
|
||||
};
|
||||
js::UpvarCookie cookie; /* upvar cookie with absolute frame
|
||||
UpvarCookie cookie; /* upvar cookie with absolute frame
|
||||
level (not relative skip), possibly
|
||||
in current frame */
|
||||
uint32 dflags:12, /* definition/use flags, see below */
|
||||
|
@ -381,11 +403,11 @@ struct JSParseNode {
|
|||
computation */
|
||||
} name;
|
||||
struct { /* lexical dependencies + sub-tree */
|
||||
js::AtomDefnMapPtr defnMap;
|
||||
JSParseNode *tree; /* sub-tree containing name uses */
|
||||
AtomDefnMapPtr defnMap;
|
||||
ParseNode *tree; /* sub-tree containing name uses */
|
||||
} nameset;
|
||||
struct { /* PN_NULLARY variant for E4X XML PI */
|
||||
js::PropertyName *target; /* target in <?target data?> */
|
||||
PropertyName *target; /* target in <?target data?> */
|
||||
JSAtom *data; /* data (or null) in <?target data?> */
|
||||
} xmlpi;
|
||||
jsdouble dval; /* aligned numeric literal value */
|
||||
|
@ -422,8 +444,8 @@ struct JSParseNode {
|
|||
#define pn_pitarget pn_u.xmlpi.target
|
||||
#define pn_pidata pn_u.xmlpi.data
|
||||
|
||||
protected:
|
||||
void init(js::TokenKind type, JSOp op, JSParseNodeArity arity) {
|
||||
protected:
|
||||
void init(TokenKind type, JSOp op, ParseNodeArity arity) {
|
||||
pn_type = type;
|
||||
pn_op = op;
|
||||
pn_arity = arity;
|
||||
|
@ -434,16 +456,11 @@ protected:
|
|||
pn_next = pn_link = NULL;
|
||||
}
|
||||
|
||||
static JSParseNode *create(JSParseNodeArity arity, JSTreeContext *tc);
|
||||
static JSParseNode *create(JSParseNodeArity arity, js::TokenKind type, JSOp op,
|
||||
const js::TokenPos &pos, JSTreeContext *tc);
|
||||
static ParseNode *create(ParseNodeArity arity, TreeContext *tc);
|
||||
|
||||
public:
|
||||
static JSParseNode *newBinaryOrAppend(js::TokenKind tt, JSOp op, JSParseNode *left,
|
||||
JSParseNode *right, JSTreeContext *tc);
|
||||
|
||||
static JSParseNode *newTernary(js::TokenKind tt, JSOp op, JSParseNode *kid1, JSParseNode *kid2,
|
||||
JSParseNode *kid3, JSTreeContext *tc);
|
||||
public:
|
||||
static ParseNode *newBinaryOrAppend(TokenKind tt, JSOp op, ParseNode *left, ParseNode *right,
|
||||
TreeContext *tc);
|
||||
|
||||
/*
|
||||
* The pn_expr and lexdef members are arms of an unsafe union. Unless you
|
||||
|
@ -451,20 +468,20 @@ public:
|
|||
* them. For less overhead and assertions for protection, use pn->expr()
|
||||
* and pn->lexdef(). Otherwise, use pn->maybeExpr() and pn->maybeLexDef().
|
||||
*/
|
||||
JSParseNode *expr() const {
|
||||
ParseNode *expr() const {
|
||||
JS_ASSERT(!pn_used);
|
||||
JS_ASSERT(pn_arity == PN_NAME || pn_arity == PN_FUNC);
|
||||
return pn_expr;
|
||||
}
|
||||
|
||||
JSDefinition *lexdef() const {
|
||||
Definition *lexdef() const {
|
||||
JS_ASSERT(pn_used || isDeoptimized());
|
||||
JS_ASSERT(pn_arity == PN_NAME);
|
||||
return pn_lexdef;
|
||||
}
|
||||
|
||||
JSParseNode *maybeExpr() { return pn_used ? NULL : expr(); }
|
||||
JSDefinition *maybeLexDef() { return pn_used ? lexdef() : NULL; }
|
||||
ParseNode *maybeExpr() { return pn_used ? NULL : expr(); }
|
||||
Definition *maybeLexDef() { return pn_used ? lexdef() : NULL; }
|
||||
|
||||
/* PN_FUNC and PN_NAME pn_dflags bits. */
|
||||
#define PND_LET 0x01 /* let (block-scoped) binding */
|
||||
|
@ -543,17 +560,17 @@ public:
|
|||
*/
|
||||
bool isTopLevel() const { return test(PND_TOPLEVEL); }
|
||||
|
||||
/* Defined below, see after struct JSDefinition. */
|
||||
/* Defined below, see after struct Definition. */
|
||||
void setFunArg();
|
||||
|
||||
void become(JSParseNode *pn2);
|
||||
void become(ParseNode *pn2);
|
||||
void clear();
|
||||
|
||||
/* True if pn is a parsenode representing a literal constant. */
|
||||
bool isLiteral() const {
|
||||
return isKind(js::TOK_NUMBER) ||
|
||||
isKind(js::TOK_STRING) ||
|
||||
(isKind(js::TOK_PRIMARY) && !isOp(JSOP_THIS));
|
||||
return isKind(TOK_NUMBER) ||
|
||||
isKind(TOK_STRING) ||
|
||||
(isKind(TOK_PRIMARY) && !isOp(JSOP_THIS));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -572,10 +589,10 @@ public:
|
|||
* a directive.
|
||||
*/
|
||||
bool isStringExprStatement() const {
|
||||
if (getKind() == js::TOK_SEMI) {
|
||||
if (getKind() == TOK_SEMI) {
|
||||
JS_ASSERT(pn_arity == PN_UNARY);
|
||||
JSParseNode *kid = pn_kid;
|
||||
return kid && kid->getKind() == js::TOK_STRING && !kid->pn_parens;
|
||||
ParseNode *kid = pn_kid;
|
||||
return kid && kid->getKind() == TOK_STRING && !kid->pn_parens;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -586,7 +603,7 @@ public:
|
|||
* contain escape sequences or line continuations.
|
||||
*/
|
||||
bool isEscapeFreeStringLiteral() const {
|
||||
JS_ASSERT(pn_type == js::TOK_STRING && !pn_parens);
|
||||
JS_ASSERT(pn_type == TOK_STRING && !pn_parens);
|
||||
JSString *str = pn_atom;
|
||||
|
||||
/*
|
||||
|
@ -606,26 +623,26 @@ public:
|
|||
* True if this node is a desugared generator expression.
|
||||
*/
|
||||
bool isGeneratorExpr() const {
|
||||
if (getKind() == js::TOK_LP) {
|
||||
JSParseNode *callee = this->pn_head;
|
||||
if (callee->getKind() == js::TOK_FUNCTION) {
|
||||
JSParseNode *body = (callee->pn_body->getKind() == js::TOK_UPVARS)
|
||||
? callee->pn_body->pn_tree
|
||||
: callee->pn_body;
|
||||
if (body->getKind() == js::TOK_LEXICALSCOPE)
|
||||
if (getKind() == TOK_LP) {
|
||||
ParseNode *callee = this->pn_head;
|
||||
if (callee->getKind() == TOK_FUNCTION) {
|
||||
ParseNode *body = (callee->pn_body->getKind() == TOK_UPVARS)
|
||||
? callee->pn_body->pn_tree
|
||||
: callee->pn_body;
|
||||
if (body->getKind() == TOK_LEXICALSCOPE)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
JSParseNode *generatorExpr() const {
|
||||
ParseNode *generatorExpr() const {
|
||||
JS_ASSERT(isGeneratorExpr());
|
||||
JSParseNode *callee = this->pn_head;
|
||||
JSParseNode *body = callee->pn_body->getKind() == js::TOK_UPVARS
|
||||
? callee->pn_body->pn_tree
|
||||
: callee->pn_body;
|
||||
JS_ASSERT(body->getKind() == js::TOK_LEXICALSCOPE);
|
||||
ParseNode *callee = this->pn_head;
|
||||
ParseNode *body = callee->pn_body->getKind() == TOK_UPVARS
|
||||
? callee->pn_body->pn_tree
|
||||
: callee->pn_body;
|
||||
JS_ASSERT(body->getKind() == TOK_LEXICALSCOPE);
|
||||
return body->pn_expr;
|
||||
}
|
||||
#endif
|
||||
|
@ -634,10 +651,10 @@ public:
|
|||
* Compute a pointer to the last element in a singly-linked list. NB: list
|
||||
* must be non-empty for correct PN_LAST usage -- this is asserted!
|
||||
*/
|
||||
JSParseNode *last() const {
|
||||
ParseNode *last() const {
|
||||
JS_ASSERT(pn_arity == PN_LIST);
|
||||
JS_ASSERT(pn_count != 0);
|
||||
return (JSParseNode *)(uintptr_t(pn_tail) - offsetof(JSParseNode, pn_next));
|
||||
return (ParseNode *)(uintptr_t(pn_tail) - offsetof(ParseNode, pn_next));
|
||||
}
|
||||
|
||||
void makeEmpty() {
|
||||
|
@ -649,7 +666,7 @@ public:
|
|||
pn_blockid = 0;
|
||||
}
|
||||
|
||||
void initList(JSParseNode *pn) {
|
||||
void initList(ParseNode *pn) {
|
||||
JS_ASSERT(pn_arity == PN_LIST);
|
||||
pn_head = pn;
|
||||
pn_tail = &pn->pn_next;
|
||||
|
@ -658,122 +675,110 @@ public:
|
|||
pn_blockid = 0;
|
||||
}
|
||||
|
||||
void append(JSParseNode *pn) {
|
||||
void append(ParseNode *pn) {
|
||||
JS_ASSERT(pn_arity == PN_LIST);
|
||||
*pn_tail = pn;
|
||||
pn_tail = &pn->pn_next;
|
||||
pn_count++;
|
||||
}
|
||||
|
||||
bool getConstantValue(JSContext *cx, bool strictChecks, js::Value *vp);
|
||||
bool getConstantValue(JSContext *cx, bool strictChecks, Value *vp);
|
||||
inline bool isConstant();
|
||||
};
|
||||
|
||||
namespace js {
|
||||
|
||||
struct NullaryNode : public JSParseNode {
|
||||
static inline NullaryNode *create(JSTreeContext *tc) {
|
||||
return (NullaryNode *)JSParseNode::create(PN_NULLARY, tc);
|
||||
struct NullaryNode : public ParseNode {
|
||||
static inline NullaryNode *create(TreeContext *tc) {
|
||||
return (NullaryNode *)ParseNode::create(PN_NULLARY, tc);
|
||||
}
|
||||
};
|
||||
|
||||
struct UnaryNode : public JSParseNode {
|
||||
static inline UnaryNode *create(JSTreeContext *tc) {
|
||||
return (UnaryNode *)JSParseNode::create(PN_UNARY, tc);
|
||||
struct UnaryNode : public ParseNode {
|
||||
UnaryNode(TokenKind type, JSOp op, const TokenPos &pos, ParseNode *kid)
|
||||
: ParseNode(type, op, PN_UNARY, pos)
|
||||
{
|
||||
pn_kid = kid;
|
||||
}
|
||||
|
||||
static inline UnaryNode *create(TreeContext *tc) {
|
||||
return (UnaryNode *)ParseNode::create(PN_UNARY, tc);
|
||||
}
|
||||
};
|
||||
|
||||
struct BinaryNode : public JSParseNode {
|
||||
static inline BinaryNode *create(TokenKind type, JSOp op, const TokenPos &pos,
|
||||
JSParseNode *left, JSParseNode *right,
|
||||
JSTreeContext *tc) {
|
||||
BinaryNode *pn = (BinaryNode *) JSParseNode::create(PN_BINARY, type, op, pos, tc);
|
||||
if (pn) {
|
||||
pn->pn_left = left;
|
||||
pn->pn_right = right;
|
||||
}
|
||||
return pn;
|
||||
struct BinaryNode : public ParseNode {
|
||||
BinaryNode(TokenKind type, JSOp op, const TokenPos &pos, ParseNode *left, ParseNode *right)
|
||||
: ParseNode(type, op, PN_BINARY, pos)
|
||||
{
|
||||
pn_left = left;
|
||||
pn_right = right;
|
||||
}
|
||||
|
||||
static inline BinaryNode *create(JSTreeContext *tc) {
|
||||
return (BinaryNode *)JSParseNode::create(PN_BINARY, tc);
|
||||
BinaryNode(TokenKind type, JSOp op, ParseNode *left, ParseNode *right)
|
||||
: ParseNode(type, op, PN_BINARY, TokenPos::box(left->pn_pos, right->pn_pos))
|
||||
{
|
||||
pn_left = left;
|
||||
pn_right = right;
|
||||
}
|
||||
|
||||
static inline BinaryNode *create(TreeContext *tc) {
|
||||
return (BinaryNode *)ParseNode::create(PN_BINARY, tc);
|
||||
}
|
||||
};
|
||||
|
||||
struct TernaryNode : public JSParseNode {
|
||||
static inline TernaryNode *create(TokenKind type, JSOp op,
|
||||
JSParseNode *kid1, JSParseNode *kid2, JSParseNode *kid3,
|
||||
JSTreeContext *tc) {
|
||||
TokenPos pos;
|
||||
pos.begin = (kid1 ? kid1 : kid2)->pn_pos.begin;
|
||||
pos.end = kid3->pn_pos.end;
|
||||
TernaryNode *pn = (TernaryNode *) JSParseNode::create(PN_TERNARY, type, op, pos, tc);
|
||||
if (pn) {
|
||||
pn->pn_kid1 = kid1;
|
||||
pn->pn_kid2 = kid2;
|
||||
pn->pn_kid3 = kid3;
|
||||
}
|
||||
return pn;
|
||||
struct TernaryNode : public ParseNode {
|
||||
TernaryNode(TokenKind type, JSOp op, ParseNode *kid1, ParseNode *kid2, ParseNode *kid3)
|
||||
: ParseNode(type, op, PN_TERNARY,
|
||||
TokenPos((kid1 ? kid1 : kid2 ? kid2 : kid3)->pn_pos.begin,
|
||||
(kid3 ? kid3 : kid2 ? kid2 : kid1)->pn_pos.end))
|
||||
{
|
||||
pn_kid1 = kid1;
|
||||
pn_kid2 = kid2;
|
||||
pn_kid3 = kid3;
|
||||
}
|
||||
|
||||
static inline TernaryNode *create(JSTreeContext *tc) {
|
||||
return (TernaryNode *)JSParseNode::create(PN_TERNARY, tc);
|
||||
static inline TernaryNode *create(TreeContext *tc) {
|
||||
return (TernaryNode *)ParseNode::create(PN_TERNARY, tc);
|
||||
}
|
||||
};
|
||||
|
||||
struct ListNode : public JSParseNode {
|
||||
static inline ListNode *create(JSTreeContext *tc) {
|
||||
return (ListNode *)JSParseNode::create(PN_LIST, tc);
|
||||
struct ListNode : public ParseNode {
|
||||
static inline ListNode *create(TreeContext *tc) {
|
||||
return (ListNode *)ParseNode::create(PN_LIST, tc);
|
||||
}
|
||||
};
|
||||
|
||||
struct FunctionNode : public JSParseNode {
|
||||
static inline FunctionNode *create(JSTreeContext *tc) {
|
||||
return (FunctionNode *)JSParseNode::create(PN_FUNC, tc);
|
||||
struct FunctionNode : public ParseNode {
|
||||
static inline FunctionNode *create(TreeContext *tc) {
|
||||
return (FunctionNode *)ParseNode::create(PN_FUNC, tc);
|
||||
}
|
||||
};
|
||||
|
||||
struct NameNode : public JSParseNode {
|
||||
static NameNode *create(JSAtom *atom, JSTreeContext *tc);
|
||||
struct NameNode : public ParseNode {
|
||||
static NameNode *create(JSAtom *atom, TreeContext *tc);
|
||||
|
||||
void inline initCommon(JSTreeContext *tc);
|
||||
inline void initCommon(TreeContext *tc);
|
||||
};
|
||||
|
||||
struct NameSetNode : public JSParseNode {
|
||||
static inline NameSetNode *create(JSTreeContext *tc) {
|
||||
return (NameSetNode *)JSParseNode::create(PN_NAMESET, tc);
|
||||
struct NameSetNode : public ParseNode {
|
||||
static inline NameSetNode *create(TreeContext *tc) {
|
||||
return (NameSetNode *)ParseNode::create(PN_NAMESET, tc);
|
||||
}
|
||||
};
|
||||
|
||||
struct LexicalScopeNode : public JSParseNode {
|
||||
static inline LexicalScopeNode *create(JSTreeContext *tc) {
|
||||
return (LexicalScopeNode *)JSParseNode::create(PN_NAME, tc);
|
||||
struct LexicalScopeNode : public ParseNode {
|
||||
static inline LexicalScopeNode *create(TreeContext *tc) {
|
||||
return (LexicalScopeNode *)ParseNode::create(PN_NAME, tc);
|
||||
}
|
||||
};
|
||||
|
||||
JSParseNode *
|
||||
NewOrRecycledNode(JSTreeContext *tc);
|
||||
|
||||
void
|
||||
AddNodeToFreeList(JSParseNode *pn, Parser *parser);
|
||||
|
||||
void
|
||||
PrepareNodeForMutation(JSParseNode *pn, JSTreeContext *tc);
|
||||
|
||||
JSParseNode *
|
||||
RecycleTree(JSParseNode *pn, JSTreeContext *tc);
|
||||
|
||||
JSParseNode *
|
||||
CloneLeftHandSide(JSParseNode *opn, JSTreeContext *tc);
|
||||
|
||||
} /* namespace js */
|
||||
ParseNode *
|
||||
CloneLeftHandSide(ParseNode *opn, TreeContext *tc);
|
||||
|
||||
/*
|
||||
* JSDefinition is a degenerate subtype of the PN_FUNC and PN_NAME variants of
|
||||
* JSParseNode, allocated only for function, var, const, and let declarations
|
||||
* that define truly lexical bindings. This means that a child of a TOK_VAR
|
||||
* list may be a JSDefinition instead of a JSParseNode. The pn_defn bit is set
|
||||
* for all JSDefinitions, clear otherwise.
|
||||
* js::Definition is a degenerate subtype of the PN_FUNC and PN_NAME variants
|
||||
* of js::ParseNode, allocated only for function, var, const, and let
|
||||
* declarations that define truly lexical bindings. This means that a child of
|
||||
* a TOK_VAR list may be a Definition instead of a ParseNode. The pn_defn
|
||||
* bit is set for all Definitions, clear otherwise.
|
||||
*
|
||||
* In an upvars list, defn->resolve() is the outermost definition the
|
||||
* name may reference. If a with block or a function that calls eval encloses
|
||||
|
@ -806,24 +811,24 @@ CloneLeftHandSide(JSParseNode *opn, JSTreeContext *tc);
|
|||
* for (each use of unqualified name x in parse order) {
|
||||
* if (this use of x is a declaration) {
|
||||
* if (x in tc->decls) { // redeclaring
|
||||
* pn = allocate a PN_NAME JSParseNode;
|
||||
* pn = allocate a PN_NAME ParseNode;
|
||||
* } else { // defining
|
||||
* dn = lookup x in tc->lexdeps;
|
||||
* if (dn) // use before def
|
||||
* remove x from tc->lexdeps;
|
||||
* else // def before use
|
||||
* dn = allocate a PN_NAME JSDefinition;
|
||||
* dn = allocate a PN_NAME Definition;
|
||||
* map x to dn via tc->decls;
|
||||
* pn = dn;
|
||||
* }
|
||||
* insert pn into its parent TOK_VAR list;
|
||||
* } else {
|
||||
* pn = allocate a JSParseNode for this reference to x;
|
||||
* pn = allocate a ParseNode for this reference to x;
|
||||
* dn = lookup x in tc's lexical scope chain;
|
||||
* if (!dn) {
|
||||
* dn = lookup x in tc->lexdeps;
|
||||
* if (!dn) {
|
||||
* dn = pre-allocate a JSDefinition for x;
|
||||
* dn = pre-allocate a Definition for x;
|
||||
* map x to dn in tc->lexdeps;
|
||||
* }
|
||||
* }
|
||||
|
@ -831,13 +836,13 @@ CloneLeftHandSide(JSParseNode *opn, JSTreeContext *tc);
|
|||
* }
|
||||
* }
|
||||
*
|
||||
* See frontend/BytecodeGenerator.h for JSTreeContext and its top*Stmt, decls, and
|
||||
* lexdeps members.
|
||||
* See frontend/BytecodeGenerator.h for js::TreeContext and its top*Stmt,
|
||||
* decls, and lexdeps members.
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* 0. To avoid bloating JSParseNode, we steal a bit from pn_arity for pn_defn
|
||||
* and set it on a JSParseNode instead of allocating a JSDefinition.
|
||||
* 0. To avoid bloating ParseNode, we steal a bit from pn_arity for pn_defn
|
||||
* and set it on a ParseNode instead of allocating a Definition.
|
||||
*
|
||||
* 1. Due to hoisting, a definition cannot be eliminated even if its "Variable
|
||||
* statement" (ECMA-262 12.2) can be proven to be dead code. RecycleTree in
|
||||
|
@ -888,10 +893,10 @@ CloneLeftHandSide(JSParseNode *opn, JSTreeContext *tc);
|
|||
*/
|
||||
#define dn_uses pn_link
|
||||
|
||||
struct JSDefinition : public JSParseNode
|
||||
struct Definition : public ParseNode
|
||||
{
|
||||
/*
|
||||
* We store definition pointers in PN_NAMESET JSAtomDefnMapPtrs in the AST,
|
||||
* We store definition pointers in PN_NAMESET AtomDefnMapPtrs in the AST,
|
||||
* but due to redefinition these nodes may become uses of other
|
||||
* definitions. This is unusual, so we simply chase the pn_lexdef link to
|
||||
* find the final definition node. See methods called from
|
||||
|
@ -899,16 +904,16 @@ struct JSDefinition : public JSParseNode
|
|||
*
|
||||
* FIXME: MakeAssignment mutates for want of a parent link...
|
||||
*/
|
||||
JSDefinition *resolve() {
|
||||
JSParseNode *pn = this;
|
||||
Definition *resolve() {
|
||||
ParseNode *pn = this;
|
||||
while (!pn->isDefn()) {
|
||||
if (pn->getKind() == js::TOK_ASSIGN) {
|
||||
if (pn->getKind() == TOK_ASSIGN) {
|
||||
pn = pn->pn_left;
|
||||
continue;
|
||||
}
|
||||
pn = pn->lexdef();
|
||||
}
|
||||
return (JSDefinition *) pn;
|
||||
return (Definition *) pn;
|
||||
}
|
||||
|
||||
bool isFreeVar() const {
|
||||
|
@ -928,9 +933,9 @@ struct JSDefinition : public JSParseNode
|
|||
static const char *kindString(Kind kind);
|
||||
|
||||
Kind kind() {
|
||||
if (getKind() == js::TOK_FUNCTION)
|
||||
if (getKind() == TOK_FUNCTION)
|
||||
return FUNCTION;
|
||||
JS_ASSERT(getKind() == js::TOK_NAME);
|
||||
JS_ASSERT(getKind() == TOK_NAME);
|
||||
if (isOp(JSOP_NOP))
|
||||
return UNKNOWN;
|
||||
if (isOp(JSOP_GETARG))
|
||||
|
@ -943,13 +948,27 @@ struct JSDefinition : public JSParseNode
|
|||
}
|
||||
};
|
||||
|
||||
class ParseNodeAllocator {
|
||||
public:
|
||||
explicit ParseNodeAllocator(JSContext *cx) : cx(cx), freelist(NULL) {}
|
||||
|
||||
void *allocNode();
|
||||
void freeNode(ParseNode *pn);
|
||||
ParseNode *freeTree(ParseNode *pn);
|
||||
void prepareNodeForMutation(ParseNode *pn);
|
||||
|
||||
private:
|
||||
JSContext *cx;
|
||||
ParseNode *freelist;
|
||||
};
|
||||
|
||||
inline bool
|
||||
JSParseNode::test(uintN flag) const
|
||||
ParseNode::test(uintN flag) const
|
||||
{
|
||||
JS_ASSERT(pn_defn || pn_arity == PN_FUNC || pn_arity == PN_NAME);
|
||||
#ifdef DEBUG
|
||||
if ((flag & (PND_ASSIGNED | PND_FUNARG)) && pn_defn && !(pn_dflags & flag)) {
|
||||
for (JSParseNode *pn = ((JSDefinition *) this)->dn_uses; pn; pn = pn->pn_link) {
|
||||
for (ParseNode *pn = ((Definition *) this)->dn_uses; pn; pn = pn->pn_link) {
|
||||
JS_ASSERT(!pn->pn_defn);
|
||||
JS_ASSERT(!(pn->pn_dflags & flag));
|
||||
}
|
||||
|
@ -959,7 +978,7 @@ JSParseNode::test(uintN flag) const
|
|||
}
|
||||
|
||||
inline void
|
||||
JSParseNode::setFunArg()
|
||||
ParseNode::setFunArg()
|
||||
{
|
||||
/*
|
||||
* pn_defn NAND pn_used must be true, per this chart:
|
||||
|
@ -977,10 +996,8 @@ JSParseNode::setFunArg()
|
|||
pn_dflags |= PND_FUNARG;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
inline void
|
||||
LinkUseToDef(JSParseNode *pn, JSDefinition *dn, JSTreeContext *tc)
|
||||
LinkUseToDef(ParseNode *pn, Definition *dn, TreeContext *tc)
|
||||
{
|
||||
JS_ASSERT(!pn->isUsed());
|
||||
JS_ASSERT(!pn->isDefn());
|
||||
|
@ -992,31 +1009,29 @@ LinkUseToDef(JSParseNode *pn, JSDefinition *dn, JSTreeContext *tc)
|
|||
pn->pn_lexdef = dn;
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
struct JSObjectBox {
|
||||
JSObjectBox *traceLink;
|
||||
JSObjectBox *emitLink;
|
||||
struct ObjectBox {
|
||||
ObjectBox *traceLink;
|
||||
ObjectBox *emitLink;
|
||||
JSObject *object;
|
||||
JSObjectBox *parent;
|
||||
ObjectBox *parent;
|
||||
uintN index;
|
||||
bool isFunctionBox;
|
||||
};
|
||||
|
||||
#define JSFB_LEVEL_BITS 14
|
||||
|
||||
struct JSFunctionBox : public JSObjectBox
|
||||
struct FunctionBox : public ObjectBox
|
||||
{
|
||||
JSParseNode *node;
|
||||
JSFunctionBox *siblings;
|
||||
JSFunctionBox *kids;
|
||||
JSFunctionBox *parent;
|
||||
JSParseNode *methods; /* would-be methods set on this;
|
||||
ParseNode *node;
|
||||
FunctionBox *siblings;
|
||||
FunctionBox *kids;
|
||||
FunctionBox *parent;
|
||||
ParseNode *methods; /* would-be methods set on this;
|
||||
these nodes are linked via
|
||||
pn_link, since lambdas are
|
||||
neither definitions nor uses
|
||||
of a binding */
|
||||
js::Bindings bindings; /* bindings for this function */
|
||||
Bindings bindings; /* bindings for this function */
|
||||
uint32 queued:1,
|
||||
inLoop:1, /* in a loop in parent function */
|
||||
level:JSFB_LEVEL_BITS;
|
||||
|
@ -1051,26 +1066,26 @@ struct JSFunctionBox : public JSObjectBox
|
|||
bool shouldUnbrand(uintN methods, uintN slowMethods) const;
|
||||
};
|
||||
|
||||
struct JSFunctionBoxQueue {
|
||||
JSFunctionBox **vector;
|
||||
struct FunctionBoxQueue {
|
||||
FunctionBox **vector;
|
||||
size_t head, tail;
|
||||
size_t lengthMask;
|
||||
|
||||
size_t count() { return head - tail; }
|
||||
size_t length() { return lengthMask + 1; }
|
||||
|
||||
JSFunctionBoxQueue()
|
||||
FunctionBoxQueue()
|
||||
: vector(NULL), head(0), tail(0), lengthMask(0) { }
|
||||
|
||||
bool init(uint32 count) {
|
||||
lengthMask = JS_BITMASK(JS_CEILING_LOG2W(count));
|
||||
vector = (JSFunctionBox **) js::OffTheBooks::malloc_(sizeof(JSFunctionBox) * length());
|
||||
vector = (FunctionBox **) OffTheBooks::malloc_(sizeof(FunctionBox) * length());
|
||||
return !!vector;
|
||||
}
|
||||
|
||||
~JSFunctionBoxQueue() { js::UnwantedForeground::free_(vector); }
|
||||
~FunctionBoxQueue() { UnwantedForeground::free_(vector); }
|
||||
|
||||
void push(JSFunctionBox *funbox) {
|
||||
void push(FunctionBox *funbox) {
|
||||
if (!funbox->queued) {
|
||||
JS_ASSERT(count() < length());
|
||||
vector[head++ & lengthMask] = funbox;
|
||||
|
@ -1078,14 +1093,16 @@ struct JSFunctionBoxQueue {
|
|||
}
|
||||
}
|
||||
|
||||
JSFunctionBox *pull() {
|
||||
FunctionBox *pull() {
|
||||
if (tail == head)
|
||||
return NULL;
|
||||
JS_ASSERT(tail < head);
|
||||
JSFunctionBox *funbox = vector[tail++ & lengthMask];
|
||||
FunctionBox *funbox = vector[tail++ & lengthMask];
|
||||
funbox->queued = false;
|
||||
return funbox;
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* ParseNode_h__ */
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -54,32 +54,26 @@
|
|||
#include "frontend/ParseMaps.h"
|
||||
#include "frontend/ParseNode.h"
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
namespace js {
|
||||
|
||||
struct GlobalScope {
|
||||
GlobalScope(JSContext *cx, JSObject *globalObj, JSCodeGenerator *cg)
|
||||
GlobalScope(JSContext *cx, JSObject *globalObj, CodeGenerator *cg)
|
||||
: globalObj(globalObj), cg(cg), defs(cx), names(cx)
|
||||
{ }
|
||||
|
||||
struct GlobalDef {
|
||||
JSAtom *atom; // If non-NULL, specifies the property name to add.
|
||||
JSFunctionBox *funbox; // If non-NULL, function value for the property.
|
||||
FunctionBox *funbox; // If non-NULL, function value for the property.
|
||||
// This value is only set/used if atom is non-NULL.
|
||||
uint32 knownSlot; // If atom is NULL, this is the known shape slot.
|
||||
|
||||
GlobalDef() { }
|
||||
GlobalDef(uint32 knownSlot)
|
||||
: atom(NULL), knownSlot(knownSlot)
|
||||
{ }
|
||||
GlobalDef(JSAtom *atom, JSFunctionBox *box) :
|
||||
atom(atom), funbox(box)
|
||||
{ }
|
||||
GlobalDef(uint32 knownSlot) : atom(NULL), knownSlot(knownSlot) { }
|
||||
GlobalDef(JSAtom *atom, FunctionBox *box) : atom(atom), funbox(box) { }
|
||||
};
|
||||
|
||||
JSObject *globalObj;
|
||||
JSCodeGenerator *cg;
|
||||
CodeGenerator *cg;
|
||||
|
||||
/*
|
||||
* This is the table of global names encountered during parsing. Each
|
||||
|
@ -103,7 +97,7 @@ namespace js {
|
|||
|
||||
enum FunctionSyntaxKind { Expression, Statement };
|
||||
|
||||
struct Parser : private js::AutoGCRooter
|
||||
struct Parser : private AutoGCRooter
|
||||
{
|
||||
JSContext *const context; /* FIXME Bug 551291: use AutoGCRooter::context? */
|
||||
void *tempFreeList[NUM_TEMP_FREELISTS];
|
||||
|
@ -112,13 +106,13 @@ struct Parser : private js::AutoGCRooter
|
|||
JSPrincipals *principals; /* principals associated with source */
|
||||
StackFrame *const callerFrame; /* scripted caller frame for eval and dbgapi */
|
||||
JSObject *const callerVarObj; /* callerFrame's varObj */
|
||||
JSParseNode *nodeList; /* list of recyclable parse-node structs */
|
||||
ParseNodeAllocator allocator;
|
||||
uint32 functionCount; /* number of functions in current unit */
|
||||
JSObjectBox *traceListHead; /* list of parsed object for GC tracing */
|
||||
JSTreeContext *tc; /* innermost tree context (stack-allocated) */
|
||||
ObjectBox *traceListHead; /* list of parsed object for GC tracing */
|
||||
TreeContext *tc; /* innermost tree context (stack-allocated) */
|
||||
|
||||
/* Root atoms and objects allocated for the parsed tree. */
|
||||
js::AutoKeepAtoms keepAtoms;
|
||||
AutoKeepAtoms keepAtoms;
|
||||
|
||||
/* Perform constant-folding; must be true when interfacing with the emitter. */
|
||||
bool foldConstants;
|
||||
|
@ -126,9 +120,9 @@ struct Parser : private js::AutoGCRooter
|
|||
Parser(JSContext *cx, JSPrincipals *prin = NULL, StackFrame *cfp = NULL, bool fold = true);
|
||||
~Parser();
|
||||
|
||||
friend void js::AutoGCRooter::trace(JSTracer *trc);
|
||||
friend struct ::JSTreeContext;
|
||||
friend struct Compiler;
|
||||
friend void AutoGCRooter::trace(JSTracer *trc);
|
||||
friend struct TreeContext;
|
||||
friend struct BytecodeCompiler;
|
||||
|
||||
/*
|
||||
* Initialize a parser. Parameters are passed on to init tokenStream.
|
||||
|
@ -149,48 +143,61 @@ struct Parser : private js::AutoGCRooter
|
|||
/*
|
||||
* Parse a top-level JS script.
|
||||
*/
|
||||
JSParseNode *parse(JSObject *chain);
|
||||
ParseNode *parse(JSObject *chain);
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
JSParseNode *parseXMLText(JSObject *chain, bool allowList);
|
||||
ParseNode *parseXMLText(JSObject *chain, bool allowList);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocate a new parsed object or function container from cx->tempPool.
|
||||
*/
|
||||
JSObjectBox *newObjectBox(JSObject *obj);
|
||||
ObjectBox *newObjectBox(JSObject *obj);
|
||||
|
||||
JSFunctionBox *newFunctionBox(JSObject *obj, JSParseNode *fn, JSTreeContext *tc);
|
||||
FunctionBox *newFunctionBox(JSObject *obj, ParseNode *fn, TreeContext *tc);
|
||||
|
||||
/*
|
||||
* Create a new function object given tree context (tc) and a name (which
|
||||
* is optional if this is a function expression).
|
||||
*/
|
||||
JSFunction *newFunction(JSTreeContext *tc, JSAtom *atom, FunctionSyntaxKind kind);
|
||||
JSFunction *newFunction(TreeContext *tc, JSAtom *atom, FunctionSyntaxKind kind);
|
||||
|
||||
/*
|
||||
* Analyze the tree of functions nested within a single compilation unit,
|
||||
* starting at funbox, recursively walking its kids, then following its
|
||||
* siblings, their kids, etc.
|
||||
*/
|
||||
bool analyzeFunctions(JSTreeContext *tc);
|
||||
void cleanFunctionList(JSFunctionBox **funbox);
|
||||
bool markFunArgs(JSFunctionBox *funbox);
|
||||
void markExtensibleScopeDescendants(JSFunctionBox *funbox, bool hasExtensibleParent);
|
||||
void setFunctionKinds(JSFunctionBox *funbox, uint32 *tcflags);
|
||||
bool analyzeFunctions(TreeContext *tc);
|
||||
void cleanFunctionList(FunctionBox **funbox);
|
||||
bool markFunArgs(FunctionBox *funbox);
|
||||
void markExtensibleScopeDescendants(FunctionBox *funbox, bool hasExtensibleParent);
|
||||
void setFunctionKinds(FunctionBox *funbox, uint32 *tcflags);
|
||||
|
||||
void trace(JSTracer *trc);
|
||||
|
||||
/*
|
||||
* Report a parse (compile) error.
|
||||
*/
|
||||
inline bool reportErrorNumber(JSParseNode *pn, uintN flags, uintN errorNumber, ...);
|
||||
inline bool reportErrorNumber(ParseNode *pn, uintN flags, uintN errorNumber, ...);
|
||||
|
||||
private:
|
||||
private:
|
||||
void *allocParseNode(size_t size) {
|
||||
JS_ASSERT(size == sizeof(ParseNode));
|
||||
return allocator.allocNode();
|
||||
}
|
||||
|
||||
public:
|
||||
ParseNode *freeTree(ParseNode *pn) { return allocator.freeTree(pn); }
|
||||
void prepareNodeForMutation(ParseNode *pn) { return allocator.prepareNodeForMutation(pn); }
|
||||
|
||||
/* new_ methods for creating parse nodes. These report OOM on context. */
|
||||
JS_DECLARE_NEW_METHODS(allocParseNode, inline)
|
||||
|
||||
private:
|
||||
/*
|
||||
* JS parsers, from lowest to highest precedence.
|
||||
*
|
||||
* Each parser must be called during the dynamic scope of a JSTreeContext
|
||||
* Each parser must be called during the dynamic scope of a TreeContext
|
||||
* object, pointed to by this->tc.
|
||||
*
|
||||
* Each returns a parse node tree or null on error.
|
||||
|
@ -203,87 +210,87 @@ private:
|
|||
* Some parsers have two versions: an always-inlined version (with an 'i'
|
||||
* suffix) and a never-inlined version (with an 'n' suffix).
|
||||
*/
|
||||
JSParseNode *functionStmt();
|
||||
JSParseNode *functionExpr();
|
||||
JSParseNode *statements();
|
||||
JSParseNode *statement();
|
||||
JSParseNode *switchStatement();
|
||||
JSParseNode *forStatement();
|
||||
JSParseNode *tryStatement();
|
||||
JSParseNode *withStatement();
|
||||
ParseNode *functionStmt();
|
||||
ParseNode *functionExpr();
|
||||
ParseNode *statements();
|
||||
ParseNode *statement();
|
||||
ParseNode *switchStatement();
|
||||
ParseNode *forStatement();
|
||||
ParseNode *tryStatement();
|
||||
ParseNode *withStatement();
|
||||
#if JS_HAS_BLOCK_SCOPE
|
||||
JSParseNode *letStatement();
|
||||
ParseNode *letStatement();
|
||||
#endif
|
||||
JSParseNode *expressionStatement();
|
||||
JSParseNode *variables(bool inLetHead);
|
||||
JSParseNode *expr();
|
||||
JSParseNode *assignExpr();
|
||||
JSParseNode *condExpr1();
|
||||
JSParseNode *orExpr1();
|
||||
JSParseNode *andExpr1i();
|
||||
JSParseNode *andExpr1n();
|
||||
JSParseNode *bitOrExpr1i();
|
||||
JSParseNode *bitOrExpr1n();
|
||||
JSParseNode *bitXorExpr1i();
|
||||
JSParseNode *bitXorExpr1n();
|
||||
JSParseNode *bitAndExpr1i();
|
||||
JSParseNode *bitAndExpr1n();
|
||||
JSParseNode *eqExpr1i();
|
||||
JSParseNode *eqExpr1n();
|
||||
JSParseNode *relExpr1i();
|
||||
JSParseNode *relExpr1n();
|
||||
JSParseNode *shiftExpr1i();
|
||||
JSParseNode *shiftExpr1n();
|
||||
JSParseNode *addExpr1i();
|
||||
JSParseNode *addExpr1n();
|
||||
JSParseNode *mulExpr1i();
|
||||
JSParseNode *mulExpr1n();
|
||||
JSParseNode *unaryExpr();
|
||||
JSParseNode *memberExpr(JSBool allowCallSyntax);
|
||||
JSParseNode *primaryExpr(js::TokenKind tt, JSBool afterDot);
|
||||
JSParseNode *parenExpr(JSBool *genexp = NULL);
|
||||
ParseNode *expressionStatement();
|
||||
ParseNode *variables(bool inLetHead);
|
||||
ParseNode *expr();
|
||||
ParseNode *assignExpr();
|
||||
ParseNode *condExpr1();
|
||||
ParseNode *orExpr1();
|
||||
ParseNode *andExpr1i();
|
||||
ParseNode *andExpr1n();
|
||||
ParseNode *bitOrExpr1i();
|
||||
ParseNode *bitOrExpr1n();
|
||||
ParseNode *bitXorExpr1i();
|
||||
ParseNode *bitXorExpr1n();
|
||||
ParseNode *bitAndExpr1i();
|
||||
ParseNode *bitAndExpr1n();
|
||||
ParseNode *eqExpr1i();
|
||||
ParseNode *eqExpr1n();
|
||||
ParseNode *relExpr1i();
|
||||
ParseNode *relExpr1n();
|
||||
ParseNode *shiftExpr1i();
|
||||
ParseNode *shiftExpr1n();
|
||||
ParseNode *addExpr1i();
|
||||
ParseNode *addExpr1n();
|
||||
ParseNode *mulExpr1i();
|
||||
ParseNode *mulExpr1n();
|
||||
ParseNode *unaryExpr();
|
||||
ParseNode *memberExpr(JSBool allowCallSyntax);
|
||||
ParseNode *primaryExpr(TokenKind tt, JSBool afterDot);
|
||||
ParseNode *parenExpr(JSBool *genexp = NULL);
|
||||
|
||||
/*
|
||||
* Additional JS parsers.
|
||||
*/
|
||||
bool recognizeDirectivePrologue(JSParseNode *pn, bool *isDirectivePrologueMember);
|
||||
bool recognizeDirectivePrologue(ParseNode *pn, bool *isDirectivePrologueMember);
|
||||
|
||||
enum FunctionType { Getter, Setter, Normal };
|
||||
bool functionArguments(JSTreeContext &funtc, JSFunctionBox *funbox, JSParseNode **list);
|
||||
JSParseNode *functionBody();
|
||||
JSParseNode *functionDef(PropertyName *name, FunctionType type, FunctionSyntaxKind kind);
|
||||
bool functionArguments(TreeContext &funtc, FunctionBox *funbox, ParseNode **list);
|
||||
ParseNode *functionBody();
|
||||
ParseNode *functionDef(PropertyName *name, FunctionType type, FunctionSyntaxKind kind);
|
||||
|
||||
JSParseNode *condition();
|
||||
JSParseNode *comprehensionTail(JSParseNode *kid, uintN blockid, bool isGenexp,
|
||||
js::TokenKind type = js::TOK_SEMI, JSOp op = JSOP_NOP);
|
||||
JSParseNode *generatorExpr(JSParseNode *kid);
|
||||
JSBool argumentList(JSParseNode *listNode);
|
||||
JSParseNode *bracketedExpr();
|
||||
JSParseNode *letBlock(JSBool statement);
|
||||
JSParseNode *returnOrYield(bool useAssignExpr);
|
||||
JSParseNode *destructuringExpr(BindData *data, js::TokenKind tt);
|
||||
ParseNode *condition();
|
||||
ParseNode *comprehensionTail(ParseNode *kid, uintN blockid, bool isGenexp,
|
||||
TokenKind type = TOK_SEMI, JSOp op = JSOP_NOP);
|
||||
ParseNode *generatorExpr(ParseNode *kid);
|
||||
JSBool argumentList(ParseNode *listNode);
|
||||
ParseNode *bracketedExpr();
|
||||
ParseNode *letBlock(JSBool statement);
|
||||
ParseNode *returnOrYield(bool useAssignExpr);
|
||||
ParseNode *destructuringExpr(BindData *data, TokenKind tt);
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
JSParseNode *endBracketedExpr();
|
||||
ParseNode *endBracketedExpr();
|
||||
|
||||
JSParseNode *propertySelector();
|
||||
JSParseNode *qualifiedSuffix(JSParseNode *pn);
|
||||
JSParseNode *qualifiedIdentifier();
|
||||
JSParseNode *attributeIdentifier();
|
||||
JSParseNode *xmlExpr(JSBool inTag);
|
||||
JSParseNode *xmlAtomNode();
|
||||
JSParseNode *xmlNameExpr();
|
||||
JSParseNode *xmlTagContent(js::TokenKind tagtype, JSAtom **namep);
|
||||
JSBool xmlElementContent(JSParseNode *pn);
|
||||
JSParseNode *xmlElementOrList(JSBool allowList);
|
||||
JSParseNode *xmlElementOrListRoot(JSBool allowList);
|
||||
ParseNode *propertySelector();
|
||||
ParseNode *qualifiedSuffix(ParseNode *pn);
|
||||
ParseNode *qualifiedIdentifier();
|
||||
ParseNode *attributeIdentifier();
|
||||
ParseNode *xmlExpr(JSBool inTag);
|
||||
ParseNode *xmlAtomNode();
|
||||
ParseNode *xmlNameExpr();
|
||||
ParseNode *xmlTagContent(TokenKind tagtype, JSAtom **namep);
|
||||
JSBool xmlElementContent(ParseNode *pn);
|
||||
ParseNode *xmlElementOrList(JSBool allowList);
|
||||
ParseNode *xmlElementOrListRoot(JSBool allowList);
|
||||
#endif /* JS_HAS_XML_SUPPORT */
|
||||
|
||||
bool setAssignmentLhsOps(JSParseNode *pn, JSOp op);
|
||||
bool setAssignmentLhsOps(ParseNode *pn, JSOp op);
|
||||
};
|
||||
|
||||
inline bool
|
||||
Parser::reportErrorNumber(JSParseNode *pn, uintN flags, uintN errorNumber, ...)
|
||||
Parser::reportErrorNumber(ParseNode *pn, uintN flags, uintN errorNumber, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, errorNumber);
|
||||
|
@ -293,10 +300,10 @@ Parser::reportErrorNumber(JSParseNode *pn, uintN flags, uintN errorNumber, ...)
|
|||
}
|
||||
|
||||
bool
|
||||
CheckStrictParameters(JSContext *cx, JSTreeContext *tc);
|
||||
CheckStrictParameters(JSContext *cx, TreeContext *tc);
|
||||
|
||||
bool
|
||||
DefineArg(JSParseNode *pn, JSAtom *atom, uintN i, JSTreeContext *tc);
|
||||
DefineArg(ParseNode *pn, JSAtom *atom, uintN i, TreeContext *tc);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
|
@ -305,6 +312,4 @@ DefineArg(JSParseNode *pn, JSAtom *atom, uintN i, JSTreeContext *tc);
|
|||
*/
|
||||
#define TS(p) (&(p)->tokenStream)
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* Parser_h__ */
|
||||
|
|
|
@ -130,10 +130,8 @@ FindKeyword(const jschar *s, size_t length)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
JSBool
|
||||
js_IsIdentifier(JSLinearString *str)
|
||||
IsIdentifier(JSLinearString *str)
|
||||
{
|
||||
const jschar *chars = str->chars();
|
||||
size_t length = str->length();
|
||||
|
@ -259,34 +257,6 @@ TokenStream::~TokenStream()
|
|||
# define fast_getc getc
|
||||
#endif
|
||||
|
||||
JS_FRIEND_API(int)
|
||||
js_fgets(char *buf, int size, FILE *file)
|
||||
{
|
||||
int n, i, c;
|
||||
JSBool crflag;
|
||||
|
||||
n = size - 1;
|
||||
if (n < 0)
|
||||
return -1;
|
||||
|
||||
crflag = JS_FALSE;
|
||||
for (i = 0; i < n && (c = fast_getc(file)) != EOF; i++) {
|
||||
buf[i] = c;
|
||||
if (c == '\n') { /* any \n ends a line */
|
||||
i++; /* keep the \n; we know there is room for \0 */
|
||||
break;
|
||||
}
|
||||
if (crflag) { /* \r not followed by \n ends line at the \r */
|
||||
ungetc(c, file);
|
||||
break; /* and overwrite c in buf with \0 */
|
||||
}
|
||||
crflag = (c == '\r');
|
||||
}
|
||||
|
||||
buf[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE void
|
||||
TokenStream::updateLineInfoForEOL()
|
||||
{
|
||||
|
@ -451,8 +421,7 @@ TokenStream::TokenBuf::findEOL()
|
|||
}
|
||||
|
||||
bool
|
||||
TokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN errorNumber,
|
||||
va_list ap)
|
||||
TokenStream::reportCompileErrorNumberVA(ParseNode *pn, uintN flags, uintN errorNumber, va_list ap)
|
||||
{
|
||||
JSErrorReport report;
|
||||
char *message;
|
||||
|
@ -579,8 +548,8 @@ TokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN erro
|
|||
}
|
||||
|
||||
bool
|
||||
js::ReportStrictModeError(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSParseNode *pn,
|
||||
uintN errorNumber, ...)
|
||||
ReportStrictModeError(JSContext *cx, TokenStream *ts, TreeContext *tc, ParseNode *pn,
|
||||
uintN errorNumber, ...)
|
||||
{
|
||||
JS_ASSERT(ts || tc);
|
||||
JS_ASSERT(cx == ts->getContext());
|
||||
|
@ -604,13 +573,13 @@ js::ReportStrictModeError(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSP
|
|||
}
|
||||
|
||||
bool
|
||||
js::ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, JSParseNode *pn,
|
||||
uintN flags, uintN errorNumber, ...)
|
||||
ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, ParseNode *pn, uintN flags,
|
||||
uintN errorNumber, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
/*
|
||||
* We don't accept a JSTreeContext argument, so we can't implement
|
||||
* We don't accept a TreeContext argument, so we can't implement
|
||||
* JSREPORT_STRICT_MODE_ERROR here. Use ReportStrictModeError instead,
|
||||
* or do the checks in the caller and pass plain old JSREPORT_ERROR.
|
||||
*/
|
||||
|
@ -953,7 +922,7 @@ TokenStream::getXMLTextOrTag(TokenKind *ttp, Token **tpp)
|
|||
*
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=336551
|
||||
*
|
||||
* The check for this is in jsparse.cpp, Compiler::compileScript.
|
||||
* The check for this is in BytecodeCompiler::compileScript.
|
||||
*/
|
||||
bool
|
||||
TokenStream::getXMLMarkup(TokenKind *ttp, Token **tpp)
|
||||
|
@ -2159,3 +2128,32 @@ TokenStream::getTokenInternal()
|
|||
return TOK_ERROR;
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
JS_FRIEND_API(int)
|
||||
js_fgets(char *buf, int size, FILE *file)
|
||||
{
|
||||
int n, i, c;
|
||||
JSBool crflag;
|
||||
|
||||
n = size - 1;
|
||||
if (n < 0)
|
||||
return -1;
|
||||
|
||||
crflag = JS_FALSE;
|
||||
for (i = 0; i < n && (c = fast_getc(file)) != EOF; i++) {
|
||||
buf[i] = c;
|
||||
if (c == '\n') { /* any \n ends a line */
|
||||
i++; /* keep the \n; we know there is room for \0 */
|
||||
break;
|
||||
}
|
||||
if (crflag) { /* \r not followed by \n ends line at the \r */
|
||||
ungetc(c, file);
|
||||
break; /* and overwrite c in buf with \0 */
|
||||
}
|
||||
crflag = (c == '\r');
|
||||
}
|
||||
|
||||
buf[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
|
|
@ -152,20 +152,20 @@ enum TokenKind {
|
|||
TOK_LIMIT /* domain size */
|
||||
};
|
||||
|
||||
static inline bool
|
||||
inline bool
|
||||
TokenKindIsXML(TokenKind tt)
|
||||
{
|
||||
return tt == TOK_AT || tt == TOK_DBLCOLON || tt == TOK_ANYNAME;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
inline bool
|
||||
TreeTypeIsXML(TokenKind tt)
|
||||
{
|
||||
return tt == TOK_XMLCOMMENT || tt == TOK_XMLCDATA || tt == TOK_XMLPI ||
|
||||
tt == TOK_XMLELEM || tt == TOK_XMLLIST;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
inline bool
|
||||
TokenKindIsDecl(TokenKind tt)
|
||||
{
|
||||
#if JS_HAS_BLOCK_SCOPE
|
||||
|
@ -179,29 +179,29 @@ struct TokenPtr {
|
|||
uint32 index; /* index of char in physical line */
|
||||
uint32 lineno; /* physical line number */
|
||||
|
||||
bool operator==(const TokenPtr& bptr) {
|
||||
bool operator==(const TokenPtr& bptr) const {
|
||||
return index == bptr.index && lineno == bptr.lineno;
|
||||
}
|
||||
|
||||
bool operator!=(const TokenPtr& bptr) {
|
||||
bool operator!=(const TokenPtr& bptr) const {
|
||||
return index != bptr.index || lineno != bptr.lineno;
|
||||
}
|
||||
|
||||
bool operator <(const TokenPtr& bptr) {
|
||||
bool operator <(const TokenPtr& bptr) const {
|
||||
return lineno < bptr.lineno ||
|
||||
(lineno == bptr.lineno && index < bptr.index);
|
||||
}
|
||||
|
||||
bool operator <=(const TokenPtr& bptr) {
|
||||
bool operator <=(const TokenPtr& bptr) const {
|
||||
return lineno < bptr.lineno ||
|
||||
(lineno == bptr.lineno && index <= bptr.index);
|
||||
}
|
||||
|
||||
bool operator >(const TokenPtr& bptr) {
|
||||
bool operator >(const TokenPtr& bptr) const {
|
||||
return !(*this <= bptr);
|
||||
}
|
||||
|
||||
bool operator >=(const TokenPtr& bptr) {
|
||||
bool operator >=(const TokenPtr& bptr) const {
|
||||
return !(*this < bptr);
|
||||
}
|
||||
};
|
||||
|
@ -210,27 +210,43 @@ struct TokenPos {
|
|||
TokenPtr begin; /* first character and line of token */
|
||||
TokenPtr end; /* index 1 past last char, last line */
|
||||
|
||||
bool operator==(const TokenPos& bpos) {
|
||||
TokenPos() {}
|
||||
|
||||
TokenPos(const TokenPtr &begin, const TokenPtr &end) : begin(begin), end(end) {
|
||||
// Assertion temporarily disabled by jorendorff. See bug 695922.
|
||||
//JS_ASSERT(begin <= end);
|
||||
}
|
||||
|
||||
/* Return a TokenPos that covers left, right, and anything in between. */
|
||||
static TokenPos box(const TokenPos &left, const TokenPos &right) {
|
||||
// Assertions temporarily disabled by jorendorff. See bug 695922.
|
||||
//JS_ASSERT(left.begin <= left.end);
|
||||
//JS_ASSERT(left.end <= right.begin);
|
||||
//JS_ASSERT(right.begin <= right.end);
|
||||
return TokenPos(left.begin, right.end);
|
||||
}
|
||||
|
||||
bool operator==(const TokenPos& bpos) const {
|
||||
return begin == bpos.begin && end == bpos.end;
|
||||
}
|
||||
|
||||
bool operator!=(const TokenPos& bpos) {
|
||||
bool operator!=(const TokenPos& bpos) const {
|
||||
return begin != bpos.begin || end != bpos.end;
|
||||
}
|
||||
|
||||
bool operator <(const TokenPos& bpos) {
|
||||
bool operator <(const TokenPos& bpos) const {
|
||||
return begin < bpos.begin;
|
||||
}
|
||||
|
||||
bool operator <=(const TokenPos& bpos) {
|
||||
bool operator <=(const TokenPos& bpos) const {
|
||||
return begin <= bpos.begin;
|
||||
}
|
||||
|
||||
bool operator >(const TokenPos& bpos) {
|
||||
bool operator >(const TokenPos& bpos) const {
|
||||
return !(*this <= bpos);
|
||||
}
|
||||
|
||||
bool operator >=(const TokenPos& bpos) {
|
||||
bool operator >=(const TokenPos& bpos) const {
|
||||
return !(*this < bpos);
|
||||
}
|
||||
};
|
||||
|
@ -417,7 +433,7 @@ class TokenStream
|
|||
bool hasOctalCharacterEscape() const { return flags & TSF_OCTAL_CHAR; }
|
||||
|
||||
/* Mutators. */
|
||||
bool reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN errorNumber, va_list ap);
|
||||
bool reportCompileErrorNumberVA(ParseNode *pn, uintN flags, uintN errorNumber, va_list ap);
|
||||
void mungeCurrentToken(TokenKind newKind) { tokens[cursor].type = newKind; }
|
||||
void mungeCurrentToken(JSOp newOp) { tokens[cursor].t_op = newOp; }
|
||||
void mungeCurrentToken(TokenKind newKind, JSOp newOp) {
|
||||
|
@ -704,16 +720,6 @@ class TokenStream
|
|||
bool xml; /* see JSOPTION_XML */
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
extern void
|
||||
js_CloseTokenStream(JSContext *cx, js::TokenStream *ts);
|
||||
|
||||
extern JS_FRIEND_API(int)
|
||||
js_fgets(char *buf, int size, FILE *file);
|
||||
|
||||
namespace js {
|
||||
|
||||
struct KeywordInfo {
|
||||
const char *chars; /* C string with keyword text */
|
||||
TokenKind tokentype;
|
||||
|
@ -725,23 +731,15 @@ struct KeywordInfo {
|
|||
* Returns a KeywordInfo for the specified characters, or NULL if the string is
|
||||
* not a keyword.
|
||||
*/
|
||||
extern const KeywordInfo *
|
||||
const KeywordInfo *
|
||||
FindKeyword(const jschar *s, size_t length);
|
||||
|
||||
} // namespace js
|
||||
|
||||
/*
|
||||
* Friend-exported API entry point to call a mapping function on each reserved
|
||||
* identifier in the scanner's keyword table.
|
||||
*/
|
||||
typedef void (*JSMapKeywordFun)(const char *);
|
||||
|
||||
/*
|
||||
* Check that str forms a valid JS identifier name. The function does not
|
||||
* check if str is a JS keyword.
|
||||
*/
|
||||
extern JSBool
|
||||
js_IsIdentifier(JSLinearString *str);
|
||||
JSBool
|
||||
IsIdentifier(JSLinearString *str);
|
||||
|
||||
/*
|
||||
* Steal one JSREPORT_* bit (see jsapi.h) to tell that arguments to the error
|
||||
|
@ -749,15 +747,13 @@ js_IsIdentifier(JSLinearString *str);
|
|||
*/
|
||||
#define JSREPORT_UC 0x100
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* Report a compile-time error by its number. Return true for a warning, false
|
||||
* for an error. When pn is not null, use it to report error's location.
|
||||
* Otherwise use ts, which must not be null.
|
||||
*/
|
||||
bool
|
||||
ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, JSParseNode *pn, uintN flags,
|
||||
ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, ParseNode *pn, uintN flags,
|
||||
uintN errorNumber, ...);
|
||||
|
||||
/*
|
||||
|
@ -770,7 +766,7 @@ ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, JSParseNode *pn, uintN
|
|||
* One could have ReportCompileErrorNumber recognize the
|
||||
* JSREPORT_STRICT_MODE_ERROR flag instead of having a separate function
|
||||
* like this one. However, the strict mode code flag we need to test is
|
||||
* in the JSTreeContext structure for that code; we would have to change
|
||||
* in the TreeContext structure for that code; we would have to change
|
||||
* the ~120 ReportCompileErrorNumber calls to pass the additional
|
||||
* argument, even though many of those sites would never use it. Using
|
||||
* ts's TSF_STRICT_MODE_CODE flag instead of tc's would be brittle: at some
|
||||
|
@ -778,9 +774,12 @@ ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, JSParseNode *pn, uintN
|
|||
* error.
|
||||
*/
|
||||
bool
|
||||
ReportStrictModeError(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSParseNode *pn,
|
||||
ReportStrictModeError(JSContext *cx, TokenStream *ts, TreeContext *tc, ParseNode *pn,
|
||||
uintN errorNumber, ...);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
extern JS_FRIEND_API(int)
|
||||
js_fgets(char *buf, int size, FILE *file);
|
||||
|
||||
#endif /* TokenStream_h__ */
|
||||
|
|
|
@ -1818,7 +1818,7 @@ JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved)
|
|||
atom = rt->atomState.typeAtoms[JSTYPE_VOID];
|
||||
if (idstr == atom) {
|
||||
*resolved = JS_TRUE;
|
||||
return obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
|
||||
return obj->defineProperty(cx, atom->asPropertyName(), UndefinedValue(),
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY);
|
||||
}
|
||||
|
@ -1889,7 +1889,6 @@ JS_PUBLIC_API(JSBool)
|
|||
JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JSRuntime *rt;
|
||||
JSAtom *atom;
|
||||
uintN i;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
|
@ -1900,9 +1899,9 @@ JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
|
|||
* Check whether we need to bind 'undefined' and define it if so.
|
||||
* Since ES5 15.1.1.3 undefined can't be deleted.
|
||||
*/
|
||||
atom = rt->atomState.typeAtoms[JSTYPE_VOID];
|
||||
if (!obj->nativeContains(cx, ATOM_TO_JSID(atom)) &&
|
||||
!obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
|
||||
PropertyName *name = rt->atomState.typeAtoms[JSTYPE_VOID];
|
||||
if (!obj->nativeContains(cx, ATOM_TO_JSID(name)) &&
|
||||
!obj->defineProperty(cx, name, UndefinedValue(),
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY)) {
|
||||
return JS_FALSE;
|
||||
|
@ -3500,7 +3499,7 @@ DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, const Value &value,
|
|||
return !!DefineNativeProperty(cx, obj, id, value, getter, setter,
|
||||
attrs, flags, tinyid);
|
||||
}
|
||||
return obj->defineProperty(cx, id, value, getter, setter, attrs);
|
||||
return obj->defineGeneric(cx, id, value, getter, setter, attrs);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
|
@ -3708,7 +3707,7 @@ GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
|||
? Proxy::getOwnPropertyDescriptor(cx, obj2, id, false, desc)
|
||||
: Proxy::getPropertyDescriptor(cx, obj2, id, false, desc);
|
||||
}
|
||||
if (!obj2->getAttributes(cx, id, &desc->attrs))
|
||||
if (!obj2->getGenericAttributes(cx, id, &desc->attrs))
|
||||
return false;
|
||||
desc->getter = NULL;
|
||||
desc->setter = NULL;
|
||||
|
@ -3802,7 +3801,7 @@ SetPropertyAttributesById(JSContext *cx, JSObject *obj, jsid id, uintN attrs, JS
|
|||
}
|
||||
JSBool ok = obj->isNative()
|
||||
? js_SetNativeAttributes(cx, obj, (Shape *) prop, attrs)
|
||||
: obj->setAttributes(cx, id, &attrs);
|
||||
: obj->setGenericAttributes(cx, id, &attrs);
|
||||
if (ok)
|
||||
*foundp = true;
|
||||
return ok;
|
||||
|
@ -3895,7 +3894,7 @@ JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
|||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj, id);
|
||||
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
|
||||
return obj->setProperty(cx, id, vp, false);
|
||||
return obj->setGeneric(cx, id, vp, false);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
|
@ -3928,7 +3927,7 @@ JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
|
|||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj, id);
|
||||
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
|
||||
return obj->deleteProperty(cx, id, rval, false);
|
||||
return obj->deleteGeneric(cx, id, rval, false);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
|
@ -4579,8 +4578,8 @@ CompileUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj, JSPrincipals *p
|
|||
AutoLastFrameCheck lfc(cx);
|
||||
|
||||
uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT | TCF_NEED_SCRIPT_OBJECT;
|
||||
return Compiler::compileScript(cx, obj, NULL, principals, tcflags,
|
||||
chars, length, filename, lineno, version);
|
||||
return BytecodeCompiler::compileScript(cx, obj, NULL, principals, tcflags, chars, length,
|
||||
filename, lineno, version);
|
||||
}
|
||||
|
||||
extern JS_PUBLIC_API(JSScript *)
|
||||
|
@ -4756,8 +4755,8 @@ CompileFileHelper(JSContext *cx, JSObject *obj, JSPrincipals *principals,
|
|||
JS_ASSERT(i <= len);
|
||||
len = i;
|
||||
uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT | TCF_NEED_SCRIPT_OBJECT;
|
||||
script = Compiler::compileScript(cx, obj, NULL, principals, tcflags, buf, len, filename, 1,
|
||||
cx->findVersion());
|
||||
script = BytecodeCompiler::compileScript(cx, obj, NULL, principals, tcflags, buf, len,
|
||||
filename, 1, cx->findVersion());
|
||||
cx->free_(buf);
|
||||
return script;
|
||||
}
|
||||
|
@ -4856,14 +4855,16 @@ CompileUCFunctionForPrincipalsCommon(JSContext *cx, JSObject *obj,
|
|||
if (!fun)
|
||||
return NULL;
|
||||
|
||||
if (!Compiler::compileFunctionBody(cx, fun, principals, &bindings,
|
||||
chars, length, filename, lineno, version)) {
|
||||
if (!BytecodeCompiler::compileFunctionBody(cx, fun, principals, &bindings,
|
||||
chars, length, filename, lineno, version))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (obj && funAtom &&
|
||||
!obj->defineProperty(cx, ATOM_TO_JSID(funAtom), ObjectValue(*fun),
|
||||
NULL, NULL, JSPROP_ENUMERATE)) {
|
||||
!obj->defineGeneric(cx, ATOM_TO_JSID(funAtom), ObjectValue(*fun), NULL, NULL,
|
||||
JSPROP_ENUMERATE))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -5018,8 +5019,8 @@ EvaluateUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj,
|
|||
|
||||
CHECK_REQUEST(cx);
|
||||
AutoLastFrameCheck lfc(cx);
|
||||
JSScript *script = Compiler::compileScript(cx, obj, NULL, principals, flags,
|
||||
chars, length, filename, lineno, compileVersion);
|
||||
JSScript *script = BytecodeCompiler::compileScript(cx, obj, NULL, principals, flags, chars,
|
||||
length, filename, lineno, compileVersion);
|
||||
if (!script)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -481,7 +481,7 @@ SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, const Value &v)
|
|||
JS_ASSERT(!JSID_IS_VOID(idr.id()));
|
||||
|
||||
Value tmp = v;
|
||||
return obj->setProperty(cx, idr.id(), &tmp, true);
|
||||
return obj->setGeneric(cx, idr.id(), &tmp, true);
|
||||
}
|
||||
|
||||
#ifdef JS_TRACER
|
||||
|
@ -541,7 +541,7 @@ DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index, bool strict)
|
|||
return 1;
|
||||
|
||||
Value v;
|
||||
if (!obj->deleteProperty(cx, idr.id(), &v, strict))
|
||||
if (!obj->deleteGeneric(cx, idr.id(), &v, strict))
|
||||
return -1;
|
||||
return v.isTrue() ? 1 : 0;
|
||||
}
|
||||
|
@ -564,13 +564,10 @@ SetOrDeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index,
|
|||
JSBool
|
||||
js_SetLengthProperty(JSContext *cx, JSObject *obj, jsdouble length)
|
||||
{
|
||||
Value v;
|
||||
jsid id;
|
||||
Value v = NumberValue(length);
|
||||
|
||||
v.setNumber(length);
|
||||
id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
|
||||
/* We don't support read-only array length yet. */
|
||||
return obj->setProperty(cx, id, &v, false);
|
||||
return obj->setProperty(cx, cx->runtime->atomState.lengthAtom, &v, false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -596,9 +593,8 @@ static JSBool
|
|||
array_length_setter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
{
|
||||
if (!obj->isArray()) {
|
||||
jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
|
||||
|
||||
return obj->defineProperty(cx, lengthId, *vp, NULL, NULL, JSPROP_ENUMERATE);
|
||||
return obj->defineProperty(cx, cx->runtime->atomState.lengthAtom, *vp,
|
||||
NULL, NULL, JSPROP_ENUMERATE);
|
||||
}
|
||||
|
||||
uint32 newlen;
|
||||
|
@ -677,7 +673,7 @@ array_length_setter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value
|
|||
jsuint index;
|
||||
Value junk;
|
||||
if (js_IdIsIndex(id, &index) && index - newlen < gap &&
|
||||
!obj->deleteProperty(cx, id, &junk, false)) {
|
||||
!obj->deleteElement(cx, index, &junk, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -903,7 +899,7 @@ array_typeOf(JSContext *cx, JSObject *obj)
|
|||
}
|
||||
|
||||
static JSBool
|
||||
array_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
|
||||
array_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
|
@ -938,6 +934,12 @@ array_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool stric
|
|||
return js_SetPropertyHelper(cx, obj, id, 0, vp, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
array_setProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict)
|
||||
{
|
||||
return array_setGeneric(cx, obj, ATOM_TO_JSID(name), vp, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
array_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict)
|
||||
{
|
||||
|
@ -980,7 +982,7 @@ array_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool s
|
|||
static JSBool
|
||||
array_setSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict)
|
||||
{
|
||||
return array_setProperty(cx, obj, SPECIALID_TO_JSID(sid), vp, strict);
|
||||
return array_setGeneric(cx, obj, SPECIALID_TO_JSID(sid), vp, strict);
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -1005,12 +1007,9 @@ js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj)
|
|||
return JS_FALSE;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
/* non-static for direct definition of array elements within the engine */
|
||||
JSBool
|
||||
array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
|
||||
JSPropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
static JSBool
|
||||
array_defineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *value,
|
||||
JSPropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
{
|
||||
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
|
||||
return JS_TRUE;
|
||||
|
@ -1043,6 +1042,15 @@ array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
|
|||
return js_DefineProperty(cx, obj, id, value, getter, setter, attrs);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
array_defineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value *value,
|
||||
JSPropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
{
|
||||
return array_defineGeneric(cx, obj, ATOM_TO_JSID(name), value, getter, setter, attrs);
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
/* non-static for direct definition of array elements within the engine */
|
||||
JSBool
|
||||
array_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *value,
|
||||
|
@ -1088,15 +1096,24 @@ static JSBool
|
|||
array_defineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *value,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
{
|
||||
return array_defineProperty(cx, obj, SPECIALID_TO_JSID(sid), value, getter, setter, attrs);
|
||||
return array_defineGeneric(cx, obj, SPECIALID_TO_JSID(sid), value, getter, setter, attrs);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
array_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
array_getGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
{
|
||||
*attrsp = JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)
|
||||
? JSPROP_PERMANENT : JSPROP_ENUMERATE;
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
array_getPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp)
|
||||
{
|
||||
*attrsp = (name == cx->runtime->atomState.lengthAtom)
|
||||
? JSPROP_PERMANENT
|
||||
: JSPROP_ENUMERATE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -1109,11 +1126,19 @@ array_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *at
|
|||
static JSBool
|
||||
array_getSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp)
|
||||
{
|
||||
return array_getAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
*attrsp = JSPROP_ENUMERATE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
array_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
array_setGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
{
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS);
|
||||
return false;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
array_setPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp)
|
||||
{
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS);
|
||||
return false;
|
||||
|
@ -1129,14 +1154,12 @@ array_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *at
|
|||
static JSBool
|
||||
array_setSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp)
|
||||
{
|
||||
return array_setAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS);
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
/* non-static for direct deletion of array elements within the engine */
|
||||
JSBool
|
||||
array_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
|
||||
static JSBool
|
||||
array_deleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
|
@ -1160,6 +1183,14 @@ array_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool
|
|||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
array_deleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict)
|
||||
{
|
||||
return array_deleteGeneric(cx, obj, ATOM_TO_JSID(name), rval, strict);
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
/* non-static for direct deletion of array elements within the engine */
|
||||
JSBool
|
||||
array_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict)
|
||||
|
@ -1184,7 +1215,7 @@ array_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSB
|
|||
static JSBool
|
||||
array_deleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict)
|
||||
{
|
||||
return array_deleteProperty(cx, obj, SPECIALID_TO_JSID(sid), rval, strict);
|
||||
return array_deleteGeneric(cx, obj, SPECIALID_TO_JSID(sid), rval, strict);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1237,7 +1268,7 @@ Class js::ArrayClass = {
|
|||
array_lookupProperty,
|
||||
array_lookupElement,
|
||||
array_lookupSpecial,
|
||||
array_defineProperty,
|
||||
array_defineGeneric,
|
||||
array_defineProperty,
|
||||
array_defineElement,
|
||||
array_defineSpecial,
|
||||
|
@ -1245,19 +1276,19 @@ Class js::ArrayClass = {
|
|||
array_getProperty,
|
||||
array_getElement,
|
||||
array_getSpecial,
|
||||
array_setProperty,
|
||||
array_setGeneric,
|
||||
array_setProperty,
|
||||
array_setElement,
|
||||
array_setSpecial,
|
||||
array_getAttributes,
|
||||
array_getAttributes,
|
||||
array_getGenericAttributes,
|
||||
array_getPropertyAttributes,
|
||||
array_getElementAttributes,
|
||||
array_getSpecialAttributes,
|
||||
array_setAttributes,
|
||||
array_setAttributes,
|
||||
array_setGenericAttributes,
|
||||
array_setPropertyAttributes,
|
||||
array_setElementAttributes,
|
||||
array_setSpecialAttributes,
|
||||
array_deleteProperty,
|
||||
array_deleteGeneric,
|
||||
array_deleteProperty,
|
||||
array_deleteElement,
|
||||
array_deleteSpecial,
|
||||
|
@ -1788,7 +1819,7 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, cons
|
|||
do {
|
||||
*tvr.addr() = *vector++;
|
||||
if (!js_ValueToStringId(cx, idval, idr.addr()) ||
|
||||
!obj->setProperty(cx, idr.id(), tvr.addr(), true)) {
|
||||
!obj->setGeneric(cx, idr.id(), tvr.addr(), true)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
idval.getDoubleRef() += 1;
|
||||
|
@ -2725,18 +2756,39 @@ TryReuseArrayType(JSObject *obj, JSObject *nobj)
|
|||
* Returns true if this is a dense array whose |count| properties starting from
|
||||
* |startingIndex| may be accessed (get, set, delete) directly through its
|
||||
* contiguous vector of elements without fear of getters, setters, etc. along
|
||||
* the prototype chain.
|
||||
* the prototype chain, or of enumerators requiring notification of
|
||||
* modifications.
|
||||
*/
|
||||
static inline bool
|
||||
CanOptimizeForDenseStorage(JSObject *arr, uint32 startingIndex, uint32 count, JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(UINT32_MAX - startingIndex >= count);
|
||||
/* If the desired properties overflow dense storage, we can't optimize. */
|
||||
if (UINT32_MAX - startingIndex < count)
|
||||
return false;
|
||||
|
||||
uint32 length = startingIndex + count;
|
||||
return arr->isDenseArray() &&
|
||||
!arr->getType(cx)->hasAllFlags(OBJECT_FLAG_NON_PACKED_ARRAY) &&
|
||||
!js_PrototypeHasIndexedProperties(cx, arr) &&
|
||||
length <= arr->getDenseArrayInitializedLength();
|
||||
/* There's no optimizing possible if it's not a dense array. */
|
||||
if (!arr->isDenseArray())
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Don't optimize if the array might be in the midst of iteration. We
|
||||
* rely on this to be able to safely move dense array elements around with
|
||||
* just a memmove (see JSObject::moveDenseArrayElements), without worrying
|
||||
* about updating any in-progress enumerators for properties implicitly
|
||||
* deleted if a hole is moved from one location to another location not yet
|
||||
* visited. See bug 690622.
|
||||
*
|
||||
* Another potential wrinkle: what if the enumeration is happening on an
|
||||
* object which merely has |arr| on its prototype chain? It turns out this
|
||||
* case can't happen, because any dense array used as the prototype of
|
||||
* another object is first slowified, for type inference's sake.
|
||||
*/
|
||||
if (JS_UNLIKELY(arr->getType(cx)->hasAllFlags(OBJECT_FLAG_ITERATED)))
|
||||
return false;
|
||||
|
||||
/* Now just watch out for getters and setters along the prototype chain. */
|
||||
return !js_PrototypeHasIndexedProperties(cx, arr) &&
|
||||
startingIndex + count <= arr->getDenseArrayInitializedLength();
|
||||
}
|
||||
|
||||
static inline bool
|
||||
|
|
|
@ -58,14 +58,6 @@ JSObject::getDenseArrayInitializedLength()
|
|||
return initializedLength;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setDenseArrayInitializedLength(uint32 length)
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
JS_ASSERT(length <= getDenseArrayCapacity());
|
||||
initializedLength = length;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::isPackedDenseArray()
|
||||
{
|
||||
|
@ -173,11 +165,11 @@ js_SetLengthProperty(JSContext *cx, JSObject *obj, jsdouble length);
|
|||
namespace js {
|
||||
|
||||
extern JSBool
|
||||
array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs);
|
||||
array_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *value,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs);
|
||||
|
||||
extern JSBool
|
||||
array_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict);
|
||||
array_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict);
|
||||
|
||||
/*
|
||||
* Copy 'length' elements from aobj to vp.
|
||||
|
|
|
@ -41,6 +41,15 @@
|
|||
#define jsarrayinlines_h___
|
||||
|
||||
#include "jsinferinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
inline void
|
||||
JSObject::setDenseArrayInitializedLength(uint32 length)
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
JS_ASSERT(length <= getDenseArrayCapacity());
|
||||
initializedLength = length;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::markDenseArrayNotPacked(JSContext *cx)
|
||||
|
|
|
@ -58,16 +58,7 @@ extern bool
|
|||
BooleanToStringBuffer(JSContext *cx, JSBool b, StringBuffer &sb);
|
||||
|
||||
inline bool
|
||||
BooleanGetPrimitiveValue(JSContext *cx, JSObject &obj, Value *vp)
|
||||
{
|
||||
if (obj.isBoolean()) {
|
||||
*vp = obj.getPrimitiveThis();
|
||||
return true;
|
||||
}
|
||||
|
||||
extern bool BooleanGetPrimitiveValueSlow(JSContext *, JSObject &, Value *);
|
||||
return BooleanGetPrimitiveValueSlow(cx, obj, vp);
|
||||
}
|
||||
BooleanGetPrimitiveValue(JSContext *cx, JSObject &obj, Value *vp);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is SpiderMonkey code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jeff Walden <jwalden+code@mit.edu> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef jsboolinlines_h___
|
||||
#define jsboolinlines_h___
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
inline bool
|
||||
BooleanGetPrimitiveValue(JSContext *cx, JSObject &obj, Value *vp)
|
||||
{
|
||||
if (obj.isBoolean()) {
|
||||
*vp = obj.getPrimitiveThis();
|
||||
return true;
|
||||
}
|
||||
|
||||
extern bool BooleanGetPrimitiveValueSlow(JSContext *, JSObject &, Value *);
|
||||
return BooleanGetPrimitiveValueSlow(cx, obj, vp);
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsboolinlines_h___ */
|
|
@ -193,7 +193,7 @@ typedef JSBool
|
|||
(* DefineGenericOp)(JSContext *cx, JSObject *obj, jsid id, const Value *value,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs);
|
||||
typedef JSBool
|
||||
(* DefinePropOp)(JSContext *cx, JSObject *obj, jsid id, const Value *value,
|
||||
(* DefinePropOp)(JSContext *cx, JSObject *obj, PropertyName *name, const Value *value,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs);
|
||||
typedef JSBool
|
||||
(* DefineElementOp)(JSContext *cx, JSObject *obj, uint32 index, const Value *value,
|
||||
|
@ -212,7 +212,7 @@ typedef JSBool
|
|||
typedef JSBool
|
||||
(* StrictGenericIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict);
|
||||
typedef JSBool
|
||||
(* StrictPropertyIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict);
|
||||
(* StrictPropertyIdOp)(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict);
|
||||
typedef JSBool
|
||||
(* StrictElementIdOp)(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict);
|
||||
typedef JSBool
|
||||
|
@ -220,7 +220,7 @@ typedef JSBool
|
|||
typedef JSBool
|
||||
(* GenericAttributesOp)(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
|
||||
typedef JSBool
|
||||
(* AttributesOp)(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
|
||||
(* PropertyAttributesOp)(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp);
|
||||
typedef JSBool
|
||||
(* ElementAttributesOp)(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp);
|
||||
typedef JSBool
|
||||
|
@ -228,7 +228,7 @@ typedef JSBool
|
|||
typedef JSBool
|
||||
(* DeleteGenericOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict);
|
||||
typedef JSBool
|
||||
(* DeleteIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict);
|
||||
(* DeleteIdOp)(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict);
|
||||
typedef JSBool
|
||||
(* DeleteElementOp)(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict);
|
||||
typedef JSBool
|
||||
|
@ -319,11 +319,11 @@ struct ObjectOps
|
|||
StrictElementIdOp setElement;
|
||||
StrictSpecialIdOp setSpecial;
|
||||
GenericAttributesOp getGenericAttributes;
|
||||
AttributesOp getAttributes;
|
||||
PropertyAttributesOp getPropertyAttributes;
|
||||
ElementAttributesOp getElementAttributes;
|
||||
SpecialAttributesOp getSpecialAttributes;
|
||||
GenericAttributesOp setGenericAttributes;
|
||||
AttributesOp setAttributes;
|
||||
PropertyAttributesOp setPropertyAttributes;
|
||||
ElementAttributesOp setElementAttributes;
|
||||
SpecialAttributesOp setSpecialAttributes;
|
||||
DeleteGenericOp deleteGeneric;
|
||||
|
|
|
@ -876,7 +876,7 @@ JSStructuredCloneReader::read(Value *vp)
|
|||
objs.popBack();
|
||||
} else {
|
||||
Value v;
|
||||
if (!startRead(&v) || !obj->defineProperty(context(), id, v))
|
||||
if (!startRead(&v) || !obj->defineGeneric(context(), id, v))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -406,7 +406,7 @@ JS_GetLinePCs(JSContext *cx, JSScript *script,
|
|||
uintN i = 0;
|
||||
for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
|
||||
offset += SN_DELTA(sn);
|
||||
JSSrcNoteType type = (JSSrcNoteType) SN_TYPE(sn);
|
||||
SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
|
||||
if (type == SRC_SETLINE || type == SRC_NEWLINE) {
|
||||
if (type == SRC_SETLINE)
|
||||
lineno = (uintN) js_GetSrcNoteOffset(sn, 0);
|
||||
|
|
|
@ -1241,7 +1241,7 @@ js_ReportUncaughtException(JSContext *cx)
|
|||
JS_ClearPendingException(cx);
|
||||
reportp = js_ErrorFromException(cx, exn);
|
||||
|
||||
/* XXX L10N angels cry once again (see also jsemit.c, /L10N gaffes/) */
|
||||
/* XXX L10N angels cry once again. see also everywhere else */
|
||||
str = js_ValueToString(cx, exn);
|
||||
JSAutoByteString bytesStorage;
|
||||
if (!str) {
|
||||
|
|
|
@ -192,8 +192,8 @@ ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee)
|
|||
{
|
||||
JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX);
|
||||
|
||||
JSObject *proto;
|
||||
if (!js_GetClassPrototype(cx, callee.getGlobal(), JSProto_Object, &proto))
|
||||
JSObject *proto = callee.getGlobal()->getOrCreateObjectPrototype(cx);
|
||||
if (!proto)
|
||||
return NULL;
|
||||
|
||||
TypeObject *type = proto->getNewType(cx);
|
||||
|
@ -1451,10 +1451,10 @@ ResolveInterpretedFunctionPrototype(JSContext *cx, JSObject *obj)
|
|||
* the prototype's .constructor property is configurable, non-enumerable,
|
||||
* and writable.
|
||||
*/
|
||||
if (!obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom),
|
||||
if (!obj->defineProperty(cx, cx->runtime->atomState.classPrototypeAtom,
|
||||
ObjectValue(*proto), JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_PERMANENT) ||
|
||||
!proto->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.constructorAtom),
|
||||
!proto->defineProperty(cx, cx->runtime->atomState.constructorAtom,
|
||||
ObjectValue(*obj), JS_PropertyStub, JS_StrictPropertyStub, 0))
|
||||
{
|
||||
return NULL;
|
||||
|
@ -2284,9 +2284,8 @@ Function(JSContext *cx, uintN argc, Value *vp)
|
|||
return false;
|
||||
|
||||
JSPrincipals *principals = PrincipalsForCompiledCode(args, cx);
|
||||
bool ok = Compiler::compileFunctionBody(cx, fun, principals, &bindings,
|
||||
chars, length, filename, lineno,
|
||||
cx->findVersion());
|
||||
bool ok = BytecodeCompiler::compileFunctionBody(cx, fun, principals, &bindings, chars, length,
|
||||
filename, lineno, cx->findVersion());
|
||||
args.rval().setObject(*fun);
|
||||
return ok;
|
||||
}
|
||||
|
@ -2582,7 +2581,7 @@ js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, Native native,
|
|||
if (!wasDelegate && obj->isDelegate())
|
||||
obj->clearDelegate();
|
||||
|
||||
if (!obj->defineProperty(cx, id, ObjectValue(*fun), gop, sop, attrs & ~JSFUN_FLAGS_MASK))
|
||||
if (!obj->defineGeneric(cx, id, ObjectValue(*fun), gop, sop, attrs & ~JSFUN_FLAGS_MASK))
|
||||
return NULL;
|
||||
|
||||
return fun;
|
||||
|
|
|
@ -448,28 +448,7 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
|
|||
|
||||
inline JSObject *
|
||||
CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
|
||||
bool ignoreSingletonClone = false)
|
||||
{
|
||||
JS_ASSERT(parent);
|
||||
JSObject *proto;
|
||||
if (!js_GetClassPrototype(cx, parent, JSProto_Function, &proto))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* For attempts to clone functions at a function definition opcode or from
|
||||
* a method barrier, don't perform the clone if the function has singleton
|
||||
* type. CloneFunctionObject was called pessimistically, and we need to
|
||||
* preserve the type's property that if it is singleton there is only a
|
||||
* single object with its type in existence.
|
||||
*/
|
||||
if (ignoreSingletonClone && fun->hasSingletonType()) {
|
||||
JS_ASSERT(fun->getProto() == proto);
|
||||
fun->setParent(parent);
|
||||
return fun;
|
||||
}
|
||||
|
||||
return js_CloneFunctionObject(cx, fun, parent, proto);
|
||||
}
|
||||
bool ignoreSingletonClone = false);
|
||||
|
||||
inline JSObject *
|
||||
CloneFunctionObject(JSContext *cx, JSFunction *fun)
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
#include "jsfun.h"
|
||||
#include "jsscript.h"
|
||||
|
||||
#include "vm/GlobalObject.h"
|
||||
|
||||
inline bool
|
||||
js::IsConstructing(CallReceiver call)
|
||||
{
|
||||
|
@ -70,4 +72,29 @@ JSFunction::setMethodAtom(JSAtom *atom)
|
|||
setSlot(METHOD_ATOM_SLOT, js::StringValue(atom));
|
||||
}
|
||||
|
||||
inline JSObject *
|
||||
CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
|
||||
bool ignoreSingletonClone /* = false */)
|
||||
{
|
||||
JS_ASSERT(parent);
|
||||
JSObject *proto = parent->getGlobal()->getOrCreateFunctionPrototype(cx);
|
||||
if (!proto)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* For attempts to clone functions at a function definition opcode or from
|
||||
* a method barrier, don't perform the clone if the function has singleton
|
||||
* type. CloneFunctionObject was called pessimistically, and we need to
|
||||
* preserve the type's property that if it is singleton there is only a
|
||||
* single object with its type in existence.
|
||||
*/
|
||||
if (ignoreSingletonClone && fun->hasSingletonType()) {
|
||||
JS_ASSERT(fun->getProto() == proto);
|
||||
fun->setParent(parent);
|
||||
return fun;
|
||||
}
|
||||
|
||||
return js_CloneFunctionObject(cx, fun, parent, proto);
|
||||
}
|
||||
|
||||
#endif /* jsfuninlines_h___ */
|
||||
|
|
|
@ -838,7 +838,7 @@ js::CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs)
|
|||
if (obj2->isNative()) {
|
||||
oldAttrs = ((Shape *) prop)->attributes();
|
||||
} else {
|
||||
if (!obj2->getAttributes(cx, id, &oldAttrs))
|
||||
if (!obj2->getGenericAttributes(cx, id, &oldAttrs))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2661,7 +2661,7 @@ BEGIN_CASE(JSOP_SETCONST)
|
|||
LOAD_ATOM(0, atom);
|
||||
JSObject &obj = regs.fp()->varObj();
|
||||
const Value &ref = regs.sp[-1];
|
||||
if (!obj.defineProperty(cx, ATOM_TO_JSID(atom), ref,
|
||||
if (!obj.defineProperty(cx, atom->asPropertyName(), ref,
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
|
||||
goto error;
|
||||
|
@ -2677,9 +2677,9 @@ BEGIN_CASE(JSOP_ENUMCONSTELEM)
|
|||
FETCH_OBJECT(cx, -2, obj);
|
||||
jsid id;
|
||||
FETCH_ELEMENT_ID(obj, -1, id);
|
||||
if (!obj->defineProperty(cx, id, ref,
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
|
||||
if (!obj->defineGeneric(cx, id, ref,
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
|
||||
goto error;
|
||||
}
|
||||
regs.sp -= 3;
|
||||
|
@ -3137,7 +3137,7 @@ BEGIN_CASE(JSOP_DELNAME)
|
|||
/* ECMA says to return true if name is undefined or inherited. */
|
||||
PUSH_BOOLEAN(true);
|
||||
if (prop) {
|
||||
if (!obj->deleteProperty(cx, id, ®s.sp[-1], false))
|
||||
if (!obj->deleteProperty(cx, atom->asPropertyName(), ®s.sp[-1], false))
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
@ -3153,7 +3153,7 @@ BEGIN_CASE(JSOP_DELPROP)
|
|||
FETCH_OBJECT(cx, -1, obj);
|
||||
|
||||
Value rval;
|
||||
if (!obj->deleteProperty(cx, id, &rval, script->strictModeCode))
|
||||
if (!obj->deleteGeneric(cx, id, &rval, script->strictModeCode))
|
||||
goto error;
|
||||
|
||||
regs.sp[-1] = rval;
|
||||
|
@ -3171,7 +3171,7 @@ BEGIN_CASE(JSOP_DELELEM)
|
|||
FETCH_ELEMENT_ID(obj, -1, id);
|
||||
|
||||
/* Get or set the element. */
|
||||
if (!obj->deleteProperty(cx, id, ®s.sp[-2], script->strictModeCode))
|
||||
if (!obj->deleteGeneric(cx, id, ®s.sp[-2], script->strictModeCode))
|
||||
goto error;
|
||||
|
||||
regs.sp--;
|
||||
|
@ -3342,7 +3342,7 @@ do_incop:
|
|||
|
||||
{
|
||||
JSAutoResolveFlags rf(cx, setPropFlags);
|
||||
if (!obj->setProperty(cx, id, &ref, script->strictModeCode))
|
||||
if (!obj->setGeneric(cx, id, &ref, script->strictModeCode))
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -3359,7 +3359,7 @@ do_incop:
|
|||
|
||||
{
|
||||
JSAutoResolveFlags rf(cx, setPropFlags);
|
||||
if (!obj->setProperty(cx, id, ®s.sp[-1], script->strictModeCode))
|
||||
if (!obj->setGeneric(cx, id, ®s.sp[-1], script->strictModeCode))
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -3557,20 +3557,20 @@ BEGIN_CASE(JSOP_CALLPROP)
|
|||
if (lval.isObject()) {
|
||||
objv = lval;
|
||||
} else {
|
||||
JSProtoKey protoKey;
|
||||
GlobalObject *global = regs.fp()->scopeChain().getGlobal();
|
||||
JSObject *pobj;
|
||||
if (lval.isString()) {
|
||||
protoKey = JSProto_String;
|
||||
pobj = global->getOrCreateStringPrototype(cx);
|
||||
} else if (lval.isNumber()) {
|
||||
protoKey = JSProto_Number;
|
||||
pobj = global->getOrCreateNumberPrototype(cx);
|
||||
} else if (lval.isBoolean()) {
|
||||
protoKey = JSProto_Boolean;
|
||||
pobj = global->getOrCreateBooleanPrototype(cx);
|
||||
} else {
|
||||
JS_ASSERT(lval.isNull() || lval.isUndefined());
|
||||
js_ReportIsNullOrUndefined(cx, -1, lval, NULL);
|
||||
goto error;
|
||||
}
|
||||
JSObject *pobj;
|
||||
if (!js_GetClassPrototype(cx, NULL, protoKey, &pobj))
|
||||
if (!pobj)
|
||||
goto error;
|
||||
objv.setObject(*pobj);
|
||||
}
|
||||
|
@ -3795,7 +3795,7 @@ BEGIN_CASE(JSOP_SETMETHOD)
|
|||
if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rval, script->strictModeCode))
|
||||
goto error;
|
||||
} else {
|
||||
if (!obj->setProperty(cx, id, &rval, script->strictModeCode))
|
||||
if (!obj->setGeneric(cx, id, &rval, script->strictModeCode))
|
||||
goto error;
|
||||
ABORT_RECORDING(cx, "Non-native set");
|
||||
}
|
||||
|
@ -3944,7 +3944,7 @@ BEGIN_CASE(JSOP_SETELEM)
|
|||
}
|
||||
} while (0);
|
||||
rval = regs.sp[-1];
|
||||
if (!obj->setProperty(cx, id, &rval, script->strictModeCode))
|
||||
if (!obj->setGeneric(cx, id, &rval, script->strictModeCode))
|
||||
goto error;
|
||||
end_setelem:;
|
||||
}
|
||||
|
@ -3958,7 +3958,7 @@ BEGIN_CASE(JSOP_ENUMELEM)
|
|||
jsid id;
|
||||
FETCH_ELEMENT_ID(obj, -1, id);
|
||||
Value rval = regs.sp[-3];
|
||||
if (!obj->setProperty(cx, id, &rval, script->strictModeCode))
|
||||
if (!obj->setGeneric(cx, id, &rval, script->strictModeCode))
|
||||
goto error;
|
||||
regs.sp -= 3;
|
||||
}
|
||||
|
@ -4215,17 +4215,12 @@ BEGIN_CASE(JSOP_REGEXP)
|
|||
{
|
||||
/*
|
||||
* Push a regexp object cloned from the regexp literal object mapped by the
|
||||
* bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was
|
||||
* flouted by many browser-based implementations.
|
||||
*
|
||||
* We avoid the GetScopeChain call here and pass fp->scopeChain as
|
||||
* js_GetClassPrototype uses the latter only to locate the global.
|
||||
* bytecode at pc.
|
||||
*/
|
||||
jsatomid index = GET_FULL_INDEX(0);
|
||||
JSObject *proto;
|
||||
if (!js_GetClassPrototype(cx, ®s.fp()->scopeChain(), JSProto_RegExp, &proto))
|
||||
JSObject *proto = regs.fp()->scopeChain().getGlobal()->getOrCreateRegExpPrototype(cx);
|
||||
if (!proto)
|
||||
goto error;
|
||||
JS_ASSERT(proto);
|
||||
JSObject *obj = js_CloneRegExpObject(cx, script->getRegExp(index), proto);
|
||||
if (!obj)
|
||||
goto error;
|
||||
|
@ -4668,8 +4663,11 @@ BEGIN_CASE(JSOP_DEFFUN)
|
|||
do {
|
||||
/* Steps 5d, 5f. */
|
||||
if (!prop || pobj != parent) {
|
||||
if (!parent->defineProperty(cx, id, rval, JS_PropertyStub, JS_StrictPropertyStub, attrs))
|
||||
if (!parent->defineProperty(cx, name, rval,
|
||||
JS_PropertyStub, JS_StrictPropertyStub, attrs))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4678,8 +4676,11 @@ BEGIN_CASE(JSOP_DEFFUN)
|
|||
Shape *shape = reinterpret_cast<Shape *>(prop);
|
||||
if (parent->isGlobal()) {
|
||||
if (shape->configurable()) {
|
||||
if (!parent->defineProperty(cx, id, rval, JS_PropertyStub, JS_StrictPropertyStub, attrs))
|
||||
if (!parent->defineProperty(cx, name, rval,
|
||||
JS_PropertyStub, JS_StrictPropertyStub, attrs))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4701,7 +4702,7 @@ BEGIN_CASE(JSOP_DEFFUN)
|
|||
*/
|
||||
|
||||
/* Step 5f. */
|
||||
if (!parent->setProperty(cx, id, &rval, script->strictModeCode))
|
||||
if (!parent->setProperty(cx, name, &rval, script->strictModeCode))
|
||||
goto error;
|
||||
} while (false);
|
||||
}
|
||||
|
@ -4728,9 +4729,11 @@ BEGIN_CASE(JSOP_DEFFUN_FC)
|
|||
if (!CheckRedeclaration(cx, &parent, id, attrs))
|
||||
goto error;
|
||||
|
||||
PropertyName *name = fun->atom->asPropertyName();
|
||||
if ((attrs == JSPROP_ENUMERATE)
|
||||
? !parent.setProperty(cx, id, &rval, script->strictModeCode)
|
||||
: !parent.defineProperty(cx, id, rval, JS_PropertyStub, JS_StrictPropertyStub, attrs)) {
|
||||
? !parent.setProperty(cx, name, &rval, script->strictModeCode)
|
||||
: !parent.defineProperty(cx, name, rval, JS_PropertyStub, JS_StrictPropertyStub, attrs))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
@ -5020,7 +5023,7 @@ BEGIN_CASE(JSOP_SETTER)
|
|||
if (!CheckRedeclaration(cx, obj, id, attrs))
|
||||
goto error;
|
||||
|
||||
if (!obj->defineProperty(cx, id, UndefinedValue(), getter, setter, attrs))
|
||||
if (!obj->defineGeneric(cx, id, UndefinedValue(), getter, setter, attrs))
|
||||
goto error;
|
||||
|
||||
regs.sp += i;
|
||||
|
@ -5209,7 +5212,7 @@ BEGIN_CASE(JSOP_INITELEM)
|
|||
goto error;
|
||||
}
|
||||
} else {
|
||||
if (!obj->defineProperty(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE))
|
||||
if (!obj->defineGeneric(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE))
|
||||
goto error;
|
||||
}
|
||||
regs.sp -= 2;
|
||||
|
@ -5243,7 +5246,7 @@ BEGIN_CASE(JSOP_DEFSHARP)
|
|||
JSMSG_BAD_SHARP_DEF, numBuf);
|
||||
goto error;
|
||||
}
|
||||
if (!obj->defineProperty(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE))
|
||||
if (!obj->defineGeneric(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE))
|
||||
goto error;
|
||||
}
|
||||
END_CASE(JSOP_DEFSHARP)
|
||||
|
@ -5570,7 +5573,7 @@ BEGIN_CASE(JSOP_SETXMLNAME)
|
|||
Value rval = regs.sp[-1];
|
||||
jsid id;
|
||||
FETCH_ELEMENT_ID(obj, -2, id);
|
||||
if (!obj->setProperty(cx, id, &rval, script->strictModeCode))
|
||||
if (!obj->setGeneric(cx, id, &rval, script->strictModeCode))
|
||||
goto error;
|
||||
rval = regs.sp[-1];
|
||||
regs.sp -= 2;
|
||||
|
|
|
@ -871,7 +871,7 @@ SuppressDeletedPropertyHelper(JSContext *cx, JSObject *obj, IdPredicate predicat
|
|||
uintN attrs;
|
||||
if (obj2.object()->isNative())
|
||||
attrs = ((Shape *) prop)->attributes();
|
||||
else if (!obj2.object()->getAttributes(cx, *idp, &attrs))
|
||||
else if (!obj2.object()->getGenericAttributes(cx, *idp, &attrs))
|
||||
return false;
|
||||
|
||||
if (attrs & JSPROP_ENUMERATE)
|
||||
|
|
154
js/src/jsobj.cpp
154
js/src/jsobj.cpp
|
@ -640,7 +640,7 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
|
|||
* If id is a string that's not an identifier, or if it's a negative
|
||||
* integer, then it must be quoted.
|
||||
*/
|
||||
bool idIsLexicalIdentifier = js_IsIdentifier(idstr);
|
||||
bool idIsLexicalIdentifier = IsIdentifier(idstr);
|
||||
if (JSID_IS_ATOM(id)
|
||||
? !idIsLexicalIdentifier
|
||||
: (!JSID_IS_INT(id) || JSID_TO_INT(id) < 0)) {
|
||||
|
@ -1027,14 +1027,14 @@ EvalCacheLookup(JSContext *cx, JSLinearString *str, StackFrame *caller, uintN st
|
|||
script->principals->subsume(script->principals, principals)))) {
|
||||
/*
|
||||
* Get the prior (cache-filling) eval's saved caller function.
|
||||
* See Compiler::compileScript in jsparse.cpp.
|
||||
* See BytecodeCompiler::compileScript.
|
||||
*/
|
||||
JSFunction *fun = script->getCallerFunction();
|
||||
|
||||
if (fun == caller->fun()) {
|
||||
/*
|
||||
* Get the source string passed for safekeeping in the
|
||||
* atom map by the prior eval to Compiler::compileScript.
|
||||
* Get the source string passed for safekeeping in the atom map
|
||||
* by the prior eval to BytecodeCompiler::compileScript.
|
||||
*/
|
||||
JSAtom *src = script->atoms[0];
|
||||
|
||||
|
@ -1273,9 +1273,10 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, StackFrame *c
|
|||
? CALLED_FROM_JSOP_EVAL
|
||||
: NOT_CALLED_FROM_JSOP_EVAL);
|
||||
uint32 tcflags = TCF_COMPILE_N_GO | TCF_NEED_MUTABLE_SCRIPT | TCF_COMPILE_FOR_EVAL;
|
||||
JSScript *compiled = Compiler::compileScript(cx, &scopeobj, caller, principals, tcflags,
|
||||
chars, length, filename, lineno,
|
||||
cx->findVersion(), linearStr, staticLevel);
|
||||
JSScript *compiled = BytecodeCompiler::compileScript(cx, &scopeobj, caller, principals,
|
||||
tcflags, chars, length, filename,
|
||||
lineno, cx->findVersion(), linearStr,
|
||||
staticLevel);
|
||||
if (!compiled)
|
||||
return false;
|
||||
|
||||
|
@ -1595,7 +1596,7 @@ js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
}
|
||||
|
||||
uintN attrs;
|
||||
if (!pobj->getAttributes(cx, id, &attrs))
|
||||
if (!pobj->getGenericAttributes(cx, id, &attrs))
|
||||
return false;
|
||||
|
||||
vp->setBoolean((attrs & JSPROP_ENUMERATE) != 0);
|
||||
|
@ -1639,8 +1640,8 @@ js::obj_defineGetter(JSContext *cx, uintN argc, Value *vp)
|
|||
if (!CheckAccess(cx, obj, id, JSACC_WATCH, &junk, &attrs))
|
||||
return JS_FALSE;
|
||||
args.rval().setUndefined();
|
||||
return obj->defineProperty(cx, id, UndefinedValue(), getter, JS_StrictPropertyStub,
|
||||
JSPROP_ENUMERATE | JSPROP_GETTER | JSPROP_SHARED);
|
||||
return obj->defineGeneric(cx, id, UndefinedValue(), getter, JS_StrictPropertyStub,
|
||||
JSPROP_ENUMERATE | JSPROP_GETTER | JSPROP_SHARED);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSBool)
|
||||
|
@ -1673,8 +1674,8 @@ js::obj_defineSetter(JSContext *cx, uintN argc, Value *vp)
|
|||
if (!CheckAccess(cx, obj, id, JSACC_WATCH, &junk, &attrs))
|
||||
return JS_FALSE;
|
||||
args.rval().setUndefined();
|
||||
return obj->defineProperty(cx, id, UndefinedValue(), JS_PropertyStub, setter,
|
||||
JSPROP_ENUMERATE | JSPROP_SETTER | JSPROP_SHARED);
|
||||
return obj->defineGeneric(cx, id, UndefinedValue(), JS_PropertyStub, setter,
|
||||
JSPROP_ENUMERATE | JSPROP_SETTER | JSPROP_SHARED);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -1808,26 +1809,20 @@ PropDesc::makeObject(JSContext *cx)
|
|||
|
||||
const JSAtomState &atomState = cx->runtime->atomState;
|
||||
if ((hasConfigurable &&
|
||||
!obj->defineProperty(cx, ATOM_TO_JSID(atomState.configurableAtom),
|
||||
BooleanValue((attrs & JSPROP_PERMANENT) == 0),
|
||||
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE)) ||
|
||||
!obj->defineProperty(cx, atomState.configurableAtom,
|
||||
BooleanValue((attrs & JSPROP_PERMANENT) == 0))) ||
|
||||
(hasEnumerable &&
|
||||
!obj->defineProperty(cx, ATOM_TO_JSID(atomState.enumerableAtom),
|
||||
BooleanValue((attrs & JSPROP_ENUMERATE) != 0),
|
||||
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE)) ||
|
||||
!obj->defineProperty(cx, atomState.enumerableAtom,
|
||||
BooleanValue((attrs & JSPROP_ENUMERATE) != 0))) ||
|
||||
(hasGet &&
|
||||
!obj->defineProperty(cx, ATOM_TO_JSID(atomState.getAtom), get,
|
||||
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE)) ||
|
||||
!obj->defineProperty(cx, atomState.getAtom, get)) ||
|
||||
(hasSet &&
|
||||
!obj->defineProperty(cx, ATOM_TO_JSID(atomState.setAtom), set,
|
||||
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE)) ||
|
||||
!obj->defineProperty(cx, atomState.setAtom, set)) ||
|
||||
(hasValue &&
|
||||
!obj->defineProperty(cx, ATOM_TO_JSID(atomState.valueAtom), value,
|
||||
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE)) ||
|
||||
!obj->defineProperty(cx, atomState.valueAtom, value)) ||
|
||||
(hasWritable &&
|
||||
!obj->defineProperty(cx, ATOM_TO_JSID(atomState.writableAtom),
|
||||
BooleanValue((attrs & JSPROP_READONLY) == 0),
|
||||
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE)))
|
||||
!obj->defineProperty(cx, atomState.writableAtom,
|
||||
BooleanValue((attrs & JSPROP_READONLY) == 0))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1863,7 +1858,7 @@ GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, PropertyDescript
|
|||
desc->setter = CastAsStrictPropertyOp(shape->setterObject());
|
||||
}
|
||||
} else {
|
||||
if (!pobj->getAttributes(cx, id, &desc->attrs))
|
||||
if (!pobj->getGenericAttributes(cx, id, &desc->attrs))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2750,7 +2745,7 @@ JSObject::sealOrFreeze(JSContext *cx, ImmutabilityType it)
|
|||
jsid id = props[i];
|
||||
|
||||
uintN attrs;
|
||||
if (!getAttributes(cx, id, &attrs))
|
||||
if (!getGenericAttributes(cx, id, &attrs))
|
||||
return false;
|
||||
|
||||
/* Make all attributes permanent; if freezing, make data attributes read-only. */
|
||||
|
@ -2765,7 +2760,7 @@ JSObject::sealOrFreeze(JSContext *cx, ImmutabilityType it)
|
|||
continue;
|
||||
|
||||
attrs |= new_attrs;
|
||||
if (!setAttributes(cx, id, &attrs))
|
||||
if (!setGenericAttributes(cx, id, &attrs))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2788,7 +2783,7 @@ JSObject::isSealedOrFrozen(JSContext *cx, ImmutabilityType it, bool *resultp)
|
|||
jsid id = props[i];
|
||||
|
||||
uintN attrs;
|
||||
if (!getAttributes(cx, id, &attrs))
|
||||
if (!getGenericAttributes(cx, id, &attrs))
|
||||
return false;
|
||||
|
||||
/*
|
||||
|
@ -3132,7 +3127,8 @@ js_CreateThisFromTrace(JSContext *cx, JSObject *ctor, uintN protoSlot)
|
|||
* GetInterpretedFunctionPrototype found that ctor.prototype is
|
||||
* primitive. Use Object.prototype for proto, per ES5 13.2.2 step 7.
|
||||
*/
|
||||
if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
|
||||
proto = parent->getGlobal()->getOrCreateObjectPrototype(cx);
|
||||
if (!proto)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -3316,87 +3312,99 @@ with_GetSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid,
|
|||
}
|
||||
|
||||
static JSBool
|
||||
with_SetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
|
||||
with_SetGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
|
||||
{
|
||||
return obj->getProto()->setProperty(cx, id, vp, strict);
|
||||
return obj->getProto()->setGeneric(cx, id, vp, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
with_SetProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict)
|
||||
{
|
||||
return obj->getProto()->setProperty(cx, name, vp, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
with_SetElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict)
|
||||
{
|
||||
jsid id;
|
||||
if (!IndexToId(cx, index, &id))
|
||||
return false;
|
||||
return with_SetProperty(cx, obj, id, vp, strict);
|
||||
return obj->getProto()->setElement(cx, index, vp, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
with_SetSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict)
|
||||
{
|
||||
return with_SetProperty(cx, obj, SPECIALID_TO_JSID(sid), vp, strict);
|
||||
return obj->getProto()->setSpecial(cx, sid, vp, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
with_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
with_GetGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
{
|
||||
return obj->getProto()->getAttributes(cx, id, attrsp);
|
||||
return obj->getProto()->getGenericAttributes(cx, id, attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
with_GetPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp)
|
||||
{
|
||||
return obj->getProto()->getPropertyAttributes(cx, name, attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
with_GetElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
|
||||
{
|
||||
jsid id;
|
||||
if (!IndexToId(cx, index, &id))
|
||||
return false;
|
||||
return with_GetAttributes(cx, obj, id, attrsp);
|
||||
return obj->getProto()->getElementAttributes(cx, index, attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
with_GetSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp)
|
||||
{
|
||||
return with_GetAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
return obj->getProto()->getSpecialAttributes(cx, sid, attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
with_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
with_SetGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
{
|
||||
return obj->getProto()->setAttributes(cx, id, attrsp);
|
||||
return obj->getProto()->setGenericAttributes(cx, id, attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
with_SetPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp)
|
||||
{
|
||||
return obj->getProto()->setPropertyAttributes(cx, name, attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
with_SetElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
|
||||
{
|
||||
jsid id;
|
||||
if (!IndexToId(cx, index, &id))
|
||||
return false;
|
||||
return with_SetAttributes(cx, obj, id, attrsp);
|
||||
return obj->getProto()->setElementAttributes(cx, index, attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
with_SetSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp)
|
||||
{
|
||||
return with_SetAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
return obj->getProto()->setSpecialAttributes(cx, sid, attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
with_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
|
||||
with_DeleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
|
||||
{
|
||||
return obj->getProto()->deleteProperty(cx, id, rval, strict);
|
||||
return obj->getProto()->deleteGeneric(cx, id, rval, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
with_DeleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict)
|
||||
{
|
||||
return obj->getProto()->deleteProperty(cx, name, rval, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
with_DeleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict)
|
||||
{
|
||||
jsid id;
|
||||
if (!IndexToId(cx, index, &id))
|
||||
return false;
|
||||
return with_DeleteProperty(cx, obj, id, rval, strict);
|
||||
return obj->getProto()->deleteElement(cx, index, rval, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
with_DeleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict)
|
||||
{
|
||||
return with_DeleteProperty(cx, obj, SPECIALID_TO_JSID(sid), rval, strict);
|
||||
return obj->getProto()->deleteSpecial(cx, sid, rval, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -3450,19 +3458,19 @@ Class js::WithClass = {
|
|||
with_GetProperty,
|
||||
with_GetElement,
|
||||
with_GetSpecial,
|
||||
with_SetProperty,
|
||||
with_SetGeneric,
|
||||
with_SetProperty,
|
||||
with_SetElement,
|
||||
with_SetSpecial,
|
||||
with_GetAttributes,
|
||||
with_GetAttributes,
|
||||
with_GetGenericAttributes,
|
||||
with_GetPropertyAttributes,
|
||||
with_GetElementAttributes,
|
||||
with_GetSpecialAttributes,
|
||||
with_SetAttributes,
|
||||
with_SetAttributes,
|
||||
with_SetGenericAttributes,
|
||||
with_SetPropertyAttributes,
|
||||
with_SetElementAttributes,
|
||||
with_SetSpecialAttributes,
|
||||
with_DeleteProperty,
|
||||
with_DeleteGeneric,
|
||||
with_DeleteProperty,
|
||||
with_DeleteElement,
|
||||
with_DeleteSpecial,
|
||||
|
@ -3576,7 +3584,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
|||
JS_ASSERT(depth <= size_t(cx->regs().sp - fp->base()));
|
||||
JS_ASSERT(count <= size_t(cx->regs().sp - fp->base() - depth));
|
||||
|
||||
/* See comments in CheckDestructuring from jsparse.cpp. */
|
||||
/* See comments in CheckDestructuring in frontend/Parser.cpp. */
|
||||
JS_ASSERT(count >= 1);
|
||||
|
||||
if (normalUnwind) {
|
||||
|
@ -3667,7 +3675,7 @@ JSObject::nonNativeSetProperty(JSContext *cx, jsid id, js::Value *vp, JSBool str
|
|||
if (wpmap && !wpmap->triggerWatchpoint(cx, this, id, vp))
|
||||
return false;
|
||||
}
|
||||
return getOps()->setProperty(cx, this, id, vp, strict);
|
||||
return getOps()->setGeneric(cx, this, id, vp, strict);
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -3712,7 +3720,7 @@ JS_CopyPropertiesFrom(JSContext *cx, JSObject *target, JSObject *obj)
|
|||
Value v = shape->hasSlot() ? obj->getSlot(shape->slot) : UndefinedValue();
|
||||
if (!cx->compartment->wrap(cx, &v))
|
||||
return false;
|
||||
if (!target->defineProperty(cx, shape->propid, v, getter, setter, attrs))
|
||||
if (!target->defineGeneric(cx, shape->propid, v, getter, setter, attrs))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -4181,7 +4189,7 @@ DefineStandardSlot(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom,
|
|||
}
|
||||
}
|
||||
|
||||
named = obj->defineProperty(cx, id, v, JS_PropertyStub, JS_StrictPropertyStub, attrs);
|
||||
named = obj->defineGeneric(cx, id, v, JS_PropertyStub, JS_StrictPropertyStub, attrs);
|
||||
return named;
|
||||
}
|
||||
|
||||
|
@ -4360,7 +4368,7 @@ DefineConstructorAndPrototype(JSContext *cx, JSObject *obj, JSProtoKey key, JSAt
|
|||
bad:
|
||||
if (named) {
|
||||
Value rval;
|
||||
obj->deleteProperty(cx, ATOM_TO_JSID(atom), &rval, false);
|
||||
obj->deleteGeneric(cx, ATOM_TO_JSID(atom), &rval, false);
|
||||
}
|
||||
if (cached)
|
||||
ClearClassObject(cx, obj, key);
|
||||
|
@ -6336,7 +6344,7 @@ js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
|||
return true;
|
||||
}
|
||||
if (!obj->isNative())
|
||||
return obj->getAttributes(cx, id, attrsp);
|
||||
return obj->getGenericAttributes(cx, id, attrsp);
|
||||
|
||||
const Shape *shape = (Shape *)prop;
|
||||
*attrsp = shape->attributes();
|
||||
|
@ -6379,7 +6387,7 @@ js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
|||
return true;
|
||||
return obj->isNative()
|
||||
? js_SetNativeAttributes(cx, obj, (Shape *) prop, *attrsp)
|
||||
: obj->setAttributes(cx, id, attrsp);
|
||||
: obj->setGenericAttributes(cx, id, attrsp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
|
|
@ -1357,22 +1357,22 @@ struct JSObject : js::gc::Cell {
|
|||
inline JSBool lookupElement(JSContext *cx, uint32 index, JSObject **objp, JSProperty **propp);
|
||||
inline JSBool lookupSpecial(JSContext *cx, js::SpecialId sid, JSObject **objp, JSProperty **propp);
|
||||
|
||||
JSBool defineProperty(JSContext *cx, jsid id, const js::Value &value,
|
||||
JSPropertyOp getter = JS_PropertyStub,
|
||||
JSStrictPropertyOp setter = JS_StrictPropertyStub,
|
||||
uintN attrs = JSPROP_ENUMERATE) {
|
||||
js::DefinePropOp op = getOps()->defineProperty;
|
||||
return (op ? op : js_DefineProperty)(cx, this, id, &value, getter, setter, attrs);
|
||||
}
|
||||
|
||||
JSBool defineElement(JSContext *cx, uint32 index, const js::Value &value,
|
||||
JSPropertyOp getter = JS_PropertyStub,
|
||||
JSStrictPropertyOp setter = JS_StrictPropertyStub,
|
||||
uintN attrs = JSPROP_ENUMERATE)
|
||||
{
|
||||
js::DefineElementOp op = getOps()->defineElement;
|
||||
return (op ? op : js_DefineElement)(cx, this, index, &value, getter, setter, attrs);
|
||||
}
|
||||
inline JSBool defineGeneric(JSContext *cx, jsid id, const js::Value &value,
|
||||
JSPropertyOp getter = JS_PropertyStub,
|
||||
JSStrictPropertyOp setter = JS_StrictPropertyStub,
|
||||
uintN attrs = JSPROP_ENUMERATE);
|
||||
inline JSBool defineProperty(JSContext *cx, js::PropertyName *name, const js::Value &value,
|
||||
JSPropertyOp getter = JS_PropertyStub,
|
||||
JSStrictPropertyOp setter = JS_StrictPropertyStub,
|
||||
uintN attrs = JSPROP_ENUMERATE);
|
||||
inline JSBool defineElement(JSContext *cx, uint32 index, const js::Value &value,
|
||||
JSPropertyOp getter = JS_PropertyStub,
|
||||
JSStrictPropertyOp setter = JS_StrictPropertyStub,
|
||||
uintN attrs = JSPROP_ENUMERATE);
|
||||
inline JSBool defineSpecial(JSContext *cx, js::SpecialId sid, const js::Value &value,
|
||||
JSPropertyOp getter = JS_PropertyStub,
|
||||
JSStrictPropertyOp setter = JS_StrictPropertyStub,
|
||||
uintN attrs = JSPROP_ENUMERATE);
|
||||
|
||||
inline JSBool getGeneric(JSContext *cx, JSObject *receiver, jsid id, js::Value *vp);
|
||||
inline JSBool getProperty(JSContext *cx, JSObject *receiver, js::PropertyName *name,
|
||||
|
@ -1385,42 +1385,29 @@ struct JSObject : js::gc::Cell {
|
|||
inline JSBool getElement(JSContext *cx, uint32 index, js::Value *vp);
|
||||
inline JSBool getSpecial(JSContext *cx, js::SpecialId sid, js::Value *vp);
|
||||
|
||||
JSBool setProperty(JSContext *cx, jsid id, js::Value *vp, JSBool strict) {
|
||||
if (getOps()->setProperty)
|
||||
return nonNativeSetProperty(cx, id, vp, strict);
|
||||
return js_SetPropertyHelper(cx, this, id, 0, vp, strict);
|
||||
}
|
||||
|
||||
JSBool setElement(JSContext *cx, uint32 index, js::Value *vp, JSBool strict) {
|
||||
if (getOps()->setElement)
|
||||
return nonNativeSetElement(cx, index, vp, strict);
|
||||
return js_SetElementHelper(cx, this, index, 0, vp, strict);
|
||||
}
|
||||
inline JSBool setGeneric(JSContext *cx, jsid id, js::Value *vp, JSBool strict);
|
||||
inline JSBool setProperty(JSContext *cx, js::PropertyName *name, js::Value *vp, JSBool strict);
|
||||
inline JSBool setElement(JSContext *cx, uint32 index, js::Value *vp, JSBool strict);
|
||||
inline JSBool setSpecial(JSContext *cx, js::SpecialId sid, js::Value *vp, JSBool strict);
|
||||
|
||||
JSBool nonNativeSetProperty(JSContext *cx, jsid id, js::Value *vp, JSBool strict);
|
||||
|
||||
JSBool nonNativeSetElement(JSContext *cx, uint32 index, js::Value *vp, JSBool strict);
|
||||
|
||||
JSBool getAttributes(JSContext *cx, jsid id, uintN *attrsp) {
|
||||
js::AttributesOp op = getOps()->getAttributes;
|
||||
return (op ? op : js_GetAttributes)(cx, this, id, attrsp);
|
||||
}
|
||||
inline JSBool getGenericAttributes(JSContext *cx, jsid id, uintN *attrsp);
|
||||
inline JSBool getPropertyAttributes(JSContext *cx, js::PropertyName *name, uintN *attrsp);
|
||||
inline JSBool getElementAttributes(JSContext *cx, uint32 index, uintN *attrsp);
|
||||
inline JSBool getSpecialAttributes(JSContext *cx, js::SpecialId sid, uintN *attrsp);
|
||||
|
||||
JSBool getElementAttributes(JSContext *cx, uint32 index, uintN *attrsp) {
|
||||
js::ElementAttributesOp op = getOps()->getElementAttributes;
|
||||
return (op ? op : js_GetElementAttributes)(cx, this, index, attrsp);
|
||||
}
|
||||
|
||||
inline JSBool setAttributes(JSContext *cx, jsid id, uintN *attrsp);
|
||||
|
||||
JSBool setElementAttributes(JSContext *cx, uint32 index, uintN *attrsp) {
|
||||
js::ElementAttributesOp op = getOps()->setElementAttributes;
|
||||
return (op ? op : js_SetElementAttributes)(cx, this, index, attrsp);
|
||||
}
|
||||
|
||||
inline JSBool deleteProperty(JSContext *cx, jsid id, js::Value *rval, JSBool strict);
|
||||
inline JSBool setGenericAttributes(JSContext *cx, jsid id, uintN *attrsp);
|
||||
inline JSBool setPropertyAttributes(JSContext *cx, js::PropertyName *name, uintN *attrsp);
|
||||
inline JSBool setElementAttributes(JSContext *cx, uint32 index, uintN *attrsp);
|
||||
inline JSBool setSpecialAttributes(JSContext *cx, js::SpecialId sid, uintN *attrsp);
|
||||
|
||||
inline JSBool deleteGeneric(JSContext *cx, jsid id, js::Value *rval, JSBool strict);
|
||||
inline JSBool deleteProperty(JSContext *cx, js::PropertyName *name, js::Value *rval, JSBool strict);
|
||||
inline JSBool deleteElement(JSContext *cx, uint32 index, js::Value *rval, JSBool strict);
|
||||
inline JSBool deleteSpecial(JSContext *cx, js::SpecialId sid, js::Value *rval, JSBool strict);
|
||||
|
||||
JSBool enumerate(JSContext *cx, JSIterateOp iterop, js::Value *statep, jsid *idp) {
|
||||
JSNewEnumerateOp op = getOps()->enumerate;
|
||||
|
|
|
@ -126,13 +126,60 @@ JSObject::unbrand(JSContext *cx)
|
|||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::setAttributes(JSContext *cx, jsid id, uintN *attrsp)
|
||||
JSObject::setGeneric(JSContext *cx, jsid id, js::Value *vp, JSBool strict)
|
||||
{
|
||||
if (getOps()->setGeneric)
|
||||
return nonNativeSetProperty(cx, id, vp, strict);
|
||||
return js_SetPropertyHelper(cx, this, id, 0, vp, strict);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::setProperty(JSContext *cx, js::PropertyName *name, js::Value *vp, JSBool strict)
|
||||
{
|
||||
return setGeneric(cx, ATOM_TO_JSID(name), vp, strict);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::setElement(JSContext *cx, uint32 index, js::Value *vp, JSBool strict)
|
||||
{
|
||||
if (getOps()->setElement)
|
||||
return nonNativeSetElement(cx, index, vp, strict);
|
||||
return js_SetElementHelper(cx, this, index, 0, vp, strict);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::setSpecial(JSContext *cx, js::SpecialId sid, js::Value *vp, JSBool strict)
|
||||
{
|
||||
return setGeneric(cx, SPECIALID_TO_JSID(sid), vp, strict);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::setGenericAttributes(JSContext *cx, jsid id, uintN *attrsp)
|
||||
{
|
||||
js::types::MarkTypePropertyConfigured(cx, this, id);
|
||||
js::AttributesOp op = getOps()->setAttributes;
|
||||
js::GenericAttributesOp op = getOps()->setGenericAttributes;
|
||||
return (op ? op : js_SetAttributes)(cx, this, id, attrsp);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::setPropertyAttributes(JSContext *cx, js::PropertyName *name, uintN *attrsp)
|
||||
{
|
||||
return setGenericAttributes(cx, ATOM_TO_JSID(name), attrsp);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::setElementAttributes(JSContext *cx, uint32 index, uintN *attrsp)
|
||||
{
|
||||
js::ElementAttributesOp op = getOps()->setElementAttributes;
|
||||
return (op ? op : js_SetElementAttributes)(cx, this, index, attrsp);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::setSpecialAttributes(JSContext *cx, js::SpecialId sid, uintN *attrsp)
|
||||
{
|
||||
return setGenericAttributes(cx, SPECIALID_TO_JSID(sid), attrsp);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::getGeneric(JSContext *cx, JSObject *receiver, jsid id, js::Value *vp)
|
||||
{
|
||||
|
@ -166,15 +213,36 @@ JSObject::getProperty(JSContext *cx, js::PropertyName *name, js::Value *vp)
|
|||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::deleteProperty(JSContext *cx, jsid id, js::Value *rval, JSBool strict)
|
||||
JSObject::deleteGeneric(JSContext *cx, jsid id, js::Value *rval, JSBool strict)
|
||||
{
|
||||
js::types::AddTypePropertyId(cx, this, id,
|
||||
js::types::Type::UndefinedType());
|
||||
js::types::MarkTypePropertyConfigured(cx, this, id);
|
||||
js::DeleteIdOp op = getOps()->deleteProperty;
|
||||
js::DeleteGenericOp op = getOps()->deleteGeneric;
|
||||
return (op ? op : js_DeleteProperty)(cx, this, id, rval, strict);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::deleteProperty(JSContext *cx, js::PropertyName *name, js::Value *rval, JSBool strict)
|
||||
{
|
||||
return deleteGeneric(cx, ATOM_TO_JSID(name), rval, strict);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::deleteElement(JSContext *cx, uint32 index, js::Value *rval, JSBool strict)
|
||||
{
|
||||
jsid id;
|
||||
if (!js::IndexToId(cx, index, &id))
|
||||
return false;
|
||||
return deleteGeneric(cx, id, rval, strict);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::deleteSpecial(JSContext *cx, js::SpecialId sid, js::Value *rval, JSBool strict)
|
||||
{
|
||||
return deleteGeneric(cx, SPECIALID_TO_JSID(sid), rval, strict);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::syncSpecialEquality()
|
||||
{
|
||||
|
@ -1116,6 +1184,44 @@ JSObject::lookupProperty(JSContext *cx, js::PropertyName *name, JSObject **objp,
|
|||
return lookupGeneric(cx, ATOM_TO_JSID(name), objp, propp);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::defineGeneric(JSContext *cx, jsid id, const js::Value &value,
|
||||
JSPropertyOp getter /* = JS_PropertyStub */,
|
||||
JSStrictPropertyOp setter /* = JS_StrictPropertyStub */,
|
||||
uintN attrs /* = JSPROP_ENUMERATE */)
|
||||
{
|
||||
js::DefineGenericOp op = getOps()->defineGeneric;
|
||||
return (op ? op : js_DefineProperty)(cx, this, id, &value, getter, setter, attrs);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::defineProperty(JSContext *cx, js::PropertyName *name, const js::Value &value,
|
||||
JSPropertyOp getter /* = JS_PropertyStub */,
|
||||
JSStrictPropertyOp setter /* = JS_StrictPropertyStub */,
|
||||
uintN attrs /* = JSPROP_ENUMERATE */)
|
||||
{
|
||||
return defineGeneric(cx, ATOM_TO_JSID(name), value, getter, setter, attrs);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::defineElement(JSContext *cx, uint32 index, const js::Value &value,
|
||||
JSPropertyOp getter /* = JS_PropertyStub */,
|
||||
JSStrictPropertyOp setter /* = JS_StrictPropertyStub */,
|
||||
uintN attrs /* = JSPROP_ENUMERATE */)
|
||||
{
|
||||
js::DefineElementOp op = getOps()->defineElement;
|
||||
return (op ? op : js_DefineElement)(cx, this, index, &value, getter, setter, attrs);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::defineSpecial(JSContext *cx, js::SpecialId sid, const js::Value &value,
|
||||
JSPropertyOp getter /* = JS_PropertyStub */,
|
||||
JSStrictPropertyOp setter /* = JS_StrictPropertyStub */,
|
||||
uintN attrs /* = JSPROP_ENUMERATE */)
|
||||
{
|
||||
return defineGeneric(cx, SPECIALID_TO_JSID(sid), value, getter, setter, attrs);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::lookupElement(JSContext *cx, uint32 index, JSObject **objp, JSProperty **propp)
|
||||
{
|
||||
|
@ -1148,18 +1254,37 @@ JSObject::getElement(JSContext *cx, uint32 index, js::Value *vp)
|
|||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::deleteElement(JSContext *cx, uint32 index, js::Value *rval, JSBool strict)
|
||||
JSObject::getSpecial(JSContext *cx, js::SpecialId sid, js::Value *vp)
|
||||
{
|
||||
return getGeneric(cx, SPECIALID_TO_JSID(sid), vp);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::getGenericAttributes(JSContext *cx, jsid id, uintN *attrsp)
|
||||
{
|
||||
js::GenericAttributesOp op = getOps()->getGenericAttributes;
|
||||
return (op ? op : js_GetAttributes)(cx, this, id, attrsp);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::getPropertyAttributes(JSContext *cx, js::PropertyName *name, uintN *attrsp)
|
||||
{
|
||||
return getGenericAttributes(cx, ATOM_TO_JSID(name), attrsp);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::getElementAttributes(JSContext *cx, uint32 index, uintN *attrsp)
|
||||
{
|
||||
jsid id;
|
||||
if (!js::IndexToId(cx, index, &id))
|
||||
return false;
|
||||
return deleteProperty(cx, id, rval, strict);
|
||||
return getGenericAttributes(cx, id, attrsp);
|
||||
}
|
||||
|
||||
inline JSBool
|
||||
JSObject::getSpecial(JSContext *cx, js::SpecialId sid, js::Value *vp)
|
||||
JSObject::getSpecialAttributes(JSContext *cx, js::SpecialId sid, uintN *attrsp)
|
||||
{
|
||||
return getGeneric(cx, SPECIALID_TO_JSID(sid), vp);
|
||||
return getGenericAttributes(cx, SPECIALID_TO_JSID(sid), attrsp);
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
#include "frontend/TokenStream.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
#include "jsboolinlines.h"
|
||||
#include "jsinferinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsstrinlines.h"
|
||||
|
@ -791,10 +792,10 @@ Walk(JSContext *cx, JSObject *holder, jsid name, const Value &reviver, Value *vp
|
|||
JS_ASSERT(!obj->isProxy());
|
||||
if (obj->isArray()) {
|
||||
/* Step 2a(ii). */
|
||||
jsuint length = obj->getArrayLength();
|
||||
uint32 length = obj->getArrayLength();
|
||||
|
||||
/* Step 2a(i), 2a(iii-iv). */
|
||||
for (jsuint i = 0; i < length; i++) {
|
||||
for (uint32 i = 0; i < length; i++) {
|
||||
jsid id;
|
||||
if (!IndexToId(cx, i, &id))
|
||||
return false;
|
||||
|
@ -817,11 +818,11 @@ Walk(JSContext *cx, JSObject *holder, jsid name, const Value &reviver, Value *vp
|
|||
*/
|
||||
if (newElement.isUndefined()) {
|
||||
/* Step 2a(iii)(2). */
|
||||
JS_ALWAYS_TRUE(array_deleteProperty(cx, obj, id, &newElement, false));
|
||||
JS_ALWAYS_TRUE(array_deleteElement(cx, obj, i, &newElement, false));
|
||||
} else {
|
||||
/* Step 2a(iii)(3). */
|
||||
JS_ALWAYS_TRUE(array_defineProperty(cx, obj, id, &newElement, JS_PropertyStub,
|
||||
JS_StrictPropertyStub, JSPROP_ENUMERATE));
|
||||
JS_ALWAYS_TRUE(array_defineElement(cx, obj, i, &newElement, JS_PropertyStub,
|
||||
JS_StrictPropertyStub, JSPROP_ENUMERATE));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -884,11 +885,8 @@ Revive(JSContext *cx, const Value &reviver, Value *vp)
|
|||
if (!obj)
|
||||
return false;
|
||||
|
||||
AutoObjectRooter tvr(cx, obj);
|
||||
if (!obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom),
|
||||
*vp, NULL, NULL, JSPROP_ENUMERATE)) {
|
||||
if (!obj->defineProperty(cx, cx->runtime->atomState.emptyAtom, *vp))
|
||||
return false;
|
||||
}
|
||||
|
||||
return Walk(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), reviver, vp);
|
||||
}
|
||||
|
|
|
@ -1753,10 +1753,8 @@ DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc)
|
|||
#if JS_HAS_DESTRUCTURING_SHORTHAND
|
||||
nameoff = ss->sprinter.offset;
|
||||
#endif
|
||||
if (!QuoteString(&ss->sprinter, atom,
|
||||
js_IsIdentifier(atom) ? 0 : (jschar)'\'')) {
|
||||
if (!QuoteString(&ss->sprinter, atom, IsIdentifier(atom) ? 0 : (jschar)'\''))
|
||||
return NULL;
|
||||
}
|
||||
if (SprintPut(&ss->sprinter, ": ", 2) < 0)
|
||||
return NULL;
|
||||
break;
|
||||
|
@ -1998,8 +1996,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
? JSOP_IFEQ \
|
||||
: JSOP_NOP)
|
||||
|
||||
#define ATOM_IS_IDENTIFIER(atom) js_IsIdentifier(atom)
|
||||
|
||||
/*
|
||||
* Given an atom already fetched from jp->script's atom map, quote/escape its
|
||||
* string appropriately into rval, and select fmt from the quoted and unquoted
|
||||
|
@ -2008,7 +2004,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
#define GET_QUOTE_AND_FMT(qfmt, ufmt, rval) \
|
||||
JS_BEGIN_MACRO \
|
||||
jschar quote_; \
|
||||
if (!ATOM_IS_IDENTIFIER(atom)) { \
|
||||
if (!IsIdentifier(atom)) { \
|
||||
quote_ = '\''; \
|
||||
fmt = qfmt; \
|
||||
} else { \
|
||||
|
@ -4563,8 +4559,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
case JSOP_INITPROP:
|
||||
case JSOP_INITMETHOD:
|
||||
LOAD_ATOM(0);
|
||||
xval = QuoteString(&ss->sprinter, atom,
|
||||
jschar(ATOM_IS_IDENTIFIER(atom) ? 0 : '\''));
|
||||
xval = QuoteString(&ss->sprinter, atom, jschar(IsIdentifier(atom) ? 0 : '\''));
|
||||
if (!xval)
|
||||
return NULL;
|
||||
isFirst = IsInitializerOp(ss->opcodes[ss->top - 2]);
|
||||
|
@ -4812,7 +4807,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
#undef POP_STR
|
||||
#undef POP_STR_PREC
|
||||
#undef LOCAL_ASSERT
|
||||
#undef ATOM_IS_IDENTIFIER
|
||||
#undef GET_QUOTE_AND_FMT
|
||||
#undef GET_ATOM_QUOTE_AND_FMT
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ typedef enum JSOp {
|
|||
|
||||
#define JOF_SHARPSLOT (1U<<24) /* first immediate is uint16 stack slot no.
|
||||
that needs fixup when in global code (see
|
||||
Compiler::compileScript) */
|
||||
BytecodeCompiler::compileScript) */
|
||||
#define JOF_GNAME (1U<<25) /* predicted global name */
|
||||
#define JOF_TYPESET (1U<<26) /* has an entry in a script's type sets */
|
||||
#define JOF_DECOMPOSE (1U<<27) /* followed by an equivalent decomposed
|
||||
|
@ -177,7 +177,8 @@ typedef enum JSOp {
|
|||
* When a short jump won't hold a relative offset, its 2-byte immediate offset
|
||||
* operand is an unsigned index of a span-dependency record, maintained until
|
||||
* code generation finishes -- after which some (but we hope not nearly all)
|
||||
* span-dependent jumps must be extended (see OptimizeSpanDeps in jsemit.c).
|
||||
* span-dependent jumps must be extended (see js::frontend::OptimizeSpanDeps in
|
||||
* frontend/BytecodeGenerator.cpp).
|
||||
*
|
||||
* If the span-dependency record index overflows SPANDEP_INDEX_MAX, the jump
|
||||
* offset will contain SPANDEP_INDEX_HUGE, indicating that the record must be
|
||||
|
|
|
@ -955,8 +955,8 @@ proxy_LookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid, JSObject **objp
|
|||
}
|
||||
|
||||
static JSBool
|
||||
proxy_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
proxy_DefineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *value,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
{
|
||||
id = js_CheckForStringIndex(id);
|
||||
|
||||
|
@ -970,6 +970,13 @@ proxy_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
|
|||
return Proxy::defineProperty(cx, obj, id, &desc);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
proxy_DefineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value *value,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
{
|
||||
return proxy_DefineGeneric(cx, obj, ATOM_TO_JSID(name), value, getter, setter, attrs);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
proxy_DefineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *value,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
|
@ -977,14 +984,14 @@ proxy_DefineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *val
|
|||
jsid id;
|
||||
if (!IndexToId(cx, index, &id))
|
||||
return false;
|
||||
return proxy_DefineProperty(cx, obj, id, value, getter, setter, attrs);
|
||||
return proxy_DefineGeneric(cx, obj, id, value, getter, setter, attrs);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
proxy_DefineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *value,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
{
|
||||
return proxy_DefineProperty(cx, obj, SPECIALID_TO_JSID(sid), value, getter, setter, attrs);
|
||||
return proxy_DefineGeneric(cx, obj, SPECIALID_TO_JSID(sid), value, getter, setter, attrs);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -1017,30 +1024,36 @@ proxy_GetSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid
|
|||
}
|
||||
|
||||
static JSBool
|
||||
proxy_SetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
|
||||
proxy_SetGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
|
||||
{
|
||||
id = js_CheckForStringIndex(id);
|
||||
|
||||
return Proxy::set(cx, obj, obj, id, strict, vp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
proxy_SetProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict)
|
||||
{
|
||||
return proxy_SetGeneric(cx, obj, ATOM_TO_JSID(name), vp, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
proxy_SetElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict)
|
||||
{
|
||||
jsid id;
|
||||
if (!IndexToId(cx, index, &id))
|
||||
return false;
|
||||
return proxy_SetProperty(cx, obj, id, vp, strict);
|
||||
return proxy_SetGeneric(cx, obj, id, vp, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
proxy_SetSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict)
|
||||
{
|
||||
return proxy_SetProperty(cx, obj, SPECIALID_TO_JSID(sid), vp, strict);
|
||||
return proxy_SetGeneric(cx, obj, SPECIALID_TO_JSID(sid), vp, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
proxy_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
proxy_GetGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
{
|
||||
id = js_CheckForStringIndex(id);
|
||||
|
||||
|
@ -1051,23 +1064,29 @@ proxy_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
|||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
proxy_GetPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp)
|
||||
{
|
||||
return proxy_GetGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
proxy_GetElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
|
||||
{
|
||||
jsid id;
|
||||
if (!IndexToId(cx, index, &id))
|
||||
return false;
|
||||
return proxy_GetAttributes(cx, obj, id, attrsp);
|
||||
return proxy_GetGenericAttributes(cx, obj, id, attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
proxy_GetSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp)
|
||||
{
|
||||
return proxy_GetAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
return proxy_GetGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
proxy_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
proxy_SetGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
{
|
||||
id = js_CheckForStringIndex(id);
|
||||
|
||||
|
@ -1079,23 +1098,29 @@ proxy_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
|||
return Proxy::defineProperty(cx, obj, id, &desc);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
proxy_SetPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp)
|
||||
{
|
||||
return proxy_SetGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
proxy_SetElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
|
||||
{
|
||||
jsid id;
|
||||
if (!IndexToId(cx, index, &id))
|
||||
return false;
|
||||
return proxy_SetAttributes(cx, obj, id, attrsp);
|
||||
return proxy_SetGenericAttributes(cx, obj, id, attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
proxy_SetSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp)
|
||||
{
|
||||
return proxy_SetAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
return proxy_SetGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
proxy_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
|
||||
proxy_DeleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
|
||||
{
|
||||
id = js_CheckForStringIndex(id);
|
||||
|
||||
|
@ -1107,19 +1132,25 @@ proxy_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool
|
|||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
proxy_DeleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict)
|
||||
{
|
||||
return proxy_DeleteGeneric(cx, obj, ATOM_TO_JSID(name), rval, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
proxy_DeleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict)
|
||||
{
|
||||
jsid id;
|
||||
if (!IndexToId(cx, index, &id))
|
||||
return false;
|
||||
return proxy_DeleteProperty(cx, obj, id, rval, strict);
|
||||
return proxy_DeleteGeneric(cx, obj, id, rval, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
proxy_DeleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict)
|
||||
{
|
||||
return proxy_DeleteProperty(cx, obj, SPECIALID_TO_JSID(sid), rval, strict);
|
||||
return proxy_DeleteGeneric(cx, obj, SPECIALID_TO_JSID(sid), rval, strict);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1213,7 +1244,7 @@ JS_FRIEND_DATA(Class) js::ObjectProxyClass = {
|
|||
proxy_LookupProperty,
|
||||
proxy_LookupElement,
|
||||
proxy_LookupSpecial,
|
||||
proxy_DefineProperty,
|
||||
proxy_DefineGeneric,
|
||||
proxy_DefineProperty,
|
||||
proxy_DefineElement,
|
||||
proxy_DefineSpecial,
|
||||
|
@ -1221,19 +1252,19 @@ JS_FRIEND_DATA(Class) js::ObjectProxyClass = {
|
|||
proxy_GetProperty,
|
||||
proxy_GetElement,
|
||||
proxy_GetSpecial,
|
||||
proxy_SetProperty,
|
||||
proxy_SetGeneric,
|
||||
proxy_SetProperty,
|
||||
proxy_SetElement,
|
||||
proxy_SetSpecial,
|
||||
proxy_GetAttributes,
|
||||
proxy_GetAttributes,
|
||||
proxy_GetGenericAttributes,
|
||||
proxy_GetPropertyAttributes,
|
||||
proxy_GetElementAttributes,
|
||||
proxy_GetSpecialAttributes,
|
||||
proxy_SetAttributes,
|
||||
proxy_SetAttributes,
|
||||
proxy_SetGenericAttributes,
|
||||
proxy_SetPropertyAttributes,
|
||||
proxy_SetElementAttributes,
|
||||
proxy_SetSpecialAttributes,
|
||||
proxy_DeleteProperty,
|
||||
proxy_DeleteGeneric,
|
||||
proxy_DeleteProperty,
|
||||
proxy_DeleteElement,
|
||||
proxy_DeleteSpecial,
|
||||
|
@ -1274,7 +1305,7 @@ JS_FRIEND_DATA(Class) js::OuterWindowProxyClass = {
|
|||
proxy_LookupProperty,
|
||||
proxy_LookupElement,
|
||||
proxy_LookupSpecial,
|
||||
proxy_DefineProperty,
|
||||
proxy_DefineGeneric,
|
||||
proxy_DefineProperty,
|
||||
proxy_DefineElement,
|
||||
proxy_DefineSpecial,
|
||||
|
@ -1282,19 +1313,19 @@ JS_FRIEND_DATA(Class) js::OuterWindowProxyClass = {
|
|||
proxy_GetProperty,
|
||||
proxy_GetElement,
|
||||
proxy_GetSpecial,
|
||||
proxy_SetProperty,
|
||||
proxy_SetGeneric,
|
||||
proxy_SetProperty,
|
||||
proxy_SetElement,
|
||||
proxy_SetSpecial,
|
||||
proxy_GetAttributes,
|
||||
proxy_GetAttributes,
|
||||
proxy_GetGenericAttributes,
|
||||
proxy_GetPropertyAttributes,
|
||||
proxy_GetElementAttributes,
|
||||
proxy_GetSpecialAttributes,
|
||||
proxy_SetAttributes,
|
||||
proxy_SetAttributes,
|
||||
proxy_SetGenericAttributes,
|
||||
proxy_SetPropertyAttributes,
|
||||
proxy_SetElementAttributes,
|
||||
proxy_SetSpecialAttributes,
|
||||
proxy_DeleteProperty,
|
||||
proxy_DeleteGeneric,
|
||||
proxy_DeleteProperty,
|
||||
proxy_DeleteElement,
|
||||
proxy_DeleteSpecial,
|
||||
|
@ -1347,7 +1378,7 @@ JS_FRIEND_DATA(Class) js::FunctionProxyClass = {
|
|||
proxy_LookupProperty,
|
||||
proxy_LookupElement,
|
||||
proxy_LookupSpecial,
|
||||
proxy_DefineProperty,
|
||||
proxy_DefineGeneric,
|
||||
proxy_DefineProperty,
|
||||
proxy_DefineElement,
|
||||
proxy_DefineSpecial,
|
||||
|
@ -1355,19 +1386,19 @@ JS_FRIEND_DATA(Class) js::FunctionProxyClass = {
|
|||
proxy_GetProperty,
|
||||
proxy_GetElement,
|
||||
proxy_GetSpecial,
|
||||
proxy_SetProperty,
|
||||
proxy_SetGeneric,
|
||||
proxy_SetProperty,
|
||||
proxy_SetElement,
|
||||
proxy_SetSpecial,
|
||||
proxy_GetAttributes,
|
||||
proxy_GetAttributes,
|
||||
proxy_GetGenericAttributes,
|
||||
proxy_GetPropertyAttributes,
|
||||
proxy_GetElementAttributes,
|
||||
proxy_GetSpecialAttributes,
|
||||
proxy_SetAttributes,
|
||||
proxy_SetAttributes,
|
||||
proxy_SetGenericAttributes,
|
||||
proxy_SetPropertyAttributes,
|
||||
proxy_SetElementAttributes,
|
||||
proxy_SetSpecialAttributes,
|
||||
proxy_DeleteProperty,
|
||||
proxy_DeleteGeneric,
|
||||
proxy_DeleteProperty,
|
||||
proxy_DeleteElement,
|
||||
proxy_DeleteSpecial,
|
||||
|
@ -1461,7 +1492,8 @@ proxy_createFunction(JSContext *cx, uintN argc, Value *vp)
|
|||
return false;
|
||||
JSObject *proto, *parent;
|
||||
parent = vp[0].toObject().getParent();
|
||||
if (!js_GetClassPrototype(cx, parent, JSProto_Function, &proto))
|
||||
proto = parent->getGlobal()->getOrCreateFunctionPrototype(cx);
|
||||
if (!proto)
|
||||
return false;
|
||||
parent = proto->getParent();
|
||||
|
||||
|
@ -1574,7 +1606,8 @@ callable_Construct(JSContext *cx, uintN argc, Value *vp)
|
|||
if (protov.isObject()) {
|
||||
proto = &protov.toObject();
|
||||
} else {
|
||||
if (!js_GetClassPrototype(cx, NULL, JSProto_Object, &proto))
|
||||
proto = callable->getGlobal()->getOrCreateObjectPrototype(cx);
|
||||
if (!proto)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -76,17 +76,12 @@ typedef uintptr_t jsatomid;
|
|||
|
||||
/* Struct typedefs. */
|
||||
typedef struct JSArgumentFormatMap JSArgumentFormatMap;
|
||||
typedef struct JSCodeGenerator JSCodeGenerator;
|
||||
typedef struct JSGCThing JSGCThing;
|
||||
typedef struct JSGenerator JSGenerator;
|
||||
typedef struct JSNativeEnumerator JSNativeEnumerator;
|
||||
typedef struct JSFunctionBox JSFunctionBox;
|
||||
typedef struct JSObjectBox JSObjectBox;
|
||||
typedef struct JSParseNode JSParseNode;
|
||||
typedef struct JSProperty JSProperty;
|
||||
typedef struct JSSharpObjectMap JSSharpObjectMap;
|
||||
typedef struct JSThread JSThread;
|
||||
typedef struct JSTreeContext JSTreeContext;
|
||||
typedef struct JSTryNote JSTryNote;
|
||||
|
||||
/* Friend "Advanced API" typedefs. */
|
||||
|
@ -120,7 +115,6 @@ class JSFixedString;
|
|||
class JSStaticAtom;
|
||||
class JSRope;
|
||||
class JSAtom;
|
||||
struct JSDefinition;
|
||||
class JSWrapper;
|
||||
|
||||
namespace js {
|
||||
|
@ -164,12 +158,18 @@ class FrameRegsIter;
|
|||
class CallReceiver;
|
||||
class CallArgs;
|
||||
|
||||
struct Compiler;
|
||||
struct BytecodeCompiler;
|
||||
struct CodeGenerator;
|
||||
struct Definition;
|
||||
struct FunctionBox;
|
||||
struct ObjectBox;
|
||||
struct ParseNode;
|
||||
struct Parser;
|
||||
class TokenStream;
|
||||
struct Token;
|
||||
struct TokenPos;
|
||||
struct TokenPtr;
|
||||
struct TreeContext;
|
||||
class UpvarCookie;
|
||||
|
||||
class Proxy;
|
||||
|
@ -218,7 +218,7 @@ class Bindings;
|
|||
class MultiDeclRange;
|
||||
class ParseMapPool;
|
||||
class DefnOrHeader;
|
||||
typedef InlineMap<JSAtom *, JSDefinition *, 24> AtomDefnMap;
|
||||
typedef InlineMap<JSAtom *, Definition *, 24> AtomDefnMap;
|
||||
typedef InlineMap<JSAtom *, jsatomid, 24> AtomIndexMap;
|
||||
typedef InlineMap<JSAtom *, DefnOrHeader, 24> AtomDOHMap;
|
||||
typedef Vector<UpvarCookie, 8> UpvarCookies;
|
||||
|
|
|
@ -137,7 +137,7 @@ char const *callbackNames[] = {
|
|||
typedef AutoValueVector NodeVector;
|
||||
|
||||
/*
|
||||
* JSParseNode is a somewhat intricate data structure, and its invariants have
|
||||
* ParseNode is a somewhat intricate data structure, and its invariants have
|
||||
* evolved, making it more likely that there could be a disconnect between the
|
||||
* parser and the AST serializer. We use these macros to check invariants on a
|
||||
* parse node and raise a dynamic error on failure.
|
||||
|
@ -428,7 +428,7 @@ class NodeBuilder
|
|||
if (!atom)
|
||||
return false;
|
||||
|
||||
return obj->defineProperty(cx, ATOM_TO_JSID(atom), val);
|
||||
return obj->defineProperty(cx, atom->asPropertyName(), val);
|
||||
}
|
||||
|
||||
bool newNodeLoc(TokenPos *pos, Value *dst);
|
||||
|
@ -660,7 +660,7 @@ NodeBuilder::newArray(NodeVector &elts, Value *dst)
|
|||
if (val.isMagic(JS_SERIALIZE_NO_NODE))
|
||||
continue;
|
||||
|
||||
if (!array->setProperty(cx, INT_TO_JSID(i), &val, false))
|
||||
if (!array->setElement(cx, i, &val, false))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1593,7 +1593,7 @@ NodeBuilder::xmlPI(Value target, Value contents, TokenPos *pos, Value *dst)
|
|||
/*
|
||||
* Serialization of parse nodes to JavaScript objects.
|
||||
*
|
||||
* All serialization methods take a non-nullable JSParseNode pointer.
|
||||
* All serialization methods take a non-nullable ParseNode pointer.
|
||||
*/
|
||||
|
||||
class ASTSerializer
|
||||
|
@ -1611,21 +1611,21 @@ class ASTSerializer
|
|||
UnaryOperator unop(TokenKind tk, JSOp op);
|
||||
AssignmentOperator aop(JSOp op);
|
||||
|
||||
bool statements(JSParseNode *pn, NodeVector &elts);
|
||||
bool expressions(JSParseNode *pn, NodeVector &elts);
|
||||
bool xmls(JSParseNode *pn, NodeVector &elts);
|
||||
bool leftAssociate(JSParseNode *pn, Value *dst);
|
||||
bool functionArgs(JSParseNode *pn, JSParseNode *pnargs, JSParseNode *pndestruct,
|
||||
JSParseNode *pnbody, NodeVector &args);
|
||||
bool statements(ParseNode *pn, NodeVector &elts);
|
||||
bool expressions(ParseNode *pn, NodeVector &elts);
|
||||
bool xmls(ParseNode *pn, NodeVector &elts);
|
||||
bool leftAssociate(ParseNode *pn, Value *dst);
|
||||
bool functionArgs(ParseNode *pn, ParseNode *pnargs, ParseNode *pndestruct, ParseNode *pnbody,
|
||||
NodeVector &args);
|
||||
|
||||
bool sourceElement(JSParseNode *pn, Value *dst);
|
||||
bool sourceElement(ParseNode *pn, Value *dst);
|
||||
|
||||
bool declaration(JSParseNode *pn, Value *dst);
|
||||
bool variableDeclaration(JSParseNode *pn, bool let, Value *dst);
|
||||
bool variableDeclarator(JSParseNode *pn, VarDeclKind *pkind, Value *dst);
|
||||
bool letHead(JSParseNode *pn, NodeVector &dtors);
|
||||
bool declaration(ParseNode *pn, Value *dst);
|
||||
bool variableDeclaration(ParseNode *pn, bool let, Value *dst);
|
||||
bool variableDeclarator(ParseNode *pn, VarDeclKind *pkind, Value *dst);
|
||||
bool letHead(ParseNode *pn, NodeVector &dtors);
|
||||
|
||||
bool optStatement(JSParseNode *pn, Value *dst) {
|
||||
bool optStatement(ParseNode *pn, Value *dst) {
|
||||
if (!pn) {
|
||||
dst->setMagic(JS_SERIALIZE_NO_NODE);
|
||||
return true;
|
||||
|
@ -1633,15 +1633,15 @@ class ASTSerializer
|
|||
return statement(pn, dst);
|
||||
}
|
||||
|
||||
bool forInit(JSParseNode *pn, Value *dst);
|
||||
bool statement(JSParseNode *pn, Value *dst);
|
||||
bool blockStatement(JSParseNode *pn, Value *dst);
|
||||
bool switchStatement(JSParseNode *pn, Value *dst);
|
||||
bool switchCase(JSParseNode *pn, Value *dst);
|
||||
bool tryStatement(JSParseNode *pn, Value *dst);
|
||||
bool catchClause(JSParseNode *pn, Value *dst);
|
||||
bool forInit(ParseNode *pn, Value *dst);
|
||||
bool statement(ParseNode *pn, Value *dst);
|
||||
bool blockStatement(ParseNode *pn, Value *dst);
|
||||
bool switchStatement(ParseNode *pn, Value *dst);
|
||||
bool switchCase(ParseNode *pn, Value *dst);
|
||||
bool tryStatement(ParseNode *pn, Value *dst);
|
||||
bool catchClause(ParseNode *pn, Value *dst);
|
||||
|
||||
bool optExpression(JSParseNode *pn, Value *dst) {
|
||||
bool optExpression(ParseNode *pn, Value *dst) {
|
||||
if (!pn) {
|
||||
dst->setMagic(JS_SERIALIZE_NO_NODE);
|
||||
return true;
|
||||
|
@ -1649,10 +1649,10 @@ class ASTSerializer
|
|||
return expression(pn, dst);
|
||||
}
|
||||
|
||||
bool expression(JSParseNode *pn, Value *dst);
|
||||
bool expression(ParseNode *pn, Value *dst);
|
||||
|
||||
bool propertyName(JSParseNode *pn, Value *dst);
|
||||
bool property(JSParseNode *pn, Value *dst);
|
||||
bool propertyName(ParseNode *pn, Value *dst);
|
||||
bool property(ParseNode *pn, Value *dst);
|
||||
|
||||
bool optIdentifier(JSAtom *atom, TokenPos *pos, Value *dst) {
|
||||
if (!atom) {
|
||||
|
@ -1663,22 +1663,22 @@ class ASTSerializer
|
|||
}
|
||||
|
||||
bool identifier(JSAtom *atom, TokenPos *pos, Value *dst);
|
||||
bool identifier(JSParseNode *pn, Value *dst);
|
||||
bool literal(JSParseNode *pn, Value *dst);
|
||||
bool identifier(ParseNode *pn, Value *dst);
|
||||
bool literal(ParseNode *pn, Value *dst);
|
||||
|
||||
bool pattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst);
|
||||
bool arrayPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst);
|
||||
bool objectPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst);
|
||||
bool pattern(ParseNode *pn, VarDeclKind *pkind, Value *dst);
|
||||
bool arrayPattern(ParseNode *pn, VarDeclKind *pkind, Value *dst);
|
||||
bool objectPattern(ParseNode *pn, VarDeclKind *pkind, Value *dst);
|
||||
|
||||
bool function(JSParseNode *pn, ASTType type, Value *dst);
|
||||
bool functionArgsAndBody(JSParseNode *pn, NodeVector &args, Value *body);
|
||||
bool functionBody(JSParseNode *pn, TokenPos *pos, Value *dst);
|
||||
bool function(ParseNode *pn, ASTType type, Value *dst);
|
||||
bool functionArgsAndBody(ParseNode *pn, NodeVector &args, Value *body);
|
||||
bool functionBody(ParseNode *pn, TokenPos *pos, Value *dst);
|
||||
|
||||
bool comprehensionBlock(JSParseNode *pn, Value *dst);
|
||||
bool comprehension(JSParseNode *pn, Value *dst);
|
||||
bool generatorExpression(JSParseNode *pn, Value *dst);
|
||||
bool comprehensionBlock(ParseNode *pn, Value *dst);
|
||||
bool comprehension(ParseNode *pn, Value *dst);
|
||||
bool generatorExpression(ParseNode *pn, Value *dst);
|
||||
|
||||
bool xml(JSParseNode *pn, Value *dst);
|
||||
bool xml(ParseNode *pn, Value *dst);
|
||||
|
||||
public:
|
||||
ASTSerializer(JSContext *c, bool l, char const *src, uint32 ln)
|
||||
|
@ -1693,7 +1693,7 @@ class ASTSerializer
|
|||
parser = p;
|
||||
}
|
||||
|
||||
bool program(JSParseNode *pn, Value *dst);
|
||||
bool program(ParseNode *pn, Value *dst);
|
||||
};
|
||||
|
||||
AssignmentOperator
|
||||
|
@ -1824,14 +1824,14 @@ ASTSerializer::binop(TokenKind tk, JSOp op)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::statements(JSParseNode *pn, NodeVector &elts)
|
||||
ASTSerializer::statements(ParseNode *pn, NodeVector &elts)
|
||||
{
|
||||
JS_ASSERT(pn->isKind(TOK_LC) && pn->isArity(PN_LIST));
|
||||
|
||||
if (!elts.reserve(pn->pn_count))
|
||||
return false;
|
||||
|
||||
for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
|
||||
for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
|
||||
Value elt;
|
||||
if (!sourceElement(next, &elt))
|
||||
return false;
|
||||
|
@ -1842,12 +1842,12 @@ ASTSerializer::statements(JSParseNode *pn, NodeVector &elts)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::expressions(JSParseNode *pn, NodeVector &elts)
|
||||
ASTSerializer::expressions(ParseNode *pn, NodeVector &elts)
|
||||
{
|
||||
if (!elts.reserve(pn->pn_count))
|
||||
return false;
|
||||
|
||||
for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
|
||||
for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
|
||||
Value elt;
|
||||
if (!expression(next, &elt))
|
||||
return false;
|
||||
|
@ -1858,12 +1858,12 @@ ASTSerializer::expressions(JSParseNode *pn, NodeVector &elts)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::xmls(JSParseNode *pn, NodeVector &elts)
|
||||
ASTSerializer::xmls(ParseNode *pn, NodeVector &elts)
|
||||
{
|
||||
if (!elts.reserve(pn->pn_count))
|
||||
return false;
|
||||
|
||||
for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
|
||||
for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
|
||||
Value elt;
|
||||
if (!xml(next, &elt))
|
||||
return false;
|
||||
|
@ -1874,7 +1874,7 @@ ASTSerializer::xmls(JSParseNode *pn, NodeVector &elts)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::blockStatement(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::blockStatement(ParseNode *pn, Value *dst)
|
||||
{
|
||||
JS_ASSERT(pn->isKind(TOK_LC));
|
||||
|
||||
|
@ -1884,7 +1884,7 @@ ASTSerializer::blockStatement(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::program(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::program(ParseNode *pn, Value *dst)
|
||||
{
|
||||
JS_ASSERT(pn->pn_pos.begin.lineno == lineno);
|
||||
|
||||
|
@ -1894,14 +1894,14 @@ ASTSerializer::program(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::sourceElement(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::sourceElement(ParseNode *pn, Value *dst)
|
||||
{
|
||||
/* SpiderMonkey allows declarations even in pure statement contexts. */
|
||||
return statement(pn, dst);
|
||||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::declaration(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::declaration(ParseNode *pn, Value *dst)
|
||||
{
|
||||
JS_ASSERT(pn->isKind(TOK_FUNCTION) || pn->isKind(TOK_VAR) || pn->isKind(TOK_LET));
|
||||
|
||||
|
@ -1919,7 +1919,7 @@ ASTSerializer::declaration(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::variableDeclaration(JSParseNode *pn, bool let, Value *dst)
|
||||
ASTSerializer::variableDeclaration(ParseNode *pn, bool let, Value *dst)
|
||||
{
|
||||
JS_ASSERT(let ? pn->isKind(TOK_LET) : pn->isKind(TOK_VAR));
|
||||
|
||||
|
@ -1939,7 +1939,7 @@ ASTSerializer::variableDeclaration(JSParseNode *pn, bool let, Value *dst)
|
|||
|
||||
if (!dtors.reserve(pn->pn_count))
|
||||
return false;
|
||||
for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
|
||||
for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
|
||||
Value child;
|
||||
if (!variableDeclarator(next, &kind, &child))
|
||||
return false;
|
||||
|
@ -1950,13 +1950,13 @@ ASTSerializer::variableDeclaration(JSParseNode *pn, bool let, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::variableDeclarator(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
|
||||
ASTSerializer::variableDeclarator(ParseNode *pn, VarDeclKind *pkind, Value *dst)
|
||||
{
|
||||
/* A destructuring declarator is always a TOK_ASSIGN. */
|
||||
JS_ASSERT(pn->isKind(TOK_NAME) || pn->isKind(TOK_ASSIGN));
|
||||
|
||||
JSParseNode *pnleft;
|
||||
JSParseNode *pnright;
|
||||
ParseNode *pnleft;
|
||||
ParseNode *pnright;
|
||||
|
||||
if (pn->isKind(TOK_NAME)) {
|
||||
pnleft = pn;
|
||||
|
@ -1974,14 +1974,14 @@ ASTSerializer::variableDeclarator(JSParseNode *pn, VarDeclKind *pkind, Value *ds
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::letHead(JSParseNode *pn, NodeVector &dtors)
|
||||
ASTSerializer::letHead(ParseNode *pn, NodeVector &dtors)
|
||||
{
|
||||
if (!dtors.reserve(pn->pn_count))
|
||||
return false;
|
||||
|
||||
VarDeclKind kind = VARDECL_LET_HEAD;
|
||||
|
||||
for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
|
||||
for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
|
||||
Value child;
|
||||
/*
|
||||
* Unlike in |variableDeclaration|, this does not update |kind|; since let-heads do
|
||||
|
@ -1996,7 +1996,7 @@ ASTSerializer::letHead(JSParseNode *pn, NodeVector &dtors)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::switchCase(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::switchCase(ParseNode *pn, Value *dst)
|
||||
{
|
||||
NodeVector stmts(cx);
|
||||
|
||||
|
@ -2008,14 +2008,14 @@ ASTSerializer::switchCase(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::switchStatement(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::switchStatement(ParseNode *pn, Value *dst)
|
||||
{
|
||||
Value disc;
|
||||
|
||||
if (!expression(pn->pn_left, &disc))
|
||||
return false;
|
||||
|
||||
JSParseNode *listNode;
|
||||
ParseNode *listNode;
|
||||
bool lexical;
|
||||
|
||||
if (pn->pn_right->isKind(TOK_LEXICALSCOPE)) {
|
||||
|
@ -2030,7 +2030,7 @@ ASTSerializer::switchStatement(JSParseNode *pn, Value *dst)
|
|||
if (!cases.reserve(listNode->pn_count))
|
||||
return false;
|
||||
|
||||
for (JSParseNode *next = listNode->pn_head; next; next = next->pn_next) {
|
||||
for (ParseNode *next = listNode->pn_head; next; next = next->pn_next) {
|
||||
Value child;
|
||||
#ifdef __GNUC__ /* quell GCC overwarning */
|
||||
child = UndefinedValue();
|
||||
|
@ -2044,7 +2044,7 @@ ASTSerializer::switchStatement(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::catchClause(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::catchClause(ParseNode *pn, Value *dst)
|
||||
{
|
||||
Value var, guard, body;
|
||||
|
||||
|
@ -2055,7 +2055,7 @@ ASTSerializer::catchClause(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::tryStatement(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::tryStatement(ParseNode *pn, Value *dst)
|
||||
{
|
||||
Value body;
|
||||
if (!statement(pn->pn_kid1, &body))
|
||||
|
@ -2066,7 +2066,7 @@ ASTSerializer::tryStatement(JSParseNode *pn, Value *dst)
|
|||
if (!clauses.reserve(pn->pn_kid2->pn_count))
|
||||
return false;
|
||||
|
||||
for (JSParseNode *next = pn->pn_kid2->pn_head; next; next = next->pn_next) {
|
||||
for (ParseNode *next = pn->pn_kid2->pn_head; next; next = next->pn_next) {
|
||||
Value clause;
|
||||
if (!catchClause(next->pn_expr, &clause))
|
||||
return false;
|
||||
|
@ -2080,7 +2080,7 @@ ASTSerializer::tryStatement(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::forInit(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::forInit(ParseNode *pn, Value *dst)
|
||||
{
|
||||
if (!pn) {
|
||||
dst->setMagic(JS_SERIALIZE_NO_NODE);
|
||||
|
@ -2095,7 +2095,7 @@ ASTSerializer::forInit(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::statement(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::statement(ParseNode *pn, Value *dst)
|
||||
{
|
||||
JS_CHECK_RECURSION(cx, return false);
|
||||
switch (pn->getKind()) {
|
||||
|
@ -2173,7 +2173,7 @@ ASTSerializer::statement(JSParseNode *pn, Value *dst)
|
|||
|
||||
case TOK_FOR:
|
||||
{
|
||||
JSParseNode *head = pn->pn_left;
|
||||
ParseNode *head = pn->pn_left;
|
||||
|
||||
Value stmt;
|
||||
if (!statement(pn->pn_right, &stmt))
|
||||
|
@ -2206,8 +2206,8 @@ ASTSerializer::statement(JSParseNode *pn, Value *dst)
|
|||
{
|
||||
LOCAL_ASSERT(pn->pn_count == 2);
|
||||
|
||||
JSParseNode *prelude = pn->pn_head;
|
||||
JSParseNode *loop = prelude->pn_next;
|
||||
ParseNode *prelude = pn->pn_head;
|
||||
ParseNode *loop = prelude->pn_next;
|
||||
|
||||
LOCAL_ASSERT(prelude->isKind(TOK_VAR) && loop->isKind(TOK_FOR));
|
||||
|
||||
|
@ -2215,7 +2215,7 @@ ASTSerializer::statement(JSParseNode *pn, Value *dst)
|
|||
if (!variableDeclaration(prelude, false, &var))
|
||||
return false;
|
||||
|
||||
JSParseNode *head = loop->pn_left;
|
||||
ParseNode *head = loop->pn_left;
|
||||
JS_ASSERT(head->isKind(TOK_IN));
|
||||
|
||||
bool isForEach = loop->pn_iflags & JSITER_FOREACH;
|
||||
|
@ -2279,7 +2279,7 @@ ASTSerializer::statement(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::leftAssociate(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::leftAssociate(ParseNode *pn, Value *dst)
|
||||
{
|
||||
JS_ASSERT(pn->isArity(PN_LIST));
|
||||
JS_ASSERT(pn->pn_count >= 1);
|
||||
|
@ -2288,16 +2288,16 @@ ASTSerializer::leftAssociate(JSParseNode *pn, Value *dst)
|
|||
bool lor = tk == TOK_OR;
|
||||
bool logop = lor || (tk == TOK_AND);
|
||||
|
||||
JSParseNode *head = pn->pn_head;
|
||||
ParseNode *head = pn->pn_head;
|
||||
Value left;
|
||||
if (!expression(head, &left))
|
||||
return false;
|
||||
for (JSParseNode *next = head->pn_next; next; next = next->pn_next) {
|
||||
for (ParseNode *next = head->pn_next; next; next = next->pn_next) {
|
||||
Value right;
|
||||
if (!expression(next, &right))
|
||||
return false;
|
||||
|
||||
TokenPos subpos = { pn->pn_pos.begin, next->pn_pos.end };
|
||||
TokenPos subpos(pn->pn_pos.begin, next->pn_pos.end);
|
||||
|
||||
if (logop) {
|
||||
if (!builder.logicalExpression(lor, left, right, &subpos, &left))
|
||||
|
@ -2316,11 +2316,11 @@ ASTSerializer::leftAssociate(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::comprehensionBlock(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::comprehensionBlock(ParseNode *pn, Value *dst)
|
||||
{
|
||||
LOCAL_ASSERT(pn->isArity(PN_BINARY));
|
||||
|
||||
JSParseNode *in = pn->pn_left;
|
||||
ParseNode *in = pn->pn_left;
|
||||
|
||||
LOCAL_ASSERT(in && in->isKind(TOK_IN));
|
||||
|
||||
|
@ -2333,13 +2333,13 @@ ASTSerializer::comprehensionBlock(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::comprehension(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::comprehension(ParseNode *pn, Value *dst)
|
||||
{
|
||||
LOCAL_ASSERT(pn->isKind(TOK_FOR));
|
||||
|
||||
NodeVector blocks(cx);
|
||||
|
||||
JSParseNode *next = pn;
|
||||
ParseNode *next = pn;
|
||||
while (next->isKind(TOK_FOR)) {
|
||||
Value block;
|
||||
if (!comprehensionBlock(next, &block) || !blocks.append(block))
|
||||
|
@ -2368,13 +2368,13 @@ ASTSerializer::comprehension(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::generatorExpression(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::generatorExpression(ParseNode *pn, Value *dst)
|
||||
{
|
||||
LOCAL_ASSERT(pn->isKind(TOK_FOR));
|
||||
|
||||
NodeVector blocks(cx);
|
||||
|
||||
JSParseNode *next = pn;
|
||||
ParseNode *next = pn;
|
||||
while (next->isKind(TOK_FOR)) {
|
||||
Value block;
|
||||
if (!comprehensionBlock(next, &block) || !blocks.append(block))
|
||||
|
@ -2401,7 +2401,7 @@ ASTSerializer::generatorExpression(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::expression(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::expression(ParseNode *pn, Value *dst)
|
||||
{
|
||||
JS_CHECK_RECURSION(cx, return false);
|
||||
switch (pn->getKind()) {
|
||||
|
@ -2509,7 +2509,7 @@ ASTSerializer::expression(JSParseNode *pn, Value *dst)
|
|||
return generatorExpression(pn->generatorExpr(), dst);
|
||||
#endif
|
||||
|
||||
JSParseNode *next = pn->pn_head;
|
||||
ParseNode *next = pn->pn_head;
|
||||
|
||||
Value callee;
|
||||
if (!expression(next, &callee))
|
||||
|
@ -2559,7 +2559,7 @@ ASTSerializer::expression(JSParseNode *pn, Value *dst)
|
|||
if (!elts.reserve(pn->pn_count))
|
||||
return false;
|
||||
|
||||
for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
|
||||
for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
|
||||
if (next->isKind(TOK_COMMA)) {
|
||||
elts.infallibleAppend(MagicValue(JS_SERIALIZE_NO_NODE));
|
||||
} else {
|
||||
|
@ -2584,7 +2584,7 @@ ASTSerializer::expression(JSParseNode *pn, Value *dst)
|
|||
if (!elts.reserve(pn->pn_count))
|
||||
return false;
|
||||
|
||||
for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
|
||||
for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
|
||||
Value prop;
|
||||
if (!property(next, &prop))
|
||||
return false;
|
||||
|
@ -2649,7 +2649,7 @@ ASTSerializer::expression(JSParseNode *pn, Value *dst)
|
|||
|
||||
LOCAL_ASSERT(pn->isArity(PN_NAME) || pn->isArity(PN_BINARY));
|
||||
|
||||
JSParseNode *pnleft;
|
||||
ParseNode *pnleft;
|
||||
bool computed;
|
||||
|
||||
if (pn->isArity(PN_BINARY)) {
|
||||
|
@ -2676,7 +2676,7 @@ ASTSerializer::expression(JSParseNode *pn, Value *dst)
|
|||
case TOK_AT:
|
||||
{
|
||||
Value expr;
|
||||
JSParseNode *kid = pn->pn_kid;
|
||||
ParseNode *kid = pn->pn_kid;
|
||||
bool computed = ((!kid->isKind(TOK_NAME) || !kid->isOp(JSOP_QNAMEPART)) &&
|
||||
!kid->isKind(TOK_DBLCOLON) &&
|
||||
!kid->isKind(TOK_ANYNAME));
|
||||
|
@ -2703,7 +2703,7 @@ ASTSerializer::expression(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::xml(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::xml(ParseNode *pn, Value *dst)
|
||||
{
|
||||
JS_CHECK_RECURSION(cx, return false);
|
||||
switch (pn->getKind()) {
|
||||
|
@ -2796,7 +2796,7 @@ ASTSerializer::xml(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::propertyName(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::propertyName(ParseNode *pn, Value *dst)
|
||||
{
|
||||
if (pn->isKind(TOK_NAME))
|
||||
return identifier(pn, dst);
|
||||
|
@ -2807,7 +2807,7 @@ ASTSerializer::propertyName(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::property(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::property(ParseNode *pn, Value *dst)
|
||||
{
|
||||
PropKind kind;
|
||||
switch (pn->getOp()) {
|
||||
|
@ -2834,7 +2834,7 @@ ASTSerializer::property(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::literal(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::literal(ParseNode *pn, Value *dst)
|
||||
{
|
||||
Value val;
|
||||
switch (pn->getKind()) {
|
||||
|
@ -2878,7 +2878,7 @@ ASTSerializer::literal(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::arrayPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
|
||||
ASTSerializer::arrayPattern(ParseNode *pn, VarDeclKind *pkind, Value *dst)
|
||||
{
|
||||
JS_ASSERT(pn->isKind(TOK_RB));
|
||||
|
||||
|
@ -2886,7 +2886,7 @@ ASTSerializer::arrayPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
|
|||
if (!elts.reserve(pn->pn_count))
|
||||
return false;
|
||||
|
||||
for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
|
||||
for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
|
||||
if (next->isKind(TOK_COMMA)) {
|
||||
elts.infallibleAppend(MagicValue(JS_SERIALIZE_NO_NODE));
|
||||
} else {
|
||||
|
@ -2901,7 +2901,7 @@ ASTSerializer::arrayPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::objectPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
|
||||
ASTSerializer::objectPattern(ParseNode *pn, VarDeclKind *pkind, Value *dst)
|
||||
{
|
||||
JS_ASSERT(pn->isKind(TOK_RC));
|
||||
|
||||
|
@ -2909,7 +2909,7 @@ ASTSerializer::objectPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
|
|||
if (!elts.reserve(pn->pn_count))
|
||||
return false;
|
||||
|
||||
for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
|
||||
for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
|
||||
LOCAL_ASSERT(next->isOp(JSOP_INITPROP));
|
||||
|
||||
Value key, patt, prop;
|
||||
|
@ -2926,7 +2926,7 @@ ASTSerializer::objectPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::pattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
|
||||
ASTSerializer::pattern(ParseNode *pn, VarDeclKind *pkind, Value *dst)
|
||||
{
|
||||
JS_CHECK_RECURSION(cx, return false);
|
||||
switch (pn->getKind()) {
|
||||
|
@ -2953,7 +2953,7 @@ ASTSerializer::identifier(JSAtom *atom, TokenPos *pos, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::identifier(JSParseNode *pn, Value *dst)
|
||||
ASTSerializer::identifier(ParseNode *pn, Value *dst)
|
||||
{
|
||||
LOCAL_ASSERT(pn->isArity(PN_NAME) || pn->isArity(PN_NULLARY));
|
||||
LOCAL_ASSERT(pn->pn_atom);
|
||||
|
@ -2962,7 +2962,7 @@ ASTSerializer::identifier(JSParseNode *pn, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::function(JSParseNode *pn, ASTType type, Value *dst)
|
||||
ASTSerializer::function(ParseNode *pn, ASTType type, Value *dst)
|
||||
{
|
||||
JSFunction *func = (JSFunction *)pn->pn_funbox->object;
|
||||
|
||||
|
@ -2986,9 +2986,9 @@ ASTSerializer::function(JSParseNode *pn, ASTType type, Value *dst)
|
|||
|
||||
NodeVector args(cx);
|
||||
|
||||
JSParseNode *argsAndBody = pn->pn_body->isKind(TOK_UPVARS)
|
||||
? pn->pn_body->pn_tree
|
||||
: pn->pn_body;
|
||||
ParseNode *argsAndBody = pn->pn_body->isKind(TOK_UPVARS)
|
||||
? pn->pn_body->pn_tree
|
||||
: pn->pn_body;
|
||||
|
||||
Value body;
|
||||
return functionArgsAndBody(argsAndBody, args, &body) &&
|
||||
|
@ -2996,10 +2996,10 @@ ASTSerializer::function(JSParseNode *pn, ASTType type, Value *dst)
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::functionArgsAndBody(JSParseNode *pn, NodeVector &args, Value *body)
|
||||
ASTSerializer::functionArgsAndBody(ParseNode *pn, NodeVector &args, Value *body)
|
||||
{
|
||||
JSParseNode *pnargs;
|
||||
JSParseNode *pnbody;
|
||||
ParseNode *pnargs;
|
||||
ParseNode *pnbody;
|
||||
|
||||
/* Extract the args and body separately. */
|
||||
if (pn->isKind(TOK_ARGSBODY)) {
|
||||
|
@ -3010,11 +3010,11 @@ ASTSerializer::functionArgsAndBody(JSParseNode *pn, NodeVector &args, Value *bod
|
|||
pnbody = pn;
|
||||
}
|
||||
|
||||
JSParseNode *pndestruct;
|
||||
ParseNode *pndestruct;
|
||||
|
||||
/* Extract the destructuring assignments. */
|
||||
if (pnbody->isArity(PN_LIST) && (pnbody->pn_xflags & PNX_DESTRUCT)) {
|
||||
JSParseNode *head = pnbody->pn_head;
|
||||
ParseNode *head = pnbody->pn_head;
|
||||
LOCAL_ASSERT(head && head->isKind(TOK_SEMI));
|
||||
|
||||
pndestruct = head->pn_kid;
|
||||
|
@ -3031,7 +3031,7 @@ ASTSerializer::functionArgsAndBody(JSParseNode *pn, NodeVector &args, Value *bod
|
|||
|
||||
case TOK_SEQ: /* expression closure with destructured args */
|
||||
{
|
||||
JSParseNode *pnstart = pnbody->pn_head->pn_next;
|
||||
ParseNode *pnstart = pnbody->pn_head->pn_next;
|
||||
LOCAL_ASSERT(pnstart && pnstart->isKind(TOK_RETURN));
|
||||
|
||||
return functionArgs(pn, pnargs, pndestruct, pnbody, args) &&
|
||||
|
@ -3040,7 +3040,7 @@ ASTSerializer::functionArgsAndBody(JSParseNode *pn, NodeVector &args, Value *bod
|
|||
|
||||
case TOK_LC: /* statement closure */
|
||||
{
|
||||
JSParseNode *pnstart = (pnbody->pn_xflags & PNX_DESTRUCT)
|
||||
ParseNode *pnstart = (pnbody->pn_xflags & PNX_DESTRUCT)
|
||||
? pnbody->pn_head->pn_next
|
||||
: pnbody->pn_head;
|
||||
|
||||
|
@ -3054,12 +3054,12 @@ ASTSerializer::functionArgsAndBody(JSParseNode *pn, NodeVector &args, Value *bod
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::functionArgs(JSParseNode *pn, JSParseNode *pnargs, JSParseNode *pndestruct,
|
||||
JSParseNode *pnbody, NodeVector &args)
|
||||
ASTSerializer::functionArgs(ParseNode *pn, ParseNode *pnargs, ParseNode *pndestruct,
|
||||
ParseNode *pnbody, NodeVector &args)
|
||||
{
|
||||
uint32 i = 0;
|
||||
JSParseNode *arg = pnargs ? pnargs->pn_head : NULL;
|
||||
JSParseNode *destruct = pndestruct ? pndestruct->pn_head : NULL;
|
||||
ParseNode *arg = pnargs ? pnargs->pn_head : NULL;
|
||||
ParseNode *destruct = pndestruct ? pndestruct->pn_head : NULL;
|
||||
Value node;
|
||||
|
||||
/*
|
||||
|
@ -3100,12 +3100,12 @@ ASTSerializer::functionArgs(JSParseNode *pn, JSParseNode *pnargs, JSParseNode *p
|
|||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::functionBody(JSParseNode *pn, TokenPos *pos, Value *dst)
|
||||
ASTSerializer::functionBody(ParseNode *pn, TokenPos *pos, Value *dst)
|
||||
{
|
||||
NodeVector elts(cx);
|
||||
|
||||
/* We aren't sure how many elements there are up front, so we'll check each append. */
|
||||
for (JSParseNode *next = pn; next; next = next->pn_next) {
|
||||
for (ParseNode *next = pn; next; next = next->pn_next) {
|
||||
Value child;
|
||||
if (!sourceElement(next, &child) || !elts.append(child))
|
||||
return false;
|
||||
|
@ -3221,7 +3221,7 @@ reflect_parse(JSContext *cx, uint32 argc, jsval *vp)
|
|||
|
||||
serialize.setParser(&parser);
|
||||
|
||||
JSParseNode *pn = parser.parse(NULL);
|
||||
ParseNode *pn = parser.parse(NULL);
|
||||
if (!pn)
|
||||
return JS_FALSE;
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
|
||||
using namespace js;
|
||||
using namespace js::gc;
|
||||
using namespace js::frontend;
|
||||
|
||||
namespace js {
|
||||
|
||||
|
@ -1097,7 +1098,7 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom
|
|||
}
|
||||
|
||||
JSScript *
|
||||
JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
||||
JSScript::NewScriptFromCG(JSContext *cx, CodeGenerator *cg)
|
||||
{
|
||||
uint32 mainLength, prologLength, nsrcnotes, nfixed;
|
||||
JSScript *script;
|
||||
|
@ -1162,10 +1163,10 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
|||
|
||||
script->sourceMap = (jschar *) cg->parser->tokenStream.releaseSourceMap();
|
||||
|
||||
if (!js_FinishTakingSrcNotes(cx, cg, script->notes()))
|
||||
if (!FinishTakingSrcNotes(cx, cg, script->notes()))
|
||||
return NULL;
|
||||
if (cg->ntrynotes != 0)
|
||||
js_FinishTakingTryNotes(cg, script->trynotes());
|
||||
FinishTakingTryNotes(cg, script->trynotes());
|
||||
if (cg->objectList.length != 0)
|
||||
cg->objectList.finish(script->objects());
|
||||
if (cg->regexpList.length != 0)
|
||||
|
@ -1470,13 +1471,6 @@ js_FramePCToLineNumber(JSContext *cx, StackFrame *fp, jsbytecode *pc)
|
|||
uintN
|
||||
js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
{
|
||||
JSOp op;
|
||||
JSFunction *fun;
|
||||
uintN lineno;
|
||||
ptrdiff_t offset, target;
|
||||
jssrcnote *sn;
|
||||
JSSrcNoteType type;
|
||||
|
||||
/* Cope with StackFrame.pc value prior to entering js_Interpret. */
|
||||
if (!pc)
|
||||
return 0;
|
||||
|
@ -1485,10 +1479,11 @@ js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
|
|||
* Special case: function definition needs no line number note because
|
||||
* the function's script contains its starting line number.
|
||||
*/
|
||||
op = js_GetOpcode(cx, script, pc);
|
||||
JSOp op = js_GetOpcode(cx, script, pc);
|
||||
if (js_CodeSpec[op].format & JOF_INDEXBASE)
|
||||
pc += js_CodeSpec[op].length;
|
||||
if (*pc == JSOP_DEFFUN) {
|
||||
JSFunction *fun;
|
||||
GET_FUNCTION_FROM_BYTECODE(script, pc, 0, fun);
|
||||
return fun->script()->lineno;
|
||||
}
|
||||
|
@ -1498,12 +1493,12 @@ js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
|
|||
* keeping track of line-number notes, until we pass the note for pc's
|
||||
* offset within script->code.
|
||||
*/
|
||||
lineno = script->lineno;
|
||||
offset = 0;
|
||||
target = pc - script->code;
|
||||
for (sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
|
||||
uintN lineno = script->lineno;
|
||||
ptrdiff_t offset = 0;
|
||||
ptrdiff_t target = pc - script->code;
|
||||
for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
|
||||
offset += SN_DELTA(sn);
|
||||
type = (JSSrcNoteType) SN_TYPE(sn);
|
||||
SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
|
||||
if (type == SRC_SETLINE) {
|
||||
if (offset <= target)
|
||||
lineno = (uintN) js_GetSrcNoteOffset(sn, 0);
|
||||
|
@ -1523,16 +1518,11 @@ js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
|
|||
jsbytecode *
|
||||
js_LineNumberToPC(JSScript *script, uintN target)
|
||||
{
|
||||
ptrdiff_t offset, best;
|
||||
uintN lineno, bestdiff, diff;
|
||||
jssrcnote *sn;
|
||||
JSSrcNoteType type;
|
||||
|
||||
offset = 0;
|
||||
best = -1;
|
||||
lineno = script->lineno;
|
||||
bestdiff = SN_LINE_LIMIT;
|
||||
for (sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
|
||||
ptrdiff_t offset = 0;
|
||||
ptrdiff_t best = -1;
|
||||
uintN lineno = script->lineno;
|
||||
uintN bestdiff = SN_LINE_LIMIT;
|
||||
for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
|
||||
/*
|
||||
* Exact-match only if offset is not in the prolog; otherwise use
|
||||
* nearest greater-or-equal line number match.
|
||||
|
@ -1540,14 +1530,14 @@ js_LineNumberToPC(JSScript *script, uintN target)
|
|||
if (lineno == target && offset >= ptrdiff_t(script->mainOffset))
|
||||
goto out;
|
||||
if (lineno >= target) {
|
||||
diff = lineno - target;
|
||||
uintN diff = lineno - target;
|
||||
if (diff < bestdiff) {
|
||||
bestdiff = diff;
|
||||
best = offset;
|
||||
}
|
||||
}
|
||||
offset += SN_DELTA(sn);
|
||||
type = (JSSrcNoteType) SN_TYPE(sn);
|
||||
SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
|
||||
if (type == SRC_SETLINE) {
|
||||
lineno = (uintN) js_GetSrcNoteOffset(sn, 0);
|
||||
} else if (type == SRC_NEWLINE) {
|
||||
|
@ -1563,18 +1553,11 @@ out:
|
|||
JS_FRIEND_API(uintN)
|
||||
js_GetScriptLineExtent(JSScript *script)
|
||||
{
|
||||
|
||||
bool counting;
|
||||
uintN lineno;
|
||||
uintN maxLineNo;
|
||||
jssrcnote *sn;
|
||||
JSSrcNoteType type;
|
||||
|
||||
lineno = script->lineno;
|
||||
maxLineNo = 0;
|
||||
counting = true;
|
||||
for (sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
|
||||
type = (JSSrcNoteType) SN_TYPE(sn);
|
||||
uintN lineno = script->lineno;
|
||||
uintN maxLineNo = 0;
|
||||
bool counting = true;
|
||||
for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
|
||||
SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
|
||||
if (type == SRC_SETLINE) {
|
||||
if (maxLineNo < lineno)
|
||||
maxLineNo = lineno;
|
||||
|
|
|
@ -447,7 +447,7 @@ struct JSScript : public js::gc::Cell {
|
|||
uint16 nClosedArgs, uint16 nClosedVars, uint32 nTypeSets,
|
||||
JSVersion version);
|
||||
|
||||
static JSScript *NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg);
|
||||
static JSScript *NewScriptFromCG(JSContext *cx, js::CodeGenerator *cg);
|
||||
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
/*
|
||||
|
|
|
@ -1524,10 +1524,8 @@ BuildFlatMatchArray(JSContext *cx, JSString *textstr, const FlatMatch &fm, Value
|
|||
vp->setObject(*obj);
|
||||
|
||||
return obj->defineElement(cx, 0, StringValue(fm.pattern())) &&
|
||||
obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.indexAtom),
|
||||
Int32Value(fm.match())) &&
|
||||
obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.inputAtom),
|
||||
StringValue(textstr));
|
||||
obj->defineProperty(cx, cx->runtime->atomState.indexAtom, Int32Value(fm.match())) &&
|
||||
obj->defineProperty(cx, cx->runtime->atomState.inputAtom, StringValue(textstr));
|
||||
}
|
||||
|
||||
typedef JSObject **MatchArgType;
|
||||
|
|
|
@ -10909,30 +10909,74 @@ TraceRecorder::getClassPrototype(JSObject* ctor, LIns*& proto_ins)
|
|||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
||||
RecordingStatus
|
||||
TraceRecorder::getClassPrototype(JSProtoKey key, LIns*& proto_ins)
|
||||
static inline void
|
||||
AssertValidPrototype(JSObject *proto, JSProtoKey key, DebugOnly<TraceMonitor *> localtm,
|
||||
JSContext *cx)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
TraceMonitor &localtm = *traceMonitor;
|
||||
/* This shouldn't have reentered. */
|
||||
JS_ASSERT(localtm->recorder);
|
||||
|
||||
/* Double-check for a matching emptyShape. */
|
||||
JS_ASSERT(proto->isNative());
|
||||
JS_ASSERT(proto->getNewType(cx)->emptyShapes);
|
||||
EmptyShape *empty = proto->getNewType(cx)->emptyShapes[0];
|
||||
JS_ASSERT(empty);
|
||||
JS_ASSERT(JSCLASS_CACHED_PROTO_KEY(empty->getClass()) == key);
|
||||
#endif
|
||||
}
|
||||
|
||||
JSObject* proto;
|
||||
if (!js_GetClassPrototype(cx, globalObj, key, &proto))
|
||||
RETURN_ERROR("error in js_GetClassPrototype");
|
||||
RecordingStatus
|
||||
TraceRecorder::getObjectPrototype(LIns*& proto_ins)
|
||||
{
|
||||
DebugOnly<TraceMonitor *> localtm = traceMonitor;
|
||||
|
||||
// This should not have reentered.
|
||||
JS_ASSERT(localtm.recorder);
|
||||
JSObject *proto = globalObj->asGlobal()->getOrCreateObjectPrototype(cx);
|
||||
if (!proto)
|
||||
RETURN_ERROR("error getting Object.prototype");
|
||||
AssertValidPrototype(proto, JSProto_Object, localtm, cx);
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Double-check that a native proto has a matching emptyShape. */
|
||||
if (key != JSProto_Array) {
|
||||
JS_ASSERT(proto->isNative());
|
||||
JS_ASSERT(proto->getNewType(cx)->emptyShapes);
|
||||
EmptyShape *empty = proto->getNewType(cx)->emptyShapes[0];
|
||||
JS_ASSERT(empty);
|
||||
JS_ASSERT(JSCLASS_CACHED_PROTO_KEY(empty->getClass()) == key);
|
||||
}
|
||||
#endif
|
||||
proto_ins = w.immpObjGC(proto);
|
||||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
||||
RecordingStatus
|
||||
TraceRecorder::getFunctionPrototype(LIns*& proto_ins)
|
||||
{
|
||||
DebugOnly<TraceMonitor *> localtm = traceMonitor;
|
||||
|
||||
JSObject *proto = globalObj->asGlobal()->getOrCreateFunctionPrototype(cx);
|
||||
if (!proto)
|
||||
RETURN_ERROR("error getting Function.prototype");
|
||||
AssertValidPrototype(proto, JSProto_Function, localtm, cx);
|
||||
|
||||
proto_ins = w.immpObjGC(proto);
|
||||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
||||
RecordingStatus
|
||||
TraceRecorder::getArrayPrototype(LIns*& proto_ins)
|
||||
{
|
||||
DebugOnly<TraceMonitor *> localtm = traceMonitor;
|
||||
|
||||
JSObject *proto = globalObj->asGlobal()->getOrCreateArrayPrototype(cx);
|
||||
if (!proto)
|
||||
RETURN_ERROR("error getting Array.prototype");
|
||||
AssertValidPrototype(proto, JSProto_Array, localtm, cx);
|
||||
|
||||
proto_ins = w.immpObjGC(proto);
|
||||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
||||
RecordingStatus
|
||||
TraceRecorder::getRegExpPrototype(LIns*& proto_ins)
|
||||
{
|
||||
DebugOnly<TraceMonitor *> localtm = traceMonitor;
|
||||
|
||||
JSObject *proto = globalObj->asGlobal()->getOrCreateRegExpPrototype(cx);
|
||||
if (!proto)
|
||||
RETURN_ERROR("error getting RegExp.prototype");
|
||||
AssertValidPrototype(proto, JSProto_RegExp, localtm, cx);
|
||||
|
||||
proto_ins = w.immpObjGC(proto);
|
||||
return RECORD_CONTINUE;
|
||||
|
@ -11631,7 +11675,7 @@ DeleteIntKey(JSContext* cx, JSObject* obj, int32 i, JSBool strict)
|
|||
}
|
||||
}
|
||||
|
||||
if (!obj->deleteProperty(cx, id, &v, strict))
|
||||
if (!obj->deleteGeneric(cx, id, &v, strict))
|
||||
SetBuiltinError(tm);
|
||||
return v.toBoolean();
|
||||
}
|
||||
|
@ -11653,7 +11697,7 @@ DeleteStrKey(JSContext* cx, JSObject* obj, JSString* str, JSBool strict)
|
|||
* jsatominlines.h) that helper early-returns if the computed property name
|
||||
* string is already atomized, and we are *not* on a perf-critical path!
|
||||
*/
|
||||
if (!js_ValueToStringId(cx, StringValue(str), &id) || !obj->deleteProperty(cx, id, &v, strict))
|
||||
if (!js_ValueToStringId(cx, StringValue(str), &id) || !obj->deleteGeneric(cx, id, &v, strict))
|
||||
SetBuiltinError(tm);
|
||||
return v.toBoolean();
|
||||
}
|
||||
|
@ -12853,7 +12897,7 @@ SetPropertyByName(JSContext* cx, JSObject* obj, JSString** namep, Value* vp, JSB
|
|||
LeaveTraceIfGlobalObject(cx, obj);
|
||||
|
||||
jsid id;
|
||||
if (!RootedStringToId(cx, namep, &id) || !obj->setProperty(cx, id, vp, strict)) {
|
||||
if (!RootedStringToId(cx, namep, &id) || !obj->setGeneric(cx, id, vp, strict)) {
|
||||
SetBuiltinError(tm);
|
||||
return false;
|
||||
}
|
||||
|
@ -12872,7 +12916,7 @@ InitPropertyByName(JSContext* cx, JSObject* obj, JSString** namep, ValueArgType
|
|||
|
||||
jsid id;
|
||||
if (!RootedStringToId(cx, namep, &id) ||
|
||||
!obj->defineProperty(cx, id, ValueArgToConstRef(arg), NULL, NULL, JSPROP_ENUMERATE)) {
|
||||
!obj->defineGeneric(cx, id, ValueArgToConstRef(arg), NULL, NULL, JSPROP_ENUMERATE)) {
|
||||
SetBuiltinError(tm);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
@ -12913,7 +12957,7 @@ SetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, Value* vp, JSBool
|
|||
LeaveTraceIfGlobalObject(cx, obj);
|
||||
|
||||
AutoIdRooter idr(cx);
|
||||
if (!js_Int32ToId(cx, index, idr.addr()) || !obj->setProperty(cx, idr.id(), vp, strict)) {
|
||||
if (!js_Int32ToId(cx, index, idr.addr()) || !obj->setGeneric(cx, idr.id(), vp, strict)) {
|
||||
SetBuiltinError(tm);
|
||||
return false;
|
||||
}
|
||||
|
@ -12931,7 +12975,7 @@ InitPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, ValueArgType arg)
|
|||
|
||||
AutoIdRooter idr(cx);
|
||||
if (!js_Int32ToId(cx, index, idr.addr()) ||
|
||||
!obj->defineProperty(cx, idr.id(), ValueArgToConstRef(arg), NULL, NULL, JSPROP_ENUMERATE)) {
|
||||
!obj->defineGeneric(cx, idr.id(), ValueArgToConstRef(arg), NULL, NULL, JSPROP_ENUMERATE)) {
|
||||
SetBuiltinError(tm);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
@ -14334,15 +14378,16 @@ TraceRecorder::record_JSOP_NEWINIT()
|
|||
hadNewInit = true;
|
||||
|
||||
JSProtoKey key = JSProtoKey(cx->regs().pc[1]);
|
||||
JS_ASSERT(key == JSProto_Array || key == JSProto_Object);
|
||||
|
||||
LIns* proto_ins;
|
||||
CHECK_STATUS_A(getClassPrototype(key, proto_ins));
|
||||
|
||||
LIns* proto_ins = NULL;
|
||||
LIns *v_ins;
|
||||
if (key == JSProto_Array) {
|
||||
CHECK_STATUS_A(getArrayPrototype(proto_ins));
|
||||
LIns *args[] = { proto_ins, cx_ins };
|
||||
v_ins = w.call(&NewDenseEmptyArray_ci, args);
|
||||
} else {
|
||||
CHECK_STATUS_A(getObjectPrototype(proto_ins));
|
||||
LIns *args[] = { w.immpNull(), proto_ins, cx_ins };
|
||||
v_ins = w.call(&js_InitializerObject_ci, args);
|
||||
}
|
||||
|
@ -14356,8 +14401,8 @@ TraceRecorder::record_JSOP_NEWARRAY()
|
|||
{
|
||||
initDepth++;
|
||||
|
||||
LIns* proto_ins;
|
||||
CHECK_STATUS_A(getClassPrototype(JSProto_Array, proto_ins));
|
||||
LIns* proto_ins = NULL;
|
||||
CHECK_STATUS_A(getArrayPrototype(proto_ins));
|
||||
|
||||
unsigned count = GET_UINT24(cx->regs().pc);
|
||||
LIns *args[] = { proto_ins, w.immi(count), cx_ins };
|
||||
|
@ -14373,8 +14418,8 @@ TraceRecorder::record_JSOP_NEWOBJECT()
|
|||
{
|
||||
initDepth++;
|
||||
|
||||
LIns* proto_ins;
|
||||
CHECK_STATUS_A(getClassPrototype(JSProto_Object, proto_ins));
|
||||
LIns* proto_ins = NULL;
|
||||
CHECK_STATUS_A(getObjectPrototype(proto_ins));
|
||||
|
||||
JSObject* baseobj = cx->fp()->script()->getObject(getFullIndex(0));
|
||||
|
||||
|
@ -15279,8 +15324,8 @@ TraceRecorder::record_JSOP_LAMBDA()
|
|||
}
|
||||
}
|
||||
|
||||
LIns *proto_ins;
|
||||
CHECK_STATUS_A(getClassPrototype(JSProto_Function, proto_ins));
|
||||
LIns *proto_ins = NULL;
|
||||
CHECK_STATUS_A(getFunctionPrototype(proto_ins));
|
||||
|
||||
LIns* args[] = { w.immpObjGC(globalObj), proto_ins, w.immpFunGC(fun), cx_ins };
|
||||
LIns* x = w.call(&js_NewNullClosure_ci, args);
|
||||
|
@ -15294,8 +15339,8 @@ TraceRecorder::record_JSOP_LAMBDA()
|
|||
if (GetBlockChainFast(cx, cx->fp(), JSOP_LAMBDA, JSOP_LAMBDA_LENGTH))
|
||||
RETURN_STOP_A("Unable to trace creating lambda in let");
|
||||
|
||||
LIns *proto_ins;
|
||||
CHECK_STATUS_A(getClassPrototype(JSProto_Function, proto_ins));
|
||||
LIns *proto_ins = NULL;
|
||||
CHECK_STATUS_A(getFunctionPrototype(proto_ins));
|
||||
LIns* scopeChain_ins = scopeChain();
|
||||
JS_ASSERT(scopeChain_ins);
|
||||
LIns* args[] = { proto_ins, scopeChain_ins, w.nameImmpNonGC(fun), cx_ins };
|
||||
|
@ -15465,8 +15510,8 @@ TraceRecorder::record_DefLocalFunSetSlot(uint32 slot, JSObject* obj)
|
|||
JSFunction* fun = obj->getFunctionPrivate();
|
||||
|
||||
if (fun->isNullClosure() && fun->getParent() == globalObj) {
|
||||
LIns *proto_ins;
|
||||
CHECK_STATUS_A(getClassPrototype(JSProto_Function, proto_ins));
|
||||
LIns *proto_ins = NULL;
|
||||
CHECK_STATUS_A(getFunctionPrototype(proto_ins));
|
||||
|
||||
LIns* args[] = { w.immpObjGC(globalObj), proto_ins, w.immpFunGC(fun), cx_ins };
|
||||
LIns* x = w.call(&js_NewNullClosure_ci, args);
|
||||
|
@ -15588,8 +15633,8 @@ TraceRecorder::record_JSOP_REGEXP()
|
|||
JSScript* script = fp->script();
|
||||
unsigned index = atoms - script->atoms + GET_INDEX(cx->regs().pc);
|
||||
|
||||
LIns* proto_ins;
|
||||
CHECK_STATUS_A(getClassPrototype(JSProto_RegExp, proto_ins));
|
||||
LIns* proto_ins = NULL;
|
||||
CHECK_STATUS_A(getRegExpPrototype(proto_ins));
|
||||
|
||||
LIns* args[] = {
|
||||
proto_ins,
|
||||
|
|
|
@ -1489,10 +1489,14 @@ class TraceRecorder
|
|||
unsigned *depthp);
|
||||
JS_REQUIRES_STACK nanojit::LIns* guardArgsLengthNotAssigned(nanojit::LIns* argsobj_ins);
|
||||
JS_REQUIRES_STACK void guardNotHole(nanojit::LIns* argsobj_ins, nanojit::LIns* ids_ins);
|
||||
|
||||
JS_REQUIRES_STACK RecordingStatus getClassPrototype(JSObject* ctor,
|
||||
nanojit::LIns*& proto_ins);
|
||||
JS_REQUIRES_STACK RecordingStatus getClassPrototype(JSProtoKey key,
|
||||
nanojit::LIns*& proto_ins);
|
||||
JS_REQUIRES_STACK RecordingStatus getObjectPrototype(nanojit::LIns*& proto_ins);
|
||||
JS_REQUIRES_STACK RecordingStatus getFunctionPrototype(nanojit::LIns*& proto_ins);
|
||||
JS_REQUIRES_STACK RecordingStatus getArrayPrototype(nanojit::LIns*& proto_ins);
|
||||
JS_REQUIRES_STACK RecordingStatus getRegExpPrototype(nanojit::LIns*& proto_ins);
|
||||
|
||||
JS_REQUIRES_STACK RecordingStatus newArray(JSObject* ctor, uint32 argc, Value* argv,
|
||||
Value* rval);
|
||||
JS_REQUIRES_STACK RecordingStatus newString(JSObject* ctor, uint32 argc, Value* argv,
|
||||
|
|
|
@ -325,8 +325,8 @@ ArrayBuffer::obj_lookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid,
|
|||
}
|
||||
|
||||
JSBool
|
||||
ArrayBuffer::obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
ArrayBuffer::obj_defineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *v,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
{
|
||||
if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom))
|
||||
return true;
|
||||
|
@ -337,6 +337,13 @@ ArrayBuffer::obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Val
|
|||
return js_DefineProperty(cx, delegate, id, v, getter, setter, attrs);
|
||||
}
|
||||
|
||||
JSBool
|
||||
ArrayBuffer::obj_defineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value *v,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
{
|
||||
return obj_defineGeneric(cx, obj, ATOM_TO_JSID(name), v, getter, setter, attrs);
|
||||
}
|
||||
|
||||
JSBool
|
||||
ArrayBuffer::obj_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *v,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
|
@ -351,7 +358,7 @@ JSBool
|
|||
ArrayBuffer::obj_defineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *v,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
{
|
||||
return obj_defineProperty(cx, obj, SPECIALID_TO_JSID(sid), v, getter, setter, attrs);
|
||||
return obj_defineGeneric(cx, obj, SPECIALID_TO_JSID(sid), v, getter, setter, attrs);
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -392,7 +399,7 @@ ArrayBuffer::obj_getSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, Sp
|
|||
}
|
||||
|
||||
JSBool
|
||||
ArrayBuffer::obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
|
||||
ArrayBuffer::obj_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
|
||||
{
|
||||
if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom))
|
||||
return true;
|
||||
|
@ -445,6 +452,12 @@ ArrayBuffer::obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, J
|
|||
return js_SetPropertyHelper(cx, delegate, id, 0, vp, strict);
|
||||
}
|
||||
|
||||
JSBool
|
||||
ArrayBuffer::obj_setProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict)
|
||||
{
|
||||
return obj_setGeneric(cx, obj, ATOM_TO_JSID(name), vp, strict);
|
||||
}
|
||||
|
||||
JSBool
|
||||
ArrayBuffer::obj_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict)
|
||||
{
|
||||
|
@ -458,11 +471,11 @@ ArrayBuffer::obj_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *v
|
|||
JSBool
|
||||
ArrayBuffer::obj_setSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict)
|
||||
{
|
||||
return obj_setProperty(cx, obj, SPECIALID_TO_JSID(sid), vp, strict);
|
||||
return obj_setGeneric(cx, obj, SPECIALID_TO_JSID(sid), vp, strict);
|
||||
}
|
||||
|
||||
JSBool
|
||||
ArrayBuffer::obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
ArrayBuffer::obj_getGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
{
|
||||
if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
|
||||
*attrsp = JSPROP_PERMANENT | JSPROP_READONLY;
|
||||
|
@ -475,6 +488,12 @@ ArrayBuffer::obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *att
|
|||
return js_GetAttributes(cx, delegate, id, attrsp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
ArrayBuffer::obj_getPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp)
|
||||
{
|
||||
return obj_getGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
ArrayBuffer::obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
|
||||
{
|
||||
|
@ -487,11 +506,11 @@ ArrayBuffer::obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index
|
|||
JSBool
|
||||
ArrayBuffer::obj_getSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp)
|
||||
{
|
||||
return obj_getAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
return obj_getGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
ArrayBuffer::obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
ArrayBuffer::obj_setGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
{
|
||||
if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
|
@ -505,6 +524,12 @@ ArrayBuffer::obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *att
|
|||
return js_SetAttributes(cx, delegate, id, attrsp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
ArrayBuffer::obj_setPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp)
|
||||
{
|
||||
return obj_setGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
ArrayBuffer::obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
|
||||
{
|
||||
|
@ -517,11 +542,11 @@ ArrayBuffer::obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index
|
|||
JSBool
|
||||
ArrayBuffer::obj_setSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp)
|
||||
{
|
||||
return obj_setAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
return obj_setGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
ArrayBuffer::obj_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
|
||||
ArrayBuffer::obj_deleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
|
||||
{
|
||||
if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
|
||||
rval->setBoolean(false);
|
||||
|
@ -534,6 +559,12 @@ ArrayBuffer::obj_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rv
|
|||
return js_DeleteProperty(cx, delegate, id, rval, strict);
|
||||
}
|
||||
|
||||
JSBool
|
||||
ArrayBuffer::obj_deleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict)
|
||||
{
|
||||
return obj_deleteGeneric(cx, obj, ATOM_TO_JSID(name), rval, strict);
|
||||
}
|
||||
|
||||
JSBool
|
||||
ArrayBuffer::obj_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict)
|
||||
{
|
||||
|
@ -546,7 +577,7 @@ ArrayBuffer::obj_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value
|
|||
JSBool
|
||||
ArrayBuffer::obj_deleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict)
|
||||
{
|
||||
return obj_deleteProperty(cx, obj, SPECIALID_TO_JSID(sid), rval, strict);
|
||||
return obj_deleteGeneric(cx, obj, SPECIALID_TO_JSID(sid), rval, strict);
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -722,7 +753,7 @@ TypedArray::obj_lookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid,
|
|||
}
|
||||
|
||||
JSBool
|
||||
TypedArray::obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
TypedArray::obj_getGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
{
|
||||
*attrsp = (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
|
||||
? JSPROP_PERMANENT | JSPROP_READONLY
|
||||
|
@ -730,6 +761,13 @@ TypedArray::obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attr
|
|||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
TypedArray::obj_getPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp)
|
||||
{
|
||||
*attrsp = JSPROP_PERMANENT | JSPROP_ENUMERATE;
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
TypedArray::obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
|
||||
{
|
||||
|
@ -740,11 +778,18 @@ TypedArray::obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index,
|
|||
JSBool
|
||||
TypedArray::obj_getSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp)
|
||||
{
|
||||
return obj_getAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
return obj_getGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
TypedArray::obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
TypedArray::obj_setGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
{
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS);
|
||||
return false;
|
||||
}
|
||||
|
||||
JSBool
|
||||
TypedArray::obj_setPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp)
|
||||
{
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS);
|
||||
return false;
|
||||
|
@ -760,7 +805,8 @@ TypedArray::obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index,
|
|||
JSBool
|
||||
TypedArray::obj_setSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp)
|
||||
{
|
||||
return obj_setAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */ int
|
||||
|
@ -1088,7 +1134,7 @@ class TypedArrayTemplate
|
|||
}
|
||||
|
||||
static JSBool
|
||||
obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
|
||||
obj_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
|
||||
{
|
||||
JSObject *tarray = getTypedArray(obj);
|
||||
JS_ASSERT(tarray);
|
||||
|
@ -1113,6 +1159,12 @@ class TypedArrayTemplate
|
|||
return setElementTail(cx, tarray, index, vp, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
obj_setProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict)
|
||||
{
|
||||
return obj_setGeneric(cx, obj, ATOM_TO_JSID(name), vp, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
obj_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict)
|
||||
{
|
||||
|
@ -1135,18 +1187,25 @@ class TypedArrayTemplate
|
|||
static JSBool
|
||||
obj_setSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict)
|
||||
{
|
||||
return obj_setProperty(cx, obj, SPECIALID_TO_JSID(sid), vp, strict);
|
||||
return obj_setGeneric(cx, obj, SPECIALID_TO_JSID(sid), vp, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
obj_defineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *v,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
{
|
||||
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
|
||||
return true;
|
||||
|
||||
Value tmp = *v;
|
||||
return obj_setProperty(cx, obj, id, &tmp, false);
|
||||
return obj_setGeneric(cx, obj, id, &tmp, false);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
obj_defineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value *v,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
{
|
||||
return obj_defineGeneric(cx, obj, ATOM_TO_JSID(name), v, getter, setter, attrs);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -1161,11 +1220,11 @@ class TypedArrayTemplate
|
|||
obj_defineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *v,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
{
|
||||
return obj_defineProperty(cx, obj, SPECIALID_TO_JSID(sid), v, getter, setter, attrs);
|
||||
return obj_defineGeneric(cx, obj, SPECIALID_TO_JSID(sid), v, getter, setter, attrs);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
obj_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
|
||||
obj_deleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
|
||||
{
|
||||
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
|
||||
rval->setBoolean(false);
|
||||
|
@ -1184,6 +1243,12 @@ class TypedArrayTemplate
|
|||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
obj_deleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict)
|
||||
{
|
||||
return obj_deleteGeneric(cx, obj, ATOM_TO_JSID(name), rval, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
obj_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict)
|
||||
{
|
||||
|
@ -1202,7 +1267,7 @@ class TypedArrayTemplate
|
|||
static JSBool
|
||||
obj_deleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict)
|
||||
{
|
||||
return obj_deleteProperty(cx, obj, SPECIALID_TO_JSID(sid), rval, strict);
|
||||
return obj_deleteGeneric(cx, obj, SPECIALID_TO_JSID(sid), rval, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -2033,7 +2098,7 @@ Class js::ArrayBufferClass = {
|
|||
ArrayBuffer::obj_lookupProperty,
|
||||
ArrayBuffer::obj_lookupElement,
|
||||
ArrayBuffer::obj_lookupSpecial,
|
||||
ArrayBuffer::obj_defineProperty,
|
||||
ArrayBuffer::obj_defineGeneric,
|
||||
ArrayBuffer::obj_defineProperty,
|
||||
ArrayBuffer::obj_defineElement,
|
||||
ArrayBuffer::obj_defineSpecial,
|
||||
|
@ -2041,19 +2106,19 @@ Class js::ArrayBufferClass = {
|
|||
ArrayBuffer::obj_getProperty,
|
||||
ArrayBuffer::obj_getElement,
|
||||
ArrayBuffer::obj_getSpecial,
|
||||
ArrayBuffer::obj_setProperty,
|
||||
ArrayBuffer::obj_setGeneric,
|
||||
ArrayBuffer::obj_setProperty,
|
||||
ArrayBuffer::obj_setElement,
|
||||
ArrayBuffer::obj_setSpecial,
|
||||
ArrayBuffer::obj_getAttributes,
|
||||
ArrayBuffer::obj_getAttributes,
|
||||
ArrayBuffer::obj_getGenericAttributes,
|
||||
ArrayBuffer::obj_getPropertyAttributes,
|
||||
ArrayBuffer::obj_getElementAttributes,
|
||||
ArrayBuffer::obj_getSpecialAttributes,
|
||||
ArrayBuffer::obj_setAttributes,
|
||||
ArrayBuffer::obj_setAttributes,
|
||||
ArrayBuffer::obj_setGenericAttributes,
|
||||
ArrayBuffer::obj_setPropertyAttributes,
|
||||
ArrayBuffer::obj_setElementAttributes,
|
||||
ArrayBuffer::obj_setSpecialAttributes,
|
||||
ArrayBuffer::obj_deleteProperty,
|
||||
ArrayBuffer::obj_deleteGeneric,
|
||||
ArrayBuffer::obj_deleteProperty,
|
||||
ArrayBuffer::obj_deleteElement,
|
||||
ArrayBuffer::obj_deleteSpecial,
|
||||
|
@ -2145,27 +2210,27 @@ JSFunctionSpec _typedArray::jsfuncs[] = { \
|
|||
_typedArray::obj_lookupProperty, \
|
||||
_typedArray::obj_lookupElement, \
|
||||
_typedArray::obj_lookupSpecial, \
|
||||
_typedArray::obj_defineProperty, \
|
||||
_typedArray::obj_defineGeneric, \
|
||||
_typedArray::obj_defineProperty, \
|
||||
_typedArray::obj_defineElement, \
|
||||
_typedArray::obj_defineSpecial, \
|
||||
_typedArray::obj_getGeneric, \
|
||||
_typedArray::obj_getGeneric, \
|
||||
_typedArray::obj_getProperty, \
|
||||
_typedArray::obj_getElement, \
|
||||
_typedArray::obj_getSpecial, \
|
||||
_typedArray::obj_setProperty, \
|
||||
_typedArray::obj_setGeneric, \
|
||||
_typedArray::obj_setProperty, \
|
||||
_typedArray::obj_setElement, \
|
||||
_typedArray::obj_setSpecial, \
|
||||
_typedArray::obj_getAttributes, \
|
||||
_typedArray::obj_getAttributes, \
|
||||
_typedArray::obj_getGenericAttributes, \
|
||||
_typedArray::obj_getPropertyAttributes, \
|
||||
_typedArray::obj_getElementAttributes, \
|
||||
_typedArray::obj_getSpecialAttributes, \
|
||||
_typedArray::obj_setAttributes, \
|
||||
_typedArray::obj_setAttributes, \
|
||||
_typedArray::obj_setGenericAttributes, \
|
||||
_typedArray::obj_setPropertyAttributes, \
|
||||
_typedArray::obj_setElementAttributes, \
|
||||
_typedArray::obj_setSpecialAttributes, \
|
||||
_typedArray::obj_deleteProperty, \
|
||||
_typedArray::obj_deleteGeneric, \
|
||||
_typedArray::obj_deleteProperty, \
|
||||
_typedArray::obj_deleteElement, \
|
||||
_typedArray::obj_deleteSpecial, \
|
||||
|
@ -2193,11 +2258,11 @@ InitTypedArrayClass(JSContext *cx, GlobalObject *global)
|
|||
if (!LinkConstructorAndPrototype(cx, ctor, proto))
|
||||
return NULL;
|
||||
|
||||
if (!ctor->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.BYTES_PER_ELEMENTAtom),
|
||||
if (!ctor->defineProperty(cx, cx->runtime->atomState.BYTES_PER_ELEMENTAtom,
|
||||
Int32Value(ArrayType::BYTES_PER_ELEMENT),
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY) ||
|
||||
!proto->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.BYTES_PER_ELEMENTAtom),
|
||||
!proto->defineProperty(cx, cx->runtime->atomState.BYTES_PER_ELEMENTAtom,
|
||||
Int32Value(ArrayType::BYTES_PER_ELEMENT),
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY))
|
||||
|
|
|
@ -88,13 +88,14 @@ struct JS_FRIEND_API(ArrayBuffer) {
|
|||
JSProperty **propp);
|
||||
|
||||
static JSBool
|
||||
obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v,
|
||||
obj_defineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *v,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs);
|
||||
static JSBool
|
||||
obj_defineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value *v,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs);
|
||||
|
||||
static JSBool
|
||||
obj_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *v,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs);
|
||||
|
||||
static JSBool
|
||||
obj_defineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *v,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs);
|
||||
|
@ -113,38 +114,38 @@ struct JS_FRIEND_API(ArrayBuffer) {
|
|||
obj_getSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid, Value *vp);
|
||||
|
||||
static JSBool
|
||||
obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict);
|
||||
|
||||
obj_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict);
|
||||
static JSBool
|
||||
obj_setProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict);
|
||||
static JSBool
|
||||
obj_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict);
|
||||
|
||||
static JSBool
|
||||
obj_setSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict);
|
||||
|
||||
static JSBool
|
||||
obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
|
||||
|
||||
obj_getGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
|
||||
static JSBool
|
||||
obj_getPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp);
|
||||
static JSBool
|
||||
obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp);
|
||||
|
||||
static JSBool
|
||||
obj_getSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp);
|
||||
|
||||
static JSBool
|
||||
obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
|
||||
|
||||
obj_setGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
|
||||
static JSBool
|
||||
obj_setPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp);
|
||||
static JSBool
|
||||
obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp);
|
||||
|
||||
static JSBool
|
||||
obj_setSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp);
|
||||
|
||||
static JSBool
|
||||
obj_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict);
|
||||
|
||||
obj_deleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict);
|
||||
static JSBool
|
||||
obj_deleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict);
|
||||
static JSBool
|
||||
obj_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict);
|
||||
|
||||
static JSBool
|
||||
obj_deleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict);
|
||||
|
||||
|
@ -222,11 +223,13 @@ struct JS_FRIEND_API(TypedArray) {
|
|||
static JSBool obj_lookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid,
|
||||
JSObject **objp, JSProperty **propp);
|
||||
|
||||
static JSBool obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
|
||||
static JSBool obj_getGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
|
||||
static JSBool obj_getPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp);
|
||||
static JSBool obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp);
|
||||
static JSBool obj_getSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp);
|
||||
|
||||
static JSBool obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
|
||||
static JSBool obj_setGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
|
||||
static JSBool obj_setPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp);
|
||||
static JSBool obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp);
|
||||
static JSBool obj_setSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp);
|
||||
|
||||
|
|
|
@ -235,7 +235,7 @@ Wrapper::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, bool
|
|||
Value *vp)
|
||||
{
|
||||
// FIXME (bug 596351): Need deal with strict mode.
|
||||
SET(wrappedObject(wrapper)->setProperty(cx, id, vp, false));
|
||||
SET(wrappedObject(wrapper)->setGeneric(cx, id, vp, false));
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
105
js/src/jsxml.cpp
105
js/src/jsxml.cpp
|
@ -1156,8 +1156,7 @@ static const char xml_namespace_str[] = "http://www.w3.org/XML/1998/namespace";
|
|||
static const char xmlns_namespace_str[] = "http://www.w3.org/2000/xmlns/";
|
||||
|
||||
static JSObject *
|
||||
ParseNodeToQName(Parser *parser, JSParseNode *pn,
|
||||
JSXMLArray *inScopeNSes, JSBool isAttributeName)
|
||||
ParseNodeToQName(Parser *parser, ParseNode *pn, JSXMLArray *inScopeNSes, JSBool isAttributeName)
|
||||
{
|
||||
JSContext *cx = parser->context;
|
||||
JSLinearString *uri, *prefix;
|
||||
|
@ -1285,14 +1284,13 @@ ChompXMLWhitespace(JSContext *cx, JSString *str)
|
|||
}
|
||||
|
||||
static JSXML *
|
||||
ParseNodeToXML(Parser *parser, JSParseNode *pn,
|
||||
JSXMLArray *inScopeNSes, uintN flags)
|
||||
ParseNodeToXML(Parser *parser, ParseNode *pn, JSXMLArray *inScopeNSes, uintN flags)
|
||||
{
|
||||
JSContext *cx = parser->context;
|
||||
JSXML *xml, *kid, *attr, *attrj;
|
||||
JSLinearString *str;
|
||||
uint32 length, n, i, j;
|
||||
JSParseNode *pn2, *pn3, *head, **pnp;
|
||||
ParseNode *pn2, *pn3, *head, **pnp;
|
||||
JSObject *ns;
|
||||
JSObject *qn, *attrjqn;
|
||||
JSXMLClass xml_class;
|
||||
|
@ -1771,7 +1769,7 @@ ParseXMLSource(JSContext *cx, JSString *src)
|
|||
return false;
|
||||
}
|
||||
|
||||
JSParseNode *pn = parser.parseXMLText(scopeChain, false);
|
||||
ParseNode *pn = parser.parseXMLText(scopeChain, false);
|
||||
uintN flags;
|
||||
if (pn && GetXMLSettingFlags(cx, &flags)) {
|
||||
AutoNamespaceArray namespaces(cx);
|
||||
|
@ -4594,17 +4592,15 @@ HasFunctionProperty(JSContext *cx, JSObject *obj, jsid funid, JSBool *found)
|
|||
if (!prop) {
|
||||
xml = (JSXML *) obj->getPrivate();
|
||||
if (HasSimpleContent(xml)) {
|
||||
AutoObjectRooter tvr(cx);
|
||||
|
||||
/*
|
||||
* Search in String.prototype to set found whenever
|
||||
* GetXMLFunction returns existing function.
|
||||
*/
|
||||
if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr()))
|
||||
JSObject *proto = obj->getGlobal()->getOrCreateStringPrototype(cx);
|
||||
if (!proto)
|
||||
return false;
|
||||
|
||||
JS_ASSERT(tvr.object());
|
||||
if (!js_LookupProperty(cx, tvr.object(), funid, &pobj, &prop))
|
||||
if (!js_LookupProperty(cx, proto, funid, &pobj, &prop))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -4787,8 +4783,8 @@ xml_lookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid, JSObject **objp,
|
|||
}
|
||||
|
||||
static JSBool
|
||||
xml_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
xml_defineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *v,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
{
|
||||
if (IsFunctionObject(*v) || getter || setter ||
|
||||
(attrs & JSPROP_ENUMERATE) == 0 ||
|
||||
|
@ -4800,6 +4796,13 @@ xml_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v,
|
|||
return PutProperty(cx, obj, id, false, &tmp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
xml_defineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value *v,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
{
|
||||
return xml_defineGeneric(cx, obj, ATOM_TO_JSID(name), v, getter, setter, attrs);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
xml_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *v,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
|
@ -4807,14 +4810,14 @@ xml_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *v,
|
|||
jsid id;
|
||||
if (!IndexToId(cx, index, &id))
|
||||
return false;
|
||||
return xml_defineProperty(cx, obj, id, v, getter, setter, attrs);
|
||||
return xml_defineGeneric(cx, obj, id, v, getter, setter, attrs);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
xml_defineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *v,
|
||||
PropertyOp getter, StrictPropertyOp setter, uintN attrs)
|
||||
{
|
||||
return xml_defineProperty(cx, obj, SPECIALID_TO_JSID(sid), v, getter, setter, attrs);
|
||||
return xml_defineGeneric(cx, obj, SPECIALID_TO_JSID(sid), v, getter, setter, attrs);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -4856,9 +4859,9 @@ xml_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
|
|||
}
|
||||
|
||||
static JSBool
|
||||
xml_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
|
||||
xml_setProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict)
|
||||
{
|
||||
return xml_setGeneric(cx, obj, id, vp, strict);
|
||||
return xml_setGeneric(cx, obj, ATOM_TO_JSID(name), vp, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -4877,7 +4880,7 @@ xml_setSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool st
|
|||
}
|
||||
|
||||
static JSBool
|
||||
xml_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
xml_getGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
{
|
||||
JSBool found;
|
||||
if (!HasProperty(cx, obj, IdToJsval(id), &found))
|
||||
|
@ -4887,23 +4890,29 @@ xml_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
xml_getPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp)
|
||||
{
|
||||
return xml_getGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
xml_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
|
||||
{
|
||||
jsid id;
|
||||
if (!IndexToId(cx, index, &id))
|
||||
return false;
|
||||
return xml_getAttributes(cx, obj, id, attrsp);
|
||||
return xml_getGenericAttributes(cx, obj, id, attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
xml_getSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp)
|
||||
{
|
||||
return xml_getAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
return xml_getGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
xml_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
xml_setGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
||||
{
|
||||
JSBool found;
|
||||
if (!HasProperty(cx, obj, IdToJsval(id), &found))
|
||||
|
@ -4917,23 +4926,29 @@ xml_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
|
|||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
xml_setPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp)
|
||||
{
|
||||
return xml_setGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
xml_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
|
||||
{
|
||||
jsid id;
|
||||
if (!IndexToId(cx, index, &id))
|
||||
return false;
|
||||
return xml_setAttributes(cx, obj, id, attrsp);
|
||||
return xml_setGenericAttributes(cx, obj, id, attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
xml_setSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp)
|
||||
{
|
||||
return xml_setAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
return xml_setGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
xml_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
|
||||
xml_deleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
|
||||
{
|
||||
JSXML *xml;
|
||||
jsval idval;
|
||||
|
@ -4977,6 +4992,12 @@ xml_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool st
|
|||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
xml_deleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict)
|
||||
{
|
||||
return xml_deleteGeneric(cx, obj, ATOM_TO_JSID(name), rval, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
xml_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict)
|
||||
{
|
||||
|
@ -5007,7 +5028,7 @@ xml_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBoo
|
|||
static JSBool
|
||||
xml_deleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict)
|
||||
{
|
||||
return xml_deleteProperty(cx, obj, SPECIALID_TO_JSID(sid), rval, strict);
|
||||
return xml_deleteGeneric(cx, obj, SPECIALID_TO_JSID(sid), rval, strict);
|
||||
}
|
||||
|
||||
static JSString *
|
||||
|
@ -5312,7 +5333,7 @@ JS_FRIEND_DATA(Class) js::XMLClass = {
|
|||
xml_lookupProperty,
|
||||
xml_lookupElement,
|
||||
xml_lookupSpecial,
|
||||
xml_defineProperty,
|
||||
xml_defineGeneric,
|
||||
xml_defineProperty,
|
||||
xml_defineElement,
|
||||
xml_defineSpecial,
|
||||
|
@ -5320,19 +5341,19 @@ JS_FRIEND_DATA(Class) js::XMLClass = {
|
|||
xml_getProperty,
|
||||
xml_getElement,
|
||||
xml_getSpecial,
|
||||
xml_setProperty,
|
||||
xml_setGeneric,
|
||||
xml_setProperty,
|
||||
xml_setElement,
|
||||
xml_setSpecial,
|
||||
xml_getAttributes,
|
||||
xml_getAttributes,
|
||||
xml_getGenericAttributes,
|
||||
xml_getPropertyAttributes,
|
||||
xml_getElementAttributes,
|
||||
xml_getSpecialAttributes,
|
||||
xml_setAttributes,
|
||||
xml_setAttributes,
|
||||
xml_setGenericAttributes,
|
||||
xml_setPropertyAttributes,
|
||||
xml_setElementAttributes,
|
||||
xml_setSpecialAttributes,
|
||||
xml_deleteProperty,
|
||||
xml_deleteGeneric,
|
||||
xml_deleteProperty,
|
||||
xml_deleteElement,
|
||||
xml_deleteSpecial,
|
||||
|
@ -6007,7 +6028,7 @@ NamespacesToJSArray(JSContext *cx, JSXMLArray *array, jsval *rval)
|
|||
if (!ns)
|
||||
continue;
|
||||
tvr.set(ObjectValue(*ns));
|
||||
if (!arrayobj->setProperty(cx, INT_TO_JSID(i), tvr.addr(), false))
|
||||
if (!arrayobj->setElement(cx, i, tvr.addr(), false))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -7403,7 +7424,7 @@ js_InitXMLClass(JSContext *cx, JSObject *obj)
|
|||
JS_DefineFunction(cx, global, js_XMLList_str, XMLList, 1, JSFUN_CONSTRUCTOR);
|
||||
if (!xmllist)
|
||||
return NULL;
|
||||
if (!xmllist->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom),
|
||||
if (!xmllist->defineProperty(cx, cx->runtime->atomState.classPrototypeAtom,
|
||||
ObjectValue(*xmlProto), JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY))
|
||||
{
|
||||
|
@ -7505,8 +7526,8 @@ js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp)
|
|||
if (!ns)
|
||||
return JS_FALSE;
|
||||
v = OBJECT_TO_JSVAL(ns);
|
||||
if (!obj->defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, v,
|
||||
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT)) {
|
||||
if (!obj->defineSpecial(cx, SpecialId::defaultXMLNamespace(), v,
|
||||
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
*vp = v;
|
||||
|
@ -7524,8 +7545,8 @@ js_SetDefaultXMLNamespace(JSContext *cx, const Value &v)
|
|||
return JS_FALSE;
|
||||
|
||||
JSObject &varobj = cx->fp()->varObj();
|
||||
if (!varobj.defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, ObjectValue(*ns),
|
||||
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT)) {
|
||||
if (!varobj.defineSpecial(cx, SpecialId::defaultXMLNamespace(), ObjectValue(*ns),
|
||||
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
|
@ -7707,7 +7728,6 @@ GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
|||
* chain lookup.
|
||||
*/
|
||||
JSObject *target = obj;
|
||||
AutoObjectRooter tvr(cx);
|
||||
for (;;) {
|
||||
if (!js_GetProperty(cx, target, id, vp))
|
||||
return false;
|
||||
|
@ -7716,7 +7736,6 @@ GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
|||
target = target->getProto();
|
||||
if (target == NULL || !target->isNative())
|
||||
break;
|
||||
tvr.setObject(target);
|
||||
}
|
||||
|
||||
JSXML *xml = (JSXML *) obj->getPrivate();
|
||||
|
@ -7724,11 +7743,11 @@ GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
|||
return true;
|
||||
|
||||
/* Search in String.prototype to implement 11.2.2.1 Step 3(f). */
|
||||
if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr()))
|
||||
JSObject *proto = obj->getGlobal()->getOrCreateStringPrototype(cx);
|
||||
if (!proto)
|
||||
return false;
|
||||
|
||||
JS_ASSERT(tvr.object());
|
||||
return tvr.object()->getGeneric(cx, id, vp);
|
||||
return proto->getGeneric(cx, id, vp);
|
||||
}
|
||||
|
||||
static JSXML *
|
||||
|
|
|
@ -1498,7 +1498,7 @@ public:
|
|||
ptrdiff_t nextOffset;
|
||||
while ((nextOffset = offset + SN_DELTA(sn)) <= relpc && !SN_IS_TERMINATOR(sn)) {
|
||||
offset = nextOffset;
|
||||
JSSrcNoteType type = (JSSrcNoteType) SN_TYPE(sn);
|
||||
SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
|
||||
if (type == SRC_SETLINE || type == SRC_NEWLINE) {
|
||||
if (type == SRC_SETLINE)
|
||||
lineno = js_GetSrcNoteOffset(sn, 0);
|
||||
|
@ -4710,14 +4710,9 @@ mjit::Compiler::jsop_callprop_str(JSAtom *atom)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bake in String.prototype. This is safe because of compileAndGo.
|
||||
* We must pass an explicit scope chain only because JSD calls into
|
||||
* here via the recompiler with a dummy context, and we need to use
|
||||
* the global object for the script we are now compiling.
|
||||
*/
|
||||
JSObject *obj;
|
||||
if (!js_GetClassPrototype(cx, globalObj, JSProto_String, &obj))
|
||||
/* Bake in String.prototype. This is safe because of compileAndGo. */
|
||||
JSObject *obj = globalObj->getOrCreateStringPrototype(cx);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
/*
|
||||
|
@ -5665,13 +5660,20 @@ mjit::Compiler::jsop_this()
|
|||
if (script->hasFunction && !script->strictModeCode) {
|
||||
FrameEntry *thisFe = frame.peek(-1);
|
||||
|
||||
/*
|
||||
* We don't inline calls to scripts which use 'this' but might require
|
||||
* 'this' to be wrapped.
|
||||
*/
|
||||
JS_ASSERT(!thisFe->isNotType(JSVAL_TYPE_OBJECT));
|
||||
|
||||
if (!thisFe->isType(JSVAL_TYPE_OBJECT)) {
|
||||
/*
|
||||
* Watch out for an obscure case where we don't know we are pushing
|
||||
* an object: the script has not yet had a 'this' value assigned,
|
||||
* so no pushed 'this' type has been inferred. Don't mark the type
|
||||
* as known in this case, preserving the invariant that compiler
|
||||
* types reflect inferred types.
|
||||
*/
|
||||
if (cx->typeInferenceEnabled() && knownPushedType(0) != JSVAL_TYPE_OBJECT) {
|
||||
prepareStubCall(Uses(1));
|
||||
INLINE_STUBCALL(stubs::This, REJOIN_FALLTHROUGH);
|
||||
return;
|
||||
}
|
||||
|
||||
JSValueType type = cx->typeInferenceEnabled()
|
||||
? types::TypeScript::ThisTypes(script)->getKnownTypeTag(cx)
|
||||
: JSVAL_TYPE_UNKNOWN;
|
||||
|
@ -5683,16 +5685,6 @@ mjit::Compiler::jsop_this()
|
|||
stubcc.rejoin(Changes(1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Watch out for an obscure case where we don't know we are pushing
|
||||
* an object: the script has not yet had a 'this' value assigned,
|
||||
* so no pushed 'this' type has been inferred. Don't mark the type
|
||||
* as known in this case, preserving the invariant that compiler
|
||||
* types reflect inferred types.
|
||||
*/
|
||||
if (cx->typeInferenceEnabled() && knownPushedType(0) != JSVAL_TYPE_OBJECT)
|
||||
return;
|
||||
|
||||
// Now we know that |this| is an object.
|
||||
frame.pop();
|
||||
frame.learnThisIsObject(type != JSVAL_TYPE_OBJECT);
|
||||
|
|
|
@ -2075,20 +2075,20 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pic)
|
|||
if (lval.isObject()) {
|
||||
objv = lval;
|
||||
} else {
|
||||
JSProtoKey protoKey;
|
||||
GlobalObject *global = f.fp()->scopeChain().getGlobal();
|
||||
JSObject *pobj;
|
||||
if (lval.isString()) {
|
||||
protoKey = JSProto_String;
|
||||
pobj = global->getOrCreateStringPrototype(cx);
|
||||
} else if (lval.isNumber()) {
|
||||
protoKey = JSProto_Number;
|
||||
pobj = global->getOrCreateNumberPrototype(cx);
|
||||
} else if (lval.isBoolean()) {
|
||||
protoKey = JSProto_Boolean;
|
||||
pobj = global->getOrCreateBooleanPrototype(cx);
|
||||
} else {
|
||||
JS_ASSERT(lval.isNull() || lval.isUndefined());
|
||||
js_ReportIsNullOrUndefined(cx, -1, lval, NULL);
|
||||
THROW();
|
||||
}
|
||||
JSObject *pobj;
|
||||
if (!js_GetClassPrototype(cx, NULL, protoKey, &pobj))
|
||||
if (!pobj)
|
||||
THROW();
|
||||
objv.setObject(*pobj);
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче