mirror of https://github.com/axmolengine/axmol.git
Merge pull request #7 from dumganhar/iss1686-synchronize
fix for conflict of project.pbxproj and updated with upstream.
This commit is contained in:
commit
47830a5ef4
|
@ -0,0 +1,342 @@
|
|||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
41E01E4E16D5D5E600ED686C /* Export.h in Headers */ = {isa = PBXBuildFile; fileRef = 41E01E4116D5D5E600ED686C /* Export.h */; };
|
||||
41E01E4F16D5D5E600ED686C /* SimpleAudioEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = 41E01E4216D5D5E600ED686C /* SimpleAudioEngine.h */; };
|
||||
41E01E5016D5D5E600ED686C /* CDAudioManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 41E01E4416D5D5E600ED686C /* CDAudioManager.h */; };
|
||||
41E01E5116D5D5E600ED686C /* CDAudioManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 41E01E4516D5D5E600ED686C /* CDAudioManager.m */; };
|
||||
41E01E5216D5D5E600ED686C /* CDConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 41E01E4616D5D5E600ED686C /* CDConfig.h */; };
|
||||
41E01E5316D5D5E600ED686C /* CDOpenALSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 41E01E4716D5D5E600ED686C /* CDOpenALSupport.h */; };
|
||||
41E01E5416D5D5E600ED686C /* CDOpenALSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 41E01E4816D5D5E600ED686C /* CDOpenALSupport.m */; };
|
||||
41E01E5516D5D5E600ED686C /* CocosDenshion.h in Headers */ = {isa = PBXBuildFile; fileRef = 41E01E4916D5D5E600ED686C /* CocosDenshion.h */; };
|
||||
41E01E5616D5D5E600ED686C /* CocosDenshion.m in Sources */ = {isa = PBXBuildFile; fileRef = 41E01E4A16D5D5E600ED686C /* CocosDenshion.m */; };
|
||||
41E01E5716D5D5E600ED686C /* SimpleAudioEngine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 41E01E4B16D5D5E600ED686C /* SimpleAudioEngine.mm */; };
|
||||
41E01E5816D5D5E600ED686C /* SimpleAudioEngine_objc.h in Headers */ = {isa = PBXBuildFile; fileRef = 41E01E4C16D5D5E600ED686C /* SimpleAudioEngine_objc.h */; };
|
||||
41E01E5916D5D5E600ED686C /* SimpleAudioEngine_objc.m in Sources */ = {isa = PBXBuildFile; fileRef = 41E01E4D16D5D5E600ED686C /* SimpleAudioEngine_objc.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
41E01E4116D5D5E600ED686C /* Export.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Export.h; sourceTree = "<group>"; };
|
||||
41E01E4216D5D5E600ED686C /* SimpleAudioEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleAudioEngine.h; sourceTree = "<group>"; };
|
||||
41E01E4416D5D5E600ED686C /* CDAudioManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDAudioManager.h; sourceTree = "<group>"; };
|
||||
41E01E4516D5D5E600ED686C /* CDAudioManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDAudioManager.m; sourceTree = "<group>"; };
|
||||
41E01E4616D5D5E600ED686C /* CDConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDConfig.h; sourceTree = "<group>"; };
|
||||
41E01E4716D5D5E600ED686C /* CDOpenALSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDOpenALSupport.h; sourceTree = "<group>"; };
|
||||
41E01E4816D5D5E600ED686C /* CDOpenALSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDOpenALSupport.m; sourceTree = "<group>"; };
|
||||
41E01E4916D5D5E600ED686C /* CocosDenshion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CocosDenshion.h; sourceTree = "<group>"; };
|
||||
41E01E4A16D5D5E600ED686C /* CocosDenshion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CocosDenshion.m; sourceTree = "<group>"; };
|
||||
41E01E4B16D5D5E600ED686C /* SimpleAudioEngine.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SimpleAudioEngine.mm; sourceTree = "<group>"; };
|
||||
41E01E4C16D5D5E600ED686C /* SimpleAudioEngine_objc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleAudioEngine_objc.h; sourceTree = "<group>"; };
|
||||
41E01E4D16D5D5E600ED686C /* SimpleAudioEngine_objc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimpleAudioEngine_objc.m; sourceTree = "<group>"; };
|
||||
D87CC2E5154FC6C500AAFE11 /* libCocosDenshion.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCocosDenshion.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
D87CC2E2154FC6C500AAFE11 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
4193AF8416C39EB1007E21D7 /* CocosDenshion */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
41E01E4016D5D5E600ED686C /* include */,
|
||||
41E01E4316D5D5E600ED686C /* ios */,
|
||||
);
|
||||
name = CocosDenshion;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
41E01E4016D5D5E600ED686C /* include */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
41E01E4116D5D5E600ED686C /* Export.h */,
|
||||
41E01E4216D5D5E600ED686C /* SimpleAudioEngine.h */,
|
||||
);
|
||||
name = include;
|
||||
path = ../include;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
41E01E4316D5D5E600ED686C /* ios */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
41E01E4416D5D5E600ED686C /* CDAudioManager.h */,
|
||||
41E01E4516D5D5E600ED686C /* CDAudioManager.m */,
|
||||
41E01E4616D5D5E600ED686C /* CDConfig.h */,
|
||||
41E01E4716D5D5E600ED686C /* CDOpenALSupport.h */,
|
||||
41E01E4816D5D5E600ED686C /* CDOpenALSupport.m */,
|
||||
41E01E4916D5D5E600ED686C /* CocosDenshion.h */,
|
||||
41E01E4A16D5D5E600ED686C /* CocosDenshion.m */,
|
||||
41E01E4B16D5D5E600ED686C /* SimpleAudioEngine.mm */,
|
||||
41E01E4C16D5D5E600ED686C /* SimpleAudioEngine_objc.h */,
|
||||
41E01E4D16D5D5E600ED686C /* SimpleAudioEngine_objc.m */,
|
||||
);
|
||||
name = ios;
|
||||
path = ../ios;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D87CC2BB154FC66100AAFE11 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4193AF8416C39EB1007E21D7 /* CocosDenshion */,
|
||||
D87CC2C9154FC66100AAFE11 /* Frameworks */,
|
||||
D87CC2C7154FC66100AAFE11 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D87CC2C7154FC66100AAFE11 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D87CC2E5154FC6C500AAFE11 /* libCocosDenshion.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D87CC2C9154FC66100AAFE11 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
D87CC2E3154FC6C500AAFE11 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
41E01E4E16D5D5E600ED686C /* Export.h in Headers */,
|
||||
41E01E4F16D5D5E600ED686C /* SimpleAudioEngine.h in Headers */,
|
||||
41E01E5016D5D5E600ED686C /* CDAudioManager.h in Headers */,
|
||||
41E01E5216D5D5E600ED686C /* CDConfig.h in Headers */,
|
||||
41E01E5316D5D5E600ED686C /* CDOpenALSupport.h in Headers */,
|
||||
41E01E5516D5D5E600ED686C /* CocosDenshion.h in Headers */,
|
||||
41E01E5816D5D5E600ED686C /* SimpleAudioEngine_objc.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
D87CC2E4154FC6C500AAFE11 /* CocosDenshion */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = D87CC2ED154FC6C500AAFE11 /* Build configuration list for PBXNativeTarget "CocosDenshion" */;
|
||||
buildPhases = (
|
||||
D87CC2E1154FC6C500AAFE11 /* Sources */,
|
||||
D87CC2E2154FC6C500AAFE11 /* Frameworks */,
|
||||
D87CC2E3154FC6C500AAFE11 /* Headers */,
|
||||
185ADB8915A3935900CD7CE0 /* ShellScript */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = CocosDenshion;
|
||||
productName = SPII;
|
||||
productReference = D87CC2E5154FC6C500AAFE11 /* libCocosDenshion.a */;
|
||||
productType = "com.apple.product-type.library.static";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
D87CC2BD154FC66100AAFE11 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
CLASSPREFIX = SP;
|
||||
LastUpgradeCheck = 0430;
|
||||
ORGANIZATIONNAME = Cocoachina;
|
||||
};
|
||||
buildConfigurationList = D87CC2C0154FC66100AAFE11 /* Build configuration list for PBXProject "CocosDenshion" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
"zh-Hans",
|
||||
"zh-Hant",
|
||||
);
|
||||
mainGroup = D87CC2BB154FC66100AAFE11;
|
||||
productRefGroup = D87CC2C7154FC66100AAFE11 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
D87CC2E4154FC6C500AAFE11 /* CocosDenshion */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
185ADB8915A3935900CD7CE0 /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
D87CC2E1154FC6C500AAFE11 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
41E01E5116D5D5E600ED686C /* CDAudioManager.m in Sources */,
|
||||
41E01E5416D5D5E600ED686C /* CDOpenALSupport.m in Sources */,
|
||||
41E01E5616D5D5E600ED686C /* CocosDenshion.m in Sources */,
|
||||
41E01E5716D5D5E600ED686C /* SimpleAudioEngine.mm in Sources */,
|
||||
41E01E5916D5D5E600ED686C /* SimpleAudioEngine_objc.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
D87CC2DC154FC66100AAFE11 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "compiler-default";
|
||||
CLANG_CXX_LIBRARY = "compiler-default";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = c89;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "";
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_VERSION = "";
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALID_ARCHS = armv7;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
D87CC2DD154FC66100AAFE11 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "compiler-default";
|
||||
CLANG_CXX_LIBRARY = "compiler-default";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = c89;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "";
|
||||
GCC_VERSION = "";
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
|
||||
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VALID_ARCHS = armv7;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
D87CC2EE154FC6C500AAFE11 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = YES;
|
||||
DSTROOT = /tmp/SPII.dst;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
GCC_C_LANGUAGE_STANDARD = "compiler-default";
|
||||
GCC_INCREASE_PRECOMPILED_HEADER_SHARING = NO;
|
||||
GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = NO;
|
||||
GCC_PREFIX_HEADER = "";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"COCOS2D_DEBUG=1",
|
||||
CC_TARGET_OS_IPHONE,
|
||||
);
|
||||
GENERATE_PKGINFO_FILE = NO;
|
||||
HEADER_SEARCH_PATHS = "\"$(SDKROOT)/usr/include/libxml2\"";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
|
||||
LIBRARY_SEARCH_PATHS = "";
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include;
|
||||
PRODUCT_NAME = CocosDenshion;
|
||||
SKIP_INSTALL = YES;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
USER_HEADER_SEARCH_PATHS = "../../cocos2dx/platform/ios ../../cocos2dx/include ../../cocos2dx/kazmath/include ../../cocos2dx/";
|
||||
VALID_ARCHS = armv7;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
D87CC2EF154FC6C500AAFE11 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = YES;
|
||||
DSTROOT = /tmp/SPII.dst;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
GCC_C_LANGUAGE_STANDARD = "compiler-default";
|
||||
GCC_INCREASE_PRECOMPILED_HEADER_SHARING = NO;
|
||||
GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = NO;
|
||||
GCC_PREFIX_HEADER = "";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = CC_TARGET_OS_IPHONE;
|
||||
GENERATE_PKGINFO_FILE = NO;
|
||||
HEADER_SEARCH_PATHS = "\"$(SDKROOT)/usr/include/libxml2\"";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
|
||||
LIBRARY_SEARCH_PATHS = "";
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include;
|
||||
PRODUCT_NAME = CocosDenshion;
|
||||
SKIP_INSTALL = YES;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
USER_HEADER_SEARCH_PATHS = "../../cocos2dx/platform/ios ../../cocos2dx/include ../../cocos2dx/kazmath/include ../../cocos2dx/";
|
||||
VALID_ARCHS = armv7;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
D87CC2C0154FC66100AAFE11 /* Build configuration list for PBXProject "CocosDenshion" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
D87CC2DC154FC66100AAFE11 /* Debug */,
|
||||
D87CC2DD154FC66100AAFE11 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
D87CC2ED154FC6C500AAFE11 /* Build configuration list for PBXNativeTarget "CocosDenshion" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
D87CC2EE154FC6C500AAFE11 /* Debug */,
|
||||
D87CC2EF154FC6C500AAFE11 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = D87CC2BD154FC66100AAFE11 /* Project object */;
|
||||
}
|
|
@ -106,6 +106,7 @@ sprite_nodes/CCSprite.cpp \
|
|||
sprite_nodes/CCSpriteBatchNode.cpp \
|
||||
sprite_nodes/CCSpriteFrame.cpp \
|
||||
sprite_nodes/CCSpriteFrameCache.cpp \
|
||||
support/ccUTF8.cpp \
|
||||
support/CCNotificationCenter.cpp \
|
||||
support/CCProfiling.cpp \
|
||||
support/CCPointExtension.cpp \
|
||||
|
|
|
@ -210,6 +210,7 @@ THE SOFTWARE.
|
|||
#include "sprite_nodes/CCSpriteFrameCache.h"
|
||||
|
||||
// support
|
||||
#include "support/ccUTF8.h"
|
||||
#include "support/CCNotificationCenter.h"
|
||||
#include "support/CCPointExtension.h"
|
||||
#include "support/CCProfiling.h"
|
||||
|
|
|
@ -41,313 +41,12 @@ http://www.angelcode.com/products/bmfont/ (Free, Windows only)
|
|||
#include "platform/CCFileUtils.h"
|
||||
#include "CCDirector.h"
|
||||
#include "textures/CCTextureCache.h"
|
||||
#include "support/ccUTF8.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
static int cc_wcslen(const unsigned short* str)
|
||||
{
|
||||
int i=0;
|
||||
while(*str++) i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Code from GLIB gutf8.c starts here. */
|
||||
|
||||
#define UTF8_COMPUTE(Char, Mask, Len) \
|
||||
if (Char < 128) \
|
||||
{ \
|
||||
Len = 1; \
|
||||
Mask = 0x7f; \
|
||||
} \
|
||||
else if ((Char & 0xe0) == 0xc0) \
|
||||
{ \
|
||||
Len = 2; \
|
||||
Mask = 0x1f; \
|
||||
} \
|
||||
else if ((Char & 0xf0) == 0xe0) \
|
||||
{ \
|
||||
Len = 3; \
|
||||
Mask = 0x0f; \
|
||||
} \
|
||||
else if ((Char & 0xf8) == 0xf0) \
|
||||
{ \
|
||||
Len = 4; \
|
||||
Mask = 0x07; \
|
||||
} \
|
||||
else if ((Char & 0xfc) == 0xf8) \
|
||||
{ \
|
||||
Len = 5; \
|
||||
Mask = 0x03; \
|
||||
} \
|
||||
else if ((Char & 0xfe) == 0xfc) \
|
||||
{ \
|
||||
Len = 6; \
|
||||
Mask = 0x01; \
|
||||
} \
|
||||
else \
|
||||
Len = -1;
|
||||
|
||||
#define UTF8_LENGTH(Char) \
|
||||
((Char) < 0x80 ? 1 : \
|
||||
((Char) < 0x800 ? 2 : \
|
||||
((Char) < 0x10000 ? 3 : \
|
||||
((Char) < 0x200000 ? 4 : \
|
||||
((Char) < 0x4000000 ? 5 : 6)))))
|
||||
|
||||
|
||||
#define UTF8_GET(Result, Chars, Count, Mask, Len) \
|
||||
(Result) = (Chars)[0] & (Mask); \
|
||||
for ((Count) = 1; (Count) < (Len); ++(Count)) \
|
||||
{ \
|
||||
if (((Chars)[(Count)] & 0xc0) != 0x80) \
|
||||
{ \
|
||||
(Result) = -1; \
|
||||
break; \
|
||||
} \
|
||||
(Result) <<= 6; \
|
||||
(Result) |= ((Chars)[(Count)] & 0x3f); \
|
||||
}
|
||||
|
||||
#define UNICODE_VALID(Char) \
|
||||
((Char) < 0x110000 && \
|
||||
(((Char) & 0xFFFFF800) != 0xD800) && \
|
||||
((Char) < 0xFDD0 || (Char) > 0xFDEF) && \
|
||||
((Char) & 0xFFFE) != 0xFFFE)
|
||||
|
||||
|
||||
static const char utf8_skip_data[256] = {
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5,
|
||||
5, 5, 5, 6, 6, 1, 1
|
||||
};
|
||||
|
||||
static const char *const g_utf8_skip = utf8_skip_data;
|
||||
|
||||
#define cc_utf8_next_char(p) (char *)((p) + g_utf8_skip[*(unsigned char *)(p)])
|
||||
|
||||
/*
|
||||
* @str: the string to search through.
|
||||
* @c: the character to find.
|
||||
*
|
||||
* Returns the index of the first occurrence of the character, if found. Otherwise -1 is returned.
|
||||
*
|
||||
* Return value: the index of the first occurrence of the character if found or -1 otherwise.
|
||||
* */
|
||||
static unsigned int cc_utf8_find_char(std::vector<unsigned short> str, unsigned short c)
|
||||
{
|
||||
unsigned int len = str.size();
|
||||
|
||||
for (unsigned int i = 0; i < len; ++i)
|
||||
if (str[i] == c) return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* @str: the string to search through.
|
||||
* @c: the character to not look for.
|
||||
*
|
||||
* Return value: the index of the last character that is not c.
|
||||
* */
|
||||
static unsigned int cc_utf8_find_last_not_char(std::vector<unsigned short> str, unsigned short c)
|
||||
{
|
||||
int len = str.size();
|
||||
|
||||
int i = len - 1;
|
||||
for (; i >= 0; --i)
|
||||
if (str[i] != c) return i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* @str: the string to trim
|
||||
* @index: the index to start trimming from.
|
||||
*
|
||||
* Trims str st str=[0, index) after the operation.
|
||||
*
|
||||
* Return value: the trimmed string.
|
||||
* */
|
||||
static void cc_utf8_trim_from(std::vector<unsigned short>* str, int index)
|
||||
{
|
||||
int size = str->size();
|
||||
if (index >= size || index < 0)
|
||||
return;
|
||||
|
||||
str->erase(str->begin() + index, str->begin() + size);
|
||||
}
|
||||
|
||||
/*
|
||||
* @ch is the unicode character whitespace?
|
||||
*
|
||||
* Reference: http://en.wikipedia.org/wiki/Whitespace_character#Unicode
|
||||
*
|
||||
* Return value: weather the character is a whitespace character.
|
||||
* */
|
||||
static bool isspace_unicode(unsigned short ch)
|
||||
{
|
||||
return (ch >= 0x0009 && ch <= 0x000D) || ch == 0x0020 || ch == 0x0085 || ch == 0x00A0 || ch == 0x1680
|
||||
|| (ch >= 0x2000 && ch <= 0x200A) || ch == 0x2028 || ch == 0x2029 || ch == 0x202F
|
||||
|| ch == 0x205F || ch == 0x3000;
|
||||
}
|
||||
|
||||
static void cc_utf8_trim_ws(std::vector<unsigned short>* str)
|
||||
{
|
||||
int len = str->size();
|
||||
|
||||
if ( len <= 0 )
|
||||
return;
|
||||
|
||||
int last_index = len - 1;
|
||||
|
||||
// Only start trimming if the last character is whitespace..
|
||||
if (isspace_unicode((*str)[last_index]))
|
||||
{
|
||||
for (int i = last_index - 1; i >= 0; --i)
|
||||
{
|
||||
if (isspace_unicode((*str)[i]))
|
||||
last_index = i;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
cc_utf8_trim_from(str, last_index);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* g_utf8_strlen:
|
||||
* @p: pointer to the start of a UTF-8 encoded string.
|
||||
* @max: the maximum number of bytes to examine. If @max
|
||||
* is less than 0, then the string is assumed to be
|
||||
* null-terminated. If @max is 0, @p will not be examined and
|
||||
* may be %NULL.
|
||||
*
|
||||
* Returns the length of the string in characters.
|
||||
*
|
||||
* Return value: the length of the string in characters
|
||||
**/
|
||||
CC_DLL long
|
||||
cc_utf8_strlen (const char * p, int max)
|
||||
{
|
||||
long len = 0;
|
||||
const char *start = p;
|
||||
|
||||
if (!(p != NULL || max == 0))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (max < 0)
|
||||
{
|
||||
while (*p)
|
||||
{
|
||||
p = cc_utf8_next_char (p);
|
||||
++len;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (max == 0 || !*p)
|
||||
return 0;
|
||||
|
||||
p = cc_utf8_next_char (p);
|
||||
|
||||
while (p - start < max && *p)
|
||||
{
|
||||
++len;
|
||||
p = cc_utf8_next_char (p);
|
||||
}
|
||||
|
||||
/* only do the last len increment if we got a complete
|
||||
* char (don't count partial chars)
|
||||
*/
|
||||
if (p - start == max)
|
||||
++len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* g_utf8_get_char:
|
||||
* @p: a pointer to Unicode character encoded as UTF-8
|
||||
*
|
||||
* Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
|
||||
* If @p does not point to a valid UTF-8 encoded character, results are
|
||||
* undefined. If you are not sure that the bytes are complete
|
||||
* valid Unicode characters, you should use g_utf8_get_char_validated()
|
||||
* instead.
|
||||
*
|
||||
* Return value: the resulting character
|
||||
**/
|
||||
static unsigned int
|
||||
cc_utf8_get_char (const char * p)
|
||||
{
|
||||
int i, mask = 0, len;
|
||||
unsigned int result;
|
||||
unsigned char c = (unsigned char) *p;
|
||||
|
||||
UTF8_COMPUTE (c, mask, len);
|
||||
if (len == -1)
|
||||
return (unsigned int) - 1;
|
||||
UTF8_GET (result, p, i, mask, len);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* cc_utf16_from_utf8:
|
||||
* @str_old: pointer to the start of a C string.
|
||||
*
|
||||
* Creates a utf8 string from a cstring.
|
||||
*
|
||||
* Return value: the newly created utf8 string.
|
||||
* */
|
||||
static unsigned short* cc_utf16_from_utf8(const char* str_old)
|
||||
{
|
||||
int len = cc_utf8_strlen(str_old, -1);
|
||||
|
||||
unsigned short* str_new = new unsigned short[len + 1];
|
||||
str_new[len] = 0;
|
||||
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
str_new[i] = cc_utf8_get_char(str_old);
|
||||
str_old = cc_utf8_next_char(str_old);
|
||||
}
|
||||
|
||||
return str_new;
|
||||
}
|
||||
|
||||
static std::vector<unsigned short> cc_utf16_vec_from_utf16_str(const unsigned short* str)
|
||||
{
|
||||
int len = cc_wcslen(str);
|
||||
std::vector<unsigned short> str_new;
|
||||
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
str_new.push_back(str[i]);
|
||||
}
|
||||
return str_new;
|
||||
}
|
||||
|
||||
//
|
||||
//FNTConfig Cache - free functions
|
||||
//
|
||||
|
@ -1017,7 +716,7 @@ void CCLabelBMFont::setString(const char *newString)
|
|||
void CCLabelBMFont::setString(const char *newString, bool fromUpdate)
|
||||
{
|
||||
CC_SAFE_DELETE_ARRAY(m_sString);
|
||||
m_sString = cc_utf16_from_utf8(newString);
|
||||
m_sString = cc_utf8_to_utf16(newString);
|
||||
|
||||
// MARMALADE CHANGE
|
||||
// THE ASSIGMENT OF STRINGS BELOW PERFORMS AN OVERLAPPING MEMCPY, WHEN fromUpdate IS TRUE
|
||||
|
|
|
@ -1 +1 @@
|
|||
07189afafe45b5ce86fe17e77400ffa055cd1831
|
||||
8e581cccdac41ebd5f1a9c26b08f02b948560fba
|
|
@ -104,6 +104,7 @@ OBJECTS = ../actions/CCAction.o \
|
|||
../sprite_nodes/CCSpriteBatchNode.o \
|
||||
../sprite_nodes/CCSpriteFrame.o \
|
||||
../sprite_nodes/CCSpriteFrameCache.o \
|
||||
../support/ccUTF8.o \
|
||||
../support/CCPointExtension.o \
|
||||
../support/CCProfiling.o \
|
||||
../support/CCUserDefault.o \
|
||||
|
|
|
@ -1 +1 @@
|
|||
4f8a2ffda386a2d2e263781a283c32d39b6dc6a7
|
||||
cc07100d26f9435ecf7b2588f14adb3d22980883
|
|
@ -156,35 +156,29 @@ files
|
|||
[sprite_nodes]
|
||||
"*.h"
|
||||
"*.cpp"
|
||||
|
||||
("../support")
|
||||
[support]
|
||||
"base64.cpp"
|
||||
"base64.h"
|
||||
# "CCArray.cpp"
|
||||
"CCPointExtension.cpp"
|
||||
"CCProfiling.cpp"
|
||||
"CCProfiling.h"
|
||||
"CCUserDefault.cpp"
|
||||
"ccUtils.cpp"
|
||||
"ccUtils.h"
|
||||
"TransformUtils.cpp"
|
||||
"TransformUtils.h"
|
||||
|
||||
("../support")
|
||||
[support]
|
||||
"*.h"
|
||||
"*.cpp"
|
||||
|
||||
("../support/data_support")
|
||||
[support/data_support]
|
||||
"*.cpp" # MH: Many ccCArray linker errors without ccCArray.cpp
|
||||
"*.h"
|
||||
("../support/image_support")
|
||||
|
||||
("../support/image_support")
|
||||
[support/image_support]
|
||||
"*.h"
|
||||
"*.cpp"
|
||||
("../support/tinyxml2")
|
||||
"*.h"
|
||||
"*.cpp"
|
||||
|
||||
("../support/tinyxml2")
|
||||
[support/tinyxml2]
|
||||
"*.h"
|
||||
"*.cpp"
|
||||
|
||||
("../support/zip_support")
|
||||
[support/zip_support]
|
||||
"*.h"
|
||||
"*.cpp"
|
||||
|
||||
|
|
|
@ -215,6 +215,7 @@ xcopy /Y /Q "$(ProjectDir)..\platform\third_party\win32\libraries\*.*" "$(OutDir
|
|||
<ClCompile Include="..\support\CCPointExtension.cpp" />
|
||||
<ClCompile Include="..\support\CCProfiling.cpp" />
|
||||
<ClCompile Include="..\support\CCUserDefault.cpp" />
|
||||
<ClCompile Include="..\support\ccUTF8.cpp" />
|
||||
<ClCompile Include="..\support\ccUtils.cpp" />
|
||||
<ClCompile Include="..\support\CCVertex.cpp" />
|
||||
<ClCompile Include="..\support\tinyxml2\tinyxml2.cpp" />
|
||||
|
@ -366,6 +367,7 @@ xcopy /Y /Q "$(ProjectDir)..\platform\third_party\win32\libraries\*.*" "$(OutDir
|
|||
<ClInclude Include="..\support\CCPointExtension.h" />
|
||||
<ClInclude Include="..\support\CCProfiling.h" />
|
||||
<ClInclude Include="..\support\CCUserDefault.h" />
|
||||
<ClInclude Include="..\support\ccUTF8.h" />
|
||||
<ClInclude Include="..\support\ccUtils.h" />
|
||||
<ClInclude Include="..\support\CCVertex.h" />
|
||||
<ClInclude Include="..\support\tinyxml2\tinyxml2.h" />
|
||||
|
|
|
@ -450,6 +450,9 @@
|
|||
<ClCompile Include="..\platform\win32\CCDevice.cpp">
|
||||
<Filter>platform\win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\support\ccUTF8.cpp">
|
||||
<Filter>support</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\base_nodes\CCAtlasNode.h">
|
||||
|
@ -901,5 +904,8 @@
|
|||
<Filter>platform\win32</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\support\tinyxml2\tinyxml2.h" />
|
||||
<ClInclude Include="..\support\ccUTF8.h">
|
||||
<Filter>support</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,529 @@
|
|||
/*
|
||||
* This file uses some implementations of gutf8.c in glib.
|
||||
*
|
||||
* gutf8.c - Operations on UTF-8 strings.
|
||||
*
|
||||
* Copyright (C) 1999 Tom Tromey
|
||||
* Copyright (C) 2000 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "ccUTF8.h"
|
||||
#include "platform/CCCommon.h"
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
int cc_wcslen(const unsigned short* str)
|
||||
{
|
||||
int i=0;
|
||||
while(*str++) i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Code from GLIB gutf8.c starts here. */
|
||||
|
||||
#define UTF8_COMPUTE(Char, Mask, Len) \
|
||||
if (Char < 128) \
|
||||
{ \
|
||||
Len = 1; \
|
||||
Mask = 0x7f; \
|
||||
} \
|
||||
else if ((Char & 0xe0) == 0xc0) \
|
||||
{ \
|
||||
Len = 2; \
|
||||
Mask = 0x1f; \
|
||||
} \
|
||||
else if ((Char & 0xf0) == 0xe0) \
|
||||
{ \
|
||||
Len = 3; \
|
||||
Mask = 0x0f; \
|
||||
} \
|
||||
else if ((Char & 0xf8) == 0xf0) \
|
||||
{ \
|
||||
Len = 4; \
|
||||
Mask = 0x07; \
|
||||
} \
|
||||
else if ((Char & 0xfc) == 0xf8) \
|
||||
{ \
|
||||
Len = 5; \
|
||||
Mask = 0x03; \
|
||||
} \
|
||||
else if ((Char & 0xfe) == 0xfc) \
|
||||
{ \
|
||||
Len = 6; \
|
||||
Mask = 0x01; \
|
||||
} \
|
||||
else \
|
||||
Len = -1;
|
||||
|
||||
#define UTF8_LENGTH(Char) \
|
||||
((Char) < 0x80 ? 1 : \
|
||||
((Char) < 0x800 ? 2 : \
|
||||
((Char) < 0x10000 ? 3 : \
|
||||
((Char) < 0x200000 ? 4 : \
|
||||
((Char) < 0x4000000 ? 5 : 6)))))
|
||||
|
||||
|
||||
#define UTF8_GET(Result, Chars, Count, Mask, Len) \
|
||||
(Result) = (Chars)[0] & (Mask); \
|
||||
for ((Count) = 1; (Count) < (Len); ++(Count)) \
|
||||
{ \
|
||||
if (((Chars)[(Count)] & 0xc0) != 0x80) \
|
||||
{ \
|
||||
(Result) = -1; \
|
||||
break; \
|
||||
} \
|
||||
(Result) <<= 6; \
|
||||
(Result) |= ((Chars)[(Count)] & 0x3f); \
|
||||
}
|
||||
|
||||
#define UNICODE_VALID(Char) \
|
||||
((Char) < 0x110000 && \
|
||||
(((Char) & 0xFFFFF800) != 0xD800) && \
|
||||
((Char) < 0xFDD0 || (Char) > 0xFDEF) && \
|
||||
((Char) & 0xFFFE) != 0xFFFE)
|
||||
|
||||
|
||||
static const char utf8_skip_data[256] = {
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5,
|
||||
5, 5, 5, 6, 6, 1, 1
|
||||
};
|
||||
|
||||
static const char *const g_utf8_skip = utf8_skip_data;
|
||||
|
||||
#define cc_utf8_next_char(p) (char *)((p) + g_utf8_skip[*(unsigned char *)(p)])
|
||||
|
||||
/*
|
||||
* @str: the string to search through.
|
||||
* @c: the character to find.
|
||||
*
|
||||
* Returns the index of the first occurrence of the character, if found. Otherwise -1 is returned.
|
||||
*
|
||||
* Return value: the index of the first occurrence of the character if found or -1 otherwise.
|
||||
* */
|
||||
static unsigned int cc_utf8_find_char(std::vector<unsigned short> str, unsigned short c)
|
||||
{
|
||||
unsigned int len = str.size();
|
||||
|
||||
for (unsigned int i = 0; i < len; ++i)
|
||||
if (str[i] == c) return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* @str: the string to search through.
|
||||
* @c: the character to not look for.
|
||||
*
|
||||
* Return value: the index of the last character that is not c.
|
||||
* */
|
||||
unsigned int cc_utf8_find_last_not_char(std::vector<unsigned short> str, unsigned short c)
|
||||
{
|
||||
int len = str.size();
|
||||
|
||||
int i = len - 1;
|
||||
for (; i >= 0; --i)
|
||||
if (str[i] != c) return i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* @str: the string to trim
|
||||
* @index: the index to start trimming from.
|
||||
*
|
||||
* Trims str st str=[0, index) after the operation.
|
||||
*
|
||||
* Return value: the trimmed string.
|
||||
* */
|
||||
static void cc_utf8_trim_from(std::vector<unsigned short>* str, int index)
|
||||
{
|
||||
int size = str->size();
|
||||
if (index >= size || index < 0)
|
||||
return;
|
||||
|
||||
str->erase(str->begin() + index, str->begin() + size);
|
||||
}
|
||||
|
||||
/*
|
||||
* @ch is the unicode character whitespace?
|
||||
*
|
||||
* Reference: http://en.wikipedia.org/wiki/Whitespace_character#Unicode
|
||||
*
|
||||
* Return value: weather the character is a whitespace character.
|
||||
* */
|
||||
bool isspace_unicode(unsigned short ch)
|
||||
{
|
||||
return (ch >= 0x0009 && ch <= 0x000D) || ch == 0x0020 || ch == 0x0085 || ch == 0x00A0 || ch == 0x1680
|
||||
|| (ch >= 0x2000 && ch <= 0x200A) || ch == 0x2028 || ch == 0x2029 || ch == 0x202F
|
||||
|| ch == 0x205F || ch == 0x3000;
|
||||
}
|
||||
|
||||
void cc_utf8_trim_ws(std::vector<unsigned short>* str)
|
||||
{
|
||||
int len = str->size();
|
||||
|
||||
if ( len <= 0 )
|
||||
return;
|
||||
|
||||
int last_index = len - 1;
|
||||
|
||||
// Only start trimming if the last character is whitespace..
|
||||
if (isspace_unicode((*str)[last_index]))
|
||||
{
|
||||
for (int i = last_index - 1; i >= 0; --i)
|
||||
{
|
||||
if (isspace_unicode((*str)[i]))
|
||||
last_index = i;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
cc_utf8_trim_from(str, last_index);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* cc_utf8_strlen:
|
||||
* @p: pointer to the start of a UTF-8 encoded string.
|
||||
* @max: the maximum number of bytes to examine. If @max
|
||||
* is less than 0, then the string is assumed to be
|
||||
* null-terminated. If @max is 0, @p will not be examined and
|
||||
* may be %NULL.
|
||||
*
|
||||
* Returns the length of the string in characters.
|
||||
*
|
||||
* Return value: the length of the string in characters
|
||||
**/
|
||||
long
|
||||
cc_utf8_strlen (const char * p, int max)
|
||||
{
|
||||
long len = 0;
|
||||
const char *start = p;
|
||||
|
||||
if (!(p != NULL || max == 0))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (max < 0)
|
||||
{
|
||||
while (*p)
|
||||
{
|
||||
p = cc_utf8_next_char (p);
|
||||
++len;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (max == 0 || !*p)
|
||||
return 0;
|
||||
|
||||
p = cc_utf8_next_char (p);
|
||||
|
||||
while (p - start < max && *p)
|
||||
{
|
||||
++len;
|
||||
p = cc_utf8_next_char (p);
|
||||
}
|
||||
|
||||
/* only do the last len increment if we got a complete
|
||||
* char (don't count partial chars)
|
||||
*/
|
||||
if (p - start == max)
|
||||
++len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* g_utf8_get_char:
|
||||
* @p: a pointer to Unicode character encoded as UTF-8
|
||||
*
|
||||
* Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
|
||||
* If @p does not point to a valid UTF-8 encoded character, results are
|
||||
* undefined. If you are not sure that the bytes are complete
|
||||
* valid Unicode characters, you should use g_utf8_get_char_validated()
|
||||
* instead.
|
||||
*
|
||||
* Return value: the resulting character
|
||||
**/
|
||||
static unsigned int
|
||||
cc_utf8_get_char (const char * p)
|
||||
{
|
||||
int i, mask = 0, len;
|
||||
unsigned int result;
|
||||
unsigned char c = (unsigned char) *p;
|
||||
|
||||
UTF8_COMPUTE (c, mask, len);
|
||||
if (len == -1)
|
||||
return (unsigned int) - 1;
|
||||
UTF8_GET (result, p, i, mask, len);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
unsigned short* cc_utf8_to_utf16(const char* str_old)
|
||||
{
|
||||
int len = cc_utf8_strlen(str_old, -1);
|
||||
|
||||
unsigned short* str_new = new unsigned short[len + 1];
|
||||
str_new[len] = 0;
|
||||
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
str_new[i] = cc_utf8_get_char(str_old);
|
||||
str_old = cc_utf8_next_char(str_old);
|
||||
}
|
||||
|
||||
return str_new;
|
||||
}
|
||||
|
||||
std::vector<unsigned short> cc_utf16_vec_from_utf16_str(const unsigned short* str)
|
||||
{
|
||||
int len = cc_wcslen(str);
|
||||
std::vector<unsigned short> str_new;
|
||||
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
str_new.push_back(str[i]);
|
||||
}
|
||||
return str_new;
|
||||
}
|
||||
|
||||
/**
|
||||
* cc_unichar_to_utf8:
|
||||
* @c: a ISO10646 character code
|
||||
* @outbuf: output buffer, must have at least 6 bytes of space.
|
||||
* If %NULL, the length will be computed and returned
|
||||
* and nothing will be written to @outbuf.
|
||||
*
|
||||
* Converts a single character to UTF-8.
|
||||
*
|
||||
* Return value: number of bytes written
|
||||
**/
|
||||
int
|
||||
cc_unichar_to_utf8 (unsigned short c,
|
||||
char *outbuf)
|
||||
{
|
||||
unsigned int len = 0;
|
||||
int first;
|
||||
int i;
|
||||
|
||||
if (c < 0x80)
|
||||
{
|
||||
first = 0;
|
||||
len = 1;
|
||||
}
|
||||
else if (c < 0x800)
|
||||
{
|
||||
first = 0xc0;
|
||||
len = 2;
|
||||
}
|
||||
else if (c < 0x10000)
|
||||
{
|
||||
first = 0xe0;
|
||||
len = 3;
|
||||
}
|
||||
else if (c < 0x200000)
|
||||
{
|
||||
first = 0xf0;
|
||||
len = 4;
|
||||
}
|
||||
else if (c < 0x4000000)
|
||||
{
|
||||
first = 0xf8;
|
||||
len = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
first = 0xfc;
|
||||
len = 6;
|
||||
}
|
||||
|
||||
if (outbuf)
|
||||
{
|
||||
for (i = len - 1; i > 0; --i)
|
||||
{
|
||||
outbuf[i] = (c & 0x3f) | 0x80;
|
||||
c >>= 6;
|
||||
}
|
||||
outbuf[0] = c | first;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#define SURROGATE_VALUE(h,l) (((h) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000)
|
||||
|
||||
/**
|
||||
* cc_utf16_to_utf8:
|
||||
* @str: a UTF-16 encoded string
|
||||
* @len: the maximum length of @str to use. If @len < 0, then
|
||||
* the string is terminated with a 0 character.
|
||||
* @items_read: location to store number of words read, or %NULL.
|
||||
* If %NULL, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
|
||||
* returned in case @str contains a trailing partial
|
||||
* character. If an error occurs then the index of the
|
||||
* invalid input is stored here.
|
||||
* @items_written: location to store number of bytes written, or %NULL.
|
||||
* The value stored here does not include the trailing
|
||||
* 0 byte.
|
||||
* @error: location to store the error occuring, or %NULL to ignore
|
||||
* errors. Any of the errors in #GConvertError other than
|
||||
* %G_CONVERT_ERROR_NO_CONVERSION may occur.
|
||||
*
|
||||
* Convert a string from UTF-16 to UTF-8. The result will be
|
||||
* terminated with a 0 byte.
|
||||
*
|
||||
* Return value: a pointer to a newly allocated UTF-8 string.
|
||||
* This value must be freed with free(). If an
|
||||
* error occurs, %NULL will be returned and
|
||||
* @error set.
|
||||
**/
|
||||
char *
|
||||
cc_utf16_to_utf8 (const unsigned short *str,
|
||||
long len,
|
||||
long *items_read,
|
||||
long *items_written)
|
||||
{
|
||||
/* This function and g_utf16_to_ucs4 are almost exactly identical - The lines that differ
|
||||
* are marked.
|
||||
*/
|
||||
const unsigned short *in;
|
||||
char *out;
|
||||
char *result = NULL;
|
||||
int n_bytes;
|
||||
unsigned short high_surrogate;
|
||||
|
||||
if (str == 0) return NULL;
|
||||
|
||||
n_bytes = 0;
|
||||
in = str;
|
||||
high_surrogate = 0;
|
||||
while ((len < 0 || in - str < len) && *in)
|
||||
{
|
||||
unsigned short c = *in;
|
||||
unsigned short wc;
|
||||
|
||||
if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
|
||||
{
|
||||
if (high_surrogate)
|
||||
{
|
||||
wc = SURROGATE_VALUE (high_surrogate, c);
|
||||
high_surrogate = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
CCLOGERROR("Invalid sequence in conversion input");
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (high_surrogate)
|
||||
{
|
||||
CCLOGERROR("Invalid sequence in conversion input");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
|
||||
{
|
||||
high_surrogate = c;
|
||||
goto next1;
|
||||
}
|
||||
else
|
||||
wc = c;
|
||||
}
|
||||
|
||||
/********** DIFFERENT for UTF8/UCS4 **********/
|
||||
n_bytes += UTF8_LENGTH (wc);
|
||||
|
||||
next1:
|
||||
in++;
|
||||
}
|
||||
|
||||
if (high_surrogate && !items_read)
|
||||
{
|
||||
CCLOGERROR("Partial character sequence at end of input");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* At this point, everything is valid, and we just need to convert
|
||||
*/
|
||||
/********** DIFFERENT for UTF8/UCS4 **********/
|
||||
result = new char[n_bytes + 1];
|
||||
|
||||
high_surrogate = 0;
|
||||
out = result;
|
||||
in = str;
|
||||
while (out < result + n_bytes)
|
||||
{
|
||||
unsigned short c = *in;
|
||||
unsigned short wc;
|
||||
|
||||
if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
|
||||
{
|
||||
wc = SURROGATE_VALUE (high_surrogate, c);
|
||||
high_surrogate = 0;
|
||||
}
|
||||
else if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
|
||||
{
|
||||
high_surrogate = c;
|
||||
goto next2;
|
||||
}
|
||||
else
|
||||
wc = c;
|
||||
|
||||
/********** DIFFERENT for UTF8/UCS4 **********/
|
||||
out += cc_unichar_to_utf8 (wc, out);
|
||||
|
||||
next2:
|
||||
in++;
|
||||
}
|
||||
|
||||
/********** DIFFERENT for UTF8/UCS4 **********/
|
||||
*out = '\0';
|
||||
|
||||
if (items_written)
|
||||
/********** DIFFERENT for UTF8/UCS4 **********/
|
||||
*items_written = out - result;
|
||||
|
||||
err_out:
|
||||
if (items_read)
|
||||
*items_read = in - str;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NS_CC_END
|
|
@ -0,0 +1,97 @@
|
|||
//
|
||||
// ccUTF8.h
|
||||
// cocos2dx
|
||||
//
|
||||
// Created by James Chen on 2/27/13.
|
||||
//
|
||||
|
||||
#ifndef __cocos2dx__ccUTF8__
|
||||
#define __cocos2dx__ccUTF8__
|
||||
|
||||
#include "platform/CCPlatformMacros.h"
|
||||
#include <vector>
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
CC_DLL int cc_wcslen(const unsigned short* str);
|
||||
|
||||
CC_DLL void cc_utf8_trim_ws(std::vector<unsigned short>* str);
|
||||
|
||||
/*
|
||||
* @ch is the unicode character whitespace?
|
||||
*
|
||||
* Reference: http://en.wikipedia.org/wiki/Whitespace_character#Unicode
|
||||
*
|
||||
* Return value: weather the character is a whitespace character.
|
||||
* */
|
||||
CC_DLL bool isspace_unicode(unsigned short ch);
|
||||
|
||||
/*
|
||||
* cc_utf8_strlen:
|
||||
* @p: pointer to the start of a UTF-8 encoded string.
|
||||
* @max: the maximum number of bytes to examine. If @max
|
||||
* is less than 0, then the string is assumed to be
|
||||
* null-terminated. If @max is 0, @p will not be examined and
|
||||
* may be %NULL.
|
||||
*
|
||||
* Returns the length of the string in characters.
|
||||
*
|
||||
* Return value: the length of the string in characters
|
||||
**/
|
||||
CC_DLL long
|
||||
cc_utf8_strlen (const char * p, int max);
|
||||
|
||||
/*
|
||||
* @str: the string to search through.
|
||||
* @c: the character to not look for.
|
||||
*
|
||||
* Return value: the index of the last character that is not c.
|
||||
* */
|
||||
CC_DLL unsigned int cc_utf8_find_last_not_char(std::vector<unsigned short> str, unsigned short c);
|
||||
|
||||
CC_DLL std::vector<unsigned short> cc_utf16_vec_from_utf16_str(const unsigned short* str);
|
||||
|
||||
/*
|
||||
* cc_utf8_to_utf16:
|
||||
* @str_old: pointer to the start of a C string.
|
||||
*
|
||||
* Creates a utf8 string from a cstring.
|
||||
*
|
||||
* Return value: the newly created utf8 string.
|
||||
* */
|
||||
CC_DLL unsigned short* cc_utf8_to_utf16(const char* str_old);
|
||||
|
||||
/**
|
||||
* cc_utf16_to_utf8:
|
||||
* @str: a UTF-16 encoded string
|
||||
* @len: the maximum length of @str to use. If @len < 0, then
|
||||
* the string is terminated with a 0 character.
|
||||
* @items_read: location to store number of words read, or %NULL.
|
||||
* If %NULL, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
|
||||
* returned in case @str contains a trailing partial
|
||||
* character. If an error occurs then the index of the
|
||||
* invalid input is stored here.
|
||||
* @items_written: location to store number of bytes written, or %NULL.
|
||||
* The value stored here does not include the trailing
|
||||
* 0 byte.
|
||||
* @error: location to store the error occuring, or %NULL to ignore
|
||||
* errors. Any of the errors in #GConvertError other than
|
||||
* %G_CONVERT_ERROR_NO_CONVERSION may occur.
|
||||
*
|
||||
* Convert a string from UTF-16 to UTF-8. The result will be
|
||||
* terminated with a 0 byte.
|
||||
*
|
||||
* Return value: a pointer to a newly allocated UTF-8 string.
|
||||
* This value must be freed with free(). If an
|
||||
* error occurs, %NULL will be returned and
|
||||
* @error set.
|
||||
**/
|
||||
CC_DLL char *
|
||||
cc_utf16_to_utf8 (const unsigned short *str,
|
||||
long len,
|
||||
long *items_read,
|
||||
long *items_written);
|
||||
|
||||
NS_CC_END
|
||||
|
||||
#endif /* defined(__cocos2dx__ccUTF8__) */
|
|
@ -31,11 +31,6 @@
|
|||
#include "jni/Java_org_cocos2dx_lib_Cocos2dxBitmap.h"
|
||||
#include "jni/Java_org_cocos2dx_lib_Cocos2dxHelper.h"
|
||||
|
||||
// This function is implemented in CCLabelBMFont.cpp
|
||||
|
||||
NS_CC_BEGIN
|
||||
extern long cc_utf8_strlen (const char * p, int max);
|
||||
NS_CC_END
|
||||
|
||||
NS_CC_EXT_BEGIN
|
||||
|
||||
|
|
|
@ -29,10 +29,6 @@
|
|||
#include "CCEditBox.h"
|
||||
#include "proj.win32/Win32InputBox.h"
|
||||
|
||||
NS_CC_BEGIN
|
||||
extern CC_DLL long cc_utf8_strlen (const char * p, int max);
|
||||
NS_CC_END
|
||||
|
||||
NS_CC_EXT_BEGIN
|
||||
|
||||
CCEditBoxImpl* __createSystemEditBox(CCEditBox* pEditBox)
|
||||
|
|
|
@ -101,6 +101,7 @@ CCTableViewVerticalFillOrder CCTableView::getVerticalFillOrder()
|
|||
|
||||
void CCTableView::reloadData()
|
||||
{
|
||||
m_eOldDirection = kCCScrollViewDirectionNone;
|
||||
CCObject* pObj = NULL;
|
||||
CCARRAY_FOREACH(m_pCellsUsed, pObj)
|
||||
{
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit cc6d8acc731c5a6970e96cc2ba231718ba693dfc
|
||||
Subproject commit 0455fdce1ec89d6bf335e395b48882aaf875d38b
|
|
@ -190,7 +190,7 @@ local function SpriteProgressToRadialMidpointChanged()
|
|||
left:setType(kCCProgressTimerTypeRadial)
|
||||
left:setMidpoint(CCPointMake(0.25, 0.75))
|
||||
left:setPosition(CCPointMake(100, s.height / 2))
|
||||
left:runAction(CCRepeatForever:create(action:copy():autorelease()))
|
||||
left:runAction(CCRepeatForever:create(CCProgressTo:create(2, 100)))
|
||||
layer:addChild(left)
|
||||
|
||||
-- Our image on the left should be a radial progress indicator, counter clockwise
|
||||
|
@ -203,7 +203,7 @@ local function SpriteProgressToRadialMidpointChanged()
|
|||
we get a counter clockwise progress.
|
||||
]]
|
||||
right:setPosition(CCPointMake(s.width - 100, s.height / 2))
|
||||
right:runAction(CCRepeatForever:create(action:copy():autorelease()))
|
||||
right:runAction(CCRepeatForever:create(CCProgressTo:create(2, 100)))
|
||||
layer:addChild(right)
|
||||
|
||||
subtitleLabel:setString("Radial w/ Different Midpoints")
|
||||
|
@ -227,7 +227,7 @@ local function SpriteProgressBarVarious()
|
|||
-- Setup for a vertical bar since the bar change rate is 0 for x meaning no horizontal change
|
||||
left:setBarChangeRate(CCPointMake(1, 0))
|
||||
left:setPosition(CCPointMake(100, s.height / 2))
|
||||
left:runAction(CCRepeatForever:create(to:copy():autorelease()))
|
||||
left:runAction(CCRepeatForever:create(CCProgressTo:create(2, 100)))
|
||||
layer:addChild(left)
|
||||
|
||||
local middle = CCProgressTimer:create(CCSprite:create(s_pPathSister2))
|
||||
|
@ -237,7 +237,7 @@ local function SpriteProgressBarVarious()
|
|||
-- Setup for a vertical bar since the bar change rate is 0 for x meaning no horizontal change
|
||||
middle:setBarChangeRate(CCPointMake(1, 1))
|
||||
middle:setPosition(CCPointMake(s.width/2, s.height/2))
|
||||
middle:runAction(CCRepeatForever:create(to:copy():autorelease()))
|
||||
middle:runAction(CCRepeatForever:create(CCProgressTo:create(2, 100)))
|
||||
layer:addChild(middle)
|
||||
|
||||
local right = CCProgressTimer:create(CCSprite:create(s_pPathSister2))
|
||||
|
@ -247,7 +247,7 @@ local function SpriteProgressBarVarious()
|
|||
-- Setup for a vertical bar since the bar change rate is 0 for x meaning no horizontal change
|
||||
right:setBarChangeRate(CCPointMake(0, 1))
|
||||
right:setPosition(CCPointMake(s.width-100, s.height/2))
|
||||
right:runAction(CCRepeatForever:create(to:copy():autorelease()))
|
||||
right:runAction(CCRepeatForever:create(CCProgressTo:create(2, 100)))
|
||||
layer:addChild(right)
|
||||
|
||||
subtitleLabel:setString("ProgressTo Bar Mid")
|
||||
|
@ -279,8 +279,8 @@ local function SpriteProgressBarTintAndFade()
|
|||
-- Setup for a vertical bar since the bar change rate is 0 for x meaning no horizontal change
|
||||
left:setBarChangeRate(CCPointMake(1, 0))
|
||||
left:setPosition(CCPointMake(100, s.height / 2))
|
||||
left:runAction(CCRepeatForever:create(to:copy():autorelease()))
|
||||
left:runAction(CCRepeatForever:create(tint:copy():autorelease()))
|
||||
left:runAction(CCRepeatForever:create(CCProgressTo:create(6, 100)))
|
||||
left:runAction(CCRepeatForever:create(CCSequence:create(array)))
|
||||
layer:addChild(left)
|
||||
|
||||
left:addChild(CCLabelTTF:create("Tint", "Marker Felt", 20.0))
|
||||
|
@ -292,8 +292,12 @@ local function SpriteProgressBarTintAndFade()
|
|||
-- Setup for a vertical bar since the bar change rate is 0 for x meaning no horizontal change
|
||||
middle:setBarChangeRate(CCPointMake(1, 1))
|
||||
middle:setPosition(CCPointMake(s.width / 2, s.height / 2))
|
||||
middle:runAction(CCRepeatForever:create(to:copy():autorelease()))
|
||||
middle:runAction(CCRepeatForever:create(fade:copy():autorelease()))
|
||||
middle:runAction(CCRepeatForever:create(CCProgressTo:create(6, 100)))
|
||||
|
||||
local fade2 = CCSequence:createWithTwoActions(
|
||||
CCFadeTo:create(1.0, 0),
|
||||
CCFadeTo:create(1.0, 255))
|
||||
middle:runAction(CCRepeatForever:create(fade2))
|
||||
layer:addChild(middle)
|
||||
|
||||
middle:addChild(CCLabelTTF:create("Fade", "Marker Felt", 20.0))
|
||||
|
@ -305,9 +309,11 @@ local function SpriteProgressBarTintAndFade()
|
|||
-- Setup for a vertical bar since the bar change rate is 0 for x meaning no horizontal change
|
||||
right:setBarChangeRate(CCPointMake(0, 1))
|
||||
right:setPosition(CCPointMake(s.width - 100, s.height / 2))
|
||||
right:runAction(CCRepeatForever:create(to:copy():autorelease()))
|
||||
right:runAction(CCRepeatForever:create(tint:copy():autorelease()))
|
||||
right:runAction(CCRepeatForever:create(fade:copy():autorelease()))
|
||||
right:runAction(CCRepeatForever:create(CCProgressTo:create(6, 100)))
|
||||
right:runAction(CCRepeatForever:create(CCSequence:create(array)))
|
||||
right:runAction(CCRepeatForever:create(CCSequence:createWithTwoActions(
|
||||
CCFadeTo:create(1.0, 0),
|
||||
CCFadeTo:create(1.0, 255))))
|
||||
layer:addChild(right)
|
||||
|
||||
right:addChild(CCLabelTTF:create("Tint and Fade", "Marker Felt", 20.0))
|
||||
|
@ -334,7 +340,7 @@ local function SpriteProgressWithSpriteFrame()
|
|||
-- Setup for a vertical bar since the bar change rate is 0 for x meaning no horizontal change
|
||||
left:setBarChangeRate(CCPointMake(1, 0))
|
||||
left:setPosition(CCPointMake(100, s.height / 2))
|
||||
left:runAction(CCRepeatForever:create(to:copy():autorelease()))
|
||||
left:runAction(CCRepeatForever:create(CCProgressTo:create(6, 100)))
|
||||
layer:addChild(left)
|
||||
|
||||
local middle = CCProgressTimer:create(CCSprite:createWithSpriteFrameName("grossini_dance_02.png"))
|
||||
|
@ -344,7 +350,7 @@ local function SpriteProgressWithSpriteFrame()
|
|||
-- Setup for a vertical bar since the bar change rate is 0 for x meaning no horizontal change
|
||||
middle:setBarChangeRate(CCPointMake(1, 1))
|
||||
middle:setPosition(CCPointMake(s.width / 2, s.height / 2))
|
||||
middle:runAction(CCRepeatForever:create(to:copy():autorelease()))
|
||||
middle:runAction(CCRepeatForever:create(CCProgressTo:create(6, 100)))
|
||||
layer:addChild(middle)
|
||||
|
||||
local right = CCProgressTimer:create(CCSprite:createWithSpriteFrameName("grossini_dance_03.png"))
|
||||
|
@ -354,7 +360,7 @@ local function SpriteProgressWithSpriteFrame()
|
|||
-- Setup for a vertical bar since the bar change rate is 0 for x meaning no horizontal change
|
||||
right:setBarChangeRate(CCPointMake(0, 1))
|
||||
right:setPosition(CCPointMake(s.width - 100, s.height / 2))
|
||||
right:runAction(CCRepeatForever:create(to:copy():autorelease()))
|
||||
right:runAction(CCRepeatForever:create(CCProgressTo:create(6, 100)))
|
||||
layer:addChild(right)
|
||||
|
||||
subtitleLabel:setString("Progress With Sprite Frame")
|
||||
|
|
|
@ -213,7 +213,9 @@ local function ActionRotate()
|
|||
local actionByBack = actionBy:reverse()
|
||||
grossini:runAction(CCSequence:createWithTwoActions(actionBy, actionByBack))
|
||||
|
||||
kathia:runAction(CCSequence:createWithTwoActions(actionTo2, actionTo0:copy():autorelease()))
|
||||
local action0Retain = CCRotateTo:create(2 , 0)
|
||||
|
||||
kathia:runAction(CCSequence:createWithTwoActions(actionTo2, action0Retain))
|
||||
|
||||
subtitleLabel:setString("RotateTo / RotateBy")
|
||||
return layer
|
||||
|
@ -699,7 +701,9 @@ local function ActionRepeat()
|
|||
|
||||
local a1 = CCMoveBy:create(1, ccp(150,0))
|
||||
local action1 = CCRepeat:create(CCSequence:createWithTwoActions(CCPlace:create(ccp(60,60)), a1), 3)
|
||||
local action2 = CCRepeatForever:create(CCSequence:createWithTwoActions(a1:copy():autorelease(), a1:reverse()))
|
||||
|
||||
local a2 = CCMoveBy:create(1, ccp(150,0))
|
||||
local action2 = CCRepeatForever:create(CCSequence:createWithTwoActions(a2, a1:reverse()))
|
||||
|
||||
kathia:runAction(action1)
|
||||
tamara:runAction(action2)
|
||||
|
@ -746,7 +750,8 @@ local function ActionRotateToRepeat()
|
|||
local act2 = CCRotateTo:create(1, 0)
|
||||
local seq = CCSequence:createWithTwoActions(act1, act2)
|
||||
local rep1 = CCRepeatForever:create(seq)
|
||||
local rep2 = CCRepeat:create(seq:copy():autorelease(), 10)
|
||||
local seq2 = CCSequence:createWithTwoActions(act1, act2)
|
||||
local rep2 = CCRepeat:create(seq2, 10)
|
||||
|
||||
tamara:runAction(rep1)
|
||||
kathia:runAction(rep2)
|
||||
|
@ -770,7 +775,12 @@ local function ActionRotateJerk()
|
|||
CCRotateTo:create(0.5, 20))
|
||||
|
||||
local rep1 = CCRepeat:create(seq, 10)
|
||||
local rep2 = CCRepeatForever:create(seq:copy():autorelease())
|
||||
|
||||
local seq2 = CCSequence:createWithTwoActions(
|
||||
CCRotateTo:create(0.5, -20),
|
||||
CCRotateTo:create(0.5, 20))
|
||||
|
||||
local rep2 = CCRepeatForever:create(seq2)
|
||||
|
||||
tamara:runAction(rep1)
|
||||
kathia:runAction(rep2)
|
||||
|
@ -932,8 +942,12 @@ local function ActionOrbit()
|
|||
local seq = CCSequence:createWithTwoActions(move, move_back)
|
||||
local rfe = CCRepeatForever:create(seq)
|
||||
kathia:runAction(rfe)
|
||||
tamara:runAction(rfe:copy():autorelease())
|
||||
grossini:runAction(rfe:copy():autorelease())
|
||||
|
||||
local rfe2 = CCRepeatForever:create(seq)
|
||||
tamara:runAction(rfe2)
|
||||
|
||||
local rfe3 = CCRepeatForever:create(seq)
|
||||
grossini:runAction(rfe3)
|
||||
|
||||
|
||||
subtitleLabel:setString("OrbitCamera action")
|
||||
|
@ -973,9 +987,9 @@ local function ActionTargeted()
|
|||
centerSprites(2)
|
||||
|
||||
local jump1 = CCJumpBy:create(2, ccp(0, 0), 100, 3)
|
||||
local jump2 = jump1:copy():autorelease()
|
||||
local jump2 = CCJumpBy:create(2, ccp(0, 0), 100, 3)
|
||||
local rot1 = CCRotateBy:create(1, 360)
|
||||
local rot2 = rot1:copy():autorelease()
|
||||
local rot2 = CCRotateBy:create(1, 360)
|
||||
|
||||
local t1 = CCTargetedAction:create(kathia, jump2)
|
||||
local t2 = CCTargetedAction:create(kathia, rot2)
|
||||
|
|
|
@ -164,7 +164,7 @@ end
|
|||
-- ShakyTiles3DDemo
|
||||
--------------------------------------
|
||||
local function ShakyTiles3DDemo(t)
|
||||
return CCShakyTiles3D:create(t, CCSizeMake(16,12), 5, false) ;
|
||||
return CCShakyTiles3D:create(t, CCSizeMake(16,12), 5, false);
|
||||
end
|
||||
|
||||
--------------------------------------
|
||||
|
|
|
@ -332,7 +332,8 @@ ScriptingCore::ScriptingCore()
|
|||
, debugGlobal_(NULL)
|
||||
{
|
||||
// set utf8 strings internally (we don't need utf16)
|
||||
JS_SetCStringsAreUTF8();
|
||||
// XXX: Removed in SpiderMonkey 19.0
|
||||
//JS_SetCStringsAreUTF8();
|
||||
this->addRegisterCallback(registerDefaultClasses);
|
||||
this->runLoop = new SimpleRunLoop();
|
||||
}
|
||||
|
@ -417,7 +418,7 @@ void ScriptingCore::createGlobalContext() {
|
|||
this->rt_ = NULL;
|
||||
}
|
||||
//JS_SetCStringsAreUTF8();
|
||||
this->rt_ = JS_NewRuntime(10 * 1024 * 1024);
|
||||
this->rt_ = JS_NewRuntime(10 * 1024 * 1024, JS_NO_HELPER_THREADS);
|
||||
this->cx_ = JS_NewContext(rt_, 10240);
|
||||
JS_SetOptions(this->cx_, JSOPTION_TYPE_INFERENCE);
|
||||
JS_SetVersion(this->cx_, JSVERSION_LATEST);
|
||||
|
@ -456,17 +457,25 @@ JSBool ScriptingCore::runScript(const char *path, JSObject* global, JSContext* c
|
|||
cx = cx_;
|
||||
}
|
||||
|
||||
js::RootedObject obj(cx, global);
|
||||
JS::CompileOptions options(cx);
|
||||
options.setUTF8(true).setFileAndLine(rpath.c_str(), 1);
|
||||
|
||||
// this will always compile the script, we can actually check if the script
|
||||
// was compiled before, because it can be in the global map
|
||||
#ifdef ANDROID
|
||||
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
|
||||
unsigned char *content = NULL;
|
||||
unsigned long contentSize = 0;
|
||||
|
||||
content = (unsigned char*)CCString::createWithContentsOfFile(rpath.c_str())->getCString();
|
||||
contentSize = strlen((char*)content);
|
||||
JSScript* script = JS_CompileScript(cx, global, (char*)content, contentSize, path, 1);
|
||||
// Not supported in SpiderMonkey 19.0
|
||||
//JSScript* script = JS_CompileScript(cx, global, (char*)content, contentSize, path, 1);
|
||||
JSScript *script = JS::Compile(cx, obj, options, (char*)content, contentSize);
|
||||
#else
|
||||
JSScript* script = JS_CompileUTF8File(cx, global, rpath.c_str());
|
||||
// Removed in SpiderMonkey 19.0
|
||||
//JSScript* script = JS_CompileUTF8File(cx, global, rpath.c_str());
|
||||
JSScript *script = JS::Compile(cx, obj, options, rpath.c_str());
|
||||
#endif
|
||||
JSBool evaluatedOK = false;
|
||||
if (script) {
|
||||
|
@ -963,15 +972,20 @@ JSBool jsval_to_uint16( JSContext *cx, jsval vp, uint16_t *outval )
|
|||
return ok;
|
||||
}
|
||||
|
||||
JSBool jsval_to_long_long(JSContext *cx, jsval v, long long* ret) {
|
||||
JSBool ok = JS_TRUE;
|
||||
JSObject *tmp = JSVAL_TO_OBJECT(v);
|
||||
ok &= JS_IsTypedArrayObject(tmp, cx) && JS_GetTypedArrayByteLength(tmp, cx) == 8;
|
||||
JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments");
|
||||
|
||||
uint32_t *data = (uint32_t *)JS_GetUint32ArrayData(tmp, cx);
|
||||
*ret = (long long)(*data);
|
||||
return ok;
|
||||
JSBool jsval_to_long_long(JSContext *cx, jsval vp, long long* r) {
|
||||
JSObject *tmp_arg;
|
||||
JSBool ok = JS_ValueToObject( cx, vp, &tmp_arg );
|
||||
JSB_PRECONDITION2( ok, cx, JS_FALSE, "Error converting value to object");
|
||||
JSB_PRECONDITION2( tmp_arg && JS_IsTypedArrayObject( tmp_arg ), cx, JS_FALSE, "Not a TypedArray object");
|
||||
JSB_PRECONDITION2( JS_GetTypedArrayByteLength( tmp_arg ) == sizeof(long long), cx, JS_FALSE, "Invalid Typed Array length");
|
||||
|
||||
uint32_t* arg_array = (uint32_t*)JS_GetArrayBufferViewData( tmp_arg );
|
||||
long long ret = arg_array[0];
|
||||
ret = ret << 32;
|
||||
ret |= arg_array[1];
|
||||
|
||||
*r = ret;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool jsval_to_std_string(JSContext *cx, jsval v, std::string* ret) {
|
||||
|
@ -1337,7 +1351,7 @@ jsval uint32_to_jsval( JSContext *cx, uint32_t number )
|
|||
|
||||
jsval long_long_to_jsval(JSContext* cx, long long v) {
|
||||
JSObject *tmp = JS_NewUint32Array(cx, 2);
|
||||
uint32_t *data = (uint32_t *)JS_GetArrayBufferViewData(tmp, cx);
|
||||
uint32_t *data = (uint32_t *)JS_GetArrayBufferViewData(tmp);
|
||||
data[0] = ((uint32_t *)(&v))[0];
|
||||
data[1] = ((uint32_t *)(&v))[1];
|
||||
return OBJECT_TO_JSVAL(tmp);
|
||||
|
@ -1611,12 +1625,12 @@ JSBool JSBDebug_BufferWrite(JSContext* cx, unsigned argc, jsval* vp)
|
|||
const char* str;
|
||||
|
||||
JSString* jsstr = JS_ValueToString(cx, argv[0]);
|
||||
str = JS_EncodeString(cx, jsstr);
|
||||
|
||||
// Not supported in SpiderMonkey v19
|
||||
//str = JS_EncodeString(cx, jsstr);
|
||||
JSStringWrapper strWrapper(jsstr);
|
||||
|
||||
// this is safe because we're already inside a lock (from clearBuffers)
|
||||
outData.append(str);
|
||||
|
||||
JS_free(cx, (void*)str);
|
||||
outData.append(strWrapper.get());
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
|
|
@ -267,16 +267,13 @@ public:
|
|||
}
|
||||
~JSStringWrapper() {
|
||||
if (buffer) {
|
||||
JS_free(ScriptingCore::getInstance()->getGlobalContext(), (void*)buffer);
|
||||
// JS_free(ScriptingCore::getInstance()->getGlobalContext(), (void*)buffer);
|
||||
CC_SAFE_DELETE_ARRAY(buffer);
|
||||
}
|
||||
}
|
||||
void set(jsval val, JSContext* cx) {
|
||||
if (val.isString()) {
|
||||
string = val.toString();
|
||||
if (!cx) {
|
||||
cx = ScriptingCore::getInstance()->getGlobalContext();
|
||||
}
|
||||
buffer = JS_EncodeString(cx, string);
|
||||
this->set(val.toString(), cx);
|
||||
} else {
|
||||
buffer = NULL;
|
||||
}
|
||||
|
@ -286,7 +283,14 @@ public:
|
|||
if (!cx) {
|
||||
cx = ScriptingCore::getInstance()->getGlobalContext();
|
||||
}
|
||||
buffer = JS_EncodeString(cx, string);
|
||||
// Not suppored in SpiderMonkey v19
|
||||
//buffer = JS_EncodeString(cx, string);
|
||||
|
||||
const jschar *chars = JS_GetStringCharsZ(cx, string);
|
||||
size_t l = JS_GetStringLength(string);
|
||||
char* pUTF8Str = cc_utf16_to_utf8((const unsigned short*)chars, l, NULL, NULL);
|
||||
buffer = pUTF8Str;
|
||||
|
||||
}
|
||||
std::string get() {
|
||||
return buffer;
|
||||
|
|
|
@ -1 +1 @@
|
|||
e0892eb5a623d56700e48e717dbc04c367b3b48a
|
||||
e4b7d86461a17a555283bbc28cba2ab48cab21cd
|
|
@ -1 +1 @@
|
|||
Subproject commit a4cf50ac9b5541a1ba948bb459fa5bf7b4917e65
|
||||
Subproject commit 9918c2317e922dd8d866e4df09b039aba8d48134
|
|
@ -1 +1 @@
|
|||
9594a5677c70358b9e128381d6481eeed0e80723
|
||||
f432fb0be7f47a71e1ceeb380fa604fab9e2ac31
|
|
@ -258,12 +258,12 @@ void JSB_CCPhysicsDebugNode_createClass(JSContext *cx, JSObject* globalObj, cons
|
|||
{0, 0, 0, 0, 0}
|
||||
};
|
||||
static JSFunctionSpec funcs[] = {
|
||||
JS_FN("_setSpace", JSB_CCPhysicsDebugNode_setSpace_, 1, JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE),
|
||||
JS_FN("getSpace", JSB_CCPhysicsDebugNode_space, 0, JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE),
|
||||
JS_FN("_setSpace", JSB_CCPhysicsDebugNode_setSpace_, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE),
|
||||
JS_FN("getSpace", JSB_CCPhysicsDebugNode_space, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
|
||||
JS_FS_END
|
||||
};
|
||||
static JSFunctionSpec st_funcs[] = {
|
||||
JS_FN("_create", JSB_CCPhysicsDebugNode_debugNodeForCPSpace__static, 1, JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE),
|
||||
JS_FN("_create", JSB_CCPhysicsDebugNode_debugNodeForCPSpace__static, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
@ -443,16 +443,16 @@ void JSPROXY_CCPhysicsSprite_createClass(JSContext *cx, JSObject* globalObj)
|
|||
{0, 0, 0, 0, 0}
|
||||
};
|
||||
static JSFunctionSpec funcs[] = {
|
||||
JS_FN("getCPBody", JSPROXY_CCPhysicsSprite_getCPBody, 0, JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE),
|
||||
JS_FN("getIgnoreBodyRotation", JSPROXY_CCPhysicsSprite_ignoreBodyRotation, 0, JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE),
|
||||
JS_FN("_setCPBody", JSPROXY_CCPhysicsSprite_setCPBody_, 1, JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE),
|
||||
JS_FN("setIgnoreBodyRotation", JSPROXY_CCPhysicsSprite_setIgnoreBodyRotation_, 1, JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE),
|
||||
JS_FN("getCPBody", JSPROXY_CCPhysicsSprite_getCPBody, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
|
||||
JS_FN("getIgnoreBodyRotation", JSPROXY_CCPhysicsSprite_ignoreBodyRotation, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
|
||||
JS_FN("_setCPBody", JSPROXY_CCPhysicsSprite_setCPBody_, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE),
|
||||
JS_FN("setIgnoreBodyRotation", JSPROXY_CCPhysicsSprite_setIgnoreBodyRotation_, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE),
|
||||
JS_FS_END
|
||||
};
|
||||
static JSFunctionSpec st_funcs[] = {
|
||||
JS_FN("create", JSPROXY_CCPhysicsSprite_spriteWithFile_rect__static, 2, JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE),
|
||||
JS_FN("createWithSpriteFrame", JSPROXY_CCPhysicsSprite_spriteWithSpriteFrame__static, 1, JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE),
|
||||
JS_FN("createWithSpriteFrameName", JSPROXY_CCPhysicsSprite_spriteWithSpriteFrameName__static, 1, JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE),
|
||||
JS_FN("create", JSPROXY_CCPhysicsSprite_spriteWithFile_rect__static, 2, JSPROP_PERMANENT | JSPROP_ENUMERATE),
|
||||
JS_FN("createWithSpriteFrame", JSPROXY_CCPhysicsSprite_spriteWithSpriteFrame__static, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE),
|
||||
JS_FN("createWithSpriteFrameName", JSPROXY_CCPhysicsSprite_spriteWithSpriteFrameName__static, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
@ -1528,8 +1528,8 @@ void JSB_cpBase_createClass(JSContext *cx, JSObject* globalObj, const char* name
|
|||
{0, 0, 0, 0, 0}
|
||||
};
|
||||
static JSFunctionSpec funcs[] = {
|
||||
JS_FN("getHandle", JSB_cpBase_getHandle, 0, JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE),
|
||||
JS_FN("setHandle", JSB_cpBase_setHandle, 1, JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE),
|
||||
JS_FN("getHandle", JSB_cpBase_getHandle, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
|
||||
JS_FN("setHandle", JSB_cpBase_setHandle, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE),
|
||||
JS_FS_END
|
||||
};
|
||||
static JSFunctionSpec st_funcs[] = {
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "js_bindings_config.h"
|
||||
#include "js_bindings_core.h"
|
||||
|
||||
|
@ -29,6 +28,7 @@
|
|||
// cocos2d + chipmunk registration files
|
||||
#include "js_bindings_chipmunk_registration.h"
|
||||
|
||||
|
||||
#pragma mark - Hash
|
||||
|
||||
using namespace cocos2d;
|
||||
|
@ -80,8 +80,12 @@ JSBool JSBCore_log(JSContext *cx, uint32_t argc, jsval *vp)
|
|||
JSString *string = NULL;
|
||||
JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S", &string);
|
||||
if (string) {
|
||||
char *cstr = JS_EncodeString(cx, string);
|
||||
fprintf(stderr, "%s\n", cstr);
|
||||
// Not supported in SpiderMonkey v19
|
||||
//char *cstr = JS_EncodeString(cx, string);
|
||||
const jschar *chars = JS_GetStringCharsZ(cx, string);
|
||||
size_t l = JS_GetStringLength(string);
|
||||
char* pUTF8Str = cc_utf16_to_utf8((const unsigned short*)chars, l, NULL, NULL);
|
||||
CCLOG(pUTF8Str);
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
|
|
|
@ -78,14 +78,12 @@ JSBool jsval_to_long( JSContext *cx, jsval vp, long *r )
|
|||
JSBool jsval_to_longlong( JSContext *cx, jsval vp, long long *r )
|
||||
{
|
||||
JSObject *tmp_arg;
|
||||
if( ! JS_ValueToObject( cx, vp, &tmp_arg ) )
|
||||
return JS_FALSE;
|
||||
JSBool ok = JS_ValueToObject( cx, vp, &tmp_arg );
|
||||
JSB_PRECONDITION2( ok, cx, JS_FALSE, "Error converting value to object");
|
||||
JSB_PRECONDITION2( tmp_arg && JS_IsTypedArrayObject( tmp_arg ), cx, JS_FALSE, "Not a TypedArray object");
|
||||
JSB_PRECONDITION2( JS_GetTypedArrayByteLength( tmp_arg ) == sizeof(long long), cx, JS_FALSE, "Invalid Typed Array length");
|
||||
|
||||
JSB_PRECONDITION( tmp_arg && JS_IsTypedArrayObject( tmp_arg, cx ), "Not a TypedArray object");
|
||||
|
||||
JSB_PRECONDITION( JS_GetTypedArrayByteLength( tmp_arg, cx ) == sizeof(long long), "Invalid Typed Array lenght");
|
||||
|
||||
int32_t* arg_array = (int32_t*)JS_GetArrayBufferViewData( tmp_arg, cx );
|
||||
uint32_t* arg_array = (uint32_t*)JS_GetArrayBufferViewData( tmp_arg );
|
||||
long long ret = arg_array[0];
|
||||
ret = ret << 32;
|
||||
ret |= arg_array[1];
|
||||
|
@ -201,17 +199,16 @@ JSBool jsval_to_charptr( JSContext *cx, jsval vp, const char **ret )
|
|||
// root it
|
||||
vp = STRING_TO_JSVAL(jsstr);
|
||||
|
||||
char *ptr = JS_EncodeString(cx, jsstr);
|
||||
|
||||
JSB_PRECONDITION2(ptr, cx, JS_FALSE, "Error encoding string");
|
||||
|
||||
// Not supported in SpiderMonkey v19
|
||||
//char *ptr = JS_EncodeString(cx, jsstr);
|
||||
JSStringWrapper strWrapper(jsstr);
|
||||
|
||||
// XXX: It is converted to CCString and then back to char* to autorelease the created object.
|
||||
CCString *tmp = CCString::create(ptr);
|
||||
CCString *tmp = CCString::create(strWrapper.get());
|
||||
|
||||
JSB_PRECONDITION2( tmp, cx, JS_FALSE, "Error creating string from UTF8");
|
||||
|
||||
*ret = tmp->getCString();
|
||||
JS_free( cx, ptr );
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
|
|
@ -1,659 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef jsgc_barrier_h___
|
||||
#define jsgc_barrier_h___
|
||||
|
||||
#include "jsapi.h"
|
||||
|
||||
#include "gc/Heap.h"
|
||||
#include "gc/Root.h"
|
||||
#include "js/HashTable.h"
|
||||
|
||||
/*
|
||||
* A write barrier is a mechanism used by incremental or generation GCs to
|
||||
* ensure that every value that needs to be marked is marked. In general, the
|
||||
* write barrier should be invoked whenever a write can cause the set of things
|
||||
* traced through by the GC to change. This includes:
|
||||
* - writes to object properties
|
||||
* - writes to array slots
|
||||
* - writes to fields like JSObject::shape_ that we trace through
|
||||
* - writes to fields in private data, like JSGenerator::obj
|
||||
* - writes to non-markable fields like JSObject::private that point to
|
||||
* markable data
|
||||
* The last category is the trickiest. Even though the private pointers does not
|
||||
* point to a GC thing, changing the private pointer may change the set of
|
||||
* objects that are traced by the GC. Therefore it needs a write barrier.
|
||||
*
|
||||
* Every barriered write should have the following form:
|
||||
* <pre-barrier>
|
||||
* obj->field = value; // do the actual write
|
||||
* <post-barrier>
|
||||
* The pre-barrier is used for incremental GC and the post-barrier is for
|
||||
* generational GC.
|
||||
*
|
||||
* PRE-BARRIER
|
||||
*
|
||||
* To understand the pre-barrier, let's consider how incremental GC works. The
|
||||
* GC itself is divided into "slices". Between each slice, JS code is allowed to
|
||||
* run. Each slice should be short so that the user doesn't notice the
|
||||
* interruptions. In our GC, the structure of the slices is as follows:
|
||||
*
|
||||
* 1. ... JS work, which leads to a request to do GC ...
|
||||
* 2. [first GC slice, which performs all root marking and possibly more marking]
|
||||
* 3. ... more JS work is allowed to run ...
|
||||
* 4. [GC mark slice, which runs entirely in drainMarkStack]
|
||||
* 5. ... more JS work ...
|
||||
* 6. [GC mark slice, which runs entirely in drainMarkStack]
|
||||
* 7. ... more JS work ...
|
||||
* 8. [GC marking finishes; sweeping done non-incrementally; GC is done]
|
||||
* 9. ... JS continues uninterrupted now that GC is finishes ...
|
||||
*
|
||||
* Of course, there may be a different number of slices depending on how much
|
||||
* marking is to be done.
|
||||
*
|
||||
* The danger inherent in this scheme is that the JS code in steps 3, 5, and 7
|
||||
* might change the heap in a way that causes the GC to collect an object that
|
||||
* is actually reachable. The write barrier prevents this from happening. We use
|
||||
* a variant of incremental GC called "snapshot at the beginning." This approach
|
||||
* guarantees the invariant that if an object is reachable in step 2, then we
|
||||
* will mark it eventually. The name comes from the idea that we take a
|
||||
* theoretical "snapshot" of all reachable objects in step 2; all objects in
|
||||
* that snapshot should eventually be marked. (Note that the write barrier
|
||||
* verifier code takes an actual snapshot.)
|
||||
*
|
||||
* The basic correctness invariant of a snapshot-at-the-beginning collector is
|
||||
* that any object reachable at the end of the GC (step 9) must either:
|
||||
* (1) have been reachable at the beginning (step 2) and thus in the snapshot
|
||||
* (2) or must have been newly allocated, in steps 3, 5, or 7.
|
||||
* To deal with case (2), any objects allocated during an incremental GC are
|
||||
* automatically marked black.
|
||||
*
|
||||
* This strategy is actually somewhat conservative: if an object becomes
|
||||
* unreachable between steps 2 and 8, it would be safe to collect it. We won't,
|
||||
* mainly for simplicity. (Also, note that the snapshot is entirely
|
||||
* theoretical. We don't actually do anything special in step 2 that we wouldn't
|
||||
* do in a non-incremental GC.
|
||||
*
|
||||
* It's the pre-barrier's job to maintain the snapshot invariant. Consider the
|
||||
* write "obj->field = value". Let the prior value of obj->field be
|
||||
* value0. Since it's possible that value0 may have been what obj->field
|
||||
* contained in step 2, when the snapshot was taken, the barrier marks
|
||||
* value0. Note that it only does this if we're in the middle of an incremental
|
||||
* GC. Since this is rare, the cost of the write barrier is usually just an
|
||||
* extra branch.
|
||||
*
|
||||
* In practice, we implement the pre-barrier differently based on the type of
|
||||
* value0. E.g., see JSObject::writeBarrierPre, which is used if obj->field is
|
||||
* a JSObject*. It takes value0 as a parameter.
|
||||
*
|
||||
* POST-BARRIER
|
||||
*
|
||||
* These are not yet implemented. Once we get generational GC, they will allow
|
||||
* us to keep track of pointers from non-nursery space into the nursery.
|
||||
*
|
||||
* IMPLEMENTATION DETAILS
|
||||
*
|
||||
* Since it would be awkward to change every write to memory into a function
|
||||
* call, this file contains a bunch of C++ classes and templates that use
|
||||
* operator overloading to take care of barriers automatically. In many cases,
|
||||
* all that's necessary to make some field be barriered is to replace
|
||||
* Type *field;
|
||||
* with
|
||||
* HeapPtr<Type> field;
|
||||
* There are also special classes HeapValue and HeapId, which barrier js::Value
|
||||
* and jsid, respectively.
|
||||
*
|
||||
* One additional note: not all object writes need to be barriered. Writes to
|
||||
* newly allocated objects do not need a pre-barrier. In these cases, we use
|
||||
* the "obj->field.init(value)" method instead of "obj->field = value". We use
|
||||
* the init naming idiom in many places to signify that a field is being
|
||||
* assigned for the first time.
|
||||
*/
|
||||
|
||||
struct JSXML;
|
||||
|
||||
namespace js {
|
||||
|
||||
template<class T, typename Unioned = uintptr_t>
|
||||
class EncapsulatedPtr
|
||||
{
|
||||
protected:
|
||||
union {
|
||||
T *value;
|
||||
Unioned other;
|
||||
};
|
||||
|
||||
public:
|
||||
EncapsulatedPtr() : value(NULL) {}
|
||||
EncapsulatedPtr(T *v) : value(v) {}
|
||||
explicit EncapsulatedPtr(const EncapsulatedPtr<T> &v) : value(v.value) {}
|
||||
|
||||
~EncapsulatedPtr() { pre(); }
|
||||
|
||||
/* Use to set the pointer to NULL. */
|
||||
void clear() {
|
||||
pre();
|
||||
value = NULL;
|
||||
}
|
||||
|
||||
EncapsulatedPtr<T, Unioned> &operator=(T *v) {
|
||||
pre();
|
||||
JS_ASSERT(!IsPoisonedPtr<T>(v));
|
||||
value = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
EncapsulatedPtr<T, Unioned> &operator=(const EncapsulatedPtr<T> &v) {
|
||||
pre();
|
||||
JS_ASSERT(!IsPoisonedPtr<T>(v.value));
|
||||
value = v.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* Use this if the automatic coercion to T* isn't working. */
|
||||
T *get() const { return value; }
|
||||
|
||||
/*
|
||||
* Use these if you want to change the value without invoking the barrier.
|
||||
* Obviously this is dangerous unless you know the barrier is not needed.
|
||||
*/
|
||||
T **unsafeGet() { return &value; }
|
||||
void unsafeSet(T *v) { value = v; }
|
||||
|
||||
Unioned *unsafeGetUnioned() { return &other; }
|
||||
|
||||
T &operator*() const { return *value; }
|
||||
T *operator->() const { return value; }
|
||||
|
||||
operator T*() const { return value; }
|
||||
|
||||
protected:
|
||||
void pre();
|
||||
};
|
||||
|
||||
template <class T, class Unioned = uintptr_t>
|
||||
class HeapPtr : public EncapsulatedPtr<T, Unioned>
|
||||
{
|
||||
public:
|
||||
HeapPtr() : EncapsulatedPtr<T>(NULL) {}
|
||||
explicit HeapPtr(T *v) : EncapsulatedPtr<T>(v) { post(); }
|
||||
explicit HeapPtr(const HeapPtr<T> &v)
|
||||
: EncapsulatedPtr<T>(v) { post(); }
|
||||
|
||||
void init(T *v) {
|
||||
JS_ASSERT(!IsPoisonedPtr<T>(v));
|
||||
this->value = v;
|
||||
post();
|
||||
}
|
||||
|
||||
HeapPtr<T, Unioned> &operator=(T *v) {
|
||||
this->pre();
|
||||
JS_ASSERT(!IsPoisonedPtr<T>(v));
|
||||
this->value = v;
|
||||
post();
|
||||
return *this;
|
||||
}
|
||||
|
||||
HeapPtr<T, Unioned> &operator=(const HeapPtr<T> &v) {
|
||||
this->pre();
|
||||
JS_ASSERT(!IsPoisonedPtr<T>(v.value));
|
||||
this->value = v.value;
|
||||
post();
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
void post() { T::writeBarrierPost(this->value, (void *)&this->value); }
|
||||
|
||||
/* Make this friend so it can access pre() and post(). */
|
||||
template<class T1, class T2>
|
||||
friend inline void
|
||||
BarrieredSetPair(JSCompartment *comp,
|
||||
HeapPtr<T1> &v1, T1 *val1,
|
||||
HeapPtr<T2> &v2, T2 *val2);
|
||||
};
|
||||
|
||||
/*
|
||||
* FixedHeapPtr is designed for one very narrow case: replacing immutable raw
|
||||
* pointers to GC-managed things, implicitly converting to a handle type for
|
||||
* ease of use. Pointers encapsulated by this type must:
|
||||
*
|
||||
* be immutable (no incremental write barriers),
|
||||
* never point into the nursery (no generational write barriers), and
|
||||
* be traced via MarkRuntime (we use fromMarkedLocation).
|
||||
*
|
||||
* In short: you *really* need to know what you're doing before you use this
|
||||
* class!
|
||||
*/
|
||||
template <class T>
|
||||
class FixedHeapPtr
|
||||
{
|
||||
T *value;
|
||||
|
||||
public:
|
||||
operator T*() const { return value; }
|
||||
T * operator->() const { return value; }
|
||||
|
||||
operator Handle<T*>() const {
|
||||
return Handle<T*>::fromMarkedLocation(&value);
|
||||
}
|
||||
|
||||
void init(T *ptr) {
|
||||
value = ptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class RelocatablePtr : public EncapsulatedPtr<T>
|
||||
{
|
||||
public:
|
||||
RelocatablePtr() : EncapsulatedPtr<T>(NULL) {}
|
||||
explicit RelocatablePtr(T *v) : EncapsulatedPtr<T>(v) {
|
||||
if (v)
|
||||
post();
|
||||
}
|
||||
explicit RelocatablePtr(const RelocatablePtr<T> &v) : EncapsulatedPtr<T>(v) {
|
||||
if (this->value)
|
||||
post();
|
||||
}
|
||||
|
||||
~RelocatablePtr() {
|
||||
if (this->value)
|
||||
relocate(this->value->compartment());
|
||||
}
|
||||
|
||||
RelocatablePtr<T> &operator=(T *v) {
|
||||
this->pre();
|
||||
JS_ASSERT(!IsPoisonedPtr<T>(v));
|
||||
if (v) {
|
||||
this->value = v;
|
||||
post();
|
||||
} else if (this->value) {
|
||||
JSCompartment *comp = this->value->compartment();
|
||||
this->value = v;
|
||||
relocate(comp);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
RelocatablePtr<T> &operator=(const RelocatablePtr<T> &v) {
|
||||
this->pre();
|
||||
JS_ASSERT(!IsPoisonedPtr<T>(v.value));
|
||||
if (v.value) {
|
||||
this->value = v.value;
|
||||
post();
|
||||
} else if (this->value) {
|
||||
JSCompartment *comp = this->value->compartment();
|
||||
this->value = v;
|
||||
relocate(comp);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
inline void post();
|
||||
inline void relocate(JSCompartment *comp);
|
||||
};
|
||||
|
||||
/*
|
||||
* This is a hack for RegExpStatics::updateFromMatch. It allows us to do two
|
||||
* barriers with only one branch to check if we're in an incremental GC.
|
||||
*/
|
||||
template<class T1, class T2>
|
||||
static inline void
|
||||
BarrieredSetPair(JSCompartment *comp,
|
||||
HeapPtr<T1> &v1, T1 *val1,
|
||||
HeapPtr<T2> &v2, T2 *val2)
|
||||
{
|
||||
if (T1::needWriteBarrierPre(comp)) {
|
||||
v1.pre();
|
||||
v2.pre();
|
||||
}
|
||||
v1.unsafeSet(val1);
|
||||
v2.unsafeSet(val2);
|
||||
v1.post();
|
||||
v2.post();
|
||||
}
|
||||
|
||||
struct Shape;
|
||||
class BaseShape;
|
||||
namespace types { struct TypeObject; }
|
||||
|
||||
typedef EncapsulatedPtr<JSObject> EncapsulatedPtrObject;
|
||||
typedef EncapsulatedPtr<JSScript> EncapsulatedPtrScript;
|
||||
|
||||
typedef RelocatablePtr<JSObject> RelocatablePtrObject;
|
||||
typedef RelocatablePtr<JSScript> RelocatablePtrScript;
|
||||
|
||||
typedef HeapPtr<JSObject> HeapPtrObject;
|
||||
typedef HeapPtr<JSFunction> HeapPtrFunction;
|
||||
typedef HeapPtr<JSString> HeapPtrString;
|
||||
typedef HeapPtr<JSScript> HeapPtrScript;
|
||||
typedef HeapPtr<Shape> HeapPtrShape;
|
||||
typedef HeapPtr<BaseShape> HeapPtrBaseShape;
|
||||
typedef HeapPtr<types::TypeObject> HeapPtrTypeObject;
|
||||
typedef HeapPtr<JSXML> HeapPtrXML;
|
||||
|
||||
/* Useful for hashtables with a HeapPtr as key. */
|
||||
template<class T>
|
||||
struct HeapPtrHasher
|
||||
{
|
||||
typedef HeapPtr<T> Key;
|
||||
typedef T *Lookup;
|
||||
|
||||
static HashNumber hash(Lookup obj) { return DefaultHasher<T *>::hash(obj); }
|
||||
static bool match(const Key &k, Lookup l) { return k.get() == l; }
|
||||
};
|
||||
|
||||
/* Specialized hashing policy for HeapPtrs. */
|
||||
template <class T>
|
||||
struct DefaultHasher< HeapPtr<T> > : HeapPtrHasher<T> { };
|
||||
|
||||
template<class T>
|
||||
struct EncapsulatedPtrHasher
|
||||
{
|
||||
typedef EncapsulatedPtr<T> Key;
|
||||
typedef T *Lookup;
|
||||
|
||||
static HashNumber hash(Lookup obj) { return DefaultHasher<T *>::hash(obj); }
|
||||
static bool match(const Key &k, Lookup l) { return k.get() == l; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct DefaultHasher< EncapsulatedPtr<T> > : EncapsulatedPtrHasher<T> { };
|
||||
|
||||
class EncapsulatedValue : public ValueOperations<EncapsulatedValue>
|
||||
{
|
||||
protected:
|
||||
Value value;
|
||||
|
||||
/*
|
||||
* Ensure that EncapsulatedValue is not constructable, except by our
|
||||
* implementations.
|
||||
*/
|
||||
EncapsulatedValue() MOZ_DELETE;
|
||||
EncapsulatedValue(const EncapsulatedValue &v) MOZ_DELETE;
|
||||
EncapsulatedValue &operator=(const Value &v) MOZ_DELETE;
|
||||
EncapsulatedValue &operator=(const EncapsulatedValue &v) MOZ_DELETE;
|
||||
|
||||
EncapsulatedValue(const Value &v) : value(v) {}
|
||||
~EncapsulatedValue() {}
|
||||
|
||||
public:
|
||||
bool operator==(const EncapsulatedValue &v) const { return value == v.value; }
|
||||
bool operator!=(const EncapsulatedValue &v) const { return value != v.value; }
|
||||
|
||||
const Value &get() const { return value; }
|
||||
Value *unsafeGet() { return &value; }
|
||||
operator const Value &() const { return value; }
|
||||
|
||||
JSGCTraceKind gcKind() const { return value.gcKind(); }
|
||||
|
||||
uint64_t asRawBits() const { return value.asRawBits(); }
|
||||
|
||||
static inline void writeBarrierPre(const Value &v);
|
||||
static inline void writeBarrierPre(JSCompartment *comp, const Value &v);
|
||||
|
||||
protected:
|
||||
inline void pre();
|
||||
inline void pre(JSCompartment *comp);
|
||||
|
||||
private:
|
||||
friend class ValueOperations<EncapsulatedValue>;
|
||||
const Value * extract() const { return &value; }
|
||||
};
|
||||
|
||||
class HeapValue : public EncapsulatedValue
|
||||
{
|
||||
public:
|
||||
explicit inline HeapValue();
|
||||
explicit inline HeapValue(const Value &v);
|
||||
explicit inline HeapValue(const HeapValue &v);
|
||||
inline ~HeapValue();
|
||||
|
||||
inline void init(const Value &v);
|
||||
inline void init(JSCompartment *comp, const Value &v);
|
||||
|
||||
inline HeapValue &operator=(const Value &v);
|
||||
inline HeapValue &operator=(const HeapValue &v);
|
||||
|
||||
/*
|
||||
* This is a faster version of operator=. Normally, operator= has to
|
||||
* determine the compartment of the value before it can decide whether to do
|
||||
* the barrier. If you already know the compartment, it's faster to pass it
|
||||
* in.
|
||||
*/
|
||||
inline void set(JSCompartment *comp, const Value &v);
|
||||
|
||||
static inline void writeBarrierPost(const Value &v, Value *addr);
|
||||
static inline void writeBarrierPost(JSCompartment *comp, const Value &v, Value *addr);
|
||||
|
||||
private:
|
||||
inline void post();
|
||||
inline void post(JSCompartment *comp);
|
||||
};
|
||||
|
||||
class RelocatableValue : public EncapsulatedValue
|
||||
{
|
||||
public:
|
||||
explicit inline RelocatableValue();
|
||||
explicit inline RelocatableValue(const Value &v);
|
||||
inline RelocatableValue(const RelocatableValue &v);
|
||||
inline ~RelocatableValue();
|
||||
|
||||
inline RelocatableValue &operator=(const Value &v);
|
||||
inline RelocatableValue &operator=(const RelocatableValue &v);
|
||||
|
||||
private:
|
||||
inline void post();
|
||||
inline void post(JSCompartment *comp);
|
||||
inline void relocate();
|
||||
};
|
||||
|
||||
class HeapSlot : public EncapsulatedValue
|
||||
{
|
||||
/*
|
||||
* Operator= is not valid for HeapSlot because is must take the object and
|
||||
* slot offset to provide to the post/generational barrier.
|
||||
*/
|
||||
inline HeapSlot &operator=(const Value &v) MOZ_DELETE;
|
||||
inline HeapSlot &operator=(const HeapValue &v) MOZ_DELETE;
|
||||
inline HeapSlot &operator=(const HeapSlot &v) MOZ_DELETE;
|
||||
|
||||
public:
|
||||
explicit inline HeapSlot() MOZ_DELETE;
|
||||
explicit inline HeapSlot(JSObject *obj, uint32_t slot, const Value &v);
|
||||
explicit inline HeapSlot(JSObject *obj, uint32_t slot, const HeapSlot &v);
|
||||
inline ~HeapSlot();
|
||||
|
||||
inline void init(JSObject *owner, uint32_t slot, const Value &v);
|
||||
inline void init(JSCompartment *comp, JSObject *owner, uint32_t slot, const Value &v);
|
||||
|
||||
inline void set(JSObject *owner, uint32_t slot, const Value &v);
|
||||
inline void set(JSCompartment *comp, JSObject *owner, uint32_t slot, const Value &v);
|
||||
|
||||
static inline void writeBarrierPost(JSObject *obj, uint32_t slot);
|
||||
static inline void writeBarrierPost(JSCompartment *comp, JSObject *obj, uint32_t slot);
|
||||
|
||||
private:
|
||||
inline void post(JSObject *owner, uint32_t slot);
|
||||
inline void post(JSCompartment *comp, JSObject *owner, uint32_t slot);
|
||||
};
|
||||
|
||||
/*
|
||||
* NOTE: This is a placeholder for bug 619558.
|
||||
*
|
||||
* Run a post write barrier that encompasses multiple contiguous slots in a
|
||||
* single step.
|
||||
*/
|
||||
inline void
|
||||
SlotRangeWriteBarrierPost(JSCompartment *comp, JSObject *obj, uint32_t start, uint32_t count);
|
||||
|
||||
/*
|
||||
* This is a post barrier for HashTables whose key can be moved during a GC.
|
||||
*/
|
||||
template <class Map, class Key>
|
||||
inline void
|
||||
HashTableWriteBarrierPost(JSCompartment *comp, const Map *map, const Key &key)
|
||||
{
|
||||
#ifdef JS_GCGENERATIONAL
|
||||
if (key && comp->gcNursery.isInside(key))
|
||||
comp->gcStoreBuffer.putGeneric(HashKeyRef(map, key));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline const Value *
|
||||
Valueify(const EncapsulatedValue *array)
|
||||
{
|
||||
JS_STATIC_ASSERT(sizeof(HeapValue) == sizeof(Value));
|
||||
JS_STATIC_ASSERT(sizeof(HeapSlot) == sizeof(Value));
|
||||
return (const Value *)array;
|
||||
}
|
||||
|
||||
static inline HeapValue *
|
||||
HeapValueify(Value *v)
|
||||
{
|
||||
JS_STATIC_ASSERT(sizeof(HeapValue) == sizeof(Value));
|
||||
JS_STATIC_ASSERT(sizeof(HeapSlot) == sizeof(Value));
|
||||
return (HeapValue *)v;
|
||||
}
|
||||
|
||||
class HeapSlotArray
|
||||
{
|
||||
HeapSlot *array;
|
||||
|
||||
public:
|
||||
HeapSlotArray(HeapSlot *array) : array(array) {}
|
||||
|
||||
operator const Value *() const { return Valueify(array); }
|
||||
operator HeapSlot *() const { return array; }
|
||||
|
||||
HeapSlotArray operator +(int offset) const { return HeapSlotArray(array + offset); }
|
||||
HeapSlotArray operator +(uint32_t offset) const { return HeapSlotArray(array + offset); }
|
||||
};
|
||||
|
||||
class EncapsulatedId
|
||||
{
|
||||
protected:
|
||||
jsid value;
|
||||
|
||||
private:
|
||||
EncapsulatedId(const EncapsulatedId &v) MOZ_DELETE;
|
||||
|
||||
public:
|
||||
explicit EncapsulatedId() : value(JSID_VOID) {}
|
||||
explicit EncapsulatedId(jsid id) : value(id) {}
|
||||
~EncapsulatedId();
|
||||
|
||||
inline EncapsulatedId &operator=(const EncapsulatedId &v);
|
||||
|
||||
bool operator==(jsid id) const { return value == id; }
|
||||
bool operator!=(jsid id) const { return value != id; }
|
||||
|
||||
jsid get() const { return value; }
|
||||
jsid *unsafeGet() { return &value; }
|
||||
operator jsid() const { return value; }
|
||||
|
||||
protected:
|
||||
inline void pre();
|
||||
};
|
||||
|
||||
class RelocatableId : public EncapsulatedId
|
||||
{
|
||||
public:
|
||||
explicit RelocatableId() : EncapsulatedId() {}
|
||||
explicit inline RelocatableId(jsid id) : EncapsulatedId(id) {}
|
||||
inline ~RelocatableId();
|
||||
|
||||
inline RelocatableId &operator=(jsid id);
|
||||
inline RelocatableId &operator=(const RelocatableId &v);
|
||||
};
|
||||
|
||||
class HeapId : public EncapsulatedId
|
||||
{
|
||||
public:
|
||||
explicit HeapId() : EncapsulatedId() {}
|
||||
explicit inline HeapId(jsid id);
|
||||
inline ~HeapId();
|
||||
|
||||
inline void init(jsid id);
|
||||
|
||||
inline HeapId &operator=(jsid id);
|
||||
inline HeapId &operator=(const HeapId &v);
|
||||
|
||||
private:
|
||||
inline void post();
|
||||
|
||||
HeapId(const HeapId &v) MOZ_DELETE;
|
||||
};
|
||||
|
||||
/*
|
||||
* Incremental GC requires that weak pointers have read barriers. This is mostly
|
||||
* an issue for empty shapes stored in JSCompartment. The problem happens when,
|
||||
* during an incremental GC, some JS code stores one of the compartment's empty
|
||||
* shapes into an object already marked black. Normally, this would not be a
|
||||
* problem, because the empty shape would have been part of the initial snapshot
|
||||
* when the GC started. However, since this is a weak pointer, it isn't. So we
|
||||
* may collect the empty shape even though a live object points to it. To fix
|
||||
* this, we mark these empty shapes black whenever they get read out.
|
||||
*/
|
||||
template<class T>
|
||||
class ReadBarriered
|
||||
{
|
||||
T *value;
|
||||
|
||||
public:
|
||||
ReadBarriered() : value(NULL) {}
|
||||
ReadBarriered(T *value) : value(value) {}
|
||||
|
||||
T *get() const {
|
||||
if (!value)
|
||||
return NULL;
|
||||
T::readBarrier(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
operator T*() const { return get(); }
|
||||
|
||||
T &operator*() const { return *get(); }
|
||||
T *operator->() const { return get(); }
|
||||
|
||||
T **unsafeGet() { return &value; }
|
||||
|
||||
void set(T *v) { value = v; }
|
||||
|
||||
operator bool() { return !!value; }
|
||||
};
|
||||
|
||||
class ReadBarrieredValue
|
||||
{
|
||||
Value value;
|
||||
|
||||
public:
|
||||
ReadBarrieredValue() : value(UndefinedValue()) {}
|
||||
ReadBarrieredValue(const Value &value) : value(value) {}
|
||||
|
||||
inline const Value &get() const;
|
||||
Value *unsafeGet() { return &value; }
|
||||
inline operator const Value &() const;
|
||||
|
||||
inline JSObject &toObject() const;
|
||||
};
|
||||
|
||||
namespace tl {
|
||||
|
||||
template <class T> struct IsRelocatableHeapType<HeapPtr<T> >
|
||||
{ static const bool result = false; };
|
||||
template <> struct IsRelocatableHeapType<HeapSlot> { static const bool result = false; };
|
||||
template <> struct IsRelocatableHeapType<HeapValue> { static const bool result = false; };
|
||||
template <> struct IsRelocatableHeapType<HeapId> { static const bool result = false; };
|
||||
|
||||
} /* namespace tl */
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsgc_barrier_h___ */
|
File diff suppressed because it is too large
Load Diff
|
@ -77,8 +77,14 @@ class MutableHandleBase {};
|
|||
|
||||
namespace JS {
|
||||
|
||||
class AutoAssertNoGC;
|
||||
|
||||
template <typename T> class MutableHandle;
|
||||
|
||||
JS_FRIEND_API(void) EnterAssertNoGCScope();
|
||||
JS_FRIEND_API(void) LeaveAssertNoGCScope();
|
||||
JS_FRIEND_API(bool) InNoGCScope();
|
||||
|
||||
/*
|
||||
* Handle provides an implicit constructor for NullPtr so that, given:
|
||||
* foo(Handle<JSObject*> h);
|
||||
|
@ -316,6 +322,169 @@ class InternalHandle<T*>
|
|||
}
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
template <typename T>
|
||||
class IntermediateNoGC
|
||||
{
|
||||
T t_;
|
||||
|
||||
public:
|
||||
IntermediateNoGC(const T &t) : t_(t) {
|
||||
EnterAssertNoGCScope();
|
||||
}
|
||||
IntermediateNoGC(const IntermediateNoGC &) {
|
||||
EnterAssertNoGCScope();
|
||||
}
|
||||
~IntermediateNoGC() {
|
||||
LeaveAssertNoGCScope();
|
||||
}
|
||||
|
||||
const T &operator->() { return t_; }
|
||||
operator const T &() { return t_; }
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return<T> wraps GC things that are returned from accessor methods. The
|
||||
* wrapper helps to ensure correct rooting of the returned pointer and safe
|
||||
* access while unrooted.
|
||||
*
|
||||
* Example usage in a method declaration:
|
||||
*
|
||||
* class Foo {
|
||||
* HeapPtrScript script_;
|
||||
* ...
|
||||
* public:
|
||||
* Return<JSScript*> script() { return script_; }
|
||||
* };
|
||||
*
|
||||
* Example usage of method (1):
|
||||
*
|
||||
* Foo foo(...);
|
||||
* RootedScript script(cx, foo->script());
|
||||
*
|
||||
* Example usage of method (2):
|
||||
*
|
||||
* Foo foo(...);
|
||||
* foo->script()->needsArgsObj();
|
||||
*
|
||||
* The purpose of this class is to assert eagerly on incorrect use of GC thing
|
||||
* pointers. For example:
|
||||
*
|
||||
* RootedShape shape(cx, ...);
|
||||
* shape->parent.init(js_NewGCThing<Shape*>(cx, ...));
|
||||
*
|
||||
* In this expression, C++ is allowed to order these calls as follows:
|
||||
*
|
||||
* Call Effect
|
||||
* ---- ------
|
||||
* 1) RootedShape::operator-> Stores shape::ptr_ to stack.
|
||||
* 2) js_NewGCThing<Shape*> Triggers GC and compaction of shapes. This
|
||||
* moves shape::ptr_ to a new location.
|
||||
* 3) HeapPtrObject::init This call takes the relocated shape::ptr_
|
||||
* as |this|, crashing or, worse, corrupting
|
||||
* the program's state on the first access
|
||||
* to a member variable.
|
||||
*
|
||||
* If Shape::parent were an accessor function returning a Return<Shape*>, this
|
||||
* could not happen: Return ensures either immediate rooting or no GC within
|
||||
* the same expression.
|
||||
*/
|
||||
template <typename T>
|
||||
class Return
|
||||
{
|
||||
friend class Rooted<T>;
|
||||
|
||||
const T ptr_;
|
||||
|
||||
public:
|
||||
template <typename S>
|
||||
Return(const S &ptr,
|
||||
typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0)
|
||||
: ptr_(ptr)
|
||||
{}
|
||||
|
||||
Return(NullPtr) : ptr_(NULL) {}
|
||||
|
||||
/*
|
||||
* |get(AutoAssertNoGC &)| is the safest way to access a Return<T> without
|
||||
* rooting it first: it is impossible to call this method without an
|
||||
* AutoAssertNoGC in scope, so the compiler will automatically catch any
|
||||
* incorrect usage.
|
||||
*
|
||||
* Example:
|
||||
* AutoAssertNoGC nogc;
|
||||
* RawScript script = fun->script().get(nogc);
|
||||
*/
|
||||
const T &get(AutoAssertNoGC &) const {
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
/*
|
||||
* |operator->|'s result cannot be stored in a local variable, so it is safe
|
||||
* to use in a CanGC context iff no GC can occur anywhere within the same
|
||||
* expression (generally from one |;| to the next). |operator->| uses a
|
||||
* temporary object as a guard and will assert if a CanGC context is
|
||||
* encountered before the next C++ Sequence Point.
|
||||
*
|
||||
* INCORRECT:
|
||||
* fun->script()->bindings = myBindings->clone(cx, ...);
|
||||
*
|
||||
* The compiler is allowed to reorder |fun->script()::operator->()| above
|
||||
* the call to |clone(cx, ...)|. In this case, the RawScript C++ stores on
|
||||
* the stack may be corrupted by a GC under |clone|. The subsequent
|
||||
* dereference of this pointer to get |bindings| will result in an invalid
|
||||
* access. This wrapper ensures that such usage asserts in DEBUG builds when
|
||||
* it encounters this situation. Without this assertion, it is possible for
|
||||
* such access to corrupt program state instead of crashing immediately.
|
||||
*
|
||||
* CORRECT:
|
||||
* RootedScript clone(cx, myBindings->clone(cx, ...));
|
||||
* fun->script()->bindings = clone;
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
IntermediateNoGC<T> operator->() const {
|
||||
return IntermediateNoGC<T>(ptr_);
|
||||
}
|
||||
#else
|
||||
const T &operator->() const {
|
||||
return ptr_;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* |unsafeGet()| is unsafe for most uses. Although it performs similar
|
||||
* checking to |operator->|, its result can be stored to a local variable.
|
||||
* For this reason, it should only be used when it would be incorrect or
|
||||
* absurd to create a new Rooted for its use: e.g. for assertions.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
IntermediateNoGC<T> unsafeGet() const {
|
||||
return IntermediateNoGC<T>(ptr_);
|
||||
}
|
||||
#else
|
||||
const T &unsafeGet() const {
|
||||
return ptr_;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* |operator==| is safe to use in any context. It is present to allow:
|
||||
* JS_ASSERT(myScript == fun->script().unsafeGet());
|
||||
*
|
||||
* To be rewritten as:
|
||||
* JS_ASSERT(fun->script() == myScript);
|
||||
*
|
||||
* Note: the new order tells C++ to use |Return<JSScript*>::operator=|
|
||||
* instead of direct pointer comparison.
|
||||
*/
|
||||
bool operator==(const T &other) { return ptr_ == other; }
|
||||
bool operator!=(const T &other) { return ptr_ != other; }
|
||||
bool operator==(const Return<T> &other) { return ptr_ == other.ptr_; }
|
||||
bool operator==(const JS::Handle<T> &other) { return ptr_ == other.get(); }
|
||||
inline bool operator==(const Rooted<T> &other);
|
||||
};
|
||||
|
||||
/*
|
||||
* By default, pointers should use the inheritance hierarchy to find their
|
||||
* ThingRootKind. Some pointer types are explicitly set in jspubtd.h so that
|
||||
|
@ -332,12 +501,6 @@ struct RootMethods<T *>
|
|||
static bool poisoned(T *v) { return IsPoisonedPtr(v); }
|
||||
};
|
||||
|
||||
#if !(defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING))
|
||||
// Defined in vm/String.h.
|
||||
template <>
|
||||
class Rooted<JSStableString *>;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
class RootedBase {};
|
||||
|
||||
|
@ -356,27 +519,23 @@ class Rooted : public RootedBase<T>
|
|||
{
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
ContextFriendFields *cx = ContextFriendFields::get(cxArg);
|
||||
|
||||
ThingRootKind kind = RootMethods<T>::kind();
|
||||
this->stack = reinterpret_cast<Rooted<T>**>(&cx->thingGCRooters[kind]);
|
||||
this->prev = *stack;
|
||||
*stack = this;
|
||||
|
||||
JS_ASSERT(!RootMethods<T>::poisoned(ptr));
|
||||
commonInit(cx->thingGCRooters);
|
||||
#endif
|
||||
}
|
||||
|
||||
void init(JSRuntime *rtArg)
|
||||
{
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
RuntimeFriendFields *rt = const_cast<RuntimeFriendFields *>(RuntimeFriendFields::get(rtArg));
|
||||
PerThreadDataFriendFields *pt = PerThreadDataFriendFields::getMainThread(rtArg);
|
||||
commonInit(pt->thingGCRooters);
|
||||
#endif
|
||||
}
|
||||
|
||||
ThingRootKind kind = RootMethods<T>::kind();
|
||||
this->stack = reinterpret_cast<Rooted<T>**>(&rt->thingGCRooters[kind]);
|
||||
this->prev = *stack;
|
||||
*stack = this;
|
||||
|
||||
JS_ASSERT(!RootMethods<T>::poisoned(ptr));
|
||||
void init(js::PerThreadData *ptArg)
|
||||
{
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
PerThreadDataFriendFields *pt = PerThreadDataFriendFields::get(ptArg);
|
||||
commonInit(pt->thingGCRooters);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -413,6 +572,40 @@ class Rooted : public RootedBase<T>
|
|||
init(cx);
|
||||
}
|
||||
|
||||
Rooted(js::PerThreadData *pt
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: ptr(RootMethods<T>::initial())
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(pt);
|
||||
}
|
||||
|
||||
Rooted(js::PerThreadData *pt, T initial
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: ptr(initial)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(pt);
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
Rooted(JSContext *cx, const Return<S> &initial
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: ptr(initial.ptr_)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(cx);
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
Rooted(js::PerThreadData *pt, const Return<S> &initial
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: ptr(initial.ptr_)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(pt);
|
||||
}
|
||||
|
||||
~Rooted()
|
||||
{
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
|
@ -445,7 +638,25 @@ class Rooted : public RootedBase<T>
|
|||
return ptr;
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
T & operator =(const Return<S> &value)
|
||||
{
|
||||
ptr = value.ptr_;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
void commonInit(Rooted<void*> **thingGCRooters) {
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
ThingRootKind kind = RootMethods<T>::kind();
|
||||
this->stack = reinterpret_cast<Rooted<T>**>(&thingGCRooters[kind]);
|
||||
this->prev = *stack;
|
||||
*stack = this;
|
||||
|
||||
JS_ASSERT(!RootMethods<T>::poisoned(ptr));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
Rooted<T> **stack, *prev;
|
||||
#endif
|
||||
|
@ -455,6 +666,19 @@ class Rooted : public RootedBase<T>
|
|||
Rooted(const Rooted &) MOZ_DELETE;
|
||||
};
|
||||
|
||||
#if !(defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING))
|
||||
// Defined in vm/String.h.
|
||||
template <>
|
||||
class Rooted<JSStableString *>;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
Return<T>::operator==(const Rooted<T> &other)
|
||||
{
|
||||
return ptr_ == other.get();
|
||||
}
|
||||
|
||||
typedef Rooted<JSObject*> RootedObject;
|
||||
typedef Rooted<JSFunction*> RootedFunction;
|
||||
typedef Rooted<JSScript*> RootedScript;
|
||||
|
@ -550,10 +774,6 @@ MutableHandle<T>::MutableHandle(js::Rooted<S> *root,
|
|||
ptr = root->address();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void) EnterAssertNoGCScope();
|
||||
JS_FRIEND_API(void) LeaveAssertNoGCScope();
|
||||
JS_FRIEND_API(bool) InNoGCScope();
|
||||
|
||||
/*
|
||||
* The scoped guard object AutoAssertNoGC forces the GC to assert if a GC is
|
||||
* attempted while the guard object is live. If you have a GC-unsafe operation
|
||||
|
@ -581,15 +801,11 @@ public:
|
|||
/*
|
||||
* AssertCanGC will assert if it is called inside of an AutoAssertNoGC region.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
JS_ALWAYS_INLINE void
|
||||
AssertCanGC()
|
||||
{
|
||||
JS_ASSERT(!InNoGCScope());
|
||||
}
|
||||
#else
|
||||
# define AssertCanGC()
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
|
||||
extern void
|
||||
|
|
|
@ -1,193 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef jsgc_statistics_h___
|
||||
#define jsgc_statistics_h___
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "jspubtd.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
struct JSCompartment;
|
||||
|
||||
namespace js {
|
||||
namespace gcstats {
|
||||
|
||||
enum Phase {
|
||||
PHASE_GC_BEGIN,
|
||||
PHASE_WAIT_BACKGROUND_THREAD,
|
||||
PHASE_PURGE,
|
||||
PHASE_MARK,
|
||||
PHASE_MARK_DISCARD_CODE,
|
||||
PHASE_MARK_ROOTS,
|
||||
PHASE_MARK_TYPES,
|
||||
PHASE_MARK_DELAYED,
|
||||
PHASE_MARK_WEAK,
|
||||
PHASE_MARK_GRAY,
|
||||
PHASE_MARK_GRAY_WEAK,
|
||||
PHASE_FINALIZE_START,
|
||||
PHASE_SWEEP,
|
||||
PHASE_SWEEP_ATOMS,
|
||||
PHASE_SWEEP_COMPARTMENTS,
|
||||
PHASE_SWEEP_TABLES,
|
||||
PHASE_SWEEP_OBJECT,
|
||||
PHASE_SWEEP_STRING,
|
||||
PHASE_SWEEP_SCRIPT,
|
||||
PHASE_SWEEP_SHAPE,
|
||||
PHASE_SWEEP_IONCODE,
|
||||
PHASE_SWEEP_DISCARD_CODE,
|
||||
PHASE_DISCARD_ANALYSIS,
|
||||
PHASE_DISCARD_TI,
|
||||
PHASE_FREE_TI_ARENA,
|
||||
PHASE_SWEEP_TYPES,
|
||||
PHASE_CLEAR_SCRIPT_ANALYSIS,
|
||||
PHASE_FINALIZE_END,
|
||||
PHASE_DESTROY,
|
||||
PHASE_GC_END,
|
||||
|
||||
PHASE_LIMIT
|
||||
};
|
||||
|
||||
enum Stat {
|
||||
STAT_NEW_CHUNK,
|
||||
STAT_DESTROY_CHUNK,
|
||||
|
||||
STAT_LIMIT
|
||||
};
|
||||
|
||||
class StatisticsSerializer;
|
||||
|
||||
struct Statistics {
|
||||
Statistics(JSRuntime *rt);
|
||||
~Statistics();
|
||||
|
||||
void beginPhase(Phase phase);
|
||||
void endPhase(Phase phase);
|
||||
|
||||
void beginSlice(int collectedCount, int compartmentCount, gcreason::Reason reason);
|
||||
void endSlice();
|
||||
|
||||
void reset(const char *reason) { slices.back().resetReason = reason; }
|
||||
void nonincremental(const char *reason) { nonincrementalReason = reason; }
|
||||
|
||||
void count(Stat s) {
|
||||
JS_ASSERT(s < STAT_LIMIT);
|
||||
counts[s]++;
|
||||
}
|
||||
|
||||
int64_t beginSCC();
|
||||
void endSCC(unsigned scc, int64_t start);
|
||||
|
||||
jschar *formatMessage();
|
||||
jschar *formatJSON(uint64_t timestamp);
|
||||
|
||||
private:
|
||||
JSRuntime *runtime;
|
||||
|
||||
int64_t startupTime;
|
||||
|
||||
FILE *fp;
|
||||
bool fullFormat;
|
||||
|
||||
/*
|
||||
* GCs can't really nest, but a second GC can be triggered from within the
|
||||
* JSGC_END callback.
|
||||
*/
|
||||
int gcDepth;
|
||||
|
||||
int collectedCount;
|
||||
int compartmentCount;
|
||||
const char *nonincrementalReason;
|
||||
|
||||
struct SliceData {
|
||||
SliceData(gcreason::Reason reason, int64_t start, size_t startFaults)
|
||||
: reason(reason), resetReason(NULL), start(start), startFaults(startFaults)
|
||||
{
|
||||
PodArrayZero(phaseTimes);
|
||||
}
|
||||
|
||||
gcreason::Reason reason;
|
||||
const char *resetReason;
|
||||
int64_t start, end;
|
||||
size_t startFaults, endFaults;
|
||||
int64_t phaseTimes[PHASE_LIMIT];
|
||||
|
||||
int64_t duration() const { return end - start; }
|
||||
};
|
||||
|
||||
Vector<SliceData, 8, SystemAllocPolicy> slices;
|
||||
|
||||
/* Most recent time when the given phase started. */
|
||||
int64_t phaseStartTimes[PHASE_LIMIT];
|
||||
|
||||
/* Total time in a given phase for this GC. */
|
||||
int64_t phaseTimes[PHASE_LIMIT];
|
||||
|
||||
/* Total time in a given phase over all GCs. */
|
||||
int64_t phaseTotals[PHASE_LIMIT];
|
||||
|
||||
/* Number of events of this type for this GC. */
|
||||
unsigned int counts[STAT_LIMIT];
|
||||
|
||||
/* Allocated space before the GC started. */
|
||||
size_t preBytes;
|
||||
|
||||
/* Sweep times for SCCs of compartments. */
|
||||
Vector<int64_t, 0, SystemAllocPolicy> sccTimes;
|
||||
|
||||
void beginGC();
|
||||
void endGC();
|
||||
|
||||
void gcDuration(int64_t *total, int64_t *maxPause);
|
||||
void sccDurations(int64_t *total, int64_t *maxPause);
|
||||
void printStats();
|
||||
bool formatData(StatisticsSerializer &ss, uint64_t timestamp);
|
||||
|
||||
double computeMMU(int64_t resolution);
|
||||
};
|
||||
|
||||
struct AutoGCSlice {
|
||||
AutoGCSlice(Statistics &stats, int collectedCount, int compartmentCount, gcreason::Reason reason
|
||||
JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: stats(stats)
|
||||
{
|
||||
JS_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
stats.beginSlice(collectedCount, compartmentCount, reason);
|
||||
}
|
||||
~AutoGCSlice() { stats.endSlice(); }
|
||||
|
||||
Statistics &stats;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
struct AutoPhase {
|
||||
AutoPhase(Statistics &stats, Phase phase JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: stats(stats), phase(phase) { JS_GUARD_OBJECT_NOTIFIER_INIT; stats.beginPhase(phase); }
|
||||
~AutoPhase() { stats.endPhase(phase); }
|
||||
|
||||
Statistics &stats;
|
||||
Phase phase;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
struct AutoSCC {
|
||||
AutoSCC(Statistics &stats, unsigned scc JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: stats(stats), scc(scc) { JS_GUARD_OBJECT_NOTIFIER_INIT; start = stats.beginSCC(); }
|
||||
~AutoSCC() { stats.endSCC(scc, start); }
|
||||
|
||||
Statistics &stats;
|
||||
unsigned scc;
|
||||
int64_t start;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
} /* namespace gcstats */
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsgc_statistics_h___ */
|
|
@ -1,398 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
#ifndef jsgc_storebuffer_h___
|
||||
#define jsgc_storebuffer_h___
|
||||
|
||||
#include "jsgc.h"
|
||||
#include "jsalloc.h"
|
||||
|
||||
#include "gc/Marking.h"
|
||||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
/*
|
||||
* Note: this is a stub Nursery that does not actually contain a heap, just a
|
||||
* set of pointers which are "inside" the nursery to implement verification.
|
||||
*/
|
||||
class Nursery
|
||||
{
|
||||
HashSet<void*, PointerHasher<void*, 3>, SystemAllocPolicy> nursery;
|
||||
|
||||
public:
|
||||
Nursery() : nursery() {}
|
||||
|
||||
bool enable() {
|
||||
if (!nursery.initialized())
|
||||
return nursery.init();
|
||||
return true;
|
||||
}
|
||||
|
||||
void disable() {
|
||||
if (!nursery.initialized())
|
||||
return;
|
||||
nursery.finish();
|
||||
}
|
||||
|
||||
bool isInside(void *cell) const {
|
||||
JS_ASSERT((uintptr_t(cell) & 0x3) == 0);
|
||||
return nursery.initialized() && nursery.has(cell);
|
||||
}
|
||||
|
||||
void insertPointer(void *cell) {
|
||||
nursery.putNew(cell);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* BufferableRef represents an abstract reference for use in the generational
|
||||
* GC's remembered set. Entries in the store buffer that cannot be represented
|
||||
* with the simple pointer-to-a-pointer scheme must derive from this class and
|
||||
* use the generic store buffer interface.
|
||||
*/
|
||||
class BufferableRef
|
||||
{
|
||||
public:
|
||||
virtual bool match(void *location) = 0;
|
||||
virtual void mark(JSTracer *trc) = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
* HashKeyRef represents a reference to a HashTable key. Manual HashTable
|
||||
* barriers should should instantiate this template with their own table/key
|
||||
* type to insert into the generic buffer with putGeneric.
|
||||
*/
|
||||
template <typename Map, typename Key>
|
||||
class HashKeyRef : public BufferableRef
|
||||
{
|
||||
Map *map;
|
||||
Key key;
|
||||
|
||||
typedef typename Map::Ptr Ptr;
|
||||
|
||||
public:
|
||||
HashKeyRef(Map *m, const Key &k) : map(m), key(k) {}
|
||||
|
||||
bool match(void *location) {
|
||||
Ptr p = map->lookup(key);
|
||||
if (!p)
|
||||
return false;
|
||||
return &p->key == location;
|
||||
}
|
||||
|
||||
void mark(JSTracer *trc) {}
|
||||
};
|
||||
|
||||
/*
|
||||
* The StoreBuffer observes all writes that occur in the system and performs
|
||||
* efficient filtering of them to derive a remembered set for nursery GC.
|
||||
*/
|
||||
class StoreBuffer
|
||||
{
|
||||
/* TODO: profile to find the ideal size for these. */
|
||||
static const size_t ValueBufferSize = 1 * 1024 * sizeof(Value *);
|
||||
static const size_t CellBufferSize = 2 * 1024 * sizeof(Cell **);
|
||||
static const size_t SlotBufferSize = 2 * 1024 * (sizeof(JSObject *) + sizeof(uint32_t));
|
||||
static const size_t RelocValueBufferSize = 1 * 1024 * sizeof(Value *);
|
||||
static const size_t RelocCellBufferSize = 1 * 1024 * sizeof(Cell **);
|
||||
static const size_t GenericBufferSize = 1 * 1024 * sizeof(int);
|
||||
static const size_t TotalSize = ValueBufferSize + CellBufferSize +
|
||||
SlotBufferSize + RelocValueBufferSize + RelocCellBufferSize +
|
||||
GenericBufferSize;
|
||||
|
||||
typedef HashSet<void *, PointerHasher<void *, 3>, SystemAllocPolicy> EdgeSet;
|
||||
|
||||
/*
|
||||
* This buffer holds only a single type of edge. Using this buffer is more
|
||||
* efficient than the generic buffer when many writes will be to the same
|
||||
* type of edge: e.g. Value or Cell*.
|
||||
*/
|
||||
template<typename T>
|
||||
class MonoTypeBuffer
|
||||
{
|
||||
friend class StoreBuffer;
|
||||
|
||||
StoreBuffer *owner;
|
||||
Nursery *nursery;
|
||||
|
||||
T *base; /* Pointer to the start of the buffer. */
|
||||
T *pos; /* Pointer to the current insertion position. */
|
||||
T *top; /* Pointer to one element after the end. */
|
||||
|
||||
MonoTypeBuffer(StoreBuffer *owner, Nursery *nursery)
|
||||
: owner(owner), nursery(nursery), base(NULL), pos(NULL), top(NULL)
|
||||
{}
|
||||
|
||||
MonoTypeBuffer &operator=(const MonoTypeBuffer& other) MOZ_DELETE;
|
||||
|
||||
bool enable(uint8_t *region, size_t len);
|
||||
void disable();
|
||||
|
||||
bool isEmpty() const { return pos == base; }
|
||||
bool isFull() const { JS_ASSERT(pos <= top); return pos == top; }
|
||||
|
||||
/* Compaction algorithms. */
|
||||
void compactNotInSet();
|
||||
|
||||
/*
|
||||
* Attempts to reduce the usage of the buffer by removing unnecessary
|
||||
* entries.
|
||||
*/
|
||||
virtual void compact();
|
||||
|
||||
/* Add one item to the buffer. */
|
||||
void put(const T &v);
|
||||
|
||||
/* For verification. */
|
||||
bool accumulateEdges(EdgeSet &edges);
|
||||
};
|
||||
|
||||
/*
|
||||
* Overrides the MonoTypeBuffer to support pointers that may be moved in
|
||||
* memory outside of the GC's control.
|
||||
*/
|
||||
template <typename T>
|
||||
class RelocatableMonoTypeBuffer : public MonoTypeBuffer<T>
|
||||
{
|
||||
friend class StoreBuffer;
|
||||
|
||||
RelocatableMonoTypeBuffer(StoreBuffer *owner, Nursery *nursery)
|
||||
: MonoTypeBuffer<T>(owner, nursery)
|
||||
{}
|
||||
|
||||
/* Override compaction to filter out removed items. */
|
||||
void compactMoved();
|
||||
virtual void compact();
|
||||
|
||||
/* Record a removal from the buffer. */
|
||||
void unput(const T &v);
|
||||
};
|
||||
|
||||
class GenericBuffer
|
||||
{
|
||||
friend class StoreBuffer;
|
||||
|
||||
StoreBuffer *owner;
|
||||
Nursery *nursery;
|
||||
|
||||
uint8_t *base; /* Pointer to start of buffer. */
|
||||
uint8_t *pos; /* Pointer to current buffer position. */
|
||||
uint8_t *top; /* Pointer to one past the last entry. */
|
||||
|
||||
GenericBuffer(StoreBuffer *owner, Nursery *nursery)
|
||||
: owner(owner), nursery(nursery)
|
||||
{}
|
||||
|
||||
GenericBuffer &operator=(const GenericBuffer& other) MOZ_DELETE;
|
||||
|
||||
bool enable(uint8_t *region, size_t len);
|
||||
void disable();
|
||||
|
||||
/* Check if a pointer is present in the buffer. */
|
||||
bool containsEdge(void *location) const;
|
||||
|
||||
template <typename T>
|
||||
void put(const T &t) {
|
||||
/* Check if we have been enabled. */
|
||||
if (!pos)
|
||||
return;
|
||||
|
||||
/* Check for overflow. */
|
||||
if (top - pos < (unsigned)(sizeof(unsigned) + sizeof(T))) {
|
||||
owner->setOverflowed();
|
||||
return;
|
||||
}
|
||||
|
||||
*((unsigned *)pos) = sizeof(T);
|
||||
pos += sizeof(unsigned);
|
||||
|
||||
T *p = (T *)pos;
|
||||
new (p) T(t);
|
||||
pos += sizeof(T);
|
||||
}
|
||||
};
|
||||
|
||||
class CellPtrEdge
|
||||
{
|
||||
friend class StoreBuffer;
|
||||
friend class StoreBuffer::MonoTypeBuffer<CellPtrEdge>;
|
||||
friend class StoreBuffer::RelocatableMonoTypeBuffer<CellPtrEdge>;
|
||||
|
||||
Cell **edge;
|
||||
|
||||
CellPtrEdge(Cell **v) : edge(v) {}
|
||||
bool operator==(const CellPtrEdge &other) const { return edge == other.edge; }
|
||||
bool operator!=(const CellPtrEdge &other) const { return edge != other.edge; }
|
||||
|
||||
void *location() const { return (void *)edge; }
|
||||
|
||||
bool inRememberedSet(Nursery *n) {
|
||||
return !n->isInside(edge) && n->isInside(*edge);
|
||||
}
|
||||
|
||||
bool isNullEdge() const {
|
||||
return !*edge;
|
||||
}
|
||||
|
||||
CellPtrEdge tagged() const { return CellPtrEdge((Cell **)(uintptr_t(edge) | 1)); }
|
||||
CellPtrEdge untagged() const { return CellPtrEdge((Cell **)(uintptr_t(edge) & ~1)); }
|
||||
bool isTagged() const { return bool(uintptr_t(edge) & 1); }
|
||||
};
|
||||
|
||||
class ValueEdge
|
||||
{
|
||||
friend class StoreBuffer;
|
||||
friend class StoreBuffer::MonoTypeBuffer<ValueEdge>;
|
||||
friend class StoreBuffer::RelocatableMonoTypeBuffer<ValueEdge>;
|
||||
|
||||
Value *edge;
|
||||
|
||||
ValueEdge(Value *v) : edge(v) {}
|
||||
bool operator==(const ValueEdge &other) const { return edge == other.edge; }
|
||||
bool operator!=(const ValueEdge &other) const { return edge != other.edge; }
|
||||
|
||||
void *deref() const { return edge->isGCThing() ? edge->toGCThing() : NULL; }
|
||||
void *location() const { return (void *)edge; }
|
||||
|
||||
bool inRememberedSet(Nursery *n) {
|
||||
return !n->isInside(edge) && n->isInside(deref());
|
||||
}
|
||||
|
||||
bool isNullEdge() const {
|
||||
return !deref();
|
||||
}
|
||||
|
||||
ValueEdge tagged() const { return ValueEdge((Value *)(uintptr_t(edge) | 1)); }
|
||||
ValueEdge untagged() const { return ValueEdge((Value *)(uintptr_t(edge) & ~1)); }
|
||||
bool isTagged() const { return bool(uintptr_t(edge) & 1); }
|
||||
};
|
||||
|
||||
struct SlotEdge
|
||||
{
|
||||
friend class StoreBuffer;
|
||||
friend class StoreBuffer::MonoTypeBuffer<SlotEdge>;
|
||||
|
||||
JSObject *object;
|
||||
uint32_t offset;
|
||||
|
||||
SlotEdge(JSObject *object, uint32_t offset) : object(object), offset(offset) {}
|
||||
|
||||
bool operator==(const SlotEdge &other) const {
|
||||
return object == other.object && offset == other.offset;
|
||||
}
|
||||
|
||||
bool operator!=(const SlotEdge &other) const {
|
||||
return object != other.object || offset != other.offset;
|
||||
}
|
||||
|
||||
HeapSlot *slotLocation() const {
|
||||
if (object->isDenseArray()) {
|
||||
if (offset >= object->getDenseArrayInitializedLength())
|
||||
return NULL;
|
||||
return (HeapSlot *)&object->getDenseArrayElement(offset);
|
||||
}
|
||||
if (offset >= object->slotSpan())
|
||||
return NULL;
|
||||
return &object->getSlotRef(offset);
|
||||
}
|
||||
|
||||
void *deref() const {
|
||||
HeapSlot *loc = slotLocation();
|
||||
return (loc && loc->isGCThing()) ? loc->toGCThing() : NULL;
|
||||
}
|
||||
|
||||
void *location() const {
|
||||
return (void *)slotLocation();
|
||||
}
|
||||
|
||||
bool inRememberedSet(Nursery *n) {
|
||||
return !n->isInside(object) && n->isInside(deref());
|
||||
}
|
||||
|
||||
bool isNullEdge() const {
|
||||
return !deref();
|
||||
}
|
||||
};
|
||||
|
||||
MonoTypeBuffer<ValueEdge> bufferVal;
|
||||
MonoTypeBuffer<CellPtrEdge> bufferCell;
|
||||
MonoTypeBuffer<SlotEdge> bufferSlot;
|
||||
RelocatableMonoTypeBuffer<ValueEdge> bufferRelocVal;
|
||||
RelocatableMonoTypeBuffer<CellPtrEdge> bufferRelocCell;
|
||||
GenericBuffer bufferGeneric;
|
||||
|
||||
Nursery *nursery;
|
||||
|
||||
void *buffer;
|
||||
|
||||
bool overflowed;
|
||||
bool enabled;
|
||||
|
||||
/* For the verifier. */
|
||||
EdgeSet edgeSet;
|
||||
|
||||
/* For use by our owned buffers. */
|
||||
void setOverflowed() { overflowed = true; }
|
||||
|
||||
public:
|
||||
StoreBuffer(Nursery *n)
|
||||
: bufferVal(this, n), bufferCell(this, n), bufferSlot(this, n),
|
||||
bufferRelocVal(this, n), bufferRelocCell(this, n), bufferGeneric(this, n),
|
||||
nursery(n), buffer(NULL), overflowed(false), enabled(false)
|
||||
{}
|
||||
|
||||
bool enable();
|
||||
void disable();
|
||||
bool isEnabled() { return enabled; }
|
||||
|
||||
/* Get the overflowed status. */
|
||||
bool hasOverflowed() const { return overflowed; }
|
||||
|
||||
/* Insert a single edge into the buffer/remembered set. */
|
||||
void putValue(Value *v) {
|
||||
bufferVal.put(v);
|
||||
}
|
||||
void putCell(Cell **o) {
|
||||
bufferCell.put(o);
|
||||
}
|
||||
void putSlot(JSObject *obj, uint32_t slot) {
|
||||
bufferSlot.put(SlotEdge(obj, slot));
|
||||
}
|
||||
|
||||
/* Insert or update a single edge in the Relocatable buffer. */
|
||||
void putRelocatableValue(Value *v) {
|
||||
bufferRelocVal.put(v);
|
||||
}
|
||||
void putRelocatableCell(Cell **c) {
|
||||
bufferRelocCell.put(c);
|
||||
}
|
||||
void removeRelocatableValue(Value *v) {
|
||||
bufferRelocVal.unput(v);
|
||||
}
|
||||
void removeRelocatableCell(Cell **c) {
|
||||
bufferRelocCell.unput(c);
|
||||
}
|
||||
|
||||
/* Insert an entry into the generic buffer. */
|
||||
template <typename T>
|
||||
void putGeneric(const T &t) {
|
||||
bufferGeneric.put(t);
|
||||
}
|
||||
|
||||
/* For the verifier. */
|
||||
bool coalesceForVerification();
|
||||
void releaseVerificationData();
|
||||
bool containsEdgeAt(void *loc) const;
|
||||
};
|
||||
|
||||
} /* namespace gc */
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsgc_storebuffer_h___ */
|
||||
#endif /* JSGC_GENERATIONAL */
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
/* Define to 1 if SpiderMonkey should support the ability to perform
|
||||
entirely too much GC. */
|
||||
#define JS_GC_ZEAL 1
|
||||
/* #undef JS_GC_ZEAL */
|
||||
|
||||
/* Define to 1 if the <endian.h> header is present and
|
||||
useable. See jscpucfg.h. */
|
||||
|
|
|
@ -375,3 +375,5 @@ MSG_DEF(JSMSG_MUST_REPORT_UNDEFINED, 321, 0, JSEXN_TYPEERR, "proxy must report
|
|||
MSG_DEF(JSMSG_CANT_SET_NW_NC, 322, 0, JSEXN_TYPEERR, "proxy can't successfully set a non-writable, non-configurable property")
|
||||
MSG_DEF(JSMSG_CANT_SET_WO_SETTER, 323, 0, JSEXN_TYPEERR, "proxy can't succesfully set an accessor property without a setter")
|
||||
MSG_DEF(JSMSG_DEBUG_BAD_REFERENT, 324, 2, JSEXN_TYPEERR, "{0} does not refer to {1}")
|
||||
MSG_DEF(JSMSG_DEBUG_WRAPPER_IN_WAY, 325, 2, JSEXN_TYPEERR, "{0} is a wrapper around {1}, but a direct reference is required")
|
||||
MSG_DEF(JSMSG_UNWRAP_DENIED, 326, 0, JSEXN_ERR, "permission denied to unwrap object")
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,76 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef js_heap_api_h___
|
||||
#define js_heap_api_h___
|
||||
|
||||
/* These values are private to the JS engine. */
|
||||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
/*
|
||||
* Page size must be static to support our arena pointer optimizations, so we
|
||||
* are forced to support each platform with non-4096 pages as a special case.
|
||||
* Note: The freelist supports a maximum arena shift of 15.
|
||||
* Note: Do not use JS_CPU_SPARC here, this header is used outside JS.
|
||||
*/
|
||||
#if (defined(SOLARIS) || defined(__FreeBSD__)) && \
|
||||
(defined(__sparc) || defined(__sparcv9) || defined(__ia64))
|
||||
const size_t PageShift = 13;
|
||||
const size_t ArenaShift = PageShift;
|
||||
#elif defined(__powerpc64__)
|
||||
const size_t PageShift = 16;
|
||||
const size_t ArenaShift = 12;
|
||||
#else
|
||||
const size_t PageShift = 12;
|
||||
const size_t ArenaShift = PageShift;
|
||||
#endif
|
||||
const size_t PageSize = size_t(1) << PageShift;
|
||||
const size_t ArenaSize = size_t(1) << ArenaShift;
|
||||
const size_t ArenaMask = ArenaSize - 1;
|
||||
|
||||
const size_t ChunkShift = 20;
|
||||
const size_t ChunkSize = size_t(1) << ChunkShift;
|
||||
const size_t ChunkMask = ChunkSize - 1;
|
||||
|
||||
} /* namespace gc */
|
||||
} /* namespace js */
|
||||
|
||||
namespace JS {
|
||||
|
||||
namespace shadow {
|
||||
|
||||
struct ArenaHeader
|
||||
{
|
||||
JSCompartment *compartment;
|
||||
};
|
||||
|
||||
} /* namespace shadow */
|
||||
|
||||
static inline shadow::ArenaHeader *
|
||||
GetGCThingArena(void *thing)
|
||||
{
|
||||
uintptr_t addr = uintptr_t(thing);
|
||||
addr &= ~js::gc::ArenaMask;
|
||||
return reinterpret_cast<shadow::ArenaHeader *>(addr);
|
||||
}
|
||||
|
||||
static inline JSCompartment *
|
||||
GetGCThingCompartment(void *thing)
|
||||
{
|
||||
JS_ASSERT(thing);
|
||||
return GetGCThingArena(thing)->compartment;
|
||||
}
|
||||
|
||||
static inline JSCompartment *
|
||||
GetObjectCompartment(JSObject *obj)
|
||||
{
|
||||
return GetGCThingCompartment(obj);
|
||||
}
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
#endif /* js_heap_api_h___ */
|
|
@ -38,22 +38,37 @@ namespace JS {
|
|||
struct TypeInferenceSizes
|
||||
{
|
||||
TypeInferenceSizes()
|
||||
: scripts(0)
|
||||
, objects(0)
|
||||
, tables(0)
|
||||
, temporary(0)
|
||||
: typeScripts(0)
|
||||
, typeResults(0)
|
||||
, analysisPool(0)
|
||||
, typePool(0)
|
||||
, pendingArrays(0)
|
||||
, allocationSiteTables(0)
|
||||
, arrayTypeTables(0)
|
||||
, objectTypeTables(0)
|
||||
, typeObjects(0)
|
||||
{}
|
||||
|
||||
size_t scripts;
|
||||
size_t objects;
|
||||
size_t tables;
|
||||
size_t temporary;
|
||||
size_t typeScripts;
|
||||
size_t typeResults;
|
||||
size_t analysisPool;
|
||||
size_t typePool;
|
||||
size_t pendingArrays;
|
||||
size_t allocationSiteTables;
|
||||
size_t arrayTypeTables;
|
||||
size_t objectTypeTables;
|
||||
size_t typeObjects;
|
||||
|
||||
void add(TypeInferenceSizes &sizes) {
|
||||
this->scripts += sizes.scripts;
|
||||
this->objects += sizes.objects;
|
||||
this->tables += sizes.tables;
|
||||
this->temporary += sizes.temporary;
|
||||
this->typeScripts += sizes.typeScripts;
|
||||
this->typeResults += sizes.typeResults;
|
||||
this->analysisPool += sizes.analysisPool;
|
||||
this->typePool += sizes.typePool;
|
||||
this->pendingArrays += sizes.pendingArrays;
|
||||
this->allocationSiteTables += sizes.allocationSiteTables;
|
||||
this->arrayTypeTables += sizes.arrayTypeTables;
|
||||
this->objectTypeTables += sizes.objectTypeTables;
|
||||
this->typeObjects += sizes.typeObjects;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -129,10 +144,15 @@ struct CompartmentStats
|
|||
, extra2(0)
|
||||
, gcHeapArenaAdmin(0)
|
||||
, gcHeapUnusedGcThings(0)
|
||||
, gcHeapObjectsNonFunction(0)
|
||||
, gcHeapObjectsOrdinary(0)
|
||||
, gcHeapObjectsFunction(0)
|
||||
, gcHeapStrings(0)
|
||||
, gcHeapShapesTree(0)
|
||||
, gcHeapObjectsDenseArray(0)
|
||||
, gcHeapObjectsSlowArray(0)
|
||||
, gcHeapObjectsCrossCompartmentWrapper(0)
|
||||
, gcHeapStringsNormal(0)
|
||||
, gcHeapStringsShort(0)
|
||||
, gcHeapShapesTreeGlobalParented(0)
|
||||
, gcHeapShapesTreeNonGlobalParented(0)
|
||||
, gcHeapShapesDict(0)
|
||||
, gcHeapShapesBase(0)
|
||||
, gcHeapScripts(0)
|
||||
|
@ -147,7 +167,7 @@ struct CompartmentStats
|
|||
, objectsExtraRegExpStatics(0)
|
||||
, objectsExtraPropertyIteratorData(0)
|
||||
, objectsExtraPrivate(0)
|
||||
, nonHugeStringChars(0)
|
||||
, stringCharsNonHuge(0)
|
||||
, shapesExtraTreeTables(0)
|
||||
, shapesExtraDictTables(0)
|
||||
, shapesExtraTreeShapeKids(0)
|
||||
|
@ -156,7 +176,7 @@ struct CompartmentStats
|
|||
, jaegerData(0)
|
||||
, ionData(0)
|
||||
, compartmentObject(0)
|
||||
, crossCompartmentWrappers(0)
|
||||
, crossCompartmentWrappersTable(0)
|
||||
, regexpCompartment(0)
|
||||
, debuggeesSet(0)
|
||||
{}
|
||||
|
@ -166,10 +186,15 @@ struct CompartmentStats
|
|||
, extra2(other.extra2)
|
||||
, gcHeapArenaAdmin(other.gcHeapArenaAdmin)
|
||||
, gcHeapUnusedGcThings(other.gcHeapUnusedGcThings)
|
||||
, gcHeapObjectsNonFunction(other.gcHeapObjectsNonFunction)
|
||||
, gcHeapObjectsOrdinary(other.gcHeapObjectsOrdinary)
|
||||
, gcHeapObjectsFunction(other.gcHeapObjectsFunction)
|
||||
, gcHeapStrings(other.gcHeapStrings)
|
||||
, gcHeapShapesTree(other.gcHeapShapesTree)
|
||||
, gcHeapObjectsDenseArray(other.gcHeapObjectsDenseArray)
|
||||
, gcHeapObjectsSlowArray(other.gcHeapObjectsSlowArray)
|
||||
, gcHeapObjectsCrossCompartmentWrapper(other.gcHeapObjectsCrossCompartmentWrapper)
|
||||
, gcHeapStringsNormal(other.gcHeapStringsNormal)
|
||||
, gcHeapStringsShort(other.gcHeapStringsShort)
|
||||
, gcHeapShapesTreeGlobalParented(other.gcHeapShapesTreeGlobalParented)
|
||||
, gcHeapShapesTreeNonGlobalParented(other.gcHeapShapesTreeNonGlobalParented)
|
||||
, gcHeapShapesDict(other.gcHeapShapesDict)
|
||||
, gcHeapShapesBase(other.gcHeapShapesBase)
|
||||
, gcHeapScripts(other.gcHeapScripts)
|
||||
|
@ -184,7 +209,7 @@ struct CompartmentStats
|
|||
, objectsExtraRegExpStatics(other.objectsExtraRegExpStatics)
|
||||
, objectsExtraPropertyIteratorData(other.objectsExtraPropertyIteratorData)
|
||||
, objectsExtraPrivate(other.objectsExtraPrivate)
|
||||
, nonHugeStringChars(other.nonHugeStringChars)
|
||||
, stringCharsNonHuge(other.stringCharsNonHuge)
|
||||
, shapesExtraTreeTables(other.shapesExtraTreeTables)
|
||||
, shapesExtraDictTables(other.shapesExtraDictTables)
|
||||
, shapesExtraTreeShapeKids(other.shapesExtraTreeShapeKids)
|
||||
|
@ -193,7 +218,7 @@ struct CompartmentStats
|
|||
, jaegerData(other.jaegerData)
|
||||
, ionData(other.ionData)
|
||||
, compartmentObject(other.compartmentObject)
|
||||
, crossCompartmentWrappers(other.crossCompartmentWrappers)
|
||||
, crossCompartmentWrappersTable(other.crossCompartmentWrappersTable)
|
||||
, regexpCompartment(other.regexpCompartment)
|
||||
, debuggeesSet(other.debuggeesSet)
|
||||
, typeInferenceSizes(other.typeInferenceSizes)
|
||||
|
@ -210,10 +235,15 @@ struct CompartmentStats
|
|||
size_t gcHeapArenaAdmin;
|
||||
size_t gcHeapUnusedGcThings;
|
||||
|
||||
size_t gcHeapObjectsNonFunction;
|
||||
size_t gcHeapObjectsOrdinary;
|
||||
size_t gcHeapObjectsFunction;
|
||||
size_t gcHeapStrings;
|
||||
size_t gcHeapShapesTree;
|
||||
size_t gcHeapObjectsDenseArray;
|
||||
size_t gcHeapObjectsSlowArray;
|
||||
size_t gcHeapObjectsCrossCompartmentWrapper;
|
||||
size_t gcHeapStringsNormal;
|
||||
size_t gcHeapStringsShort;
|
||||
size_t gcHeapShapesTreeGlobalParented;
|
||||
size_t gcHeapShapesTreeNonGlobalParented;
|
||||
size_t gcHeapShapesDict;
|
||||
size_t gcHeapShapesBase;
|
||||
size_t gcHeapScripts;
|
||||
|
@ -229,7 +259,7 @@ struct CompartmentStats
|
|||
size_t objectsExtraRegExpStatics;
|
||||
size_t objectsExtraPropertyIteratorData;
|
||||
size_t objectsExtraPrivate;
|
||||
size_t nonHugeStringChars;
|
||||
size_t stringCharsNonHuge;
|
||||
size_t shapesExtraTreeTables;
|
||||
size_t shapesExtraDictTables;
|
||||
size_t shapesExtraTreeShapeKids;
|
||||
|
@ -238,7 +268,7 @@ struct CompartmentStats
|
|||
size_t jaegerData;
|
||||
size_t ionData;
|
||||
size_t compartmentObject;
|
||||
size_t crossCompartmentWrappers;
|
||||
size_t crossCompartmentWrappersTable;
|
||||
size_t regexpCompartment;
|
||||
size_t debuggeesSet;
|
||||
|
||||
|
@ -253,10 +283,15 @@ struct CompartmentStats
|
|||
ADD(gcHeapArenaAdmin);
|
||||
ADD(gcHeapUnusedGcThings);
|
||||
|
||||
ADD(gcHeapObjectsNonFunction);
|
||||
ADD(gcHeapObjectsOrdinary);
|
||||
ADD(gcHeapObjectsFunction);
|
||||
ADD(gcHeapStrings);
|
||||
ADD(gcHeapShapesTree);
|
||||
ADD(gcHeapObjectsDenseArray);
|
||||
ADD(gcHeapObjectsSlowArray);
|
||||
ADD(gcHeapObjectsCrossCompartmentWrapper);
|
||||
ADD(gcHeapStringsNormal);
|
||||
ADD(gcHeapStringsShort);
|
||||
ADD(gcHeapShapesTreeGlobalParented);
|
||||
ADD(gcHeapShapesTreeNonGlobalParented);
|
||||
ADD(gcHeapShapesDict);
|
||||
ADD(gcHeapShapesBase);
|
||||
ADD(gcHeapScripts);
|
||||
|
@ -272,7 +307,7 @@ struct CompartmentStats
|
|||
ADD(objectsExtraRegExpStatics);
|
||||
ADD(objectsExtraPropertyIteratorData);
|
||||
ADD(objectsExtraPrivate);
|
||||
ADD(nonHugeStringChars);
|
||||
ADD(stringCharsNonHuge);
|
||||
ADD(shapesExtraTreeTables);
|
||||
ADD(shapesExtraDictTables);
|
||||
ADD(shapesExtraTreeShapeKids);
|
||||
|
@ -281,7 +316,7 @@ struct CompartmentStats
|
|||
ADD(jaegerData);
|
||||
ADD(ionData);
|
||||
ADD(compartmentObject);
|
||||
ADD(crossCompartmentWrappers);
|
||||
ADD(crossCompartmentWrappersTable);
|
||||
ADD(regexpCompartment);
|
||||
ADD(debuggeesSet);
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
#include "jstypes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
# include "js/TemplateLib.h"
|
||||
# include "mozilla/Scoped.h"
|
||||
|
||||
|
@ -36,12 +35,8 @@ namespace js {
|
|||
|
||||
/* The private namespace is a superset of the public/shared namespaces. */
|
||||
using namespace JS;
|
||||
using namespace mozilla;
|
||||
|
||||
} /* namespace js */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
* Pattern used to overwrite freed memory. If you are accessing an object with
|
||||
|
@ -103,7 +98,7 @@ PrintBacktrace()
|
|||
int32_t OOM_traceIdx = 0;
|
||||
OOM_traceSize = backtrace(OOM_trace, JS_OOM_BACKTRACE_SIZE);
|
||||
OOM_traceSymbols = backtrace_symbols(OOM_trace, OOM_traceSize);
|
||||
|
||||
|
||||
if (!OOM_traceSymbols)
|
||||
return;
|
||||
|
||||
|
@ -171,6 +166,8 @@ static JS_INLINE void js_free(void* p)
|
|||
}
|
||||
#endif/* JS_USE_CUSTOM_ALLOCATOR */
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
* Replace bit-scanning code sequences with CPU-specific instructions to
|
||||
* speedup calculations of ceiling/floor log2.
|
||||
|
@ -330,6 +327,8 @@ JS_PUBLIC_API(size_t) js_FloorLog2wImpl(size_t n);
|
|||
# error "NOT SUPPORTED"
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
/*
|
||||
* Internal function.
|
||||
* Compute the log of the least power of 2 greater than or equal to n. This is
|
||||
|
@ -371,9 +370,6 @@ JS_FLOOR_LOG2W(size_t n)
|
|||
#define JS_ROTATE_LEFT32(a, bits) (((a) << (bits)) | ((a) >> (32 - (bits))))
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <new>
|
||||
|
||||
/*
|
||||
|
@ -903,8 +899,6 @@ inline bool IsPoisonedPtr(T *v)
|
|||
|
||||
}
|
||||
|
||||
#endif /* defined(__cplusplus) */
|
||||
|
||||
/*
|
||||
* This is SpiderMonkey's equivalent to |nsMallocSizeOfFun|.
|
||||
*/
|
||||
|
|
|
@ -242,7 +242,7 @@ class Vector : private AllocPolicy
|
|||
size_t mReserved; /* Max elements of reserved or used space in this vector. */
|
||||
#endif
|
||||
|
||||
AlignedStorage<sInlineBytes> storage;
|
||||
mozilla::AlignedStorage<sInlineBytes> storage;
|
||||
|
||||
#ifdef DEBUG
|
||||
friend class ReentrancyGuard;
|
||||
|
@ -255,7 +255,11 @@ class Vector : private AllocPolicy
|
|||
/* private accessors */
|
||||
|
||||
bool usingInlineStorage() const {
|
||||
return mBegin == (T *)storage.addr();
|
||||
return mBegin == inlineStorage();
|
||||
}
|
||||
|
||||
T *inlineStorage() const {
|
||||
return (T *)storage.addr();
|
||||
}
|
||||
|
||||
T *beginNoCheck() const {
|
||||
|
@ -427,7 +431,7 @@ class Vector : private AllocPolicy
|
|||
internalAppendN(t, n);
|
||||
}
|
||||
template <class U> void infallibleAppend(const U *begin, const U *end) {
|
||||
internalAppend(begin, PointerRangeSize(begin, end));
|
||||
internalAppend(begin, mozilla::PointerRangeSize(begin, end));
|
||||
}
|
||||
template <class U> void infallibleAppend(const U *begin, size_t length) {
|
||||
internalAppend(begin, length);
|
||||
|
@ -479,6 +483,8 @@ class Vector : private AllocPolicy
|
|||
* object (which must be heap-allocated) itself.
|
||||
*/
|
||||
size_t sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const;
|
||||
|
||||
void swap(Vector &other);
|
||||
};
|
||||
|
||||
/* This does the re-entrancy check plus several other sanity checks. */
|
||||
|
@ -506,6 +512,9 @@ template <class T, size_t N, class AllocPolicy>
|
|||
JS_ALWAYS_INLINE
|
||||
Vector<T, N, AllocPolicy>::Vector(MoveRef<Vector> rhs)
|
||||
: AllocPolicy(rhs)
|
||||
#ifdef DEBUG
|
||||
, entered(false)
|
||||
#endif
|
||||
{
|
||||
mLength = rhs->mLength;
|
||||
mCapacity = rhs->mCapacity;
|
||||
|
@ -856,7 +865,7 @@ JS_ALWAYS_INLINE bool
|
|||
Vector<T,N,AP>::append(const U *insBegin, const U *insEnd)
|
||||
{
|
||||
REENTRANCY_GUARD_ET_AL;
|
||||
size_t needed = PointerRangeSize(insBegin, insEnd);
|
||||
size_t needed = mozilla::PointerRangeSize(insBegin, insEnd);
|
||||
if (mLength + needed > mCapacity && !growStorageBy(needed))
|
||||
return false;
|
||||
|
||||
|
@ -995,6 +1004,33 @@ Vector<T,N,AP>::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const
|
|||
return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
template <class T, size_t N, class AP>
|
||||
inline void
|
||||
Vector<T,N,AP>::swap(Vector &other)
|
||||
{
|
||||
// TODO Implement N != 0
|
||||
JS_STATIC_ASSERT(N == 0);
|
||||
|
||||
// This only works when inline storage is always empty.
|
||||
if (!usingInlineStorage() && other.usingInlineStorage()) {
|
||||
other.mBegin = mBegin;
|
||||
mBegin = inlineStorage();
|
||||
} else if (usingInlineStorage() && !other.usingInlineStorage()) {
|
||||
mBegin = other.mBegin;
|
||||
other.mBegin = other.inlineStorage();
|
||||
} else if (!usingInlineStorage() && !other.usingInlineStorage()) {
|
||||
Swap(mBegin, other.mBegin);
|
||||
} else {
|
||||
// This case is a no-op, since we'd set both to use their inline storage.
|
||||
}
|
||||
|
||||
Swap(mLength, other.mLength);
|
||||
Swap(mCapacity, other.mCapacity);
|
||||
#ifdef DEBUG
|
||||
Swap(mReserved, other.mReserved);
|
||||
#endif
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
|
|
@ -18,6 +18,8 @@ namespace js {
|
|||
* - public copy constructor, assignment, destructor
|
||||
* - void *malloc_(size_t)
|
||||
* Responsible for OOM reporting on NULL return value.
|
||||
* - void *calloc_(size_t)
|
||||
* Responsible for OOM reporting on NULL return value.
|
||||
* - void *realloc_(size_t)
|
||||
* Responsible for OOM reporting on NULL return value.
|
||||
* The *used* bytes of the previous buffer is passed in
|
||||
|
@ -33,6 +35,7 @@ class SystemAllocPolicy
|
|||
{
|
||||
public:
|
||||
void *malloc_(size_t bytes) { return js_malloc(bytes); }
|
||||
void *calloc_(size_t bytes) { return js_calloc(bytes); }
|
||||
void *realloc_(void *p, size_t oldBytes, size_t bytes) { return js_realloc(p, bytes); }
|
||||
void free_(void *p) { js_free(p); }
|
||||
void reportAllocOverflow() const {}
|
||||
|
@ -71,6 +74,13 @@ class TempAllocPolicy
|
|||
return p;
|
||||
}
|
||||
|
||||
void *calloc_(size_t bytes) {
|
||||
void *p = js_calloc(bytes);
|
||||
if (JS_UNLIKELY(!p))
|
||||
p = onOutOfMemory(NULL, bytes);
|
||||
return p;
|
||||
}
|
||||
|
||||
void *realloc_(void *p, size_t oldBytes, size_t bytes) {
|
||||
void *p2 = js_realloc(p, bytes);
|
||||
if (JS_UNLIKELY(!p2))
|
||||
|
|
|
@ -1 +1 @@
|
|||
4f78a759104eea6e7790c03ce0130299eeaa3968
|
||||
ba4ed5550f4042bc9963d0e15cce943b9f0be17a
|
|
@ -13,7 +13,6 @@
|
|||
#include "jsapi.h"
|
||||
#include "jsprvtd.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
namespace JS {
|
||||
|
||||
struct FrameDescription
|
||||
|
@ -47,9 +46,6 @@ JS_FRIEND_API(void) js_DumpValue(const js::Value &val);
|
|||
JS_FRIEND_API(void) js_DumpId(jsid id);
|
||||
JS_FRIEND_API(void) js_DumpStackFrame(JSContext *cx, js::StackFrame *start = NULL);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
js_DumpBacktrace(JSContext *cx);
|
||||
|
@ -432,6 +428,4 @@ JS_UnwrapObjectAndInnerize(JSObject *obj);
|
|||
extern JS_FRIEND_API(JSBool)
|
||||
js_CallContextDebugHandler(JSContext *cx);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* jsdbgapi_h___ */
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
#include "jstypes.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
#if defined(__GNUC__) && defined(__i386__) && (__GNUC__ >= 3) && !defined(XP_OS2)
|
||||
#define JS_DHASH_FASTCALL __attribute__ ((regparm (3),stdcall))
|
||||
#elif defined(XP_WIN)
|
||||
|
@ -598,6 +596,4 @@ extern JS_PUBLIC_API(void)
|
|||
JS_DHashTableDumpMeter(JSDHashTable *table, JSDHashEnumerator dump, FILE *fp);
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* jsdhash_h___ */
|
||||
|
|
|
@ -8,12 +8,28 @@
|
|||
#define jsfriendapi_h___
|
||||
|
||||
#include "jsclass.h"
|
||||
#include "jscpucfg.h"
|
||||
#include "jspubtd.h"
|
||||
#include "jsprvtd.h"
|
||||
|
||||
#include "js/HeapAPI.h"
|
||||
|
||||
#include "mozilla/GuardObjects.h"
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
/*
|
||||
* This macro checks if the stack pointer has exceeded a given limit. If
|
||||
* |tolerance| is non-zero, it returns true only if the stack pointer has
|
||||
* exceeded the limit by more than |tolerance| bytes.
|
||||
*/
|
||||
#if JS_STACK_GROWTH_DIRECTION > 0
|
||||
# define JS_CHECK_STACK_SIZE_WITH_TOLERANCE(limit, sp, tolerance) \
|
||||
((uintptr_t)(sp) < (limit)+(tolerance))
|
||||
#else
|
||||
# define JS_CHECK_STACK_SIZE_WITH_TOLERANCE(limit, sp, tolerance) \
|
||||
((uintptr_t)(sp) > (limit)-(tolerance))
|
||||
#endif
|
||||
|
||||
#define JS_CHECK_STACK_SIZE(limit, lval) JS_CHECK_STACK_SIZE_WITH_TOLERANCE(limit, lval, 0)
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
|
||||
|
@ -139,8 +155,6 @@ extern JS_FRIEND_API(void)
|
|||
js_DumpChars(const jschar *s, size_t n);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
extern JS_FRIEND_API(bool)
|
||||
JS_CopyPropertiesFrom(JSContext *cx, JSObject *target, JSObject *obj);
|
||||
|
||||
|
@ -171,12 +185,6 @@ struct JSFunctionSpecWithHelp {
|
|||
extern JS_FRIEND_API(bool)
|
||||
JS_DefineFunctionsWithHelp(JSContext *cx, JSObject *obj, const JSFunctionSpecWithHelp *fs);
|
||||
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
typedef bool (* JS_SourceHook)(JSContext *cx, JSScript *script, jschar **src, uint32_t *length);
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
|
@ -184,6 +192,8 @@ JS_SetSourceHook(JSRuntime *rt, JS_SourceHook hook);
|
|||
|
||||
namespace js {
|
||||
|
||||
extern mozilla::ThreadLocal<PerThreadData *> TlsPerThreadData;
|
||||
|
||||
inline JSRuntime *
|
||||
GetRuntime(const JSContext *cx)
|
||||
{
|
||||
|
@ -259,15 +269,34 @@ TraceWeakMaps(WeakMapTracer *trc);
|
|||
extern JS_FRIEND_API(bool)
|
||||
GCThingIsMarkedGray(void *thing);
|
||||
|
||||
extern JS_FRIEND_API(bool)
|
||||
AreGCGrayBitsValid(JSRuntime *rt);
|
||||
|
||||
/*
|
||||
* Unsets the gray bit for anything reachable from |thing|. |kind| should not be
|
||||
* JSTRACE_SHAPE. |thing| should be non-null.
|
||||
*/
|
||||
extern JS_FRIEND_API(void)
|
||||
UnmarkGrayGCThingRecursively(void *thing, JSGCTraceKind kind);
|
||||
|
||||
typedef void
|
||||
(GCThingCallback)(void *closure, void *gcthing);
|
||||
(*GCThingCallback)(void *closure, void *gcthing);
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
VisitGrayWrapperTargets(JSCompartment *comp, GCThingCallback *callback, void *closure);
|
||||
VisitGrayWrapperTargets(JSCompartment *comp, GCThingCallback callback, void *closure);
|
||||
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
GetWeakmapKeyDelegate(JSObject *key);
|
||||
|
||||
JS_FRIEND_API(JSGCTraceKind)
|
||||
GCThingTraceKind(void *thing);
|
||||
|
||||
/*
|
||||
* Invoke cellCallback on every gray JS_OBJECT in the given compartment.
|
||||
*/
|
||||
extern JS_FRIEND_API(void)
|
||||
IterateGrayObjects(JSCompartment *compartment, GCThingCallback cellCallback, void *data);
|
||||
|
||||
/*
|
||||
* Shadow declarations of JS internal structures, for access by inline access
|
||||
* functions below. Do not use these structures in any other way. When adding
|
||||
|
@ -527,7 +556,13 @@ GetNativeStackLimit(const JSRuntime *rt)
|
|||
return RuntimeFriendFields::get(rt)->nativeStackLimit;
|
||||
}
|
||||
|
||||
#define JS_CHECK_RECURSION(cx, onerror) \
|
||||
/*
|
||||
* These macros report a stack overflow and run |onerror| if we are close to
|
||||
* using up the C stack. The JS_CHECK_CHROME_RECURSION variant gives us a little
|
||||
* extra space so that we can ensure that crucial code is able to run.
|
||||
*/
|
||||
|
||||
#define JS_CHECK_RECURSION(cx, onerror) \
|
||||
JS_BEGIN_MACRO \
|
||||
int stackDummy_; \
|
||||
if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(js::GetRuntime(cx)), &stackDummy_)) { \
|
||||
|
@ -536,6 +571,18 @@ GetNativeStackLimit(const JSRuntime *rt)
|
|||
} \
|
||||
JS_END_MACRO
|
||||
|
||||
#define JS_CHECK_CHROME_RECURSION(cx, onerror) \
|
||||
JS_BEGIN_MACRO \
|
||||
int stackDummy_; \
|
||||
if (!JS_CHECK_STACK_SIZE_WITH_TOLERANCE(js::GetNativeStackLimit(js::GetRuntime(cx)), \
|
||||
&stackDummy_, \
|
||||
1024 * sizeof(size_t))) \
|
||||
{ \
|
||||
js_ReportOverRecursed(cx); \
|
||||
onerror; \
|
||||
} \
|
||||
JS_END_MACRO
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
StartPCCountProfiling(JSContext *cx);
|
||||
|
||||
|
@ -979,8 +1026,6 @@ uint32_t GetListBaseExpandoSlot();
|
|||
|
||||
} /* namespace js */
|
||||
|
||||
#endif
|
||||
|
||||
/* Implemented in jsdate.cpp. */
|
||||
|
||||
/*
|
||||
|
@ -1017,8 +1062,6 @@ js_GetSCOffset(JSStructuredCloneWriter* writer);
|
|||
|
||||
/* Typed Array functions, implemented in jstypedarray.cpp */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace js {
|
||||
namespace ArrayBufferView {
|
||||
|
||||
|
@ -1038,6 +1081,12 @@ enum ViewType {
|
|||
*/
|
||||
TYPE_UINT8_CLAMPED,
|
||||
|
||||
/*
|
||||
* Type returned for a DataView. Note that there is no single element type
|
||||
* in this case.
|
||||
*/
|
||||
TYPE_DATAVIEW,
|
||||
|
||||
TYPE_MAX
|
||||
};
|
||||
|
||||
|
@ -1045,9 +1094,6 @@ enum ViewType {
|
|||
} /* namespace js */
|
||||
|
||||
typedef js::ArrayBufferView::ViewType JSArrayBufferViewType;
|
||||
#else
|
||||
typedef uint32_t JSArrayBufferViewType;
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* Create a new typed array with nelements elements.
|
||||
|
@ -1150,41 +1196,40 @@ JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes);
|
|||
* the various accessor JSAPI calls defined below.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsTypedArrayObject(JSObject *obj, JSContext *cx);
|
||||
JS_IsTypedArrayObject(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Check whether obj supports JS_GetArrayBufferView* APIs. Note that this may
|
||||
* return false if a security wrapper is encountered that denies the
|
||||
* unwrapping. If this test or one of the more specific tests succeeds, then it
|
||||
* is safe to call the various ArrayBufferView accessor JSAPI calls defined
|
||||
* below. cx MUST be non-NULL and valid.
|
||||
* below.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsArrayBufferViewObject(JSObject *obj, JSContext *cx);
|
||||
JS_IsArrayBufferViewObject(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Test for specific typed array types (ArrayBufferView subtypes)
|
||||
*/
|
||||
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsInt8Array(JSObject *obj, JSContext *cx);
|
||||
JS_IsInt8Array(JSObject *obj);
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsUint8Array(JSObject *obj, JSContext *cx);
|
||||
JS_IsUint8Array(JSObject *obj);
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsUint8ClampedArray(JSObject *obj, JSContext *cx);
|
||||
JS_IsUint8ClampedArray(JSObject *obj);
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsInt16Array(JSObject *obj, JSContext *cx);
|
||||
JS_IsInt16Array(JSObject *obj);
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsUint16Array(JSObject *obj, JSContext *cx);
|
||||
JS_IsUint16Array(JSObject *obj);
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsInt32Array(JSObject *obj, JSContext *cx);
|
||||
JS_IsInt32Array(JSObject *obj);
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsUint32Array(JSObject *obj, JSContext *cx);
|
||||
JS_IsUint32Array(JSObject *obj);
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsFloat32Array(JSObject *obj, JSContext *cx);
|
||||
JS_IsFloat32Array(JSObject *obj);
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsFloat64Array(JSObject *obj, JSContext *cx);
|
||||
|
||||
JS_IsFloat64Array(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Unwrap Typed arrays all at once. Return NULL without throwing if the object
|
||||
|
@ -1192,38 +1237,37 @@ JS_IsFloat64Array(JSObject *obj, JSContext *cx);
|
|||
* success, filling both outparameters.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsInt8Array(JSContext *cx, JSObject *obj, uint32_t *length, int8_t **data);
|
||||
JS_GetObjectAsInt8Array(JSObject *obj, uint32_t *length, int8_t **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsUint8Array(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data);
|
||||
JS_GetObjectAsUint8Array(JSObject *obj, uint32_t *length, uint8_t **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsUint8ClampedArray(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data);
|
||||
JS_GetObjectAsUint8ClampedArray(JSObject *obj, uint32_t *length, uint8_t **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsInt16Array(JSContext *cx, JSObject *obj, uint32_t *length, int16_t **data);
|
||||
JS_GetObjectAsInt16Array(JSObject *obj, uint32_t *length, int16_t **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsUint16Array(JSContext *cx, JSObject *obj, uint32_t *length, uint16_t **data);
|
||||
JS_GetObjectAsUint16Array(JSObject *obj, uint32_t *length, uint16_t **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsInt32Array(JSContext *cx, JSObject *obj, uint32_t *length, int32_t **data);
|
||||
JS_GetObjectAsInt32Array(JSObject *obj, uint32_t *length, int32_t **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsUint32Array(JSContext *cx, JSObject *obj, uint32_t *length, uint32_t **data);
|
||||
JS_GetObjectAsUint32Array(JSObject *obj, uint32_t *length, uint32_t **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsFloat32Array(JSContext *cx, JSObject *obj, uint32_t *length, float **data);
|
||||
JS_GetObjectAsFloat32Array(JSObject *obj, uint32_t *length, float **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsFloat64Array(JSContext *cx, JSObject *obj, uint32_t *length, double **data);
|
||||
JS_GetObjectAsFloat64Array(JSObject *obj, uint32_t *length, double **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsArrayBufferView(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data);
|
||||
JS_GetObjectAsArrayBufferView(JSObject *obj, uint32_t *length, uint8_t **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsArrayBuffer(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data);
|
||||
JS_GetObjectAsArrayBuffer(JSObject *obj, uint32_t *length, uint8_t **data);
|
||||
|
||||
/*
|
||||
* Get the type of elements in a typed array.
|
||||
* Get the type of elements in a typed array, or TYPE_DATAVIEW if a DataView.
|
||||
*
|
||||
* |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
|
||||
* be known that it would pass such a test: it is a typed array or a wrapper of
|
||||
* a typed array, and the unwrapping will succeed. If cx is NULL, then DEBUG
|
||||
* builds may be unable to assert when unwrapping should be disallowed.
|
||||
* |obj| must have passed a JS_IsArrayBufferView/JS_Is*Array test, or somehow
|
||||
* be known that it would pass such a test: it is an ArrayBufferView or a
|
||||
* wrapper of an ArrayBufferView, and the unwrapping will succeed.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSArrayBufferViewType)
|
||||
JS_GetTypedArrayType(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetArrayBufferViewType(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Check whether obj supports the JS_GetArrayBuffer* APIs. Note that this may
|
||||
|
@ -1232,18 +1276,17 @@ JS_GetTypedArrayType(JSObject *obj, JSContext *maybecx);
|
|||
* accessor JSAPI calls defined below.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsArrayBufferObject(JSObject *obj, JSContext *maybecx);
|
||||
JS_IsArrayBufferObject(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return the available byte length of an array buffer.
|
||||
*
|
||||
* |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known
|
||||
* that it would pass such a test: it is an ArrayBuffer or a wrapper of an
|
||||
* ArrayBuffer, and the unwrapping will succeed. If cx is NULL, then DEBUG
|
||||
* builds may be unable to assert when unwrapping should be disallowed.
|
||||
* ArrayBuffer, and the unwrapping will succeed.
|
||||
*/
|
||||
extern JS_FRIEND_API(uint32_t)
|
||||
JS_GetArrayBufferByteLength(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetArrayBufferByteLength(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return a pointer to an array buffer's data. The buffer is still owned by the
|
||||
|
@ -1252,22 +1295,20 @@ JS_GetArrayBufferByteLength(JSObject *obj, JSContext *maybecx);
|
|||
*
|
||||
* |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known
|
||||
* that it would pass such a test: it is an ArrayBuffer or a wrapper of an
|
||||
* ArrayBuffer, and the unwrapping will succeed. If cx is NULL, then DEBUG
|
||||
* builds may be unable to assert when unwrapping should be disallowed.
|
||||
* ArrayBuffer, and the unwrapping will succeed.
|
||||
*/
|
||||
extern JS_FRIEND_API(uint8_t *)
|
||||
JS_GetArrayBufferData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetArrayBufferData(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return the number of elements in a typed array.
|
||||
*
|
||||
* |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
|
||||
* be known that it would pass such a test: it is a typed array or a wrapper of
|
||||
* a typed array, and the unwrapping will succeed. If cx is NULL, then DEBUG
|
||||
* builds may be unable to assert when unwrapping should be disallowed.
|
||||
* a typed array, and the unwrapping will succeed.
|
||||
*/
|
||||
extern JS_FRIEND_API(uint32_t)
|
||||
JS_GetTypedArrayLength(JSObject *obj, JSContext *cx);
|
||||
JS_GetTypedArrayLength(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return the byte offset from the start of an array buffer to the start of a
|
||||
|
@ -1275,22 +1316,20 @@ JS_GetTypedArrayLength(JSObject *obj, JSContext *cx);
|
|||
*
|
||||
* |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
|
||||
* be known that it would pass such a test: it is a typed array or a wrapper of
|
||||
* a typed array, and the unwrapping will succeed. If cx is NULL, then DEBUG
|
||||
* builds may be unable to assert when unwrapping should be disallowed.
|
||||
* a typed array, and the unwrapping will succeed.
|
||||
*/
|
||||
extern JS_FRIEND_API(uint32_t)
|
||||
JS_GetTypedArrayByteOffset(JSObject *obj, JSContext *cx);
|
||||
JS_GetTypedArrayByteOffset(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return the byte length of a typed array.
|
||||
*
|
||||
* |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
|
||||
* be known that it would pass such a test: it is a typed array or a wrapper of
|
||||
* a typed array, and the unwrapping will succeed. If cx is NULL, then DEBUG
|
||||
* builds may be unable to assert when unwrapping should be disallowed.
|
||||
* a typed array, and the unwrapping will succeed.
|
||||
*/
|
||||
extern JS_FRIEND_API(uint32_t)
|
||||
JS_GetTypedArrayByteLength(JSObject *obj, JSContext *cx);
|
||||
JS_GetTypedArrayByteLength(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Check whether obj supports JS_ArrayBufferView* APIs. Note that this may
|
||||
|
@ -1298,13 +1337,13 @@ JS_GetTypedArrayByteLength(JSObject *obj, JSContext *cx);
|
|||
* unwrapping.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsArrayBufferViewObject(JSObject *obj, JSContext *cx);
|
||||
JS_IsArrayBufferViewObject(JSObject *obj);
|
||||
|
||||
/*
|
||||
* More generic name for JS_GetTypedArrayByteLength to cover DataViews as well
|
||||
*/
|
||||
extern JS_FRIEND_API(uint32_t)
|
||||
JS_GetArrayBufferViewByteLength(JSObject *obj, JSContext *cx);
|
||||
JS_GetArrayBufferViewByteLength(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return a pointer to the start of the data referenced by a typed array. The
|
||||
|
@ -1313,43 +1352,48 @@ JS_GetArrayBufferViewByteLength(JSObject *obj, JSContext *cx);
|
|||
*
|
||||
* |obj| must have passed a JS_Is*Array test, or somehow be known that it would
|
||||
* pass such a test: it is a typed array or a wrapper of a typed array, and the
|
||||
* unwrapping will succeed. If cx is NULL, then DEBUG builds may be unable to
|
||||
* assert when unwrapping should be disallowed.
|
||||
* unwrapping will succeed.
|
||||
*/
|
||||
|
||||
extern JS_FRIEND_API(int8_t *)
|
||||
JS_GetInt8ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetInt8ArrayData(JSObject *obj);
|
||||
extern JS_FRIEND_API(uint8_t *)
|
||||
JS_GetUint8ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetUint8ArrayData(JSObject *obj);
|
||||
extern JS_FRIEND_API(uint8_t *)
|
||||
JS_GetUint8ClampedArrayData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetUint8ClampedArrayData(JSObject *obj);
|
||||
extern JS_FRIEND_API(int16_t *)
|
||||
JS_GetInt16ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetInt16ArrayData(JSObject *obj);
|
||||
extern JS_FRIEND_API(uint16_t *)
|
||||
JS_GetUint16ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetUint16ArrayData(JSObject *obj);
|
||||
extern JS_FRIEND_API(int32_t *)
|
||||
JS_GetInt32ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetInt32ArrayData(JSObject *obj);
|
||||
extern JS_FRIEND_API(uint32_t *)
|
||||
JS_GetUint32ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetUint32ArrayData(JSObject *obj);
|
||||
extern JS_FRIEND_API(float *)
|
||||
JS_GetFloat32ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetFloat32ArrayData(JSObject *obj);
|
||||
extern JS_FRIEND_API(double *)
|
||||
JS_GetFloat64ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetFloat64ArrayData(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Same as above, but for any kind of ArrayBufferView. Prefer the type-specific
|
||||
* versions when possible.
|
||||
*/
|
||||
extern JS_FRIEND_API(void *)
|
||||
JS_GetArrayBufferViewData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetArrayBufferViewData(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Check whether obj supports JS_GetDataView* APIs. Note that this may fail and
|
||||
* throw an exception if a security wrapper is encountered that denies the
|
||||
* operation.
|
||||
* Return the ArrayBuffer underlying an ArrayBufferView. If the buffer has been
|
||||
* neutered, this will still return the neutered buffer. |obj| must be an
|
||||
* object that would return true for JS_IsArrayBufferViewObject().
|
||||
*/
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetArrayBufferViewBuffer(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Check whether obj supports JS_GetDataView* APIs.
|
||||
*/
|
||||
JS_FRIEND_API(JSBool)
|
||||
JS_IsDataViewObject(JSContext *cx, JSObject *obj, JSBool *isDataView);
|
||||
JS_IsDataViewObject(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return the byte offset of a data view into its array buffer. |obj| must be a
|
||||
|
@ -1357,11 +1401,10 @@ JS_IsDataViewObject(JSContext *cx, JSObject *obj, JSBool *isDataView);
|
|||
*
|
||||
* |obj| must have passed a JS_IsDataViewObject test, or somehow be known that
|
||||
* it would pass such a test: it is a data view or a wrapper of a data view,
|
||||
* and the unwrapping will succeed. If cx is NULL, then DEBUG builds may be
|
||||
* unable to assert when unwrapping should be disallowed.
|
||||
* and the unwrapping will succeed.
|
||||
*/
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetDataViewByteOffset(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetDataViewByteOffset(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return the byte length of a data view.
|
||||
|
@ -1372,7 +1415,7 @@ JS_GetDataViewByteOffset(JSObject *obj, JSContext *maybecx);
|
|||
* unable to assert when unwrapping should be disallowed.
|
||||
*/
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetDataViewByteLength(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetDataViewByteLength(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return a pointer to the beginning of the data referenced by a DataView.
|
||||
|
@ -1383,9 +1426,8 @@ JS_GetDataViewByteLength(JSObject *obj, JSContext *maybecx);
|
|||
* unable to assert when unwrapping should be disallowed.
|
||||
*/
|
||||
JS_FRIEND_API(void *)
|
||||
JS_GetDataViewData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetDataViewData(JSObject *obj);
|
||||
|
||||
#ifdef __cplusplus
|
||||
/*
|
||||
* This struct contains metadata passed from the DOM to the JS Engine for JIT
|
||||
* optimizations on DOM property accessors. Eventually, this should be made
|
||||
|
@ -1420,15 +1462,16 @@ FUNCTION_VALUE_TO_JITINFO(const JS::Value& v)
|
|||
return reinterpret_cast<js::shadow::Function *>(&v.toObject())->jitinfo;
|
||||
}
|
||||
|
||||
/* Statically asserted in jsfun.h. */
|
||||
static const unsigned JS_FUNCTION_INTERPRETED_BIT = 0x1;
|
||||
|
||||
static JS_ALWAYS_INLINE void
|
||||
SET_JITINFO(JSFunction * func, const JSJitInfo *info)
|
||||
{
|
||||
js::shadow::Function *fun = reinterpret_cast<js::shadow::Function *>(func);
|
||||
/* JS_ASSERT(func->isNative()). 0x4000 is JSFUN_INTERPRETED */
|
||||
JS_ASSERT(!(fun->flags & 0x4000));
|
||||
JS_ASSERT(!(fun->flags & JS_FUNCTION_INTERPRETED_BIT));
|
||||
fun->jitinfo = info;
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* Engine-internal extensions of jsid. This code is here only until we
|
||||
|
@ -1494,8 +1537,6 @@ JSID_TO_ATOM(jsid id)
|
|||
|
||||
JS_STATIC_ASSERT(sizeof(jsid) == JS_BYTES_PER_WORD);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace js {
|
||||
|
||||
static JS_ALWAYS_INLINE Value
|
||||
|
@ -1517,8 +1558,12 @@ IdToJsval(jsid id)
|
|||
return IdToValue(id);
|
||||
}
|
||||
|
||||
extern JS_FRIEND_API(bool)
|
||||
IsReadOnlyDateMethod(JS::IsAcceptableThis test, JS::NativeImpl method);
|
||||
|
||||
extern JS_FRIEND_API(bool)
|
||||
IsTypedArrayThisCheck(JS::IsAcceptableThis test);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* jsfriendapi_h___ */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -38,25 +38,4 @@ typedef struct PRLock PRLock;
|
|||
|
||||
#endif /* JS_THREADSAFE */
|
||||
|
||||
namespace js {
|
||||
|
||||
class AutoAtomicIncrement
|
||||
{
|
||||
int32_t *p;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
||||
public:
|
||||
AutoAtomicIncrement(int32_t *p JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: p(p) {
|
||||
JS_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
JS_ATOMIC_INCREMENT(p);
|
||||
}
|
||||
|
||||
~AutoAtomicIncrement() {
|
||||
JS_ATOMIC_DECREMENT(p);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jslock_h___ */
|
||||
|
|
|
@ -38,7 +38,7 @@ enum DecodingMode { STRICT, LEGACY };
|
|||
namespace js {
|
||||
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
ParseJSONWithReviver(JSContext *cx, const jschar *chars, size_t length, HandleValue filter,
|
||||
ParseJSONWithReviver(JSContext *cx, JS::StableCharPtr chars, size_t length, HandleValue filter,
|
||||
MutableHandleValue vp, DecodingMode decodingMode = STRICT);
|
||||
|
||||
} /* namespace js */
|
||||
|
|
|
@ -16,10 +16,9 @@
|
|||
** %hd, %hu, %hx, %hX, %ho - 16-bit versions of above
|
||||
** %ld, %lu, %lx, %lX, %lo - 32-bit versions of above
|
||||
** %lld, %llu, %llx, %llX, %llo - 64 bit versions of above
|
||||
** %s - string
|
||||
** %hs - 16-bit version of above (only available if js_CStringsAreUTF8)
|
||||
** %s - ascii string
|
||||
** %hs - ucs2 string
|
||||
** %c - character
|
||||
** %hc - 16-bit version of above (only available if js_CStringsAreUTF8)
|
||||
** %p - pointer (deals with machine dependent pointer size)
|
||||
** %f - float
|
||||
** %g - float
|
||||
|
@ -28,8 +27,6 @@
|
|||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
** sprintf into a fixed size buffer. Guarantees that a NUL is at the end
|
||||
** of the buffer. Returns the length of the written output, NOT including
|
||||
|
@ -77,6 +74,4 @@ extern JS_PUBLIC_API(char*) JS_vsmprintf(const char *fmt, va_list ap);
|
|||
extern JS_PUBLIC_API(char*) JS_vsprintf_append(char *last, const char *fmt, va_list ap);
|
||||
extern JS_PUBLIC_API(uint32_t) JS_vsxprintf(JSStuffFunc f, void *arg, const char *fmt, va_list ap);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* jsprf_h___ */
|
||||
|
|
|
@ -60,5 +60,6 @@
|
|||
macro(Set, 38, js_InitSetClass) \
|
||||
macro(DataView, 39, js_InitTypedArrayClasses) \
|
||||
macro(ParallelArray, 40, js_InitParallelArrayClass) \
|
||||
macro(Intl, 41, js_InitIntlClass) \
|
||||
|
||||
#endif /* jsprototypes_h___ */
|
||||
|
|
|
@ -26,7 +26,9 @@ class JS_FRIEND_API(Wrapper);
|
|||
*
|
||||
* Proxy traps are grouped into fundamental and derived traps. Every proxy has
|
||||
* to at least provide implementations for the fundamental traps, but the
|
||||
* derived traps can be implemented in terms of the fundamental ones.
|
||||
* derived traps can be implemented in terms of the fundamental ones
|
||||
* BaseProxyHandler provides implementations of the derived traps in terms of
|
||||
* the (pure virtual) fundamental traps.
|
||||
*
|
||||
* To minimize code duplication, a set of abstract proxy handler classes is
|
||||
* provided, from which other handlers may inherit. These abstract classes
|
||||
|
@ -34,9 +36,9 @@ class JS_FRIEND_API(Wrapper);
|
|||
*
|
||||
* BaseProxyHandler
|
||||
* |
|
||||
* IndirectProxyHandler
|
||||
* |
|
||||
* DirectProxyHandler
|
||||
* |
|
||||
* Wrapper
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -69,20 +71,6 @@ class JS_FRIEND_API(BaseProxyHandler) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* The function Wrapper::wrapperHandler takes a pointer to a
|
||||
* BaseProxyHandler and returns a pointer to a Wrapper if and only if the
|
||||
* BaseProxyHandler is a wrapper handler (otherwise, it returns NULL).
|
||||
*
|
||||
* Unfortunately, we can't inherit Wrapper from BaseProxyHandler, since that
|
||||
* would create a dreaded diamond, and we can't use dynamic_cast to cast
|
||||
* BaseProxyHandler to Wrapper, since that would require us to compile with
|
||||
* run-time type information. Hence the need for this virtual function.
|
||||
*/
|
||||
virtual Wrapper *toWrapper() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ES5 Harmony fundamental proxy traps. */
|
||||
virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id,
|
||||
bool set, PropertyDescriptor *desc) = 0;
|
||||
|
@ -130,17 +118,14 @@ class JS_FRIEND_API(BaseProxyHandler) {
|
|||
};
|
||||
|
||||
/*
|
||||
* IndirectProxyHandler assumes that a target exists. Moreover, it assumes the
|
||||
* target is a JSObject. Consequently, it provides default implementations for
|
||||
* the fundamental traps that forward their behavior to the target. The derived
|
||||
* traps, however, are inherited from BaseProxyHandler, and therefore still
|
||||
* implemented in terms of the fundamental ones. This allows consumers of this
|
||||
* class to define custom behavior without implementing the entire gamut of
|
||||
* proxy traps.
|
||||
* DirectProxyHandler includes a notion of a target object. All traps are
|
||||
* reimplemented such that they forward their behavior to the target. This
|
||||
* allows consumers of this class to forward to another object as transparently
|
||||
* and efficiently as possible.
|
||||
*/
|
||||
class JS_PUBLIC_API(IndirectProxyHandler) : public BaseProxyHandler {
|
||||
public:
|
||||
explicit IndirectProxyHandler(void *family);
|
||||
class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler {
|
||||
public:
|
||||
explicit DirectProxyHandler(void *family);
|
||||
|
||||
/* ES5 Harmony fundamental proxy traps. */
|
||||
virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id,
|
||||
|
@ -158,11 +143,21 @@ class JS_PUBLIC_API(IndirectProxyHandler) : public BaseProxyHandler {
|
|||
virtual bool enumerate(JSContext *cx, JSObject *proxy,
|
||||
AutoIdVector &props) MOZ_OVERRIDE;
|
||||
|
||||
/* ES5 Harmony derived proxy traps. */
|
||||
virtual bool has(JSContext *cx, JSObject *proxy, jsid id,
|
||||
bool *bp) MOZ_OVERRIDE;
|
||||
virtual bool hasOwn(JSContext *cx, JSObject *proxy, jsid id,
|
||||
bool *bp) MOZ_OVERRIDE;
|
||||
virtual bool get(JSContext *cx, JSObject *proxy, JSObject *receiver,
|
||||
jsid id, Value *vp) MOZ_OVERRIDE;
|
||||
virtual bool set(JSContext *cx, JSObject *proxy, JSObject *receiver,
|
||||
jsid id, bool strict, Value *vp) MOZ_OVERRIDE;
|
||||
virtual bool keys(JSContext *cx, JSObject *proxy,
|
||||
AutoIdVector &props) MOZ_OVERRIDE;
|
||||
virtual bool iterate(JSContext *cx, JSObject *proxy, unsigned flags,
|
||||
Value *vp) MOZ_OVERRIDE;
|
||||
|
||||
/* Spidermonkey extensions. */
|
||||
virtual bool call(JSContext *cx, JSObject *proxy, unsigned argc,
|
||||
Value *vp) MOZ_OVERRIDE;
|
||||
virtual bool construct(JSContext *cx, JSObject *proxy, unsigned argc,
|
||||
Value *argv, Value *rval) MOZ_OVERRIDE;
|
||||
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
|
||||
CallArgs args) MOZ_OVERRIDE;
|
||||
virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
|
||||
|
@ -182,33 +177,6 @@ class JS_PUBLIC_API(IndirectProxyHandler) : public BaseProxyHandler {
|
|||
virtual JSObject *weakmapKeyDelegate(JSObject *proxy);
|
||||
};
|
||||
|
||||
/*
|
||||
* DirectProxyHandler has the same assumptions about the target as its base,
|
||||
* IndirectProxyHandler. Its fundamental traps are inherited from this class,
|
||||
* and therefore forward their behavior to the target. The derived traps,
|
||||
* however, are overrided so that, they too, forward their behavior to the
|
||||
* target. This allows consumers of this class to forward to another object as
|
||||
* transparently as possible.
|
||||
*/
|
||||
class JS_PUBLIC_API(DirectProxyHandler) : public IndirectProxyHandler {
|
||||
public:
|
||||
explicit DirectProxyHandler(void *family);
|
||||
|
||||
/* ES5 Harmony derived proxy traps. */
|
||||
virtual bool has(JSContext *cx, JSObject *proxy, jsid id,
|
||||
bool *bp) MOZ_OVERRIDE;
|
||||
virtual bool hasOwn(JSContext *cx, JSObject *proxy, jsid id,
|
||||
bool *bp) MOZ_OVERRIDE;
|
||||
virtual bool get(JSContext *cx, JSObject *proxy, JSObject *receiver,
|
||||
jsid id, Value *vp) MOZ_OVERRIDE;
|
||||
virtual bool set(JSContext *cx, JSObject *proxy, JSObject *receiver,
|
||||
jsid id, bool strict, Value *vp) MOZ_OVERRIDE;
|
||||
virtual bool keys(JSContext *cx, JSObject *proxy,
|
||||
AutoIdVector &props) MOZ_OVERRIDE;
|
||||
virtual bool iterate(JSContext *cx, JSObject *proxy, unsigned flags,
|
||||
Value *vp) MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
/* Dispatch point for handlers that executes the appropriate C++ or scripted traps. */
|
||||
class Proxy {
|
||||
public:
|
||||
|
@ -350,13 +318,12 @@ NewProxyObject(JSContext *cx, BaseProxyHandler *handler, const Value &priv,
|
|||
JSObject *proto, JSObject *parent,
|
||||
JSObject *call = NULL, JSObject *construct = NULL);
|
||||
|
||||
} /* namespace js */
|
||||
JSObject *
|
||||
RenewProxyObject(JSContext *cx, JSObject *obj, BaseProxyHandler *handler, Value priv);
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
} /* namespace js */
|
||||
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
js_InitProxyClass(JSContext *cx, JSHandleObject obj);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,8 +29,6 @@
|
|||
#include "js/Vector.h"
|
||||
#endif
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
* Convenience constants.
|
||||
*/
|
||||
|
@ -129,7 +127,7 @@ class ScriptFrameIter;
|
|||
|
||||
class Proxy;
|
||||
class JS_FRIEND_API(BaseProxyHandler);
|
||||
class JS_FRIEND_API(DirectWrapper);
|
||||
class JS_FRIEND_API(Wrapper);
|
||||
class JS_FRIEND_API(CrossCompartmentWrapper);
|
||||
|
||||
class TempAllocPolicy;
|
||||
|
@ -379,16 +377,5 @@ typedef JSObject *
|
|||
typedef JSObject *
|
||||
(* JSIteratorOp)(JSContext *cx, JSHandleObject obj, JSBool keysonly);
|
||||
|
||||
/*
|
||||
* The following determines whether JS_EncodeCharacters and JS_DecodeBytes
|
||||
* treat char[] as utf-8 or simply as bytes that need to be inflated/deflated.
|
||||
*/
|
||||
#ifdef JS_C_STRINGS_ARE_UTF8
|
||||
# define js_CStringsAreUTF8 JS_TRUE
|
||||
#else
|
||||
extern JSBool js_CStringsAreUTF8;
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* jsprvtd_h___ */
|
||||
|
|
|
@ -39,6 +39,8 @@ namespace JS { class Value; }
|
|||
*/
|
||||
#ifdef __cplusplus
|
||||
|
||||
#define JS_NO_JSVAL_JSID_STRUCT_TYPES
|
||||
|
||||
# if defined(DEBUG) && !defined(JS_NO_JSVAL_JSID_STRUCT_TYPES)
|
||||
# define JS_USE_JSID_STRUCT_TYPES
|
||||
# endif
|
||||
|
@ -60,8 +62,6 @@ typedef ptrdiff_t jsid;
|
|||
# define JSID_BITS(id) (id)
|
||||
#endif
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
#ifdef WIN32
|
||||
typedef wchar_t jschar;
|
||||
#else
|
||||
|
@ -217,8 +217,6 @@ typedef JSBool JSCallOnceType;
|
|||
#endif
|
||||
typedef JSBool (*JSInitCallback)(void);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace js {
|
||||
|
@ -311,14 +309,6 @@ struct RuntimeFriendFields {
|
|||
/* Limit pointer for checking native stack consumption. */
|
||||
uintptr_t nativeStackLimit;
|
||||
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
/*
|
||||
* Stack allocated GC roots for stack GC heap pointers, which may be
|
||||
* overwritten if moved during a GC.
|
||||
*/
|
||||
Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
|
||||
#endif
|
||||
|
||||
RuntimeFriendFields()
|
||||
: interrupt(0),
|
||||
nativeStackLimit(0) { }
|
||||
|
@ -328,6 +318,32 @@ struct RuntimeFriendFields {
|
|||
}
|
||||
};
|
||||
|
||||
class PerThreadData;
|
||||
|
||||
struct PerThreadDataFriendFields
|
||||
{
|
||||
PerThreadDataFriendFields();
|
||||
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
/*
|
||||
* Stack allocated GC roots for stack GC heap pointers, which may be
|
||||
* overwritten if moved during a GC.
|
||||
*/
|
||||
Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
|
||||
#endif
|
||||
|
||||
static PerThreadDataFriendFields *get(js::PerThreadData *pt) {
|
||||
return reinterpret_cast<PerThreadDataFriendFields *>(pt);
|
||||
}
|
||||
|
||||
static PerThreadDataFriendFields *getMainThread(JSRuntime *rt) {
|
||||
// mainThread must always appear directly after |RuntimeFriendFields|.
|
||||
// Tested by a JS_STATIC_ASSERT in |jsfriendapi.cpp|
|
||||
return reinterpret_cast<PerThreadDataFriendFields *>(
|
||||
reinterpret_cast<char*>(rt) + sizeof(RuntimeFriendFields));
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
|
|
@ -46,11 +46,11 @@
|
|||
**
|
||||
***********************************************************************/
|
||||
|
||||
#define JS_EXTERN_API(type) extern MOZ_EXPORT_API(type)
|
||||
#define JS_EXPORT_API(type) MOZ_EXPORT_API(type)
|
||||
#define JS_EXPORT_DATA(type) MOZ_EXPORT_DATA(type)
|
||||
#define JS_IMPORT_API(type) MOZ_IMPORT_API(type)
|
||||
#define JS_IMPORT_DATA(type) MOZ_IMPORT_DATA(type)
|
||||
#define JS_EXTERN_API(type) extern MOZ_EXPORT type
|
||||
#define JS_EXPORT_API(type) MOZ_EXPORT type
|
||||
#define JS_EXPORT_DATA(type) MOZ_EXPORT type
|
||||
#define JS_IMPORT_API(type) MOZ_IMPORT_API type
|
||||
#define JS_IMPORT_DATA(type) MOZ_IMPORT_DATA type
|
||||
|
||||
/*
|
||||
* The linkage of JS API functions differs depending on whether the file is
|
||||
|
@ -62,11 +62,11 @@
|
|||
# define JS_PUBLIC_API(t) t
|
||||
# define JS_PUBLIC_DATA(t) t
|
||||
#elif defined(EXPORT_JS_API) || defined(STATIC_EXPORTABLE_JS_API)
|
||||
# define JS_PUBLIC_API(t) MOZ_EXPORT_API(t)
|
||||
# define JS_PUBLIC_DATA(t) MOZ_EXPORT_DATA(t)
|
||||
# define JS_PUBLIC_API(t) MOZ_EXPORT t
|
||||
# define JS_PUBLIC_DATA(t) MOZ_EXPORT t
|
||||
#else
|
||||
# define JS_PUBLIC_API(t) MOZ_IMPORT_API(t)
|
||||
# define JS_PUBLIC_DATA(t) MOZ_IMPORT_DATA(t)
|
||||
# define JS_PUBLIC_API(t) MOZ_IMPORT_API t
|
||||
# define JS_PUBLIC_DATA(t) MOZ_IMPORT_DATA t
|
||||
#endif
|
||||
|
||||
#define JS_FRIEND_API(t) JS_PUBLIC_API(t)
|
||||
|
@ -181,8 +181,6 @@
|
|||
#endif
|
||||
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/************************************************************************
|
||||
** TYPES: JSBool
|
||||
** DESCRIPTION:
|
||||
|
@ -282,6 +280,4 @@ typedef int JSBool;
|
|||
# define JS_EXTENSION_(s) s
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* jstypes_h___ */
|
||||
|
|
|
@ -369,23 +369,23 @@ class Compressor
|
|||
z_stream zs;
|
||||
const unsigned char *inp;
|
||||
size_t inplen;
|
||||
size_t outbytes;
|
||||
|
||||
public:
|
||||
Compressor(const unsigned char *inp, size_t inplen, unsigned char *out)
|
||||
: inp(inp),
|
||||
inplen(inplen)
|
||||
{
|
||||
JS_ASSERT(inplen > 0);
|
||||
zs.opaque = NULL;
|
||||
zs.next_in = (Bytef *)inp;
|
||||
zs.avail_in = 0;
|
||||
zs.next_out = out;
|
||||
zs.avail_out = inplen;
|
||||
}
|
||||
enum Status {
|
||||
MOREOUTPUT,
|
||||
DONE,
|
||||
CONTINUE,
|
||||
OOM
|
||||
};
|
||||
|
||||
Compressor(const unsigned char *inp, size_t inplen);
|
||||
~Compressor();
|
||||
bool init();
|
||||
void setOutput(unsigned char *out, size_t outlen);
|
||||
size_t outWritten() const { return outbytes; }
|
||||
/* Compress some of the input. Return true if it should be called again. */
|
||||
bool compressMore();
|
||||
/* Finalize compression. Return the length of the compressed input. */
|
||||
size_t finish();
|
||||
Status compressMore();
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
|
||||
#include "js/Utility.h"
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
* Try to get jsvals 64-bit aligned. We could almost assert that all values are
|
||||
* aligned, but MSVC and GCC occasionally break alignment.
|
||||
|
@ -835,8 +833,6 @@ JS_CANONICALIZE_NAN(double d)
|
|||
return d;
|
||||
}
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#ifdef __cplusplus
|
||||
static jsval_layout JSVAL_TO_IMPL(JS::Value);
|
||||
static JS::Value IMPL_TO_JSVAL(jsval_layout);
|
||||
|
|
|
@ -170,4 +170,7 @@
|
|||
MOZ_NOT_REACHED("don't call this! to be used in the new object representation")
|
||||
#endif
|
||||
|
||||
/* ECMAScript Internationalization API isn't fully implemented yet. */
|
||||
#define ENABLE_INTL_API 0
|
||||
|
||||
#endif /* jsversion_h___ */
|
||||
|
|
|
@ -18,36 +18,24 @@ namespace js {
|
|||
class DummyFrameGuard;
|
||||
|
||||
/*
|
||||
* A wrapper is essentially a proxy that restricts access to certain traps. The
|
||||
* way in which a wrapper restricts access to its traps depends on the
|
||||
* particular policy for that wrapper. To allow a wrapper's policy to be
|
||||
* customized, the Wrapper base class contains two functions, enter/leave, which
|
||||
* are called as a policy enforcement check before/after each trap is forwarded.
|
||||
*
|
||||
* To minimize code duplication, a set of abstract wrapper classes is
|
||||
* provided, from which other wrappers may inherit. These abstract classes are
|
||||
* organized in the following hierarchy:
|
||||
*
|
||||
* BaseProxyHandler Wrapper
|
||||
* | | |
|
||||
* IndirectProxyHandler | |
|
||||
* | | | |
|
||||
* | IndirectWrapper |
|
||||
* | |
|
||||
* DirectProxyHandler |
|
||||
* | |
|
||||
* DirectWrapper
|
||||
* A wrapper is a proxy with a target object to which it generally forwards
|
||||
* operations, but may restrict access to certain operations or instrument
|
||||
* the trap operations in various ways. A wrapper is distinct from a Direct Proxy
|
||||
* Handler in the sense that it can be "unwrapped" in C++, exposing the underlying
|
||||
* object (Direct Proxy Handlers have an underlying target object, but don't
|
||||
* expect to expose this object via any kind of unwrapping operation). Callers
|
||||
* should be careful to avoid unwrapping security wrappers in the wrong context.
|
||||
*/
|
||||
class JS_FRIEND_API(Wrapper)
|
||||
class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
|
||||
{
|
||||
unsigned mFlags;
|
||||
bool mSafeToUnwrap;
|
||||
|
||||
public:
|
||||
enum Action {
|
||||
GET,
|
||||
SET,
|
||||
CALL,
|
||||
PUNCTURE
|
||||
CALL
|
||||
};
|
||||
|
||||
enum Flags {
|
||||
|
@ -55,128 +43,42 @@ class JS_FRIEND_API(Wrapper)
|
|||
LAST_USED_FLAG = CROSS_COMPARTMENT
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
PermitObjectAccess,
|
||||
PermitPropertyAccess,
|
||||
DenyAccess
|
||||
} Permission;
|
||||
/*
|
||||
* Wrappers can explicitly specify that they are unsafe to unwrap from a
|
||||
* security perspective (as is the case for SecurityWrappers). If a wrapper
|
||||
* is not safe to unwrap, operations requiring full access to the underlying
|
||||
* object (via UnwrapObjectChecked) will throw. Otherwise, they will succeed.
|
||||
*/
|
||||
void setSafeToUnwrap(bool safe) { mSafeToUnwrap = safe; };
|
||||
bool isSafeToUnwrap() { return mSafeToUnwrap; };
|
||||
|
||||
static JSObject *New(JSContext *cx, JSObject *obj, JSObject *proto,
|
||||
JSObject *parent, Wrapper *handler);
|
||||
|
||||
static JSObject *Renew(JSContext *cx, JSObject *existing, JSObject *obj, Wrapper *handler);
|
||||
|
||||
static Wrapper *wrapperHandler(RawObject wrapper);
|
||||
|
||||
static JSObject *wrappedObject(RawObject wrapper);
|
||||
|
||||
explicit Wrapper(unsigned flags);
|
||||
|
||||
unsigned flags() const {
|
||||
return mFlags;
|
||||
}
|
||||
|
||||
/*
|
||||
* The function Wrapper::New takes a pointer to a Wrapper as the handler
|
||||
* object. It then passes it on to the function NewProxyObject, which
|
||||
* expects a pointer to a BaseProxyHandler as the handler object. We don't
|
||||
* want to change Wrapper::New to take a pointer to a BaseProxyHandler,
|
||||
* because that would allow the creation of wrappers with non-wrapper
|
||||
* handlers. Unfortunately, we can't inherit Wrapper from BaseProxyHandler,
|
||||
* since that would create a dreaded diamond, and we can't use dynamic_cast
|
||||
* to cast Wrapper to BaseProxyHandler, since that would require us to
|
||||
* compile with run time type information. Hence the need for this virtual
|
||||
* function.
|
||||
*/
|
||||
virtual BaseProxyHandler *toBaseProxyHandler() = 0;
|
||||
|
||||
/* Policy enforcement traps.
|
||||
*
|
||||
* enter() allows the policy to specify whether the caller may perform |act|
|
||||
* on the underlying object's |id| property. In the case when |act| is CALL,
|
||||
* |id| is generally JSID_VOID.
|
||||
*
|
||||
* The |act| parameter to enter() specifies the action being performed. GET,
|
||||
* SET, and CALL are self-explanatory, but PUNCTURE requires more
|
||||
* explanation:
|
||||
*
|
||||
* GET and SET allow for a very fine-grained security membrane, through
|
||||
* which access can be granted or denied on a per-property, per-object, and
|
||||
* per-action basis. Sometimes though, we just want to asks if we can access
|
||||
* _everything_ behind the wrapper barrier. For example, when the structured
|
||||
* clone algorithm runs up against a cross-compartment wrapper, it needs to
|
||||
* know whether it can enter the compartment and keep cloning, or whether it
|
||||
* should throw. This is the role of PUNCTURE.
|
||||
*
|
||||
* PUNCTURE allows the policy to specify whether the wrapper barrier may
|
||||
* be lifted - that is to say, whether the caller is allowed to access
|
||||
* anything that the wrapped object could access. This is a very powerful
|
||||
* permission, and thus should generally be denied for security wrappers
|
||||
* except under very special circumstances. When |act| is PUNCTURE, |id|
|
||||
* should be JSID_VOID.
|
||||
* The |act| parameter to enter() specifies the action being performed.
|
||||
*/
|
||||
virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, Action act,
|
||||
bool *bp);
|
||||
};
|
||||
|
||||
/*
|
||||
* IndirectWrapper forwards its traps by forwarding them to
|
||||
* IndirectProxyHandler. In effect, IndirectWrapper behaves the same as
|
||||
* IndirectProxyHandler, except that it adds policy enforcement checks to each
|
||||
* fundamental trap.
|
||||
*/
|
||||
class JS_FRIEND_API(IndirectWrapper) : public Wrapper,
|
||||
public IndirectProxyHandler
|
||||
{
|
||||
public:
|
||||
explicit IndirectWrapper(unsigned flags);
|
||||
explicit Wrapper(unsigned flags, bool hasPrototype = false);
|
||||
|
||||
virtual BaseProxyHandler* toBaseProxyHandler() {
|
||||
return this;
|
||||
}
|
||||
|
||||
virtual Wrapper *toWrapper() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/* ES5 Harmony fundamental wrapper traps. */
|
||||
virtual bool getPropertyDescriptor(JSContext *cx, JSObject *wrapper,
|
||||
jsid id, bool set,
|
||||
PropertyDescriptor *desc) MOZ_OVERRIDE;
|
||||
virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper,
|
||||
jsid id, bool set,
|
||||
PropertyDescriptor *desc) MOZ_OVERRIDE;
|
||||
virtual bool defineProperty(JSContext *cx, JSObject *wrapper, jsid id,
|
||||
PropertyDescriptor *desc) MOZ_OVERRIDE;
|
||||
virtual bool getOwnPropertyNames(JSContext *cx, JSObject *wrapper,
|
||||
AutoIdVector &props) MOZ_OVERRIDE;
|
||||
virtual bool delete_(JSContext *cx, JSObject *wrapper, jsid id,
|
||||
bool *bp) MOZ_OVERRIDE;
|
||||
virtual bool enumerate(JSContext *cx, JSObject *wrapper,
|
||||
AutoIdVector &props) MOZ_OVERRIDE;
|
||||
|
||||
/* Spidermonkey extensions. */
|
||||
virtual bool defaultValue(JSContext *cx, JSObject *wrapper_, JSType hint,
|
||||
Value *vp) MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
/*
|
||||
* DirectWrapper forwards its traps by forwarding them to DirectProxyHandler.
|
||||
* In effect, DirectWrapper behaves the same as DirectProxyHandler, except that
|
||||
* it adds policy enforcement checks to each trap.
|
||||
*/
|
||||
class JS_FRIEND_API(DirectWrapper) : public Wrapper, public DirectProxyHandler
|
||||
{
|
||||
public:
|
||||
explicit DirectWrapper(unsigned flags, bool hasPrototype = false);
|
||||
|
||||
virtual ~DirectWrapper();
|
||||
|
||||
virtual BaseProxyHandler* toBaseProxyHandler() {
|
||||
return this;
|
||||
}
|
||||
|
||||
virtual Wrapper *toWrapper() {
|
||||
return this;
|
||||
}
|
||||
virtual ~Wrapper();
|
||||
|
||||
/* ES5 Harmony fundamental wrapper traps. */
|
||||
virtual bool getPropertyDescriptor(JSContext *cx, JSObject *wrapper,
|
||||
|
@ -214,14 +116,14 @@ class JS_FRIEND_API(DirectWrapper) : public Wrapper, public DirectProxyHandler
|
|||
virtual bool defaultValue(JSContext *cx, JSObject *wrapper_, JSType hint,
|
||||
Value *vp) MOZ_OVERRIDE;
|
||||
|
||||
static DirectWrapper singleton;
|
||||
static DirectWrapper singletonWithPrototype;
|
||||
static Wrapper singleton;
|
||||
static Wrapper singletonWithPrototype;
|
||||
|
||||
static void *getWrapperFamily();
|
||||
};
|
||||
|
||||
/* Base class for all cross compartment wrapper handlers. */
|
||||
class JS_FRIEND_API(CrossCompartmentWrapper) : public DirectWrapper
|
||||
class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper
|
||||
{
|
||||
public:
|
||||
CrossCompartmentWrapper(unsigned flags, bool hasPrototype = false);
|
||||
|
@ -280,13 +182,22 @@ class JS_FRIEND_API(SecurityWrapper) : public Base
|
|||
public:
|
||||
SecurityWrapper(unsigned flags);
|
||||
|
||||
virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, Wrapper::Action act,
|
||||
bool *bp) MOZ_OVERRIDE;
|
||||
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
|
||||
CallArgs args) MOZ_OVERRIDE;
|
||||
virtual bool objectClassIs(JSObject *obj, ESClassValue classValue, JSContext *cx) MOZ_OVERRIDE;
|
||||
virtual bool regexp_toShared(JSContext *cx, JSObject *proxy, RegExpGuard *g) MOZ_OVERRIDE;
|
||||
|
||||
/*
|
||||
* Allow our subclasses to select the superclass behavior they want without
|
||||
* needing to specify an exact superclass.
|
||||
*/
|
||||
typedef Base Permissive;
|
||||
typedef SecurityWrapper<Base> Restrictive;
|
||||
};
|
||||
|
||||
typedef SecurityWrapper<DirectWrapper> SameCompartmentSecurityWrapper;
|
||||
typedef SecurityWrapper<Wrapper> SameCompartmentSecurityWrapper;
|
||||
typedef SecurityWrapper<CrossCompartmentWrapper> CrossCompartmentSecurityWrapper;
|
||||
|
||||
class JS_FRIEND_API(DeadObjectProxy) : public BaseProxyHandler
|
||||
|
@ -327,7 +238,8 @@ class JS_FRIEND_API(DeadObjectProxy) : public BaseProxyHandler
|
|||
};
|
||||
|
||||
extern JSObject *
|
||||
TransparentObjectWrapper(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSObject *parent,
|
||||
TransparentObjectWrapper(JSContext *cx, JSObject *existing, JSObject *obj,
|
||||
JSObject *wrappedProto, JSObject *parent,
|
||||
unsigned flags);
|
||||
|
||||
// Proxy family for wrappers. Public so that IsWrapper() can be fully inlined by
|
||||
|
@ -352,16 +264,19 @@ UnwrapObject(JSObject *obj, bool stopAtOuter = true, unsigned *flagsp = NULL);
|
|||
// code should never be unwrapping outer window wrappers, we always stop at
|
||||
// outer windows.
|
||||
JS_FRIEND_API(JSObject *)
|
||||
UnwrapObjectChecked(JSContext *cx, RawObject obj);
|
||||
UnwrapObjectChecked(RawObject obj);
|
||||
|
||||
// Unwrap only the outermost security wrapper, with the same semantics as
|
||||
// above. This is the checked version of Wrapper::wrappedObject.
|
||||
JS_FRIEND_API(JSObject *)
|
||||
UnwrapOneChecked(JSContext *cx, HandleObject obj);
|
||||
UnwrapOneChecked(RawObject obj);
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
IsCrossCompartmentWrapper(RawObject obj);
|
||||
|
||||
bool
|
||||
IsDeadProxyObject(RawObject obj);
|
||||
|
||||
JSObject *
|
||||
NewDeadProxyObject(JSContext *cx, JSObject *parent);
|
||||
|
||||
|
@ -381,6 +296,34 @@ JS_FRIEND_API(bool)
|
|||
RecomputeWrappers(JSContext *cx, const CompartmentFilter &sourceFilter,
|
||||
const CompartmentFilter &targetFilter);
|
||||
|
||||
/*
|
||||
* This auto class should be used around any code, such as brain transplants,
|
||||
* that may touch dead compartments. Brain transplants can cause problems
|
||||
* because they operate on all compartments, whether live or dead. A brain
|
||||
* transplant can cause a formerly dead object to be "reanimated" by causing a
|
||||
* read or write barrier to be invoked on it during the transplant. In this way,
|
||||
* a compartment becomes a zombie, kept alive by repeatedly consuming
|
||||
* (transplanted) brains.
|
||||
*
|
||||
* To work around this issue, we observe when mark bits are set on objects in
|
||||
* dead compartments. If this happens during a brain transplant, we do a full,
|
||||
* non-incremental GC at the end of the brain transplant. This will clean up any
|
||||
* objects that were improperly marked.
|
||||
*/
|
||||
struct JS_FRIEND_API(AutoMaybeTouchDeadCompartments)
|
||||
{
|
||||
// The version that takes an object just uses it for its runtime.
|
||||
AutoMaybeTouchDeadCompartments(JSContext *cx);
|
||||
AutoMaybeTouchDeadCompartments(JSObject *obj);
|
||||
~AutoMaybeTouchDeadCompartments();
|
||||
|
||||
private:
|
||||
JSRuntime *runtime;
|
||||
unsigned markCount;
|
||||
bool inIncremental;
|
||||
bool manipulatingDeadCompartments;
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -93,6 +93,8 @@
|
|||
# endif
|
||||
# if __GNUC_MINOR__ >= 4
|
||||
# define MOZ_HAVE_CXX11_DELETE
|
||||
# endif
|
||||
# if __GNUC_MINOR__ >= 5
|
||||
# define MOZ_HAVE_CXX11_ENUM_TYPE
|
||||
# define MOZ_HAVE_CXX11_STRONG_ENUMS
|
||||
# endif
|
||||
|
@ -356,6 +358,9 @@
|
|||
* supported, as with MOZ_ENUM_TYPE(). For simplicity, it is currently
|
||||
* mandatory. As with MOZ_ENUM_TYPE(), it will do nothing on compilers that do
|
||||
* not support it.
|
||||
*
|
||||
* Note that the workaround implemented here is not compatible with enums
|
||||
* nested inside a class.
|
||||
*/
|
||||
#if defined(MOZ_HAVE_CXX11_STRONG_ENUMS)
|
||||
/* All compilers that support strong enums also support an explicit
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#ifndef mozilla_BloomFilter_h_
|
||||
#define mozilla_BloomFilter_h_
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/StandardInteger.h"
|
||||
#include "mozilla/Util.h"
|
||||
|
|
|
@ -385,13 +385,13 @@ IsSubValid(T x, T y)
|
|||
}
|
||||
|
||||
template<typename T,
|
||||
bool IsSigned = IsSigned<T>::value,
|
||||
bool IsTSigned = IsSigned<T>::value,
|
||||
bool TwiceBiggerTypeIsSupported =
|
||||
IsSupported<typename TwiceBiggerType<T>::Type>::value>
|
||||
struct IsMulValidImpl {};
|
||||
|
||||
template<typename T, bool IsSigned>
|
||||
struct IsMulValidImpl<T, IsSigned, true>
|
||||
template<typename T, bool IsTSigned>
|
||||
struct IsMulValidImpl<T, IsTSigned, true>
|
||||
{
|
||||
static bool run(T x, T y)
|
||||
{
|
||||
|
@ -451,7 +451,7 @@ IsDivValid(T x, T y)
|
|||
}
|
||||
|
||||
// This is just to shut up msvc warnings about negating unsigned ints.
|
||||
template<typename T, bool IsSigned = IsSigned<T>::value>
|
||||
template<typename T, bool IsTSigned = IsSigned<T>::value>
|
||||
struct OppositeIfSignedImpl
|
||||
{
|
||||
static T run(T x) { return -x; }
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* A set abstraction for enumeration values. */
|
||||
|
||||
#ifndef mozilla_EnumSet_h
|
||||
#define mozilla_EnumSet_h
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/StandardInteger.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* EnumSet<T> is a set of values defined by an enumeration. It is implemented
|
||||
* using a 32 bit mask for each value so it will only work for enums with an int
|
||||
* representation less than 32. It works both for enum and enum class types.
|
||||
*/
|
||||
template<typename T>
|
||||
class EnumSet
|
||||
{
|
||||
public:
|
||||
EnumSet()
|
||||
: mBitField(0)
|
||||
{ }
|
||||
|
||||
EnumSet(T aEnum)
|
||||
: mBitField(aEnum)
|
||||
{ }
|
||||
|
||||
EnumSet(T aEnum1, T aEnum2)
|
||||
: mBitField(bitFor(aEnum1) |
|
||||
bitFor(aEnum2))
|
||||
{ }
|
||||
|
||||
EnumSet(T aEnum1, T aEnum2, T aEnum3)
|
||||
: mBitField(bitFor(aEnum1) |
|
||||
bitFor(aEnum2) |
|
||||
bitFor(aEnum3))
|
||||
{ }
|
||||
|
||||
EnumSet(T aEnum1, T aEnum2, T aEnum3, T aEnum4)
|
||||
: mBitField(bitFor(aEnum1) |
|
||||
bitFor(aEnum2) |
|
||||
bitFor(aEnum3) |
|
||||
bitFor(aEnum4))
|
||||
{ }
|
||||
|
||||
EnumSet(const EnumSet& aEnumSet)
|
||||
: mBitField(aEnumSet.mBitField)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Add an element
|
||||
*/
|
||||
void operator+=(T aEnum) {
|
||||
mBitField |= bitFor(aEnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an element
|
||||
*/
|
||||
EnumSet<T> operator+(T aEnum) const {
|
||||
EnumSet<T> result(*this);
|
||||
result += aEnum;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Union
|
||||
*/
|
||||
void operator+=(const EnumSet<T> aEnumSet) {
|
||||
mBitField |= aEnumSet.mBitField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Union
|
||||
*/
|
||||
EnumSet<T> operator+(const EnumSet<T> aEnumSet) const {
|
||||
EnumSet<T> result(*this);
|
||||
result += aEnumSet;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an element
|
||||
*/
|
||||
void operator-=(T aEnum) {
|
||||
mBitField &= ~(bitFor(aEnum));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an element
|
||||
*/
|
||||
EnumSet<T> operator-(T aEnum) const {
|
||||
EnumSet<T> result(*this);
|
||||
result -= aEnum;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a set of elements
|
||||
*/
|
||||
void operator-=(const EnumSet<T> aEnumSet) {
|
||||
mBitField &= ~(aEnumSet.mBitField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a set of elements
|
||||
*/
|
||||
EnumSet<T> operator-(const EnumSet<T> aEnumSet) const {
|
||||
EnumSet<T> result(*this);
|
||||
result -= aEnumSet;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Intersection
|
||||
*/
|
||||
void operator&=(const EnumSet<T> aEnumSet) {
|
||||
mBitField &= aEnumSet.mBitField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Intersection
|
||||
*/
|
||||
EnumSet<T> operator&(const EnumSet<T> aEnumSet) const {
|
||||
EnumSet<T> result(*this);
|
||||
result &= aEnumSet;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality
|
||||
*/
|
||||
|
||||
bool operator==(const EnumSet<T> aEnumSet) const {
|
||||
return mBitField == aEnumSet.mBitField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test is an element is contained in the set
|
||||
*/
|
||||
bool contains(T aEnum) const {
|
||||
return mBitField & bitFor(aEnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of elements in the set
|
||||
*/
|
||||
|
||||
uint8_t size() {
|
||||
uint8_t count = 0;
|
||||
for (uint32_t bitField = mBitField; bitField; bitField >>= 1) {
|
||||
if (bitField & 1)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private:
|
||||
static uint32_t bitFor(T aEnum) {
|
||||
uint32_t bitNumber(aEnum);
|
||||
MOZ_ASSERT(bitNumber < 32);
|
||||
return 1U << bitNumber;
|
||||
}
|
||||
|
||||
uint32_t mBitField;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_EnumSet_h_
|
|
@ -66,7 +66,7 @@ namespace detail {
|
|||
* For more details, and examples of using these macros, see
|
||||
* https://developer.mozilla.org/en/Using_RAII_classes_in_Mozilla
|
||||
*/
|
||||
class MOZ_EXPORT_API(GuardObjectNotifier)
|
||||
class MOZ_EXPORT GuardObjectNotifier
|
||||
{
|
||||
private:
|
||||
bool* statementDone;
|
||||
|
@ -83,7 +83,7 @@ class MOZ_EXPORT_API(GuardObjectNotifier)
|
|||
}
|
||||
};
|
||||
|
||||
class MOZ_EXPORT_API(GuardObjectNotificationReceiver)
|
||||
class MOZ_EXPORT GuardObjectNotificationReceiver
|
||||
{
|
||||
private:
|
||||
bool statementDone;
|
||||
|
|
|
@ -351,7 +351,7 @@ HashString(const wchar_t* str, size_t length)
|
|||
* same result out of HashBytes as you would out of HashString.
|
||||
*/
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
extern MFBT_API(uint32_t)
|
||||
extern MFBT_API uint32_t
|
||||
HashBytes(const void* bytes, size_t length);
|
||||
|
||||
} /* namespace mozilla */
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
* LinkedListElement<T>. A given object may be in only one linked list at a
|
||||
* time.
|
||||
*
|
||||
* A LinkedListElement automatically removes itself from the list upon
|
||||
* destruction, and a LinkedList will fatally assert in debug builds if it's
|
||||
* non-empty when it's destructed.
|
||||
*
|
||||
* For example, you might use LinkedList in a simple observer list class as
|
||||
* follows.
|
||||
*
|
||||
|
@ -36,6 +40,8 @@
|
|||
* void removeObserver(Observer* observer) {
|
||||
* // Will assert if |observer| is not part of some list.
|
||||
* observer.remove();
|
||||
* // Or, will assert if |observer| is not part of |list| specifically.
|
||||
* // observer.removeFrom(list);
|
||||
* }
|
||||
*
|
||||
* void notifyObservers(char* topic) {
|
||||
|
@ -101,8 +107,19 @@ class LinkedListElement
|
|||
LinkedListElement* prev;
|
||||
const bool isSentinel;
|
||||
|
||||
LinkedListElement* thisDuringConstruction() { return this; }
|
||||
|
||||
public:
|
||||
LinkedListElement() : next(this), prev(this), isSentinel(false) { }
|
||||
LinkedListElement()
|
||||
: next(thisDuringConstruction()),
|
||||
prev(thisDuringConstruction()),
|
||||
isSentinel(false)
|
||||
{ }
|
||||
|
||||
~LinkedListElement() {
|
||||
if (!isSentinel && isInList())
|
||||
remove();
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the next element in the list, or NULL if this is the last element in
|
||||
|
@ -158,6 +175,15 @@ class LinkedListElement
|
|||
prev = this;
|
||||
}
|
||||
|
||||
/*
|
||||
* Identical to remove(), but also asserts in debug builds that this element
|
||||
* is in list.
|
||||
*/
|
||||
void removeFrom(const LinkedList<T>& list) {
|
||||
list.assertContains(asT());
|
||||
remove();
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if |this| part is of a linked list, and false otherwise.
|
||||
*/
|
||||
|
@ -175,11 +201,10 @@ class LinkedListElement
|
|||
};
|
||||
|
||||
LinkedListElement(NodeKind nodeKind)
|
||||
: next(this),
|
||||
prev(this),
|
||||
: next(thisDuringConstruction()),
|
||||
prev(thisDuringConstruction()),
|
||||
isSentinel(nodeKind == NODE_KIND_SENTINEL)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
/*
|
||||
* Return |this| cast to T* if we're a normal node, or return NULL if we're
|
||||
|
@ -240,6 +265,10 @@ class LinkedList
|
|||
public:
|
||||
LinkedList() : sentinel(LinkedListElement<T>::NODE_KIND_SENTINEL) { }
|
||||
|
||||
~LinkedList() {
|
||||
MOZ_ASSERT(isEmpty());
|
||||
}
|
||||
|
||||
/*
|
||||
* Add elem to the front of the list.
|
||||
*/
|
||||
|
@ -375,6 +404,21 @@ class LinkedList
|
|||
}
|
||||
|
||||
private:
|
||||
friend class LinkedListElement<T>;
|
||||
|
||||
void assertContains(const T* t) const {
|
||||
#ifdef DEBUG
|
||||
for (const T* elem = getFirst();
|
||||
elem;
|
||||
elem = elem->getNext())
|
||||
{
|
||||
if (elem == t)
|
||||
return;
|
||||
}
|
||||
MOZ_NOT_REACHED("element wasn't found in this list!");
|
||||
#endif
|
||||
}
|
||||
|
||||
LinkedList& operator=(const LinkedList<T>& other) MOZ_DELETE;
|
||||
LinkedList(const LinkedList<T>& other) MOZ_DELETE;
|
||||
};
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
# endif
|
||||
#elif defined(__GNUC__)
|
||||
# if defined(_GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
|
||||
# if (__GNUC__ * 1000 + __GNU_MINOR__) >= 4006
|
||||
# if (__GNUC__ * 1000 + __GNUC_MINOR__) >= 4006
|
||||
# define MOZ_HAVE_CXX11_NULLPTR
|
||||
# endif
|
||||
# endif
|
||||
|
|
|
@ -128,13 +128,13 @@ class RangedPtr
|
|||
|
||||
RangedPtr<T> operator+(size_t inc) {
|
||||
MOZ_ASSERT(inc <= size_t(-1) / sizeof(T));
|
||||
MOZ_ASSERT(ptr + inc > ptr);
|
||||
MOZ_ASSERT(ptr + inc >= ptr);
|
||||
return create(ptr + inc);
|
||||
}
|
||||
|
||||
RangedPtr<T> operator-(size_t dec) {
|
||||
MOZ_ASSERT(dec <= size_t(-1) / sizeof(T));
|
||||
MOZ_ASSERT(ptr - dec < ptr);
|
||||
MOZ_ASSERT(ptr - dec <= ptr);
|
||||
return create(ptr - dec);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,44 +5,57 @@
|
|||
|
||||
/* Simple class for computing SHA1. */
|
||||
|
||||
/*
|
||||
* To compute the SHA1 of a buffer using this class you should write something
|
||||
* like:
|
||||
* void SHA1(const uint8_t* buf, unsigned size, uint8_t hash[20])
|
||||
* {
|
||||
* SHA1Sum S;
|
||||
* S.update(buf, size);
|
||||
* S.finish(hash);
|
||||
* }
|
||||
* If there are multiple buffers or chunks, the update method can be called
|
||||
* multiple times and the SHA1 is computed on the concatenation of all the
|
||||
* buffers passed to it.
|
||||
* The finish method may only be called once and cannot be followed by calls
|
||||
* to update.
|
||||
*/
|
||||
|
||||
#ifndef mozilla_SHA1_h_
|
||||
#define mozilla_SHA1_h_
|
||||
|
||||
#include "mozilla/StandardInteger.h"
|
||||
#include "mozilla/Types.h"
|
||||
|
||||
namespace mozilla {
|
||||
class SHA1Sum {
|
||||
union {
|
||||
uint32_t w[16]; /* input buffer */
|
||||
uint8_t b[64];
|
||||
} u;
|
||||
uint64_t size; /* count of hashed bytes. */
|
||||
unsigned H[22]; /* 5 state variables, 16 tmp values, 1 extra */
|
||||
bool mDone;
|
||||
#include <stddef.h>
|
||||
|
||||
public:
|
||||
static const unsigned int HashSize = 20;
|
||||
MFBT_API() SHA1Sum();
|
||||
MFBT_API(void) update(const void* dataIn, uint32_t len);
|
||||
MFBT_API(void) finish(uint8_t hashout[20]);
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* This class computes the SHA1 hash of a byte sequence, or of the concatenation
|
||||
* of multiple sequences. For example, computing the SHA1 of two sequences of
|
||||
* bytes could be done as follows:
|
||||
*
|
||||
* void SHA1(const uint8_t* buf1, uint32_t size1,
|
||||
* const uint8_t* buf2, uint32_t size2,
|
||||
* SHA1Sum::Hash& hash)
|
||||
* {
|
||||
* SHA1Sum s;
|
||||
* s.update(buf1, size1);
|
||||
* s.update(buf2, size2);
|
||||
* s.finish(hash);
|
||||
* }
|
||||
*
|
||||
* The finish method may only be called once and cannot be followed by calls
|
||||
* to update.
|
||||
*/
|
||||
class SHA1Sum
|
||||
{
|
||||
union {
|
||||
uint32_t w[16]; /* input buffer */
|
||||
uint8_t b[64];
|
||||
} u;
|
||||
uint64_t size; /* count of hashed bytes. */
|
||||
unsigned H[22]; /* 5 state variables, 16 tmp values, 1 extra */
|
||||
bool mDone;
|
||||
|
||||
public:
|
||||
MFBT_API SHA1Sum();
|
||||
|
||||
static const size_t HashSize = 20;
|
||||
typedef uint8_t Hash[HashSize];
|
||||
|
||||
/* Add len bytes of dataIn to the data sequence being hashed. */
|
||||
MFBT_API void update(const void* dataIn, uint32_t len);
|
||||
|
||||
/* Compute the final hash of all data into hashOut. */
|
||||
MFBT_API void finish(SHA1Sum::Hash& hashOut);
|
||||
};
|
||||
}
|
||||
|
||||
} /* namespace mozilla */
|
||||
|
||||
#endif /* mozilla_SHA1_h_ */
|
||||
|
|
|
@ -9,6 +9,25 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* The trickery used to implement IsBaseOf here makes it possible to use it for
|
||||
* the cases of private and multiple inheritance. This code was inspired by the
|
||||
* sample code here:
|
||||
*
|
||||
* http://stackoverflow.com/questions/2910979/how-is-base-of-works
|
||||
*/
|
||||
template<class Base, class Derived>
|
||||
class IsBaseOfHelper
|
||||
{
|
||||
public:
|
||||
operator Base*() const;
|
||||
operator Derived*();
|
||||
};
|
||||
|
||||
} /* namespace detail */
|
||||
|
||||
/*
|
||||
* IsBaseOf allows to know whether a given class is derived from another.
|
||||
*
|
||||
|
@ -25,12 +44,47 @@ template<class Base, class Derived>
|
|||
class IsBaseOf
|
||||
{
|
||||
private:
|
||||
static char test(Base* b);
|
||||
static int test(...);
|
||||
template<class T>
|
||||
static char test(Derived*, T);
|
||||
static int test(Base*, int);
|
||||
|
||||
public:
|
||||
static const bool value =
|
||||
sizeof(test(static_cast<Derived*>(0))) == sizeof(char);
|
||||
sizeof(test(detail::IsBaseOfHelper<Base, Derived>(), int())) == sizeof(char);
|
||||
};
|
||||
|
||||
template<class Base, class Derived>
|
||||
class IsBaseOf<Base, const Derived>
|
||||
{
|
||||
private:
|
||||
template<class T>
|
||||
static char test(Derived*, T);
|
||||
static int test(Base*, int);
|
||||
|
||||
public:
|
||||
static const bool value =
|
||||
sizeof(test(detail::IsBaseOfHelper<Base, Derived>(), int())) == sizeof(char);
|
||||
};
|
||||
|
||||
template<class Base, class Derived>
|
||||
class IsBaseOf<Base&, Derived&>
|
||||
{
|
||||
public:
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template<class Type>
|
||||
class IsBaseOf<Type, Type>
|
||||
{
|
||||
public:
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template<class Type>
|
||||
class IsBaseOf<Type, const Type>
|
||||
{
|
||||
public:
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -27,63 +27,60 @@
|
|||
/* Implement compiler and linker macros needed for APIs. */
|
||||
|
||||
/*
|
||||
* MOZ_EXPORT_API is used to declare and define a method which is externally
|
||||
* MOZ_EXPORT is used to declare and define a symbol or type which is externally
|
||||
* visible to users of the current library. It encapsulates various decorations
|
||||
* needed to properly export the method's symbol. MOZ_EXPORT_DATA serves the
|
||||
* same purpose for data.
|
||||
* needed to properly export the method's symbol.
|
||||
*
|
||||
* api.h:
|
||||
* extern MOZ_EXPORT_API(int) MeaningOfLife(void);
|
||||
* extern MOZ_EXPORT_DATA(int) LuggageCombination;
|
||||
* extern MOZ_EXPORT int MeaningOfLife(void);
|
||||
* extern MOZ_EXPORT int LuggageCombination;
|
||||
*
|
||||
* api.c:
|
||||
* MOZ_EXPORT_API(int) MeaningOfLife(void) { return 42; }
|
||||
* MOZ_EXPORT_DATA(int) LuggageCombination = 12345;
|
||||
* int MeaningOfLife(void) { return 42; }
|
||||
* int LuggageCombination = 12345;
|
||||
*
|
||||
* If you are merely sharing a method across files, just use plain |extern|.
|
||||
* These macros are designed for use by library interfaces -- not for normal
|
||||
* methods or data used cross-file.
|
||||
*/
|
||||
#if defined(WIN32) || defined(XP_OS2)
|
||||
# define MOZ_EXPORT_API(type) __declspec(dllexport) type
|
||||
# define MOZ_EXPORT_DATA(type) __declspec(dllexport) type
|
||||
# define MOZ_EXPORT __declspec(dllexport)
|
||||
#else /* Unix */
|
||||
# ifdef HAVE_VISIBILITY_ATTRIBUTE
|
||||
# define MOZ_EXTERNAL_VIS __attribute__((visibility("default")))
|
||||
# define MOZ_EXPORT __attribute__((visibility("default")))
|
||||
# elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
|
||||
# define MOZ_EXTERNAL_VIS __global
|
||||
# define MOZ_EXPORT __global
|
||||
# else
|
||||
# define MOZ_EXTERNAL_VIS
|
||||
# define MOZ_EXPORT /* nothing */
|
||||
# endif
|
||||
# define MOZ_EXPORT_API(type) MOZ_EXTERNAL_VIS type
|
||||
# define MOZ_EXPORT_DATA(type) MOZ_EXTERNAL_VIS type
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Whereas implementers use MOZ_EXPORT_API and MOZ_EXPORT_DATA to declare and
|
||||
* define library symbols, users use MOZ_IMPORT_API and MOZ_IMPORT_DATA to
|
||||
* access them. Most often the implementer of the library will expose an API
|
||||
* macro which expands to either the export or import version of the macro,
|
||||
* depending upon the compilation mode.
|
||||
* Whereas implementers use MOZ_EXPORT to declare and define library symbols,
|
||||
* users use MOZ_IMPORT_API and MOZ_IMPORT_DATA to access them. Most often the
|
||||
* implementer of the library will expose an API macro which expands to either
|
||||
* the export or import version of the macro, depending upon the compilation
|
||||
* mode.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
# if defined(__MWERKS__)
|
||||
# define MOZ_IMPORT_API(x) x
|
||||
# define MOZ_IMPORT_API /* nothing */
|
||||
# else
|
||||
# define MOZ_IMPORT_API(x) __declspec(dllimport) x
|
||||
# define MOZ_IMPORT_API __declspec(dllimport)
|
||||
# endif
|
||||
#elif defined(XP_OS2)
|
||||
# define MOZ_IMPORT_API(x) __declspec(dllimport) x
|
||||
# define MOZ_IMPORT_API __declspec(dllimport)
|
||||
#else
|
||||
# define MOZ_IMPORT_API(x) MOZ_EXPORT_API(x)
|
||||
# define MOZ_IMPORT_API MOZ_EXPORT
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(__MWERKS__)
|
||||
# define MOZ_IMPORT_DATA(x) __declspec(dllimport) x
|
||||
# define MOZ_IMPORT_DATA __declspec(dllimport)
|
||||
#elif defined(XP_OS2)
|
||||
# define MOZ_IMPORT_DATA(x) __declspec(dllimport) x
|
||||
# define MOZ_IMPORT_DATA __declspec(dllimport)
|
||||
#else
|
||||
# define MOZ_IMPORT_DATA(x) MOZ_EXPORT_DATA(x)
|
||||
# define MOZ_IMPORT_DATA MOZ_EXPORT
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -92,19 +89,22 @@
|
|||
* declarations when using mfbt.
|
||||
*/
|
||||
#if defined(IMPL_MFBT)
|
||||
# define MFBT_API(type) MOZ_EXPORT_API(type)
|
||||
# define MFBT_DATA(type) MOZ_EXPORT_DATA(type)
|
||||
# define MFBT_API MOZ_EXPORT
|
||||
# define MFBT_DATA MOZ_EXPORT
|
||||
#else
|
||||
/*
|
||||
* When mozglue is linked in the program, we need the MFBT API symbols
|
||||
* to be weak.
|
||||
* On linux mozglue is linked in the program and we link libxul.so with
|
||||
* -z,defs. Normally that causes the linker to reject undefined references in
|
||||
* libxul.so, but as a loophole it allows undefined references to weak
|
||||
* symbols. We add the weak attribute to the import version of the MFBT API
|
||||
* macros to exploit this.
|
||||
*/
|
||||
# if defined(MOZ_GLUE_IN_PROGRAM)
|
||||
# define MFBT_API(type) __attribute__((weak)) MOZ_IMPORT_API(type)
|
||||
# define MFBT_DATA(type) __attribute__((weak)) MOZ_IMPORT_DATA(type)
|
||||
# define MFBT_API __attribute__((weak)) MOZ_IMPORT_API
|
||||
# define MFBT_DATA __attribute__((weak)) MOZ_IMPORT_DATA
|
||||
# else
|
||||
# define MFBT_API(type) MOZ_IMPORT_API(type)
|
||||
# define MFBT_DATA(type) MOZ_IMPORT_DATA(type)
|
||||
# define MFBT_API MOZ_IMPORT_API
|
||||
# define MFBT_DATA MOZ_IMPORT_DATA
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
@ -117,7 +117,7 @@
|
|||
*
|
||||
* MOZ_BEGIN_EXTERN_C
|
||||
*
|
||||
* extern MOZ_EXPORT_API(int) MostRandomNumber(void);
|
||||
* extern MOZ_EXPORT int MostRandomNumber(void);
|
||||
* ...other declarations...
|
||||
*
|
||||
* MOZ_END_EXTERN_C
|
||||
|
|
|
@ -126,6 +126,10 @@ class WeakPtr
|
|||
return ref->get();
|
||||
}
|
||||
|
||||
T* get() const {
|
||||
return ref->get();
|
||||
}
|
||||
|
||||
private:
|
||||
friend class SupportsWeakPtr<T>;
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
0b43ca82a2e3c648187f17aa0ea261a8d98ac2a5
|
||||
50e1e403ec323943f3ab7274127546140d2d5d0a
|
|
@ -1 +1 @@
|
|||
04eff728bf10911147107d4237d102d9b96067e7
|
||||
60e397be69b5e1699754e996d4392c0e1b8a154c
|
|
@ -1,659 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef jsgc_barrier_h___
|
||||
#define jsgc_barrier_h___
|
||||
|
||||
#include "jsapi.h"
|
||||
|
||||
#include "gc/Heap.h"
|
||||
#include "gc/Root.h"
|
||||
#include "js/HashTable.h"
|
||||
|
||||
/*
|
||||
* A write barrier is a mechanism used by incremental or generation GCs to
|
||||
* ensure that every value that needs to be marked is marked. In general, the
|
||||
* write barrier should be invoked whenever a write can cause the set of things
|
||||
* traced through by the GC to change. This includes:
|
||||
* - writes to object properties
|
||||
* - writes to array slots
|
||||
* - writes to fields like JSObject::shape_ that we trace through
|
||||
* - writes to fields in private data, like JSGenerator::obj
|
||||
* - writes to non-markable fields like JSObject::private that point to
|
||||
* markable data
|
||||
* The last category is the trickiest. Even though the private pointers does not
|
||||
* point to a GC thing, changing the private pointer may change the set of
|
||||
* objects that are traced by the GC. Therefore it needs a write barrier.
|
||||
*
|
||||
* Every barriered write should have the following form:
|
||||
* <pre-barrier>
|
||||
* obj->field = value; // do the actual write
|
||||
* <post-barrier>
|
||||
* The pre-barrier is used for incremental GC and the post-barrier is for
|
||||
* generational GC.
|
||||
*
|
||||
* PRE-BARRIER
|
||||
*
|
||||
* To understand the pre-barrier, let's consider how incremental GC works. The
|
||||
* GC itself is divided into "slices". Between each slice, JS code is allowed to
|
||||
* run. Each slice should be short so that the user doesn't notice the
|
||||
* interruptions. In our GC, the structure of the slices is as follows:
|
||||
*
|
||||
* 1. ... JS work, which leads to a request to do GC ...
|
||||
* 2. [first GC slice, which performs all root marking and possibly more marking]
|
||||
* 3. ... more JS work is allowed to run ...
|
||||
* 4. [GC mark slice, which runs entirely in drainMarkStack]
|
||||
* 5. ... more JS work ...
|
||||
* 6. [GC mark slice, which runs entirely in drainMarkStack]
|
||||
* 7. ... more JS work ...
|
||||
* 8. [GC marking finishes; sweeping done non-incrementally; GC is done]
|
||||
* 9. ... JS continues uninterrupted now that GC is finishes ...
|
||||
*
|
||||
* Of course, there may be a different number of slices depending on how much
|
||||
* marking is to be done.
|
||||
*
|
||||
* The danger inherent in this scheme is that the JS code in steps 3, 5, and 7
|
||||
* might change the heap in a way that causes the GC to collect an object that
|
||||
* is actually reachable. The write barrier prevents this from happening. We use
|
||||
* a variant of incremental GC called "snapshot at the beginning." This approach
|
||||
* guarantees the invariant that if an object is reachable in step 2, then we
|
||||
* will mark it eventually. The name comes from the idea that we take a
|
||||
* theoretical "snapshot" of all reachable objects in step 2; all objects in
|
||||
* that snapshot should eventually be marked. (Note that the write barrier
|
||||
* verifier code takes an actual snapshot.)
|
||||
*
|
||||
* The basic correctness invariant of a snapshot-at-the-beginning collector is
|
||||
* that any object reachable at the end of the GC (step 9) must either:
|
||||
* (1) have been reachable at the beginning (step 2) and thus in the snapshot
|
||||
* (2) or must have been newly allocated, in steps 3, 5, or 7.
|
||||
* To deal with case (2), any objects allocated during an incremental GC are
|
||||
* automatically marked black.
|
||||
*
|
||||
* This strategy is actually somewhat conservative: if an object becomes
|
||||
* unreachable between steps 2 and 8, it would be safe to collect it. We won't,
|
||||
* mainly for simplicity. (Also, note that the snapshot is entirely
|
||||
* theoretical. We don't actually do anything special in step 2 that we wouldn't
|
||||
* do in a non-incremental GC.
|
||||
*
|
||||
* It's the pre-barrier's job to maintain the snapshot invariant. Consider the
|
||||
* write "obj->field = value". Let the prior value of obj->field be
|
||||
* value0. Since it's possible that value0 may have been what obj->field
|
||||
* contained in step 2, when the snapshot was taken, the barrier marks
|
||||
* value0. Note that it only does this if we're in the middle of an incremental
|
||||
* GC. Since this is rare, the cost of the write barrier is usually just an
|
||||
* extra branch.
|
||||
*
|
||||
* In practice, we implement the pre-barrier differently based on the type of
|
||||
* value0. E.g., see JSObject::writeBarrierPre, which is used if obj->field is
|
||||
* a JSObject*. It takes value0 as a parameter.
|
||||
*
|
||||
* POST-BARRIER
|
||||
*
|
||||
* These are not yet implemented. Once we get generational GC, they will allow
|
||||
* us to keep track of pointers from non-nursery space into the nursery.
|
||||
*
|
||||
* IMPLEMENTATION DETAILS
|
||||
*
|
||||
* Since it would be awkward to change every write to memory into a function
|
||||
* call, this file contains a bunch of C++ classes and templates that use
|
||||
* operator overloading to take care of barriers automatically. In many cases,
|
||||
* all that's necessary to make some field be barriered is to replace
|
||||
* Type *field;
|
||||
* with
|
||||
* HeapPtr<Type> field;
|
||||
* There are also special classes HeapValue and HeapId, which barrier js::Value
|
||||
* and jsid, respectively.
|
||||
*
|
||||
* One additional note: not all object writes need to be barriered. Writes to
|
||||
* newly allocated objects do not need a pre-barrier. In these cases, we use
|
||||
* the "obj->field.init(value)" method instead of "obj->field = value". We use
|
||||
* the init naming idiom in many places to signify that a field is being
|
||||
* assigned for the first time.
|
||||
*/
|
||||
|
||||
struct JSXML;
|
||||
|
||||
namespace js {
|
||||
|
||||
template<class T, typename Unioned = uintptr_t>
|
||||
class EncapsulatedPtr
|
||||
{
|
||||
protected:
|
||||
union {
|
||||
T *value;
|
||||
Unioned other;
|
||||
};
|
||||
|
||||
public:
|
||||
EncapsulatedPtr() : value(NULL) {}
|
||||
EncapsulatedPtr(T *v) : value(v) {}
|
||||
explicit EncapsulatedPtr(const EncapsulatedPtr<T> &v) : value(v.value) {}
|
||||
|
||||
~EncapsulatedPtr() { pre(); }
|
||||
|
||||
/* Use to set the pointer to NULL. */
|
||||
void clear() {
|
||||
pre();
|
||||
value = NULL;
|
||||
}
|
||||
|
||||
EncapsulatedPtr<T, Unioned> &operator=(T *v) {
|
||||
pre();
|
||||
JS_ASSERT(!IsPoisonedPtr<T>(v));
|
||||
value = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
EncapsulatedPtr<T, Unioned> &operator=(const EncapsulatedPtr<T> &v) {
|
||||
pre();
|
||||
JS_ASSERT(!IsPoisonedPtr<T>(v.value));
|
||||
value = v.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* Use this if the automatic coercion to T* isn't working. */
|
||||
T *get() const { return value; }
|
||||
|
||||
/*
|
||||
* Use these if you want to change the value without invoking the barrier.
|
||||
* Obviously this is dangerous unless you know the barrier is not needed.
|
||||
*/
|
||||
T **unsafeGet() { return &value; }
|
||||
void unsafeSet(T *v) { value = v; }
|
||||
|
||||
Unioned *unsafeGetUnioned() { return &other; }
|
||||
|
||||
T &operator*() const { return *value; }
|
||||
T *operator->() const { return value; }
|
||||
|
||||
operator T*() const { return value; }
|
||||
|
||||
protected:
|
||||
void pre();
|
||||
};
|
||||
|
||||
template <class T, class Unioned = uintptr_t>
|
||||
class HeapPtr : public EncapsulatedPtr<T, Unioned>
|
||||
{
|
||||
public:
|
||||
HeapPtr() : EncapsulatedPtr<T>(NULL) {}
|
||||
explicit HeapPtr(T *v) : EncapsulatedPtr<T>(v) { post(); }
|
||||
explicit HeapPtr(const HeapPtr<T> &v)
|
||||
: EncapsulatedPtr<T>(v) { post(); }
|
||||
|
||||
void init(T *v) {
|
||||
JS_ASSERT(!IsPoisonedPtr<T>(v));
|
||||
this->value = v;
|
||||
post();
|
||||
}
|
||||
|
||||
HeapPtr<T, Unioned> &operator=(T *v) {
|
||||
this->pre();
|
||||
JS_ASSERT(!IsPoisonedPtr<T>(v));
|
||||
this->value = v;
|
||||
post();
|
||||
return *this;
|
||||
}
|
||||
|
||||
HeapPtr<T, Unioned> &operator=(const HeapPtr<T> &v) {
|
||||
this->pre();
|
||||
JS_ASSERT(!IsPoisonedPtr<T>(v.value));
|
||||
this->value = v.value;
|
||||
post();
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
void post() { T::writeBarrierPost(this->value, (void *)&this->value); }
|
||||
|
||||
/* Make this friend so it can access pre() and post(). */
|
||||
template<class T1, class T2>
|
||||
friend inline void
|
||||
BarrieredSetPair(JSCompartment *comp,
|
||||
HeapPtr<T1> &v1, T1 *val1,
|
||||
HeapPtr<T2> &v2, T2 *val2);
|
||||
};
|
||||
|
||||
/*
|
||||
* FixedHeapPtr is designed for one very narrow case: replacing immutable raw
|
||||
* pointers to GC-managed things, implicitly converting to a handle type for
|
||||
* ease of use. Pointers encapsulated by this type must:
|
||||
*
|
||||
* be immutable (no incremental write barriers),
|
||||
* never point into the nursery (no generational write barriers), and
|
||||
* be traced via MarkRuntime (we use fromMarkedLocation).
|
||||
*
|
||||
* In short: you *really* need to know what you're doing before you use this
|
||||
* class!
|
||||
*/
|
||||
template <class T>
|
||||
class FixedHeapPtr
|
||||
{
|
||||
T *value;
|
||||
|
||||
public:
|
||||
operator T*() const { return value; }
|
||||
T * operator->() const { return value; }
|
||||
|
||||
operator Handle<T*>() const {
|
||||
return Handle<T*>::fromMarkedLocation(&value);
|
||||
}
|
||||
|
||||
void init(T *ptr) {
|
||||
value = ptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class RelocatablePtr : public EncapsulatedPtr<T>
|
||||
{
|
||||
public:
|
||||
RelocatablePtr() : EncapsulatedPtr<T>(NULL) {}
|
||||
explicit RelocatablePtr(T *v) : EncapsulatedPtr<T>(v) {
|
||||
if (v)
|
||||
post();
|
||||
}
|
||||
explicit RelocatablePtr(const RelocatablePtr<T> &v) : EncapsulatedPtr<T>(v) {
|
||||
if (this->value)
|
||||
post();
|
||||
}
|
||||
|
||||
~RelocatablePtr() {
|
||||
if (this->value)
|
||||
relocate(this->value->compartment());
|
||||
}
|
||||
|
||||
RelocatablePtr<T> &operator=(T *v) {
|
||||
this->pre();
|
||||
JS_ASSERT(!IsPoisonedPtr<T>(v));
|
||||
if (v) {
|
||||
this->value = v;
|
||||
post();
|
||||
} else if (this->value) {
|
||||
JSCompartment *comp = this->value->compartment();
|
||||
this->value = v;
|
||||
relocate(comp);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
RelocatablePtr<T> &operator=(const RelocatablePtr<T> &v) {
|
||||
this->pre();
|
||||
JS_ASSERT(!IsPoisonedPtr<T>(v.value));
|
||||
if (v.value) {
|
||||
this->value = v.value;
|
||||
post();
|
||||
} else if (this->value) {
|
||||
JSCompartment *comp = this->value->compartment();
|
||||
this->value = v;
|
||||
relocate(comp);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
inline void post();
|
||||
inline void relocate(JSCompartment *comp);
|
||||
};
|
||||
|
||||
/*
|
||||
* This is a hack for RegExpStatics::updateFromMatch. It allows us to do two
|
||||
* barriers with only one branch to check if we're in an incremental GC.
|
||||
*/
|
||||
template<class T1, class T2>
|
||||
static inline void
|
||||
BarrieredSetPair(JSCompartment *comp,
|
||||
HeapPtr<T1> &v1, T1 *val1,
|
||||
HeapPtr<T2> &v2, T2 *val2)
|
||||
{
|
||||
if (T1::needWriteBarrierPre(comp)) {
|
||||
v1.pre();
|
||||
v2.pre();
|
||||
}
|
||||
v1.unsafeSet(val1);
|
||||
v2.unsafeSet(val2);
|
||||
v1.post();
|
||||
v2.post();
|
||||
}
|
||||
|
||||
struct Shape;
|
||||
class BaseShape;
|
||||
namespace types { struct TypeObject; }
|
||||
|
||||
typedef EncapsulatedPtr<JSObject> EncapsulatedPtrObject;
|
||||
typedef EncapsulatedPtr<JSScript> EncapsulatedPtrScript;
|
||||
|
||||
typedef RelocatablePtr<JSObject> RelocatablePtrObject;
|
||||
typedef RelocatablePtr<JSScript> RelocatablePtrScript;
|
||||
|
||||
typedef HeapPtr<JSObject> HeapPtrObject;
|
||||
typedef HeapPtr<JSFunction> HeapPtrFunction;
|
||||
typedef HeapPtr<JSString> HeapPtrString;
|
||||
typedef HeapPtr<JSScript> HeapPtrScript;
|
||||
typedef HeapPtr<Shape> HeapPtrShape;
|
||||
typedef HeapPtr<BaseShape> HeapPtrBaseShape;
|
||||
typedef HeapPtr<types::TypeObject> HeapPtrTypeObject;
|
||||
typedef HeapPtr<JSXML> HeapPtrXML;
|
||||
|
||||
/* Useful for hashtables with a HeapPtr as key. */
|
||||
template<class T>
|
||||
struct HeapPtrHasher
|
||||
{
|
||||
typedef HeapPtr<T> Key;
|
||||
typedef T *Lookup;
|
||||
|
||||
static HashNumber hash(Lookup obj) { return DefaultHasher<T *>::hash(obj); }
|
||||
static bool match(const Key &k, Lookup l) { return k.get() == l; }
|
||||
};
|
||||
|
||||
/* Specialized hashing policy for HeapPtrs. */
|
||||
template <class T>
|
||||
struct DefaultHasher< HeapPtr<T> > : HeapPtrHasher<T> { };
|
||||
|
||||
template<class T>
|
||||
struct EncapsulatedPtrHasher
|
||||
{
|
||||
typedef EncapsulatedPtr<T> Key;
|
||||
typedef T *Lookup;
|
||||
|
||||
static HashNumber hash(Lookup obj) { return DefaultHasher<T *>::hash(obj); }
|
||||
static bool match(const Key &k, Lookup l) { return k.get() == l; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct DefaultHasher< EncapsulatedPtr<T> > : EncapsulatedPtrHasher<T> { };
|
||||
|
||||
class EncapsulatedValue : public ValueOperations<EncapsulatedValue>
|
||||
{
|
||||
protected:
|
||||
Value value;
|
||||
|
||||
/*
|
||||
* Ensure that EncapsulatedValue is not constructable, except by our
|
||||
* implementations.
|
||||
*/
|
||||
EncapsulatedValue() MOZ_DELETE;
|
||||
EncapsulatedValue(const EncapsulatedValue &v) MOZ_DELETE;
|
||||
EncapsulatedValue &operator=(const Value &v) MOZ_DELETE;
|
||||
EncapsulatedValue &operator=(const EncapsulatedValue &v) MOZ_DELETE;
|
||||
|
||||
EncapsulatedValue(const Value &v) : value(v) {}
|
||||
~EncapsulatedValue() {}
|
||||
|
||||
public:
|
||||
bool operator==(const EncapsulatedValue &v) const { return value == v.value; }
|
||||
bool operator!=(const EncapsulatedValue &v) const { return value != v.value; }
|
||||
|
||||
const Value &get() const { return value; }
|
||||
Value *unsafeGet() { return &value; }
|
||||
operator const Value &() const { return value; }
|
||||
|
||||
JSGCTraceKind gcKind() const { return value.gcKind(); }
|
||||
|
||||
uint64_t asRawBits() const { return value.asRawBits(); }
|
||||
|
||||
static inline void writeBarrierPre(const Value &v);
|
||||
static inline void writeBarrierPre(JSCompartment *comp, const Value &v);
|
||||
|
||||
protected:
|
||||
inline void pre();
|
||||
inline void pre(JSCompartment *comp);
|
||||
|
||||
private:
|
||||
friend class ValueOperations<EncapsulatedValue>;
|
||||
const Value * extract() const { return &value; }
|
||||
};
|
||||
|
||||
class HeapValue : public EncapsulatedValue
|
||||
{
|
||||
public:
|
||||
explicit inline HeapValue();
|
||||
explicit inline HeapValue(const Value &v);
|
||||
explicit inline HeapValue(const HeapValue &v);
|
||||
inline ~HeapValue();
|
||||
|
||||
inline void init(const Value &v);
|
||||
inline void init(JSCompartment *comp, const Value &v);
|
||||
|
||||
inline HeapValue &operator=(const Value &v);
|
||||
inline HeapValue &operator=(const HeapValue &v);
|
||||
|
||||
/*
|
||||
* This is a faster version of operator=. Normally, operator= has to
|
||||
* determine the compartment of the value before it can decide whether to do
|
||||
* the barrier. If you already know the compartment, it's faster to pass it
|
||||
* in.
|
||||
*/
|
||||
inline void set(JSCompartment *comp, const Value &v);
|
||||
|
||||
static inline void writeBarrierPost(const Value &v, Value *addr);
|
||||
static inline void writeBarrierPost(JSCompartment *comp, const Value &v, Value *addr);
|
||||
|
||||
private:
|
||||
inline void post();
|
||||
inline void post(JSCompartment *comp);
|
||||
};
|
||||
|
||||
class RelocatableValue : public EncapsulatedValue
|
||||
{
|
||||
public:
|
||||
explicit inline RelocatableValue();
|
||||
explicit inline RelocatableValue(const Value &v);
|
||||
inline RelocatableValue(const RelocatableValue &v);
|
||||
inline ~RelocatableValue();
|
||||
|
||||
inline RelocatableValue &operator=(const Value &v);
|
||||
inline RelocatableValue &operator=(const RelocatableValue &v);
|
||||
|
||||
private:
|
||||
inline void post();
|
||||
inline void post(JSCompartment *comp);
|
||||
inline void relocate();
|
||||
};
|
||||
|
||||
class HeapSlot : public EncapsulatedValue
|
||||
{
|
||||
/*
|
||||
* Operator= is not valid for HeapSlot because is must take the object and
|
||||
* slot offset to provide to the post/generational barrier.
|
||||
*/
|
||||
inline HeapSlot &operator=(const Value &v) MOZ_DELETE;
|
||||
inline HeapSlot &operator=(const HeapValue &v) MOZ_DELETE;
|
||||
inline HeapSlot &operator=(const HeapSlot &v) MOZ_DELETE;
|
||||
|
||||
public:
|
||||
explicit inline HeapSlot() MOZ_DELETE;
|
||||
explicit inline HeapSlot(JSObject *obj, uint32_t slot, const Value &v);
|
||||
explicit inline HeapSlot(JSObject *obj, uint32_t slot, const HeapSlot &v);
|
||||
inline ~HeapSlot();
|
||||
|
||||
inline void init(JSObject *owner, uint32_t slot, const Value &v);
|
||||
inline void init(JSCompartment *comp, JSObject *owner, uint32_t slot, const Value &v);
|
||||
|
||||
inline void set(JSObject *owner, uint32_t slot, const Value &v);
|
||||
inline void set(JSCompartment *comp, JSObject *owner, uint32_t slot, const Value &v);
|
||||
|
||||
static inline void writeBarrierPost(JSObject *obj, uint32_t slot);
|
||||
static inline void writeBarrierPost(JSCompartment *comp, JSObject *obj, uint32_t slot);
|
||||
|
||||
private:
|
||||
inline void post(JSObject *owner, uint32_t slot);
|
||||
inline void post(JSCompartment *comp, JSObject *owner, uint32_t slot);
|
||||
};
|
||||
|
||||
/*
|
||||
* NOTE: This is a placeholder for bug 619558.
|
||||
*
|
||||
* Run a post write barrier that encompasses multiple contiguous slots in a
|
||||
* single step.
|
||||
*/
|
||||
inline void
|
||||
SlotRangeWriteBarrierPost(JSCompartment *comp, JSObject *obj, uint32_t start, uint32_t count);
|
||||
|
||||
/*
|
||||
* This is a post barrier for HashTables whose key can be moved during a GC.
|
||||
*/
|
||||
template <class Map, class Key>
|
||||
inline void
|
||||
HashTableWriteBarrierPost(JSCompartment *comp, const Map *map, const Key &key)
|
||||
{
|
||||
#ifdef JS_GCGENERATIONAL
|
||||
if (key && comp->gcNursery.isInside(key))
|
||||
comp->gcStoreBuffer.putGeneric(HashKeyRef(map, key));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline const Value *
|
||||
Valueify(const EncapsulatedValue *array)
|
||||
{
|
||||
JS_STATIC_ASSERT(sizeof(HeapValue) == sizeof(Value));
|
||||
JS_STATIC_ASSERT(sizeof(HeapSlot) == sizeof(Value));
|
||||
return (const Value *)array;
|
||||
}
|
||||
|
||||
static inline HeapValue *
|
||||
HeapValueify(Value *v)
|
||||
{
|
||||
JS_STATIC_ASSERT(sizeof(HeapValue) == sizeof(Value));
|
||||
JS_STATIC_ASSERT(sizeof(HeapSlot) == sizeof(Value));
|
||||
return (HeapValue *)v;
|
||||
}
|
||||
|
||||
class HeapSlotArray
|
||||
{
|
||||
HeapSlot *array;
|
||||
|
||||
public:
|
||||
HeapSlotArray(HeapSlot *array) : array(array) {}
|
||||
|
||||
operator const Value *() const { return Valueify(array); }
|
||||
operator HeapSlot *() const { return array; }
|
||||
|
||||
HeapSlotArray operator +(int offset) const { return HeapSlotArray(array + offset); }
|
||||
HeapSlotArray operator +(uint32_t offset) const { return HeapSlotArray(array + offset); }
|
||||
};
|
||||
|
||||
class EncapsulatedId
|
||||
{
|
||||
protected:
|
||||
jsid value;
|
||||
|
||||
private:
|
||||
EncapsulatedId(const EncapsulatedId &v) MOZ_DELETE;
|
||||
|
||||
public:
|
||||
explicit EncapsulatedId() : value(JSID_VOID) {}
|
||||
explicit EncapsulatedId(jsid id) : value(id) {}
|
||||
~EncapsulatedId();
|
||||
|
||||
inline EncapsulatedId &operator=(const EncapsulatedId &v);
|
||||
|
||||
bool operator==(jsid id) const { return value == id; }
|
||||
bool operator!=(jsid id) const { return value != id; }
|
||||
|
||||
jsid get() const { return value; }
|
||||
jsid *unsafeGet() { return &value; }
|
||||
operator jsid() const { return value; }
|
||||
|
||||
protected:
|
||||
inline void pre();
|
||||
};
|
||||
|
||||
class RelocatableId : public EncapsulatedId
|
||||
{
|
||||
public:
|
||||
explicit RelocatableId() : EncapsulatedId() {}
|
||||
explicit inline RelocatableId(jsid id) : EncapsulatedId(id) {}
|
||||
inline ~RelocatableId();
|
||||
|
||||
inline RelocatableId &operator=(jsid id);
|
||||
inline RelocatableId &operator=(const RelocatableId &v);
|
||||
};
|
||||
|
||||
class HeapId : public EncapsulatedId
|
||||
{
|
||||
public:
|
||||
explicit HeapId() : EncapsulatedId() {}
|
||||
explicit inline HeapId(jsid id);
|
||||
inline ~HeapId();
|
||||
|
||||
inline void init(jsid id);
|
||||
|
||||
inline HeapId &operator=(jsid id);
|
||||
inline HeapId &operator=(const HeapId &v);
|
||||
|
||||
private:
|
||||
inline void post();
|
||||
|
||||
HeapId(const HeapId &v) MOZ_DELETE;
|
||||
};
|
||||
|
||||
/*
|
||||
* Incremental GC requires that weak pointers have read barriers. This is mostly
|
||||
* an issue for empty shapes stored in JSCompartment. The problem happens when,
|
||||
* during an incremental GC, some JS code stores one of the compartment's empty
|
||||
* shapes into an object already marked black. Normally, this would not be a
|
||||
* problem, because the empty shape would have been part of the initial snapshot
|
||||
* when the GC started. However, since this is a weak pointer, it isn't. So we
|
||||
* may collect the empty shape even though a live object points to it. To fix
|
||||
* this, we mark these empty shapes black whenever they get read out.
|
||||
*/
|
||||
template<class T>
|
||||
class ReadBarriered
|
||||
{
|
||||
T *value;
|
||||
|
||||
public:
|
||||
ReadBarriered() : value(NULL) {}
|
||||
ReadBarriered(T *value) : value(value) {}
|
||||
|
||||
T *get() const {
|
||||
if (!value)
|
||||
return NULL;
|
||||
T::readBarrier(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
operator T*() const { return get(); }
|
||||
|
||||
T &operator*() const { return *get(); }
|
||||
T *operator->() const { return get(); }
|
||||
|
||||
T **unsafeGet() { return &value; }
|
||||
|
||||
void set(T *v) { value = v; }
|
||||
|
||||
operator bool() { return !!value; }
|
||||
};
|
||||
|
||||
class ReadBarrieredValue
|
||||
{
|
||||
Value value;
|
||||
|
||||
public:
|
||||
ReadBarrieredValue() : value(UndefinedValue()) {}
|
||||
ReadBarrieredValue(const Value &value) : value(value) {}
|
||||
|
||||
inline const Value &get() const;
|
||||
Value *unsafeGet() { return &value; }
|
||||
inline operator const Value &() const;
|
||||
|
||||
inline JSObject &toObject() const;
|
||||
};
|
||||
|
||||
namespace tl {
|
||||
|
||||
template <class T> struct IsRelocatableHeapType<HeapPtr<T> >
|
||||
{ static const bool result = false; };
|
||||
template <> struct IsRelocatableHeapType<HeapSlot> { static const bool result = false; };
|
||||
template <> struct IsRelocatableHeapType<HeapValue> { static const bool result = false; };
|
||||
template <> struct IsRelocatableHeapType<HeapId> { static const bool result = false; };
|
||||
|
||||
} /* namespace tl */
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsgc_barrier_h___ */
|
File diff suppressed because it is too large
Load Diff
|
@ -77,8 +77,14 @@ class MutableHandleBase {};
|
|||
|
||||
namespace JS {
|
||||
|
||||
class AutoAssertNoGC;
|
||||
|
||||
template <typename T> class MutableHandle;
|
||||
|
||||
JS_FRIEND_API(void) EnterAssertNoGCScope();
|
||||
JS_FRIEND_API(void) LeaveAssertNoGCScope();
|
||||
JS_FRIEND_API(bool) InNoGCScope();
|
||||
|
||||
/*
|
||||
* Handle provides an implicit constructor for NullPtr so that, given:
|
||||
* foo(Handle<JSObject*> h);
|
||||
|
@ -316,6 +322,169 @@ class InternalHandle<T*>
|
|||
}
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
template <typename T>
|
||||
class IntermediateNoGC
|
||||
{
|
||||
T t_;
|
||||
|
||||
public:
|
||||
IntermediateNoGC(const T &t) : t_(t) {
|
||||
EnterAssertNoGCScope();
|
||||
}
|
||||
IntermediateNoGC(const IntermediateNoGC &) {
|
||||
EnterAssertNoGCScope();
|
||||
}
|
||||
~IntermediateNoGC() {
|
||||
LeaveAssertNoGCScope();
|
||||
}
|
||||
|
||||
const T &operator->() { return t_; }
|
||||
operator const T &() { return t_; }
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return<T> wraps GC things that are returned from accessor methods. The
|
||||
* wrapper helps to ensure correct rooting of the returned pointer and safe
|
||||
* access while unrooted.
|
||||
*
|
||||
* Example usage in a method declaration:
|
||||
*
|
||||
* class Foo {
|
||||
* HeapPtrScript script_;
|
||||
* ...
|
||||
* public:
|
||||
* Return<JSScript*> script() { return script_; }
|
||||
* };
|
||||
*
|
||||
* Example usage of method (1):
|
||||
*
|
||||
* Foo foo(...);
|
||||
* RootedScript script(cx, foo->script());
|
||||
*
|
||||
* Example usage of method (2):
|
||||
*
|
||||
* Foo foo(...);
|
||||
* foo->script()->needsArgsObj();
|
||||
*
|
||||
* The purpose of this class is to assert eagerly on incorrect use of GC thing
|
||||
* pointers. For example:
|
||||
*
|
||||
* RootedShape shape(cx, ...);
|
||||
* shape->parent.init(js_NewGCThing<Shape*>(cx, ...));
|
||||
*
|
||||
* In this expression, C++ is allowed to order these calls as follows:
|
||||
*
|
||||
* Call Effect
|
||||
* ---- ------
|
||||
* 1) RootedShape::operator-> Stores shape::ptr_ to stack.
|
||||
* 2) js_NewGCThing<Shape*> Triggers GC and compaction of shapes. This
|
||||
* moves shape::ptr_ to a new location.
|
||||
* 3) HeapPtrObject::init This call takes the relocated shape::ptr_
|
||||
* as |this|, crashing or, worse, corrupting
|
||||
* the program's state on the first access
|
||||
* to a member variable.
|
||||
*
|
||||
* If Shape::parent were an accessor function returning a Return<Shape*>, this
|
||||
* could not happen: Return ensures either immediate rooting or no GC within
|
||||
* the same expression.
|
||||
*/
|
||||
template <typename T>
|
||||
class Return
|
||||
{
|
||||
friend class Rooted<T>;
|
||||
|
||||
const T ptr_;
|
||||
|
||||
public:
|
||||
template <typename S>
|
||||
Return(const S &ptr,
|
||||
typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0)
|
||||
: ptr_(ptr)
|
||||
{}
|
||||
|
||||
Return(NullPtr) : ptr_(NULL) {}
|
||||
|
||||
/*
|
||||
* |get(AutoAssertNoGC &)| is the safest way to access a Return<T> without
|
||||
* rooting it first: it is impossible to call this method without an
|
||||
* AutoAssertNoGC in scope, so the compiler will automatically catch any
|
||||
* incorrect usage.
|
||||
*
|
||||
* Example:
|
||||
* AutoAssertNoGC nogc;
|
||||
* RawScript script = fun->script().get(nogc);
|
||||
*/
|
||||
const T &get(AutoAssertNoGC &) const {
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
/*
|
||||
* |operator->|'s result cannot be stored in a local variable, so it is safe
|
||||
* to use in a CanGC context iff no GC can occur anywhere within the same
|
||||
* expression (generally from one |;| to the next). |operator->| uses a
|
||||
* temporary object as a guard and will assert if a CanGC context is
|
||||
* encountered before the next C++ Sequence Point.
|
||||
*
|
||||
* INCORRECT:
|
||||
* fun->script()->bindings = myBindings->clone(cx, ...);
|
||||
*
|
||||
* The compiler is allowed to reorder |fun->script()::operator->()| above
|
||||
* the call to |clone(cx, ...)|. In this case, the RawScript C++ stores on
|
||||
* the stack may be corrupted by a GC under |clone|. The subsequent
|
||||
* dereference of this pointer to get |bindings| will result in an invalid
|
||||
* access. This wrapper ensures that such usage asserts in DEBUG builds when
|
||||
* it encounters this situation. Without this assertion, it is possible for
|
||||
* such access to corrupt program state instead of crashing immediately.
|
||||
*
|
||||
* CORRECT:
|
||||
* RootedScript clone(cx, myBindings->clone(cx, ...));
|
||||
* fun->script()->bindings = clone;
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
IntermediateNoGC<T> operator->() const {
|
||||
return IntermediateNoGC<T>(ptr_);
|
||||
}
|
||||
#else
|
||||
const T &operator->() const {
|
||||
return ptr_;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* |unsafeGet()| is unsafe for most uses. Although it performs similar
|
||||
* checking to |operator->|, its result can be stored to a local variable.
|
||||
* For this reason, it should only be used when it would be incorrect or
|
||||
* absurd to create a new Rooted for its use: e.g. for assertions.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
IntermediateNoGC<T> unsafeGet() const {
|
||||
return IntermediateNoGC<T>(ptr_);
|
||||
}
|
||||
#else
|
||||
const T &unsafeGet() const {
|
||||
return ptr_;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* |operator==| is safe to use in any context. It is present to allow:
|
||||
* JS_ASSERT(myScript == fun->script().unsafeGet());
|
||||
*
|
||||
* To be rewritten as:
|
||||
* JS_ASSERT(fun->script() == myScript);
|
||||
*
|
||||
* Note: the new order tells C++ to use |Return<JSScript*>::operator=|
|
||||
* instead of direct pointer comparison.
|
||||
*/
|
||||
bool operator==(const T &other) { return ptr_ == other; }
|
||||
bool operator!=(const T &other) { return ptr_ != other; }
|
||||
bool operator==(const Return<T> &other) { return ptr_ == other.ptr_; }
|
||||
bool operator==(const JS::Handle<T> &other) { return ptr_ == other.get(); }
|
||||
inline bool operator==(const Rooted<T> &other);
|
||||
};
|
||||
|
||||
/*
|
||||
* By default, pointers should use the inheritance hierarchy to find their
|
||||
* ThingRootKind. Some pointer types are explicitly set in jspubtd.h so that
|
||||
|
@ -332,12 +501,6 @@ struct RootMethods<T *>
|
|||
static bool poisoned(T *v) { return IsPoisonedPtr(v); }
|
||||
};
|
||||
|
||||
#if !(defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING))
|
||||
// Defined in vm/String.h.
|
||||
template <>
|
||||
class Rooted<JSStableString *>;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
class RootedBase {};
|
||||
|
||||
|
@ -356,27 +519,23 @@ class Rooted : public RootedBase<T>
|
|||
{
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
ContextFriendFields *cx = ContextFriendFields::get(cxArg);
|
||||
|
||||
ThingRootKind kind = RootMethods<T>::kind();
|
||||
this->stack = reinterpret_cast<Rooted<T>**>(&cx->thingGCRooters[kind]);
|
||||
this->prev = *stack;
|
||||
*stack = this;
|
||||
|
||||
JS_ASSERT(!RootMethods<T>::poisoned(ptr));
|
||||
commonInit(cx->thingGCRooters);
|
||||
#endif
|
||||
}
|
||||
|
||||
void init(JSRuntime *rtArg)
|
||||
{
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
RuntimeFriendFields *rt = const_cast<RuntimeFriendFields *>(RuntimeFriendFields::get(rtArg));
|
||||
PerThreadDataFriendFields *pt = PerThreadDataFriendFields::getMainThread(rtArg);
|
||||
commonInit(pt->thingGCRooters);
|
||||
#endif
|
||||
}
|
||||
|
||||
ThingRootKind kind = RootMethods<T>::kind();
|
||||
this->stack = reinterpret_cast<Rooted<T>**>(&rt->thingGCRooters[kind]);
|
||||
this->prev = *stack;
|
||||
*stack = this;
|
||||
|
||||
JS_ASSERT(!RootMethods<T>::poisoned(ptr));
|
||||
void init(js::PerThreadData *ptArg)
|
||||
{
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
PerThreadDataFriendFields *pt = PerThreadDataFriendFields::get(ptArg);
|
||||
commonInit(pt->thingGCRooters);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -413,6 +572,40 @@ class Rooted : public RootedBase<T>
|
|||
init(cx);
|
||||
}
|
||||
|
||||
Rooted(js::PerThreadData *pt
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: ptr(RootMethods<T>::initial())
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(pt);
|
||||
}
|
||||
|
||||
Rooted(js::PerThreadData *pt, T initial
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: ptr(initial)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(pt);
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
Rooted(JSContext *cx, const Return<S> &initial
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: ptr(initial.ptr_)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(cx);
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
Rooted(js::PerThreadData *pt, const Return<S> &initial
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: ptr(initial.ptr_)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(pt);
|
||||
}
|
||||
|
||||
~Rooted()
|
||||
{
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
|
@ -445,7 +638,25 @@ class Rooted : public RootedBase<T>
|
|||
return ptr;
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
T & operator =(const Return<S> &value)
|
||||
{
|
||||
ptr = value.ptr_;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
void commonInit(Rooted<void*> **thingGCRooters) {
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
ThingRootKind kind = RootMethods<T>::kind();
|
||||
this->stack = reinterpret_cast<Rooted<T>**>(&thingGCRooters[kind]);
|
||||
this->prev = *stack;
|
||||
*stack = this;
|
||||
|
||||
JS_ASSERT(!RootMethods<T>::poisoned(ptr));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
Rooted<T> **stack, *prev;
|
||||
#endif
|
||||
|
@ -455,6 +666,19 @@ class Rooted : public RootedBase<T>
|
|||
Rooted(const Rooted &) MOZ_DELETE;
|
||||
};
|
||||
|
||||
#if !(defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING))
|
||||
// Defined in vm/String.h.
|
||||
template <>
|
||||
class Rooted<JSStableString *>;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
Return<T>::operator==(const Rooted<T> &other)
|
||||
{
|
||||
return ptr_ == other.get();
|
||||
}
|
||||
|
||||
typedef Rooted<JSObject*> RootedObject;
|
||||
typedef Rooted<JSFunction*> RootedFunction;
|
||||
typedef Rooted<JSScript*> RootedScript;
|
||||
|
@ -550,10 +774,6 @@ MutableHandle<T>::MutableHandle(js::Rooted<S> *root,
|
|||
ptr = root->address();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void) EnterAssertNoGCScope();
|
||||
JS_FRIEND_API(void) LeaveAssertNoGCScope();
|
||||
JS_FRIEND_API(bool) InNoGCScope();
|
||||
|
||||
/*
|
||||
* The scoped guard object AutoAssertNoGC forces the GC to assert if a GC is
|
||||
* attempted while the guard object is live. If you have a GC-unsafe operation
|
||||
|
@ -581,15 +801,11 @@ public:
|
|||
/*
|
||||
* AssertCanGC will assert if it is called inside of an AutoAssertNoGC region.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
JS_ALWAYS_INLINE void
|
||||
AssertCanGC()
|
||||
{
|
||||
JS_ASSERT(!InNoGCScope());
|
||||
}
|
||||
#else
|
||||
# define AssertCanGC()
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
|
||||
extern void
|
||||
|
|
|
@ -1,193 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef jsgc_statistics_h___
|
||||
#define jsgc_statistics_h___
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "jspubtd.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
struct JSCompartment;
|
||||
|
||||
namespace js {
|
||||
namespace gcstats {
|
||||
|
||||
enum Phase {
|
||||
PHASE_GC_BEGIN,
|
||||
PHASE_WAIT_BACKGROUND_THREAD,
|
||||
PHASE_PURGE,
|
||||
PHASE_MARK,
|
||||
PHASE_MARK_DISCARD_CODE,
|
||||
PHASE_MARK_ROOTS,
|
||||
PHASE_MARK_TYPES,
|
||||
PHASE_MARK_DELAYED,
|
||||
PHASE_MARK_WEAK,
|
||||
PHASE_MARK_GRAY,
|
||||
PHASE_MARK_GRAY_WEAK,
|
||||
PHASE_FINALIZE_START,
|
||||
PHASE_SWEEP,
|
||||
PHASE_SWEEP_ATOMS,
|
||||
PHASE_SWEEP_COMPARTMENTS,
|
||||
PHASE_SWEEP_TABLES,
|
||||
PHASE_SWEEP_OBJECT,
|
||||
PHASE_SWEEP_STRING,
|
||||
PHASE_SWEEP_SCRIPT,
|
||||
PHASE_SWEEP_SHAPE,
|
||||
PHASE_SWEEP_IONCODE,
|
||||
PHASE_SWEEP_DISCARD_CODE,
|
||||
PHASE_DISCARD_ANALYSIS,
|
||||
PHASE_DISCARD_TI,
|
||||
PHASE_FREE_TI_ARENA,
|
||||
PHASE_SWEEP_TYPES,
|
||||
PHASE_CLEAR_SCRIPT_ANALYSIS,
|
||||
PHASE_FINALIZE_END,
|
||||
PHASE_DESTROY,
|
||||
PHASE_GC_END,
|
||||
|
||||
PHASE_LIMIT
|
||||
};
|
||||
|
||||
enum Stat {
|
||||
STAT_NEW_CHUNK,
|
||||
STAT_DESTROY_CHUNK,
|
||||
|
||||
STAT_LIMIT
|
||||
};
|
||||
|
||||
class StatisticsSerializer;
|
||||
|
||||
struct Statistics {
|
||||
Statistics(JSRuntime *rt);
|
||||
~Statistics();
|
||||
|
||||
void beginPhase(Phase phase);
|
||||
void endPhase(Phase phase);
|
||||
|
||||
void beginSlice(int collectedCount, int compartmentCount, gcreason::Reason reason);
|
||||
void endSlice();
|
||||
|
||||
void reset(const char *reason) { slices.back().resetReason = reason; }
|
||||
void nonincremental(const char *reason) { nonincrementalReason = reason; }
|
||||
|
||||
void count(Stat s) {
|
||||
JS_ASSERT(s < STAT_LIMIT);
|
||||
counts[s]++;
|
||||
}
|
||||
|
||||
int64_t beginSCC();
|
||||
void endSCC(unsigned scc, int64_t start);
|
||||
|
||||
jschar *formatMessage();
|
||||
jschar *formatJSON(uint64_t timestamp);
|
||||
|
||||
private:
|
||||
JSRuntime *runtime;
|
||||
|
||||
int64_t startupTime;
|
||||
|
||||
FILE *fp;
|
||||
bool fullFormat;
|
||||
|
||||
/*
|
||||
* GCs can't really nest, but a second GC can be triggered from within the
|
||||
* JSGC_END callback.
|
||||
*/
|
||||
int gcDepth;
|
||||
|
||||
int collectedCount;
|
||||
int compartmentCount;
|
||||
const char *nonincrementalReason;
|
||||
|
||||
struct SliceData {
|
||||
SliceData(gcreason::Reason reason, int64_t start, size_t startFaults)
|
||||
: reason(reason), resetReason(NULL), start(start), startFaults(startFaults)
|
||||
{
|
||||
PodArrayZero(phaseTimes);
|
||||
}
|
||||
|
||||
gcreason::Reason reason;
|
||||
const char *resetReason;
|
||||
int64_t start, end;
|
||||
size_t startFaults, endFaults;
|
||||
int64_t phaseTimes[PHASE_LIMIT];
|
||||
|
||||
int64_t duration() const { return end - start; }
|
||||
};
|
||||
|
||||
Vector<SliceData, 8, SystemAllocPolicy> slices;
|
||||
|
||||
/* Most recent time when the given phase started. */
|
||||
int64_t phaseStartTimes[PHASE_LIMIT];
|
||||
|
||||
/* Total time in a given phase for this GC. */
|
||||
int64_t phaseTimes[PHASE_LIMIT];
|
||||
|
||||
/* Total time in a given phase over all GCs. */
|
||||
int64_t phaseTotals[PHASE_LIMIT];
|
||||
|
||||
/* Number of events of this type for this GC. */
|
||||
unsigned int counts[STAT_LIMIT];
|
||||
|
||||
/* Allocated space before the GC started. */
|
||||
size_t preBytes;
|
||||
|
||||
/* Sweep times for SCCs of compartments. */
|
||||
Vector<int64_t, 0, SystemAllocPolicy> sccTimes;
|
||||
|
||||
void beginGC();
|
||||
void endGC();
|
||||
|
||||
void gcDuration(int64_t *total, int64_t *maxPause);
|
||||
void sccDurations(int64_t *total, int64_t *maxPause);
|
||||
void printStats();
|
||||
bool formatData(StatisticsSerializer &ss, uint64_t timestamp);
|
||||
|
||||
double computeMMU(int64_t resolution);
|
||||
};
|
||||
|
||||
struct AutoGCSlice {
|
||||
AutoGCSlice(Statistics &stats, int collectedCount, int compartmentCount, gcreason::Reason reason
|
||||
JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: stats(stats)
|
||||
{
|
||||
JS_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
stats.beginSlice(collectedCount, compartmentCount, reason);
|
||||
}
|
||||
~AutoGCSlice() { stats.endSlice(); }
|
||||
|
||||
Statistics &stats;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
struct AutoPhase {
|
||||
AutoPhase(Statistics &stats, Phase phase JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: stats(stats), phase(phase) { JS_GUARD_OBJECT_NOTIFIER_INIT; stats.beginPhase(phase); }
|
||||
~AutoPhase() { stats.endPhase(phase); }
|
||||
|
||||
Statistics &stats;
|
||||
Phase phase;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
struct AutoSCC {
|
||||
AutoSCC(Statistics &stats, unsigned scc JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: stats(stats), scc(scc) { JS_GUARD_OBJECT_NOTIFIER_INIT; start = stats.beginSCC(); }
|
||||
~AutoSCC() { stats.endSCC(scc, start); }
|
||||
|
||||
Statistics &stats;
|
||||
unsigned scc;
|
||||
int64_t start;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
} /* namespace gcstats */
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsgc_statistics_h___ */
|
|
@ -1,398 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
#ifndef jsgc_storebuffer_h___
|
||||
#define jsgc_storebuffer_h___
|
||||
|
||||
#include "jsgc.h"
|
||||
#include "jsalloc.h"
|
||||
|
||||
#include "gc/Marking.h"
|
||||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
/*
|
||||
* Note: this is a stub Nursery that does not actually contain a heap, just a
|
||||
* set of pointers which are "inside" the nursery to implement verification.
|
||||
*/
|
||||
class Nursery
|
||||
{
|
||||
HashSet<void*, PointerHasher<void*, 3>, SystemAllocPolicy> nursery;
|
||||
|
||||
public:
|
||||
Nursery() : nursery() {}
|
||||
|
||||
bool enable() {
|
||||
if (!nursery.initialized())
|
||||
return nursery.init();
|
||||
return true;
|
||||
}
|
||||
|
||||
void disable() {
|
||||
if (!nursery.initialized())
|
||||
return;
|
||||
nursery.finish();
|
||||
}
|
||||
|
||||
bool isInside(void *cell) const {
|
||||
JS_ASSERT((uintptr_t(cell) & 0x3) == 0);
|
||||
return nursery.initialized() && nursery.has(cell);
|
||||
}
|
||||
|
||||
void insertPointer(void *cell) {
|
||||
nursery.putNew(cell);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* BufferableRef represents an abstract reference for use in the generational
|
||||
* GC's remembered set. Entries in the store buffer that cannot be represented
|
||||
* with the simple pointer-to-a-pointer scheme must derive from this class and
|
||||
* use the generic store buffer interface.
|
||||
*/
|
||||
class BufferableRef
|
||||
{
|
||||
public:
|
||||
virtual bool match(void *location) = 0;
|
||||
virtual void mark(JSTracer *trc) = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
* HashKeyRef represents a reference to a HashTable key. Manual HashTable
|
||||
* barriers should should instantiate this template with their own table/key
|
||||
* type to insert into the generic buffer with putGeneric.
|
||||
*/
|
||||
template <typename Map, typename Key>
|
||||
class HashKeyRef : public BufferableRef
|
||||
{
|
||||
Map *map;
|
||||
Key key;
|
||||
|
||||
typedef typename Map::Ptr Ptr;
|
||||
|
||||
public:
|
||||
HashKeyRef(Map *m, const Key &k) : map(m), key(k) {}
|
||||
|
||||
bool match(void *location) {
|
||||
Ptr p = map->lookup(key);
|
||||
if (!p)
|
||||
return false;
|
||||
return &p->key == location;
|
||||
}
|
||||
|
||||
void mark(JSTracer *trc) {}
|
||||
};
|
||||
|
||||
/*
|
||||
* The StoreBuffer observes all writes that occur in the system and performs
|
||||
* efficient filtering of them to derive a remembered set for nursery GC.
|
||||
*/
|
||||
class StoreBuffer
|
||||
{
|
||||
/* TODO: profile to find the ideal size for these. */
|
||||
static const size_t ValueBufferSize = 1 * 1024 * sizeof(Value *);
|
||||
static const size_t CellBufferSize = 2 * 1024 * sizeof(Cell **);
|
||||
static const size_t SlotBufferSize = 2 * 1024 * (sizeof(JSObject *) + sizeof(uint32_t));
|
||||
static const size_t RelocValueBufferSize = 1 * 1024 * sizeof(Value *);
|
||||
static const size_t RelocCellBufferSize = 1 * 1024 * sizeof(Cell **);
|
||||
static const size_t GenericBufferSize = 1 * 1024 * sizeof(int);
|
||||
static const size_t TotalSize = ValueBufferSize + CellBufferSize +
|
||||
SlotBufferSize + RelocValueBufferSize + RelocCellBufferSize +
|
||||
GenericBufferSize;
|
||||
|
||||
typedef HashSet<void *, PointerHasher<void *, 3>, SystemAllocPolicy> EdgeSet;
|
||||
|
||||
/*
|
||||
* This buffer holds only a single type of edge. Using this buffer is more
|
||||
* efficient than the generic buffer when many writes will be to the same
|
||||
* type of edge: e.g. Value or Cell*.
|
||||
*/
|
||||
template<typename T>
|
||||
class MonoTypeBuffer
|
||||
{
|
||||
friend class StoreBuffer;
|
||||
|
||||
StoreBuffer *owner;
|
||||
Nursery *nursery;
|
||||
|
||||
T *base; /* Pointer to the start of the buffer. */
|
||||
T *pos; /* Pointer to the current insertion position. */
|
||||
T *top; /* Pointer to one element after the end. */
|
||||
|
||||
MonoTypeBuffer(StoreBuffer *owner, Nursery *nursery)
|
||||
: owner(owner), nursery(nursery), base(NULL), pos(NULL), top(NULL)
|
||||
{}
|
||||
|
||||
MonoTypeBuffer &operator=(const MonoTypeBuffer& other) MOZ_DELETE;
|
||||
|
||||
bool enable(uint8_t *region, size_t len);
|
||||
void disable();
|
||||
|
||||
bool isEmpty() const { return pos == base; }
|
||||
bool isFull() const { JS_ASSERT(pos <= top); return pos == top; }
|
||||
|
||||
/* Compaction algorithms. */
|
||||
void compactNotInSet();
|
||||
|
||||
/*
|
||||
* Attempts to reduce the usage of the buffer by removing unnecessary
|
||||
* entries.
|
||||
*/
|
||||
virtual void compact();
|
||||
|
||||
/* Add one item to the buffer. */
|
||||
void put(const T &v);
|
||||
|
||||
/* For verification. */
|
||||
bool accumulateEdges(EdgeSet &edges);
|
||||
};
|
||||
|
||||
/*
|
||||
* Overrides the MonoTypeBuffer to support pointers that may be moved in
|
||||
* memory outside of the GC's control.
|
||||
*/
|
||||
template <typename T>
|
||||
class RelocatableMonoTypeBuffer : public MonoTypeBuffer<T>
|
||||
{
|
||||
friend class StoreBuffer;
|
||||
|
||||
RelocatableMonoTypeBuffer(StoreBuffer *owner, Nursery *nursery)
|
||||
: MonoTypeBuffer<T>(owner, nursery)
|
||||
{}
|
||||
|
||||
/* Override compaction to filter out removed items. */
|
||||
void compactMoved();
|
||||
virtual void compact();
|
||||
|
||||
/* Record a removal from the buffer. */
|
||||
void unput(const T &v);
|
||||
};
|
||||
|
||||
class GenericBuffer
|
||||
{
|
||||
friend class StoreBuffer;
|
||||
|
||||
StoreBuffer *owner;
|
||||
Nursery *nursery;
|
||||
|
||||
uint8_t *base; /* Pointer to start of buffer. */
|
||||
uint8_t *pos; /* Pointer to current buffer position. */
|
||||
uint8_t *top; /* Pointer to one past the last entry. */
|
||||
|
||||
GenericBuffer(StoreBuffer *owner, Nursery *nursery)
|
||||
: owner(owner), nursery(nursery)
|
||||
{}
|
||||
|
||||
GenericBuffer &operator=(const GenericBuffer& other) MOZ_DELETE;
|
||||
|
||||
bool enable(uint8_t *region, size_t len);
|
||||
void disable();
|
||||
|
||||
/* Check if a pointer is present in the buffer. */
|
||||
bool containsEdge(void *location) const;
|
||||
|
||||
template <typename T>
|
||||
void put(const T &t) {
|
||||
/* Check if we have been enabled. */
|
||||
if (!pos)
|
||||
return;
|
||||
|
||||
/* Check for overflow. */
|
||||
if (top - pos < (unsigned)(sizeof(unsigned) + sizeof(T))) {
|
||||
owner->setOverflowed();
|
||||
return;
|
||||
}
|
||||
|
||||
*((unsigned *)pos) = sizeof(T);
|
||||
pos += sizeof(unsigned);
|
||||
|
||||
T *p = (T *)pos;
|
||||
new (p) T(t);
|
||||
pos += sizeof(T);
|
||||
}
|
||||
};
|
||||
|
||||
class CellPtrEdge
|
||||
{
|
||||
friend class StoreBuffer;
|
||||
friend class StoreBuffer::MonoTypeBuffer<CellPtrEdge>;
|
||||
friend class StoreBuffer::RelocatableMonoTypeBuffer<CellPtrEdge>;
|
||||
|
||||
Cell **edge;
|
||||
|
||||
CellPtrEdge(Cell **v) : edge(v) {}
|
||||
bool operator==(const CellPtrEdge &other) const { return edge == other.edge; }
|
||||
bool operator!=(const CellPtrEdge &other) const { return edge != other.edge; }
|
||||
|
||||
void *location() const { return (void *)edge; }
|
||||
|
||||
bool inRememberedSet(Nursery *n) {
|
||||
return !n->isInside(edge) && n->isInside(*edge);
|
||||
}
|
||||
|
||||
bool isNullEdge() const {
|
||||
return !*edge;
|
||||
}
|
||||
|
||||
CellPtrEdge tagged() const { return CellPtrEdge((Cell **)(uintptr_t(edge) | 1)); }
|
||||
CellPtrEdge untagged() const { return CellPtrEdge((Cell **)(uintptr_t(edge) & ~1)); }
|
||||
bool isTagged() const { return bool(uintptr_t(edge) & 1); }
|
||||
};
|
||||
|
||||
class ValueEdge
|
||||
{
|
||||
friend class StoreBuffer;
|
||||
friend class StoreBuffer::MonoTypeBuffer<ValueEdge>;
|
||||
friend class StoreBuffer::RelocatableMonoTypeBuffer<ValueEdge>;
|
||||
|
||||
Value *edge;
|
||||
|
||||
ValueEdge(Value *v) : edge(v) {}
|
||||
bool operator==(const ValueEdge &other) const { return edge == other.edge; }
|
||||
bool operator!=(const ValueEdge &other) const { return edge != other.edge; }
|
||||
|
||||
void *deref() const { return edge->isGCThing() ? edge->toGCThing() : NULL; }
|
||||
void *location() const { return (void *)edge; }
|
||||
|
||||
bool inRememberedSet(Nursery *n) {
|
||||
return !n->isInside(edge) && n->isInside(deref());
|
||||
}
|
||||
|
||||
bool isNullEdge() const {
|
||||
return !deref();
|
||||
}
|
||||
|
||||
ValueEdge tagged() const { return ValueEdge((Value *)(uintptr_t(edge) | 1)); }
|
||||
ValueEdge untagged() const { return ValueEdge((Value *)(uintptr_t(edge) & ~1)); }
|
||||
bool isTagged() const { return bool(uintptr_t(edge) & 1); }
|
||||
};
|
||||
|
||||
struct SlotEdge
|
||||
{
|
||||
friend class StoreBuffer;
|
||||
friend class StoreBuffer::MonoTypeBuffer<SlotEdge>;
|
||||
|
||||
JSObject *object;
|
||||
uint32_t offset;
|
||||
|
||||
SlotEdge(JSObject *object, uint32_t offset) : object(object), offset(offset) {}
|
||||
|
||||
bool operator==(const SlotEdge &other) const {
|
||||
return object == other.object && offset == other.offset;
|
||||
}
|
||||
|
||||
bool operator!=(const SlotEdge &other) const {
|
||||
return object != other.object || offset != other.offset;
|
||||
}
|
||||
|
||||
HeapSlot *slotLocation() const {
|
||||
if (object->isDenseArray()) {
|
||||
if (offset >= object->getDenseArrayInitializedLength())
|
||||
return NULL;
|
||||
return (HeapSlot *)&object->getDenseArrayElement(offset);
|
||||
}
|
||||
if (offset >= object->slotSpan())
|
||||
return NULL;
|
||||
return &object->getSlotRef(offset);
|
||||
}
|
||||
|
||||
void *deref() const {
|
||||
HeapSlot *loc = slotLocation();
|
||||
return (loc && loc->isGCThing()) ? loc->toGCThing() : NULL;
|
||||
}
|
||||
|
||||
void *location() const {
|
||||
return (void *)slotLocation();
|
||||
}
|
||||
|
||||
bool inRememberedSet(Nursery *n) {
|
||||
return !n->isInside(object) && n->isInside(deref());
|
||||
}
|
||||
|
||||
bool isNullEdge() const {
|
||||
return !deref();
|
||||
}
|
||||
};
|
||||
|
||||
MonoTypeBuffer<ValueEdge> bufferVal;
|
||||
MonoTypeBuffer<CellPtrEdge> bufferCell;
|
||||
MonoTypeBuffer<SlotEdge> bufferSlot;
|
||||
RelocatableMonoTypeBuffer<ValueEdge> bufferRelocVal;
|
||||
RelocatableMonoTypeBuffer<CellPtrEdge> bufferRelocCell;
|
||||
GenericBuffer bufferGeneric;
|
||||
|
||||
Nursery *nursery;
|
||||
|
||||
void *buffer;
|
||||
|
||||
bool overflowed;
|
||||
bool enabled;
|
||||
|
||||
/* For the verifier. */
|
||||
EdgeSet edgeSet;
|
||||
|
||||
/* For use by our owned buffers. */
|
||||
void setOverflowed() { overflowed = true; }
|
||||
|
||||
public:
|
||||
StoreBuffer(Nursery *n)
|
||||
: bufferVal(this, n), bufferCell(this, n), bufferSlot(this, n),
|
||||
bufferRelocVal(this, n), bufferRelocCell(this, n), bufferGeneric(this, n),
|
||||
nursery(n), buffer(NULL), overflowed(false), enabled(false)
|
||||
{}
|
||||
|
||||
bool enable();
|
||||
void disable();
|
||||
bool isEnabled() { return enabled; }
|
||||
|
||||
/* Get the overflowed status. */
|
||||
bool hasOverflowed() const { return overflowed; }
|
||||
|
||||
/* Insert a single edge into the buffer/remembered set. */
|
||||
void putValue(Value *v) {
|
||||
bufferVal.put(v);
|
||||
}
|
||||
void putCell(Cell **o) {
|
||||
bufferCell.put(o);
|
||||
}
|
||||
void putSlot(JSObject *obj, uint32_t slot) {
|
||||
bufferSlot.put(SlotEdge(obj, slot));
|
||||
}
|
||||
|
||||
/* Insert or update a single edge in the Relocatable buffer. */
|
||||
void putRelocatableValue(Value *v) {
|
||||
bufferRelocVal.put(v);
|
||||
}
|
||||
void putRelocatableCell(Cell **c) {
|
||||
bufferRelocCell.put(c);
|
||||
}
|
||||
void removeRelocatableValue(Value *v) {
|
||||
bufferRelocVal.unput(v);
|
||||
}
|
||||
void removeRelocatableCell(Cell **c) {
|
||||
bufferRelocCell.unput(c);
|
||||
}
|
||||
|
||||
/* Insert an entry into the generic buffer. */
|
||||
template <typename T>
|
||||
void putGeneric(const T &t) {
|
||||
bufferGeneric.put(t);
|
||||
}
|
||||
|
||||
/* For the verifier. */
|
||||
bool coalesceForVerification();
|
||||
void releaseVerificationData();
|
||||
bool containsEdgeAt(void *loc) const;
|
||||
};
|
||||
|
||||
} /* namespace gc */
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsgc_storebuffer_h___ */
|
||||
#endif /* JSGC_GENERATIONAL */
|
|
@ -60,7 +60,7 @@
|
|||
|
||||
/* Some mozilla code uses JS-friend APIs that depend on JS_METHODJIT being
|
||||
correct. */
|
||||
#define JS_METHODJIT 1
|
||||
/* #undef JS_METHODJIT */
|
||||
|
||||
/* Define to 1 to enable support for E4X (ECMA-357), 0 to disable it. */
|
||||
#define JS_HAS_XML_SUPPORT 1
|
||||
|
|
|
@ -375,3 +375,5 @@ MSG_DEF(JSMSG_MUST_REPORT_UNDEFINED, 321, 0, JSEXN_TYPEERR, "proxy must report
|
|||
MSG_DEF(JSMSG_CANT_SET_NW_NC, 322, 0, JSEXN_TYPEERR, "proxy can't successfully set a non-writable, non-configurable property")
|
||||
MSG_DEF(JSMSG_CANT_SET_WO_SETTER, 323, 0, JSEXN_TYPEERR, "proxy can't succesfully set an accessor property without a setter")
|
||||
MSG_DEF(JSMSG_DEBUG_BAD_REFERENT, 324, 2, JSEXN_TYPEERR, "{0} does not refer to {1}")
|
||||
MSG_DEF(JSMSG_DEBUG_WRAPPER_IN_WAY, 325, 2, JSEXN_TYPEERR, "{0} is a wrapper around {1}, but a direct reference is required")
|
||||
MSG_DEF(JSMSG_UNWRAP_DENIED, 326, 0, JSEXN_ERR, "permission denied to unwrap object")
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,76 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef js_heap_api_h___
|
||||
#define js_heap_api_h___
|
||||
|
||||
/* These values are private to the JS engine. */
|
||||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
/*
|
||||
* Page size must be static to support our arena pointer optimizations, so we
|
||||
* are forced to support each platform with non-4096 pages as a special case.
|
||||
* Note: The freelist supports a maximum arena shift of 15.
|
||||
* Note: Do not use JS_CPU_SPARC here, this header is used outside JS.
|
||||
*/
|
||||
#if (defined(SOLARIS) || defined(__FreeBSD__)) && \
|
||||
(defined(__sparc) || defined(__sparcv9) || defined(__ia64))
|
||||
const size_t PageShift = 13;
|
||||
const size_t ArenaShift = PageShift;
|
||||
#elif defined(__powerpc64__)
|
||||
const size_t PageShift = 16;
|
||||
const size_t ArenaShift = 12;
|
||||
#else
|
||||
const size_t PageShift = 12;
|
||||
const size_t ArenaShift = PageShift;
|
||||
#endif
|
||||
const size_t PageSize = size_t(1) << PageShift;
|
||||
const size_t ArenaSize = size_t(1) << ArenaShift;
|
||||
const size_t ArenaMask = ArenaSize - 1;
|
||||
|
||||
const size_t ChunkShift = 20;
|
||||
const size_t ChunkSize = size_t(1) << ChunkShift;
|
||||
const size_t ChunkMask = ChunkSize - 1;
|
||||
|
||||
} /* namespace gc */
|
||||
} /* namespace js */
|
||||
|
||||
namespace JS {
|
||||
|
||||
namespace shadow {
|
||||
|
||||
struct ArenaHeader
|
||||
{
|
||||
JSCompartment *compartment;
|
||||
};
|
||||
|
||||
} /* namespace shadow */
|
||||
|
||||
static inline shadow::ArenaHeader *
|
||||
GetGCThingArena(void *thing)
|
||||
{
|
||||
uintptr_t addr = uintptr_t(thing);
|
||||
addr &= ~js::gc::ArenaMask;
|
||||
return reinterpret_cast<shadow::ArenaHeader *>(addr);
|
||||
}
|
||||
|
||||
static inline JSCompartment *
|
||||
GetGCThingCompartment(void *thing)
|
||||
{
|
||||
JS_ASSERT(thing);
|
||||
return GetGCThingArena(thing)->compartment;
|
||||
}
|
||||
|
||||
static inline JSCompartment *
|
||||
GetObjectCompartment(JSObject *obj)
|
||||
{
|
||||
return GetGCThingCompartment(obj);
|
||||
}
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
#endif /* js_heap_api_h___ */
|
|
@ -38,22 +38,37 @@ namespace JS {
|
|||
struct TypeInferenceSizes
|
||||
{
|
||||
TypeInferenceSizes()
|
||||
: scripts(0)
|
||||
, objects(0)
|
||||
, tables(0)
|
||||
, temporary(0)
|
||||
: typeScripts(0)
|
||||
, typeResults(0)
|
||||
, analysisPool(0)
|
||||
, typePool(0)
|
||||
, pendingArrays(0)
|
||||
, allocationSiteTables(0)
|
||||
, arrayTypeTables(0)
|
||||
, objectTypeTables(0)
|
||||
, typeObjects(0)
|
||||
{}
|
||||
|
||||
size_t scripts;
|
||||
size_t objects;
|
||||
size_t tables;
|
||||
size_t temporary;
|
||||
size_t typeScripts;
|
||||
size_t typeResults;
|
||||
size_t analysisPool;
|
||||
size_t typePool;
|
||||
size_t pendingArrays;
|
||||
size_t allocationSiteTables;
|
||||
size_t arrayTypeTables;
|
||||
size_t objectTypeTables;
|
||||
size_t typeObjects;
|
||||
|
||||
void add(TypeInferenceSizes &sizes) {
|
||||
this->scripts += sizes.scripts;
|
||||
this->objects += sizes.objects;
|
||||
this->tables += sizes.tables;
|
||||
this->temporary += sizes.temporary;
|
||||
this->typeScripts += sizes.typeScripts;
|
||||
this->typeResults += sizes.typeResults;
|
||||
this->analysisPool += sizes.analysisPool;
|
||||
this->typePool += sizes.typePool;
|
||||
this->pendingArrays += sizes.pendingArrays;
|
||||
this->allocationSiteTables += sizes.allocationSiteTables;
|
||||
this->arrayTypeTables += sizes.arrayTypeTables;
|
||||
this->objectTypeTables += sizes.objectTypeTables;
|
||||
this->typeObjects += sizes.typeObjects;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -129,10 +144,15 @@ struct CompartmentStats
|
|||
, extra2(0)
|
||||
, gcHeapArenaAdmin(0)
|
||||
, gcHeapUnusedGcThings(0)
|
||||
, gcHeapObjectsNonFunction(0)
|
||||
, gcHeapObjectsOrdinary(0)
|
||||
, gcHeapObjectsFunction(0)
|
||||
, gcHeapStrings(0)
|
||||
, gcHeapShapesTree(0)
|
||||
, gcHeapObjectsDenseArray(0)
|
||||
, gcHeapObjectsSlowArray(0)
|
||||
, gcHeapObjectsCrossCompartmentWrapper(0)
|
||||
, gcHeapStringsNormal(0)
|
||||
, gcHeapStringsShort(0)
|
||||
, gcHeapShapesTreeGlobalParented(0)
|
||||
, gcHeapShapesTreeNonGlobalParented(0)
|
||||
, gcHeapShapesDict(0)
|
||||
, gcHeapShapesBase(0)
|
||||
, gcHeapScripts(0)
|
||||
|
@ -147,7 +167,7 @@ struct CompartmentStats
|
|||
, objectsExtraRegExpStatics(0)
|
||||
, objectsExtraPropertyIteratorData(0)
|
||||
, objectsExtraPrivate(0)
|
||||
, nonHugeStringChars(0)
|
||||
, stringCharsNonHuge(0)
|
||||
, shapesExtraTreeTables(0)
|
||||
, shapesExtraDictTables(0)
|
||||
, shapesExtraTreeShapeKids(0)
|
||||
|
@ -156,7 +176,7 @@ struct CompartmentStats
|
|||
, jaegerData(0)
|
||||
, ionData(0)
|
||||
, compartmentObject(0)
|
||||
, crossCompartmentWrappers(0)
|
||||
, crossCompartmentWrappersTable(0)
|
||||
, regexpCompartment(0)
|
||||
, debuggeesSet(0)
|
||||
{}
|
||||
|
@ -166,10 +186,15 @@ struct CompartmentStats
|
|||
, extra2(other.extra2)
|
||||
, gcHeapArenaAdmin(other.gcHeapArenaAdmin)
|
||||
, gcHeapUnusedGcThings(other.gcHeapUnusedGcThings)
|
||||
, gcHeapObjectsNonFunction(other.gcHeapObjectsNonFunction)
|
||||
, gcHeapObjectsOrdinary(other.gcHeapObjectsOrdinary)
|
||||
, gcHeapObjectsFunction(other.gcHeapObjectsFunction)
|
||||
, gcHeapStrings(other.gcHeapStrings)
|
||||
, gcHeapShapesTree(other.gcHeapShapesTree)
|
||||
, gcHeapObjectsDenseArray(other.gcHeapObjectsDenseArray)
|
||||
, gcHeapObjectsSlowArray(other.gcHeapObjectsSlowArray)
|
||||
, gcHeapObjectsCrossCompartmentWrapper(other.gcHeapObjectsCrossCompartmentWrapper)
|
||||
, gcHeapStringsNormal(other.gcHeapStringsNormal)
|
||||
, gcHeapStringsShort(other.gcHeapStringsShort)
|
||||
, gcHeapShapesTreeGlobalParented(other.gcHeapShapesTreeGlobalParented)
|
||||
, gcHeapShapesTreeNonGlobalParented(other.gcHeapShapesTreeNonGlobalParented)
|
||||
, gcHeapShapesDict(other.gcHeapShapesDict)
|
||||
, gcHeapShapesBase(other.gcHeapShapesBase)
|
||||
, gcHeapScripts(other.gcHeapScripts)
|
||||
|
@ -184,7 +209,7 @@ struct CompartmentStats
|
|||
, objectsExtraRegExpStatics(other.objectsExtraRegExpStatics)
|
||||
, objectsExtraPropertyIteratorData(other.objectsExtraPropertyIteratorData)
|
||||
, objectsExtraPrivate(other.objectsExtraPrivate)
|
||||
, nonHugeStringChars(other.nonHugeStringChars)
|
||||
, stringCharsNonHuge(other.stringCharsNonHuge)
|
||||
, shapesExtraTreeTables(other.shapesExtraTreeTables)
|
||||
, shapesExtraDictTables(other.shapesExtraDictTables)
|
||||
, shapesExtraTreeShapeKids(other.shapesExtraTreeShapeKids)
|
||||
|
@ -193,7 +218,7 @@ struct CompartmentStats
|
|||
, jaegerData(other.jaegerData)
|
||||
, ionData(other.ionData)
|
||||
, compartmentObject(other.compartmentObject)
|
||||
, crossCompartmentWrappers(other.crossCompartmentWrappers)
|
||||
, crossCompartmentWrappersTable(other.crossCompartmentWrappersTable)
|
||||
, regexpCompartment(other.regexpCompartment)
|
||||
, debuggeesSet(other.debuggeesSet)
|
||||
, typeInferenceSizes(other.typeInferenceSizes)
|
||||
|
@ -210,10 +235,15 @@ struct CompartmentStats
|
|||
size_t gcHeapArenaAdmin;
|
||||
size_t gcHeapUnusedGcThings;
|
||||
|
||||
size_t gcHeapObjectsNonFunction;
|
||||
size_t gcHeapObjectsOrdinary;
|
||||
size_t gcHeapObjectsFunction;
|
||||
size_t gcHeapStrings;
|
||||
size_t gcHeapShapesTree;
|
||||
size_t gcHeapObjectsDenseArray;
|
||||
size_t gcHeapObjectsSlowArray;
|
||||
size_t gcHeapObjectsCrossCompartmentWrapper;
|
||||
size_t gcHeapStringsNormal;
|
||||
size_t gcHeapStringsShort;
|
||||
size_t gcHeapShapesTreeGlobalParented;
|
||||
size_t gcHeapShapesTreeNonGlobalParented;
|
||||
size_t gcHeapShapesDict;
|
||||
size_t gcHeapShapesBase;
|
||||
size_t gcHeapScripts;
|
||||
|
@ -229,7 +259,7 @@ struct CompartmentStats
|
|||
size_t objectsExtraRegExpStatics;
|
||||
size_t objectsExtraPropertyIteratorData;
|
||||
size_t objectsExtraPrivate;
|
||||
size_t nonHugeStringChars;
|
||||
size_t stringCharsNonHuge;
|
||||
size_t shapesExtraTreeTables;
|
||||
size_t shapesExtraDictTables;
|
||||
size_t shapesExtraTreeShapeKids;
|
||||
|
@ -238,7 +268,7 @@ struct CompartmentStats
|
|||
size_t jaegerData;
|
||||
size_t ionData;
|
||||
size_t compartmentObject;
|
||||
size_t crossCompartmentWrappers;
|
||||
size_t crossCompartmentWrappersTable;
|
||||
size_t regexpCompartment;
|
||||
size_t debuggeesSet;
|
||||
|
||||
|
@ -253,10 +283,15 @@ struct CompartmentStats
|
|||
ADD(gcHeapArenaAdmin);
|
||||
ADD(gcHeapUnusedGcThings);
|
||||
|
||||
ADD(gcHeapObjectsNonFunction);
|
||||
ADD(gcHeapObjectsOrdinary);
|
||||
ADD(gcHeapObjectsFunction);
|
||||
ADD(gcHeapStrings);
|
||||
ADD(gcHeapShapesTree);
|
||||
ADD(gcHeapObjectsDenseArray);
|
||||
ADD(gcHeapObjectsSlowArray);
|
||||
ADD(gcHeapObjectsCrossCompartmentWrapper);
|
||||
ADD(gcHeapStringsNormal);
|
||||
ADD(gcHeapStringsShort);
|
||||
ADD(gcHeapShapesTreeGlobalParented);
|
||||
ADD(gcHeapShapesTreeNonGlobalParented);
|
||||
ADD(gcHeapShapesDict);
|
||||
ADD(gcHeapShapesBase);
|
||||
ADD(gcHeapScripts);
|
||||
|
@ -272,7 +307,7 @@ struct CompartmentStats
|
|||
ADD(objectsExtraRegExpStatics);
|
||||
ADD(objectsExtraPropertyIteratorData);
|
||||
ADD(objectsExtraPrivate);
|
||||
ADD(nonHugeStringChars);
|
||||
ADD(stringCharsNonHuge);
|
||||
ADD(shapesExtraTreeTables);
|
||||
ADD(shapesExtraDictTables);
|
||||
ADD(shapesExtraTreeShapeKids);
|
||||
|
@ -281,7 +316,7 @@ struct CompartmentStats
|
|||
ADD(jaegerData);
|
||||
ADD(ionData);
|
||||
ADD(compartmentObject);
|
||||
ADD(crossCompartmentWrappers);
|
||||
ADD(crossCompartmentWrappersTable);
|
||||
ADD(regexpCompartment);
|
||||
ADD(debuggeesSet);
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
#include "jstypes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
# include "js/TemplateLib.h"
|
||||
# include "mozilla/Scoped.h"
|
||||
|
||||
|
@ -36,12 +35,8 @@ namespace js {
|
|||
|
||||
/* The private namespace is a superset of the public/shared namespaces. */
|
||||
using namespace JS;
|
||||
using namespace mozilla;
|
||||
|
||||
} /* namespace js */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
* Pattern used to overwrite freed memory. If you are accessing an object with
|
||||
|
@ -103,7 +98,7 @@ PrintBacktrace()
|
|||
int32_t OOM_traceIdx = 0;
|
||||
OOM_traceSize = backtrace(OOM_trace, JS_OOM_BACKTRACE_SIZE);
|
||||
OOM_traceSymbols = backtrace_symbols(OOM_trace, OOM_traceSize);
|
||||
|
||||
|
||||
if (!OOM_traceSymbols)
|
||||
return;
|
||||
|
||||
|
@ -171,6 +166,8 @@ static JS_INLINE void js_free(void* p)
|
|||
}
|
||||
#endif/* JS_USE_CUSTOM_ALLOCATOR */
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
* Replace bit-scanning code sequences with CPU-specific instructions to
|
||||
* speedup calculations of ceiling/floor log2.
|
||||
|
@ -330,6 +327,8 @@ JS_PUBLIC_API(size_t) js_FloorLog2wImpl(size_t n);
|
|||
# error "NOT SUPPORTED"
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
/*
|
||||
* Internal function.
|
||||
* Compute the log of the least power of 2 greater than or equal to n. This is
|
||||
|
@ -371,9 +370,6 @@ JS_FLOOR_LOG2W(size_t n)
|
|||
#define JS_ROTATE_LEFT32(a, bits) (((a) << (bits)) | ((a) >> (32 - (bits))))
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <new>
|
||||
|
||||
/*
|
||||
|
@ -903,8 +899,6 @@ inline bool IsPoisonedPtr(T *v)
|
|||
|
||||
}
|
||||
|
||||
#endif /* defined(__cplusplus) */
|
||||
|
||||
/*
|
||||
* This is SpiderMonkey's equivalent to |nsMallocSizeOfFun|.
|
||||
*/
|
||||
|
|
|
@ -242,7 +242,7 @@ class Vector : private AllocPolicy
|
|||
size_t mReserved; /* Max elements of reserved or used space in this vector. */
|
||||
#endif
|
||||
|
||||
AlignedStorage<sInlineBytes> storage;
|
||||
mozilla::AlignedStorage<sInlineBytes> storage;
|
||||
|
||||
#ifdef DEBUG
|
||||
friend class ReentrancyGuard;
|
||||
|
@ -255,7 +255,11 @@ class Vector : private AllocPolicy
|
|||
/* private accessors */
|
||||
|
||||
bool usingInlineStorage() const {
|
||||
return mBegin == (T *)storage.addr();
|
||||
return mBegin == inlineStorage();
|
||||
}
|
||||
|
||||
T *inlineStorage() const {
|
||||
return (T *)storage.addr();
|
||||
}
|
||||
|
||||
T *beginNoCheck() const {
|
||||
|
@ -427,7 +431,7 @@ class Vector : private AllocPolicy
|
|||
internalAppendN(t, n);
|
||||
}
|
||||
template <class U> void infallibleAppend(const U *begin, const U *end) {
|
||||
internalAppend(begin, PointerRangeSize(begin, end));
|
||||
internalAppend(begin, mozilla::PointerRangeSize(begin, end));
|
||||
}
|
||||
template <class U> void infallibleAppend(const U *begin, size_t length) {
|
||||
internalAppend(begin, length);
|
||||
|
@ -479,6 +483,8 @@ class Vector : private AllocPolicy
|
|||
* object (which must be heap-allocated) itself.
|
||||
*/
|
||||
size_t sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const;
|
||||
|
||||
void swap(Vector &other);
|
||||
};
|
||||
|
||||
/* This does the re-entrancy check plus several other sanity checks. */
|
||||
|
@ -506,6 +512,9 @@ template <class T, size_t N, class AllocPolicy>
|
|||
JS_ALWAYS_INLINE
|
||||
Vector<T, N, AllocPolicy>::Vector(MoveRef<Vector> rhs)
|
||||
: AllocPolicy(rhs)
|
||||
#ifdef DEBUG
|
||||
, entered(false)
|
||||
#endif
|
||||
{
|
||||
mLength = rhs->mLength;
|
||||
mCapacity = rhs->mCapacity;
|
||||
|
@ -856,7 +865,7 @@ JS_ALWAYS_INLINE bool
|
|||
Vector<T,N,AP>::append(const U *insBegin, const U *insEnd)
|
||||
{
|
||||
REENTRANCY_GUARD_ET_AL;
|
||||
size_t needed = PointerRangeSize(insBegin, insEnd);
|
||||
size_t needed = mozilla::PointerRangeSize(insBegin, insEnd);
|
||||
if (mLength + needed > mCapacity && !growStorageBy(needed))
|
||||
return false;
|
||||
|
||||
|
@ -995,6 +1004,33 @@ Vector<T,N,AP>::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const
|
|||
return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
template <class T, size_t N, class AP>
|
||||
inline void
|
||||
Vector<T,N,AP>::swap(Vector &other)
|
||||
{
|
||||
// TODO Implement N != 0
|
||||
JS_STATIC_ASSERT(N == 0);
|
||||
|
||||
// This only works when inline storage is always empty.
|
||||
if (!usingInlineStorage() && other.usingInlineStorage()) {
|
||||
other.mBegin = mBegin;
|
||||
mBegin = inlineStorage();
|
||||
} else if (usingInlineStorage() && !other.usingInlineStorage()) {
|
||||
mBegin = other.mBegin;
|
||||
other.mBegin = other.inlineStorage();
|
||||
} else if (!usingInlineStorage() && !other.usingInlineStorage()) {
|
||||
Swap(mBegin, other.mBegin);
|
||||
} else {
|
||||
// This case is a no-op, since we'd set both to use their inline storage.
|
||||
}
|
||||
|
||||
Swap(mLength, other.mLength);
|
||||
Swap(mCapacity, other.mCapacity);
|
||||
#ifdef DEBUG
|
||||
Swap(mReserved, other.mReserved);
|
||||
#endif
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
|
|
@ -18,6 +18,8 @@ namespace js {
|
|||
* - public copy constructor, assignment, destructor
|
||||
* - void *malloc_(size_t)
|
||||
* Responsible for OOM reporting on NULL return value.
|
||||
* - void *calloc_(size_t)
|
||||
* Responsible for OOM reporting on NULL return value.
|
||||
* - void *realloc_(size_t)
|
||||
* Responsible for OOM reporting on NULL return value.
|
||||
* The *used* bytes of the previous buffer is passed in
|
||||
|
@ -33,6 +35,7 @@ class SystemAllocPolicy
|
|||
{
|
||||
public:
|
||||
void *malloc_(size_t bytes) { return js_malloc(bytes); }
|
||||
void *calloc_(size_t bytes) { return js_calloc(bytes); }
|
||||
void *realloc_(void *p, size_t oldBytes, size_t bytes) { return js_realloc(p, bytes); }
|
||||
void free_(void *p) { js_free(p); }
|
||||
void reportAllocOverflow() const {}
|
||||
|
@ -71,6 +74,13 @@ class TempAllocPolicy
|
|||
return p;
|
||||
}
|
||||
|
||||
void *calloc_(size_t bytes) {
|
||||
void *p = js_calloc(bytes);
|
||||
if (JS_UNLIKELY(!p))
|
||||
p = onOutOfMemory(NULL, bytes);
|
||||
return p;
|
||||
}
|
||||
|
||||
void *realloc_(void *p, size_t oldBytes, size_t bytes) {
|
||||
void *p2 = js_realloc(p, bytes);
|
||||
if (JS_UNLIKELY(!p2))
|
||||
|
|
|
@ -1 +1 @@
|
|||
4f78a759104eea6e7790c03ce0130299eeaa3968
|
||||
ba4ed5550f4042bc9963d0e15cce943b9f0be17a
|
|
@ -13,7 +13,6 @@
|
|||
#include "jsapi.h"
|
||||
#include "jsprvtd.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
namespace JS {
|
||||
|
||||
struct FrameDescription
|
||||
|
@ -47,9 +46,6 @@ JS_FRIEND_API(void) js_DumpValue(const js::Value &val);
|
|||
JS_FRIEND_API(void) js_DumpId(jsid id);
|
||||
JS_FRIEND_API(void) js_DumpStackFrame(JSContext *cx, js::StackFrame *start = NULL);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
js_DumpBacktrace(JSContext *cx);
|
||||
|
@ -432,6 +428,4 @@ JS_UnwrapObjectAndInnerize(JSObject *obj);
|
|||
extern JS_FRIEND_API(JSBool)
|
||||
js_CallContextDebugHandler(JSContext *cx);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* jsdbgapi_h___ */
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
#include "jstypes.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
#if defined(__GNUC__) && defined(__i386__) && (__GNUC__ >= 3) && !defined(XP_OS2)
|
||||
#define JS_DHASH_FASTCALL __attribute__ ((regparm (3),stdcall))
|
||||
#elif defined(XP_WIN)
|
||||
|
@ -598,6 +596,4 @@ extern JS_PUBLIC_API(void)
|
|||
JS_DHashTableDumpMeter(JSDHashTable *table, JSDHashEnumerator dump, FILE *fp);
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* jsdhash_h___ */
|
||||
|
|
|
@ -8,12 +8,28 @@
|
|||
#define jsfriendapi_h___
|
||||
|
||||
#include "jsclass.h"
|
||||
#include "jscpucfg.h"
|
||||
#include "jspubtd.h"
|
||||
#include "jsprvtd.h"
|
||||
|
||||
#include "js/HeapAPI.h"
|
||||
|
||||
#include "mozilla/GuardObjects.h"
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
/*
|
||||
* This macro checks if the stack pointer has exceeded a given limit. If
|
||||
* |tolerance| is non-zero, it returns true only if the stack pointer has
|
||||
* exceeded the limit by more than |tolerance| bytes.
|
||||
*/
|
||||
#if JS_STACK_GROWTH_DIRECTION > 0
|
||||
# define JS_CHECK_STACK_SIZE_WITH_TOLERANCE(limit, sp, tolerance) \
|
||||
((uintptr_t)(sp) < (limit)+(tolerance))
|
||||
#else
|
||||
# define JS_CHECK_STACK_SIZE_WITH_TOLERANCE(limit, sp, tolerance) \
|
||||
((uintptr_t)(sp) > (limit)-(tolerance))
|
||||
#endif
|
||||
|
||||
#define JS_CHECK_STACK_SIZE(limit, lval) JS_CHECK_STACK_SIZE_WITH_TOLERANCE(limit, lval, 0)
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
|
||||
|
@ -139,8 +155,6 @@ extern JS_FRIEND_API(void)
|
|||
js_DumpChars(const jschar *s, size_t n);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
extern JS_FRIEND_API(bool)
|
||||
JS_CopyPropertiesFrom(JSContext *cx, JSObject *target, JSObject *obj);
|
||||
|
||||
|
@ -171,12 +185,6 @@ struct JSFunctionSpecWithHelp {
|
|||
extern JS_FRIEND_API(bool)
|
||||
JS_DefineFunctionsWithHelp(JSContext *cx, JSObject *obj, const JSFunctionSpecWithHelp *fs);
|
||||
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
typedef bool (* JS_SourceHook)(JSContext *cx, JSScript *script, jschar **src, uint32_t *length);
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
|
@ -184,6 +192,8 @@ JS_SetSourceHook(JSRuntime *rt, JS_SourceHook hook);
|
|||
|
||||
namespace js {
|
||||
|
||||
extern mozilla::ThreadLocal<PerThreadData *> TlsPerThreadData;
|
||||
|
||||
inline JSRuntime *
|
||||
GetRuntime(const JSContext *cx)
|
||||
{
|
||||
|
@ -259,15 +269,34 @@ TraceWeakMaps(WeakMapTracer *trc);
|
|||
extern JS_FRIEND_API(bool)
|
||||
GCThingIsMarkedGray(void *thing);
|
||||
|
||||
extern JS_FRIEND_API(bool)
|
||||
AreGCGrayBitsValid(JSRuntime *rt);
|
||||
|
||||
/*
|
||||
* Unsets the gray bit for anything reachable from |thing|. |kind| should not be
|
||||
* JSTRACE_SHAPE. |thing| should be non-null.
|
||||
*/
|
||||
extern JS_FRIEND_API(void)
|
||||
UnmarkGrayGCThingRecursively(void *thing, JSGCTraceKind kind);
|
||||
|
||||
typedef void
|
||||
(GCThingCallback)(void *closure, void *gcthing);
|
||||
(*GCThingCallback)(void *closure, void *gcthing);
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
VisitGrayWrapperTargets(JSCompartment *comp, GCThingCallback *callback, void *closure);
|
||||
VisitGrayWrapperTargets(JSCompartment *comp, GCThingCallback callback, void *closure);
|
||||
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
GetWeakmapKeyDelegate(JSObject *key);
|
||||
|
||||
JS_FRIEND_API(JSGCTraceKind)
|
||||
GCThingTraceKind(void *thing);
|
||||
|
||||
/*
|
||||
* Invoke cellCallback on every gray JS_OBJECT in the given compartment.
|
||||
*/
|
||||
extern JS_FRIEND_API(void)
|
||||
IterateGrayObjects(JSCompartment *compartment, GCThingCallback cellCallback, void *data);
|
||||
|
||||
/*
|
||||
* Shadow declarations of JS internal structures, for access by inline access
|
||||
* functions below. Do not use these structures in any other way. When adding
|
||||
|
@ -527,7 +556,13 @@ GetNativeStackLimit(const JSRuntime *rt)
|
|||
return RuntimeFriendFields::get(rt)->nativeStackLimit;
|
||||
}
|
||||
|
||||
#define JS_CHECK_RECURSION(cx, onerror) \
|
||||
/*
|
||||
* These macros report a stack overflow and run |onerror| if we are close to
|
||||
* using up the C stack. The JS_CHECK_CHROME_RECURSION variant gives us a little
|
||||
* extra space so that we can ensure that crucial code is able to run.
|
||||
*/
|
||||
|
||||
#define JS_CHECK_RECURSION(cx, onerror) \
|
||||
JS_BEGIN_MACRO \
|
||||
int stackDummy_; \
|
||||
if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(js::GetRuntime(cx)), &stackDummy_)) { \
|
||||
|
@ -536,6 +571,18 @@ GetNativeStackLimit(const JSRuntime *rt)
|
|||
} \
|
||||
JS_END_MACRO
|
||||
|
||||
#define JS_CHECK_CHROME_RECURSION(cx, onerror) \
|
||||
JS_BEGIN_MACRO \
|
||||
int stackDummy_; \
|
||||
if (!JS_CHECK_STACK_SIZE_WITH_TOLERANCE(js::GetNativeStackLimit(js::GetRuntime(cx)), \
|
||||
&stackDummy_, \
|
||||
1024 * sizeof(size_t))) \
|
||||
{ \
|
||||
js_ReportOverRecursed(cx); \
|
||||
onerror; \
|
||||
} \
|
||||
JS_END_MACRO
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
StartPCCountProfiling(JSContext *cx);
|
||||
|
||||
|
@ -979,8 +1026,6 @@ uint32_t GetListBaseExpandoSlot();
|
|||
|
||||
} /* namespace js */
|
||||
|
||||
#endif
|
||||
|
||||
/* Implemented in jsdate.cpp. */
|
||||
|
||||
/*
|
||||
|
@ -1017,8 +1062,6 @@ js_GetSCOffset(JSStructuredCloneWriter* writer);
|
|||
|
||||
/* Typed Array functions, implemented in jstypedarray.cpp */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace js {
|
||||
namespace ArrayBufferView {
|
||||
|
||||
|
@ -1038,6 +1081,12 @@ enum ViewType {
|
|||
*/
|
||||
TYPE_UINT8_CLAMPED,
|
||||
|
||||
/*
|
||||
* Type returned for a DataView. Note that there is no single element type
|
||||
* in this case.
|
||||
*/
|
||||
TYPE_DATAVIEW,
|
||||
|
||||
TYPE_MAX
|
||||
};
|
||||
|
||||
|
@ -1045,9 +1094,6 @@ enum ViewType {
|
|||
} /* namespace js */
|
||||
|
||||
typedef js::ArrayBufferView::ViewType JSArrayBufferViewType;
|
||||
#else
|
||||
typedef uint32_t JSArrayBufferViewType;
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* Create a new typed array with nelements elements.
|
||||
|
@ -1150,41 +1196,40 @@ JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes);
|
|||
* the various accessor JSAPI calls defined below.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsTypedArrayObject(JSObject *obj, JSContext *cx);
|
||||
JS_IsTypedArrayObject(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Check whether obj supports JS_GetArrayBufferView* APIs. Note that this may
|
||||
* return false if a security wrapper is encountered that denies the
|
||||
* unwrapping. If this test or one of the more specific tests succeeds, then it
|
||||
* is safe to call the various ArrayBufferView accessor JSAPI calls defined
|
||||
* below. cx MUST be non-NULL and valid.
|
||||
* below.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsArrayBufferViewObject(JSObject *obj, JSContext *cx);
|
||||
JS_IsArrayBufferViewObject(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Test for specific typed array types (ArrayBufferView subtypes)
|
||||
*/
|
||||
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsInt8Array(JSObject *obj, JSContext *cx);
|
||||
JS_IsInt8Array(JSObject *obj);
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsUint8Array(JSObject *obj, JSContext *cx);
|
||||
JS_IsUint8Array(JSObject *obj);
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsUint8ClampedArray(JSObject *obj, JSContext *cx);
|
||||
JS_IsUint8ClampedArray(JSObject *obj);
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsInt16Array(JSObject *obj, JSContext *cx);
|
||||
JS_IsInt16Array(JSObject *obj);
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsUint16Array(JSObject *obj, JSContext *cx);
|
||||
JS_IsUint16Array(JSObject *obj);
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsInt32Array(JSObject *obj, JSContext *cx);
|
||||
JS_IsInt32Array(JSObject *obj);
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsUint32Array(JSObject *obj, JSContext *cx);
|
||||
JS_IsUint32Array(JSObject *obj);
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsFloat32Array(JSObject *obj, JSContext *cx);
|
||||
JS_IsFloat32Array(JSObject *obj);
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsFloat64Array(JSObject *obj, JSContext *cx);
|
||||
|
||||
JS_IsFloat64Array(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Unwrap Typed arrays all at once. Return NULL without throwing if the object
|
||||
|
@ -1192,38 +1237,37 @@ JS_IsFloat64Array(JSObject *obj, JSContext *cx);
|
|||
* success, filling both outparameters.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsInt8Array(JSContext *cx, JSObject *obj, uint32_t *length, int8_t **data);
|
||||
JS_GetObjectAsInt8Array(JSObject *obj, uint32_t *length, int8_t **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsUint8Array(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data);
|
||||
JS_GetObjectAsUint8Array(JSObject *obj, uint32_t *length, uint8_t **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsUint8ClampedArray(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data);
|
||||
JS_GetObjectAsUint8ClampedArray(JSObject *obj, uint32_t *length, uint8_t **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsInt16Array(JSContext *cx, JSObject *obj, uint32_t *length, int16_t **data);
|
||||
JS_GetObjectAsInt16Array(JSObject *obj, uint32_t *length, int16_t **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsUint16Array(JSContext *cx, JSObject *obj, uint32_t *length, uint16_t **data);
|
||||
JS_GetObjectAsUint16Array(JSObject *obj, uint32_t *length, uint16_t **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsInt32Array(JSContext *cx, JSObject *obj, uint32_t *length, int32_t **data);
|
||||
JS_GetObjectAsInt32Array(JSObject *obj, uint32_t *length, int32_t **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsUint32Array(JSContext *cx, JSObject *obj, uint32_t *length, uint32_t **data);
|
||||
JS_GetObjectAsUint32Array(JSObject *obj, uint32_t *length, uint32_t **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsFloat32Array(JSContext *cx, JSObject *obj, uint32_t *length, float **data);
|
||||
JS_GetObjectAsFloat32Array(JSObject *obj, uint32_t *length, float **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsFloat64Array(JSContext *cx, JSObject *obj, uint32_t *length, double **data);
|
||||
JS_GetObjectAsFloat64Array(JSObject *obj, uint32_t *length, double **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsArrayBufferView(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data);
|
||||
JS_GetObjectAsArrayBufferView(JSObject *obj, uint32_t *length, uint8_t **data);
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetObjectAsArrayBuffer(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data);
|
||||
JS_GetObjectAsArrayBuffer(JSObject *obj, uint32_t *length, uint8_t **data);
|
||||
|
||||
/*
|
||||
* Get the type of elements in a typed array.
|
||||
* Get the type of elements in a typed array, or TYPE_DATAVIEW if a DataView.
|
||||
*
|
||||
* |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
|
||||
* be known that it would pass such a test: it is a typed array or a wrapper of
|
||||
* a typed array, and the unwrapping will succeed. If cx is NULL, then DEBUG
|
||||
* builds may be unable to assert when unwrapping should be disallowed.
|
||||
* |obj| must have passed a JS_IsArrayBufferView/JS_Is*Array test, or somehow
|
||||
* be known that it would pass such a test: it is an ArrayBufferView or a
|
||||
* wrapper of an ArrayBufferView, and the unwrapping will succeed.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSArrayBufferViewType)
|
||||
JS_GetTypedArrayType(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetArrayBufferViewType(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Check whether obj supports the JS_GetArrayBuffer* APIs. Note that this may
|
||||
|
@ -1232,18 +1276,17 @@ JS_GetTypedArrayType(JSObject *obj, JSContext *maybecx);
|
|||
* accessor JSAPI calls defined below.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsArrayBufferObject(JSObject *obj, JSContext *maybecx);
|
||||
JS_IsArrayBufferObject(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return the available byte length of an array buffer.
|
||||
*
|
||||
* |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known
|
||||
* that it would pass such a test: it is an ArrayBuffer or a wrapper of an
|
||||
* ArrayBuffer, and the unwrapping will succeed. If cx is NULL, then DEBUG
|
||||
* builds may be unable to assert when unwrapping should be disallowed.
|
||||
* ArrayBuffer, and the unwrapping will succeed.
|
||||
*/
|
||||
extern JS_FRIEND_API(uint32_t)
|
||||
JS_GetArrayBufferByteLength(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetArrayBufferByteLength(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return a pointer to an array buffer's data. The buffer is still owned by the
|
||||
|
@ -1252,22 +1295,20 @@ JS_GetArrayBufferByteLength(JSObject *obj, JSContext *maybecx);
|
|||
*
|
||||
* |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known
|
||||
* that it would pass such a test: it is an ArrayBuffer or a wrapper of an
|
||||
* ArrayBuffer, and the unwrapping will succeed. If cx is NULL, then DEBUG
|
||||
* builds may be unable to assert when unwrapping should be disallowed.
|
||||
* ArrayBuffer, and the unwrapping will succeed.
|
||||
*/
|
||||
extern JS_FRIEND_API(uint8_t *)
|
||||
JS_GetArrayBufferData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetArrayBufferData(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return the number of elements in a typed array.
|
||||
*
|
||||
* |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
|
||||
* be known that it would pass such a test: it is a typed array or a wrapper of
|
||||
* a typed array, and the unwrapping will succeed. If cx is NULL, then DEBUG
|
||||
* builds may be unable to assert when unwrapping should be disallowed.
|
||||
* a typed array, and the unwrapping will succeed.
|
||||
*/
|
||||
extern JS_FRIEND_API(uint32_t)
|
||||
JS_GetTypedArrayLength(JSObject *obj, JSContext *cx);
|
||||
JS_GetTypedArrayLength(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return the byte offset from the start of an array buffer to the start of a
|
||||
|
@ -1275,22 +1316,20 @@ JS_GetTypedArrayLength(JSObject *obj, JSContext *cx);
|
|||
*
|
||||
* |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
|
||||
* be known that it would pass such a test: it is a typed array or a wrapper of
|
||||
* a typed array, and the unwrapping will succeed. If cx is NULL, then DEBUG
|
||||
* builds may be unable to assert when unwrapping should be disallowed.
|
||||
* a typed array, and the unwrapping will succeed.
|
||||
*/
|
||||
extern JS_FRIEND_API(uint32_t)
|
||||
JS_GetTypedArrayByteOffset(JSObject *obj, JSContext *cx);
|
||||
JS_GetTypedArrayByteOffset(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return the byte length of a typed array.
|
||||
*
|
||||
* |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
|
||||
* be known that it would pass such a test: it is a typed array or a wrapper of
|
||||
* a typed array, and the unwrapping will succeed. If cx is NULL, then DEBUG
|
||||
* builds may be unable to assert when unwrapping should be disallowed.
|
||||
* a typed array, and the unwrapping will succeed.
|
||||
*/
|
||||
extern JS_FRIEND_API(uint32_t)
|
||||
JS_GetTypedArrayByteLength(JSObject *obj, JSContext *cx);
|
||||
JS_GetTypedArrayByteLength(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Check whether obj supports JS_ArrayBufferView* APIs. Note that this may
|
||||
|
@ -1298,13 +1337,13 @@ JS_GetTypedArrayByteLength(JSObject *obj, JSContext *cx);
|
|||
* unwrapping.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsArrayBufferViewObject(JSObject *obj, JSContext *cx);
|
||||
JS_IsArrayBufferViewObject(JSObject *obj);
|
||||
|
||||
/*
|
||||
* More generic name for JS_GetTypedArrayByteLength to cover DataViews as well
|
||||
*/
|
||||
extern JS_FRIEND_API(uint32_t)
|
||||
JS_GetArrayBufferViewByteLength(JSObject *obj, JSContext *cx);
|
||||
JS_GetArrayBufferViewByteLength(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return a pointer to the start of the data referenced by a typed array. The
|
||||
|
@ -1313,43 +1352,48 @@ JS_GetArrayBufferViewByteLength(JSObject *obj, JSContext *cx);
|
|||
*
|
||||
* |obj| must have passed a JS_Is*Array test, or somehow be known that it would
|
||||
* pass such a test: it is a typed array or a wrapper of a typed array, and the
|
||||
* unwrapping will succeed. If cx is NULL, then DEBUG builds may be unable to
|
||||
* assert when unwrapping should be disallowed.
|
||||
* unwrapping will succeed.
|
||||
*/
|
||||
|
||||
extern JS_FRIEND_API(int8_t *)
|
||||
JS_GetInt8ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetInt8ArrayData(JSObject *obj);
|
||||
extern JS_FRIEND_API(uint8_t *)
|
||||
JS_GetUint8ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetUint8ArrayData(JSObject *obj);
|
||||
extern JS_FRIEND_API(uint8_t *)
|
||||
JS_GetUint8ClampedArrayData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetUint8ClampedArrayData(JSObject *obj);
|
||||
extern JS_FRIEND_API(int16_t *)
|
||||
JS_GetInt16ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetInt16ArrayData(JSObject *obj);
|
||||
extern JS_FRIEND_API(uint16_t *)
|
||||
JS_GetUint16ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetUint16ArrayData(JSObject *obj);
|
||||
extern JS_FRIEND_API(int32_t *)
|
||||
JS_GetInt32ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetInt32ArrayData(JSObject *obj);
|
||||
extern JS_FRIEND_API(uint32_t *)
|
||||
JS_GetUint32ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetUint32ArrayData(JSObject *obj);
|
||||
extern JS_FRIEND_API(float *)
|
||||
JS_GetFloat32ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetFloat32ArrayData(JSObject *obj);
|
||||
extern JS_FRIEND_API(double *)
|
||||
JS_GetFloat64ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetFloat64ArrayData(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Same as above, but for any kind of ArrayBufferView. Prefer the type-specific
|
||||
* versions when possible.
|
||||
*/
|
||||
extern JS_FRIEND_API(void *)
|
||||
JS_GetArrayBufferViewData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetArrayBufferViewData(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Check whether obj supports JS_GetDataView* APIs. Note that this may fail and
|
||||
* throw an exception if a security wrapper is encountered that denies the
|
||||
* operation.
|
||||
* Return the ArrayBuffer underlying an ArrayBufferView. If the buffer has been
|
||||
* neutered, this will still return the neutered buffer. |obj| must be an
|
||||
* object that would return true for JS_IsArrayBufferViewObject().
|
||||
*/
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetArrayBufferViewBuffer(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Check whether obj supports JS_GetDataView* APIs.
|
||||
*/
|
||||
JS_FRIEND_API(JSBool)
|
||||
JS_IsDataViewObject(JSContext *cx, JSObject *obj, JSBool *isDataView);
|
||||
JS_IsDataViewObject(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return the byte offset of a data view into its array buffer. |obj| must be a
|
||||
|
@ -1357,11 +1401,10 @@ JS_IsDataViewObject(JSContext *cx, JSObject *obj, JSBool *isDataView);
|
|||
*
|
||||
* |obj| must have passed a JS_IsDataViewObject test, or somehow be known that
|
||||
* it would pass such a test: it is a data view or a wrapper of a data view,
|
||||
* and the unwrapping will succeed. If cx is NULL, then DEBUG builds may be
|
||||
* unable to assert when unwrapping should be disallowed.
|
||||
* and the unwrapping will succeed.
|
||||
*/
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetDataViewByteOffset(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetDataViewByteOffset(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return the byte length of a data view.
|
||||
|
@ -1372,7 +1415,7 @@ JS_GetDataViewByteOffset(JSObject *obj, JSContext *maybecx);
|
|||
* unable to assert when unwrapping should be disallowed.
|
||||
*/
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetDataViewByteLength(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetDataViewByteLength(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return a pointer to the beginning of the data referenced by a DataView.
|
||||
|
@ -1383,9 +1426,8 @@ JS_GetDataViewByteLength(JSObject *obj, JSContext *maybecx);
|
|||
* unable to assert when unwrapping should be disallowed.
|
||||
*/
|
||||
JS_FRIEND_API(void *)
|
||||
JS_GetDataViewData(JSObject *obj, JSContext *maybecx);
|
||||
JS_GetDataViewData(JSObject *obj);
|
||||
|
||||
#ifdef __cplusplus
|
||||
/*
|
||||
* This struct contains metadata passed from the DOM to the JS Engine for JIT
|
||||
* optimizations on DOM property accessors. Eventually, this should be made
|
||||
|
@ -1420,15 +1462,16 @@ FUNCTION_VALUE_TO_JITINFO(const JS::Value& v)
|
|||
return reinterpret_cast<js::shadow::Function *>(&v.toObject())->jitinfo;
|
||||
}
|
||||
|
||||
/* Statically asserted in jsfun.h. */
|
||||
static const unsigned JS_FUNCTION_INTERPRETED_BIT = 0x1;
|
||||
|
||||
static JS_ALWAYS_INLINE void
|
||||
SET_JITINFO(JSFunction * func, const JSJitInfo *info)
|
||||
{
|
||||
js::shadow::Function *fun = reinterpret_cast<js::shadow::Function *>(func);
|
||||
/* JS_ASSERT(func->isNative()). 0x4000 is JSFUN_INTERPRETED */
|
||||
JS_ASSERT(!(fun->flags & 0x4000));
|
||||
JS_ASSERT(!(fun->flags & JS_FUNCTION_INTERPRETED_BIT));
|
||||
fun->jitinfo = info;
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* Engine-internal extensions of jsid. This code is here only until we
|
||||
|
@ -1494,8 +1537,6 @@ JSID_TO_ATOM(jsid id)
|
|||
|
||||
JS_STATIC_ASSERT(sizeof(jsid) == JS_BYTES_PER_WORD);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace js {
|
||||
|
||||
static JS_ALWAYS_INLINE Value
|
||||
|
@ -1517,8 +1558,12 @@ IdToJsval(jsid id)
|
|||
return IdToValue(id);
|
||||
}
|
||||
|
||||
extern JS_FRIEND_API(bool)
|
||||
IsReadOnlyDateMethod(JS::IsAcceptableThis test, JS::NativeImpl method);
|
||||
|
||||
extern JS_FRIEND_API(bool)
|
||||
IsTypedArrayThisCheck(JS::IsAcceptableThis test);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* jsfriendapi_h___ */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -38,25 +38,4 @@ typedef struct PRLock PRLock;
|
|||
|
||||
#endif /* JS_THREADSAFE */
|
||||
|
||||
namespace js {
|
||||
|
||||
class AutoAtomicIncrement
|
||||
{
|
||||
int32_t *p;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
||||
public:
|
||||
AutoAtomicIncrement(int32_t *p JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: p(p) {
|
||||
JS_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
JS_ATOMIC_INCREMENT(p);
|
||||
}
|
||||
|
||||
~AutoAtomicIncrement() {
|
||||
JS_ATOMIC_DECREMENT(p);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jslock_h___ */
|
||||
|
|
|
@ -38,7 +38,7 @@ enum DecodingMode { STRICT, LEGACY };
|
|||
namespace js {
|
||||
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
ParseJSONWithReviver(JSContext *cx, const jschar *chars, size_t length, HandleValue filter,
|
||||
ParseJSONWithReviver(JSContext *cx, JS::StableCharPtr chars, size_t length, HandleValue filter,
|
||||
MutableHandleValue vp, DecodingMode decodingMode = STRICT);
|
||||
|
||||
} /* namespace js */
|
||||
|
|
|
@ -16,10 +16,9 @@
|
|||
** %hd, %hu, %hx, %hX, %ho - 16-bit versions of above
|
||||
** %ld, %lu, %lx, %lX, %lo - 32-bit versions of above
|
||||
** %lld, %llu, %llx, %llX, %llo - 64 bit versions of above
|
||||
** %s - string
|
||||
** %hs - 16-bit version of above (only available if js_CStringsAreUTF8)
|
||||
** %s - ascii string
|
||||
** %hs - ucs2 string
|
||||
** %c - character
|
||||
** %hc - 16-bit version of above (only available if js_CStringsAreUTF8)
|
||||
** %p - pointer (deals with machine dependent pointer size)
|
||||
** %f - float
|
||||
** %g - float
|
||||
|
@ -28,8 +27,6 @@
|
|||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
** sprintf into a fixed size buffer. Guarantees that a NUL is at the end
|
||||
** of the buffer. Returns the length of the written output, NOT including
|
||||
|
@ -77,6 +74,4 @@ extern JS_PUBLIC_API(char*) JS_vsmprintf(const char *fmt, va_list ap);
|
|||
extern JS_PUBLIC_API(char*) JS_vsprintf_append(char *last, const char *fmt, va_list ap);
|
||||
extern JS_PUBLIC_API(uint32_t) JS_vsxprintf(JSStuffFunc f, void *arg, const char *fmt, va_list ap);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* jsprf_h___ */
|
||||
|
|
|
@ -60,5 +60,6 @@
|
|||
macro(Set, 38, js_InitSetClass) \
|
||||
macro(DataView, 39, js_InitTypedArrayClasses) \
|
||||
macro(ParallelArray, 40, js_InitParallelArrayClass) \
|
||||
macro(Intl, 41, js_InitIntlClass) \
|
||||
|
||||
#endif /* jsprototypes_h___ */
|
||||
|
|
|
@ -26,7 +26,9 @@ class JS_FRIEND_API(Wrapper);
|
|||
*
|
||||
* Proxy traps are grouped into fundamental and derived traps. Every proxy has
|
||||
* to at least provide implementations for the fundamental traps, but the
|
||||
* derived traps can be implemented in terms of the fundamental ones.
|
||||
* derived traps can be implemented in terms of the fundamental ones
|
||||
* BaseProxyHandler provides implementations of the derived traps in terms of
|
||||
* the (pure virtual) fundamental traps.
|
||||
*
|
||||
* To minimize code duplication, a set of abstract proxy handler classes is
|
||||
* provided, from which other handlers may inherit. These abstract classes
|
||||
|
@ -34,9 +36,9 @@ class JS_FRIEND_API(Wrapper);
|
|||
*
|
||||
* BaseProxyHandler
|
||||
* |
|
||||
* IndirectProxyHandler
|
||||
* |
|
||||
* DirectProxyHandler
|
||||
* |
|
||||
* Wrapper
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -69,20 +71,6 @@ class JS_FRIEND_API(BaseProxyHandler) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* The function Wrapper::wrapperHandler takes a pointer to a
|
||||
* BaseProxyHandler and returns a pointer to a Wrapper if and only if the
|
||||
* BaseProxyHandler is a wrapper handler (otherwise, it returns NULL).
|
||||
*
|
||||
* Unfortunately, we can't inherit Wrapper from BaseProxyHandler, since that
|
||||
* would create a dreaded diamond, and we can't use dynamic_cast to cast
|
||||
* BaseProxyHandler to Wrapper, since that would require us to compile with
|
||||
* run-time type information. Hence the need for this virtual function.
|
||||
*/
|
||||
virtual Wrapper *toWrapper() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ES5 Harmony fundamental proxy traps. */
|
||||
virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id,
|
||||
bool set, PropertyDescriptor *desc) = 0;
|
||||
|
@ -130,17 +118,14 @@ class JS_FRIEND_API(BaseProxyHandler) {
|
|||
};
|
||||
|
||||
/*
|
||||
* IndirectProxyHandler assumes that a target exists. Moreover, it assumes the
|
||||
* target is a JSObject. Consequently, it provides default implementations for
|
||||
* the fundamental traps that forward their behavior to the target. The derived
|
||||
* traps, however, are inherited from BaseProxyHandler, and therefore still
|
||||
* implemented in terms of the fundamental ones. This allows consumers of this
|
||||
* class to define custom behavior without implementing the entire gamut of
|
||||
* proxy traps.
|
||||
* DirectProxyHandler includes a notion of a target object. All traps are
|
||||
* reimplemented such that they forward their behavior to the target. This
|
||||
* allows consumers of this class to forward to another object as transparently
|
||||
* and efficiently as possible.
|
||||
*/
|
||||
class JS_PUBLIC_API(IndirectProxyHandler) : public BaseProxyHandler {
|
||||
public:
|
||||
explicit IndirectProxyHandler(void *family);
|
||||
class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler {
|
||||
public:
|
||||
explicit DirectProxyHandler(void *family);
|
||||
|
||||
/* ES5 Harmony fundamental proxy traps. */
|
||||
virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id,
|
||||
|
@ -158,11 +143,21 @@ class JS_PUBLIC_API(IndirectProxyHandler) : public BaseProxyHandler {
|
|||
virtual bool enumerate(JSContext *cx, JSObject *proxy,
|
||||
AutoIdVector &props) MOZ_OVERRIDE;
|
||||
|
||||
/* ES5 Harmony derived proxy traps. */
|
||||
virtual bool has(JSContext *cx, JSObject *proxy, jsid id,
|
||||
bool *bp) MOZ_OVERRIDE;
|
||||
virtual bool hasOwn(JSContext *cx, JSObject *proxy, jsid id,
|
||||
bool *bp) MOZ_OVERRIDE;
|
||||
virtual bool get(JSContext *cx, JSObject *proxy, JSObject *receiver,
|
||||
jsid id, Value *vp) MOZ_OVERRIDE;
|
||||
virtual bool set(JSContext *cx, JSObject *proxy, JSObject *receiver,
|
||||
jsid id, bool strict, Value *vp) MOZ_OVERRIDE;
|
||||
virtual bool keys(JSContext *cx, JSObject *proxy,
|
||||
AutoIdVector &props) MOZ_OVERRIDE;
|
||||
virtual bool iterate(JSContext *cx, JSObject *proxy, unsigned flags,
|
||||
Value *vp) MOZ_OVERRIDE;
|
||||
|
||||
/* Spidermonkey extensions. */
|
||||
virtual bool call(JSContext *cx, JSObject *proxy, unsigned argc,
|
||||
Value *vp) MOZ_OVERRIDE;
|
||||
virtual bool construct(JSContext *cx, JSObject *proxy, unsigned argc,
|
||||
Value *argv, Value *rval) MOZ_OVERRIDE;
|
||||
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
|
||||
CallArgs args) MOZ_OVERRIDE;
|
||||
virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
|
||||
|
@ -182,33 +177,6 @@ class JS_PUBLIC_API(IndirectProxyHandler) : public BaseProxyHandler {
|
|||
virtual JSObject *weakmapKeyDelegate(JSObject *proxy);
|
||||
};
|
||||
|
||||
/*
|
||||
* DirectProxyHandler has the same assumptions about the target as its base,
|
||||
* IndirectProxyHandler. Its fundamental traps are inherited from this class,
|
||||
* and therefore forward their behavior to the target. The derived traps,
|
||||
* however, are overrided so that, they too, forward their behavior to the
|
||||
* target. This allows consumers of this class to forward to another object as
|
||||
* transparently as possible.
|
||||
*/
|
||||
class JS_PUBLIC_API(DirectProxyHandler) : public IndirectProxyHandler {
|
||||
public:
|
||||
explicit DirectProxyHandler(void *family);
|
||||
|
||||
/* ES5 Harmony derived proxy traps. */
|
||||
virtual bool has(JSContext *cx, JSObject *proxy, jsid id,
|
||||
bool *bp) MOZ_OVERRIDE;
|
||||
virtual bool hasOwn(JSContext *cx, JSObject *proxy, jsid id,
|
||||
bool *bp) MOZ_OVERRIDE;
|
||||
virtual bool get(JSContext *cx, JSObject *proxy, JSObject *receiver,
|
||||
jsid id, Value *vp) MOZ_OVERRIDE;
|
||||
virtual bool set(JSContext *cx, JSObject *proxy, JSObject *receiver,
|
||||
jsid id, bool strict, Value *vp) MOZ_OVERRIDE;
|
||||
virtual bool keys(JSContext *cx, JSObject *proxy,
|
||||
AutoIdVector &props) MOZ_OVERRIDE;
|
||||
virtual bool iterate(JSContext *cx, JSObject *proxy, unsigned flags,
|
||||
Value *vp) MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
/* Dispatch point for handlers that executes the appropriate C++ or scripted traps. */
|
||||
class Proxy {
|
||||
public:
|
||||
|
@ -350,13 +318,12 @@ NewProxyObject(JSContext *cx, BaseProxyHandler *handler, const Value &priv,
|
|||
JSObject *proto, JSObject *parent,
|
||||
JSObject *call = NULL, JSObject *construct = NULL);
|
||||
|
||||
} /* namespace js */
|
||||
JSObject *
|
||||
RenewProxyObject(JSContext *cx, JSObject *obj, BaseProxyHandler *handler, Value priv);
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
} /* namespace js */
|
||||
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
js_InitProxyClass(JSContext *cx, JSHandleObject obj);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,8 +29,6 @@
|
|||
#include "js/Vector.h"
|
||||
#endif
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
* Convenience constants.
|
||||
*/
|
||||
|
@ -129,7 +127,7 @@ class ScriptFrameIter;
|
|||
|
||||
class Proxy;
|
||||
class JS_FRIEND_API(BaseProxyHandler);
|
||||
class JS_FRIEND_API(DirectWrapper);
|
||||
class JS_FRIEND_API(Wrapper);
|
||||
class JS_FRIEND_API(CrossCompartmentWrapper);
|
||||
|
||||
class TempAllocPolicy;
|
||||
|
@ -379,16 +377,5 @@ typedef JSObject *
|
|||
typedef JSObject *
|
||||
(* JSIteratorOp)(JSContext *cx, JSHandleObject obj, JSBool keysonly);
|
||||
|
||||
/*
|
||||
* The following determines whether JS_EncodeCharacters and JS_DecodeBytes
|
||||
* treat char[] as utf-8 or simply as bytes that need to be inflated/deflated.
|
||||
*/
|
||||
#ifdef JS_C_STRINGS_ARE_UTF8
|
||||
# define js_CStringsAreUTF8 JS_TRUE
|
||||
#else
|
||||
extern JSBool js_CStringsAreUTF8;
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* jsprvtd_h___ */
|
||||
|
|
|
@ -39,6 +39,8 @@ namespace JS { class Value; }
|
|||
*/
|
||||
#ifdef __cplusplus
|
||||
|
||||
#define JS_NO_JSVAL_JSID_STRUCT_TYPES
|
||||
|
||||
# if defined(DEBUG) && !defined(JS_NO_JSVAL_JSID_STRUCT_TYPES)
|
||||
# define JS_USE_JSID_STRUCT_TYPES
|
||||
# endif
|
||||
|
@ -60,8 +62,6 @@ typedef ptrdiff_t jsid;
|
|||
# define JSID_BITS(id) (id)
|
||||
#endif
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
#ifdef WIN32
|
||||
typedef wchar_t jschar;
|
||||
#else
|
||||
|
@ -217,8 +217,6 @@ typedef JSBool JSCallOnceType;
|
|||
#endif
|
||||
typedef JSBool (*JSInitCallback)(void);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace js {
|
||||
|
@ -311,14 +309,6 @@ struct RuntimeFriendFields {
|
|||
/* Limit pointer for checking native stack consumption. */
|
||||
uintptr_t nativeStackLimit;
|
||||
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
/*
|
||||
* Stack allocated GC roots for stack GC heap pointers, which may be
|
||||
* overwritten if moved during a GC.
|
||||
*/
|
||||
Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
|
||||
#endif
|
||||
|
||||
RuntimeFriendFields()
|
||||
: interrupt(0),
|
||||
nativeStackLimit(0) { }
|
||||
|
@ -328,6 +318,32 @@ struct RuntimeFriendFields {
|
|||
}
|
||||
};
|
||||
|
||||
class PerThreadData;
|
||||
|
||||
struct PerThreadDataFriendFields
|
||||
{
|
||||
PerThreadDataFriendFields();
|
||||
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
/*
|
||||
* Stack allocated GC roots for stack GC heap pointers, which may be
|
||||
* overwritten if moved during a GC.
|
||||
*/
|
||||
Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
|
||||
#endif
|
||||
|
||||
static PerThreadDataFriendFields *get(js::PerThreadData *pt) {
|
||||
return reinterpret_cast<PerThreadDataFriendFields *>(pt);
|
||||
}
|
||||
|
||||
static PerThreadDataFriendFields *getMainThread(JSRuntime *rt) {
|
||||
// mainThread must always appear directly after |RuntimeFriendFields|.
|
||||
// Tested by a JS_STATIC_ASSERT in |jsfriendapi.cpp|
|
||||
return reinterpret_cast<PerThreadDataFriendFields *>(
|
||||
reinterpret_cast<char*>(rt) + sizeof(RuntimeFriendFields));
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
|
|
@ -46,11 +46,11 @@
|
|||
**
|
||||
***********************************************************************/
|
||||
|
||||
#define JS_EXTERN_API(type) extern MOZ_EXPORT_API(type)
|
||||
#define JS_EXPORT_API(type) MOZ_EXPORT_API(type)
|
||||
#define JS_EXPORT_DATA(type) MOZ_EXPORT_DATA(type)
|
||||
#define JS_IMPORT_API(type) MOZ_IMPORT_API(type)
|
||||
#define JS_IMPORT_DATA(type) MOZ_IMPORT_DATA(type)
|
||||
#define JS_EXTERN_API(type) extern MOZ_EXPORT type
|
||||
#define JS_EXPORT_API(type) MOZ_EXPORT type
|
||||
#define JS_EXPORT_DATA(type) MOZ_EXPORT type
|
||||
#define JS_IMPORT_API(type) MOZ_IMPORT_API type
|
||||
#define JS_IMPORT_DATA(type) MOZ_IMPORT_DATA type
|
||||
|
||||
/*
|
||||
* The linkage of JS API functions differs depending on whether the file is
|
||||
|
@ -62,11 +62,11 @@
|
|||
# define JS_PUBLIC_API(t) t
|
||||
# define JS_PUBLIC_DATA(t) t
|
||||
#elif defined(EXPORT_JS_API) || defined(STATIC_EXPORTABLE_JS_API)
|
||||
# define JS_PUBLIC_API(t) MOZ_EXPORT_API(t)
|
||||
# define JS_PUBLIC_DATA(t) MOZ_EXPORT_DATA(t)
|
||||
# define JS_PUBLIC_API(t) MOZ_EXPORT t
|
||||
# define JS_PUBLIC_DATA(t) MOZ_EXPORT t
|
||||
#else
|
||||
# define JS_PUBLIC_API(t) MOZ_IMPORT_API(t)
|
||||
# define JS_PUBLIC_DATA(t) MOZ_IMPORT_DATA(t)
|
||||
# define JS_PUBLIC_API(t) MOZ_IMPORT_API t
|
||||
# define JS_PUBLIC_DATA(t) MOZ_IMPORT_DATA t
|
||||
#endif
|
||||
|
||||
#define JS_FRIEND_API(t) JS_PUBLIC_API(t)
|
||||
|
@ -181,8 +181,6 @@
|
|||
#endif
|
||||
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/************************************************************************
|
||||
** TYPES: JSBool
|
||||
** DESCRIPTION:
|
||||
|
@ -282,6 +280,4 @@ typedef int JSBool;
|
|||
# define JS_EXTENSION_(s) s
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* jstypes_h___ */
|
||||
|
|
|
@ -369,23 +369,23 @@ class Compressor
|
|||
z_stream zs;
|
||||
const unsigned char *inp;
|
||||
size_t inplen;
|
||||
size_t outbytes;
|
||||
|
||||
public:
|
||||
Compressor(const unsigned char *inp, size_t inplen, unsigned char *out)
|
||||
: inp(inp),
|
||||
inplen(inplen)
|
||||
{
|
||||
JS_ASSERT(inplen > 0);
|
||||
zs.opaque = NULL;
|
||||
zs.next_in = (Bytef *)inp;
|
||||
zs.avail_in = 0;
|
||||
zs.next_out = out;
|
||||
zs.avail_out = inplen;
|
||||
}
|
||||
enum Status {
|
||||
MOREOUTPUT,
|
||||
DONE,
|
||||
CONTINUE,
|
||||
OOM
|
||||
};
|
||||
|
||||
Compressor(const unsigned char *inp, size_t inplen);
|
||||
~Compressor();
|
||||
bool init();
|
||||
void setOutput(unsigned char *out, size_t outlen);
|
||||
size_t outWritten() const { return outbytes; }
|
||||
/* Compress some of the input. Return true if it should be called again. */
|
||||
bool compressMore();
|
||||
/* Finalize compression. Return the length of the compressed input. */
|
||||
size_t finish();
|
||||
Status compressMore();
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
|
||||
#include "js/Utility.h"
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
* Try to get jsvals 64-bit aligned. We could almost assert that all values are
|
||||
* aligned, but MSVC and GCC occasionally break alignment.
|
||||
|
@ -835,8 +833,6 @@ JS_CANONICALIZE_NAN(double d)
|
|||
return d;
|
||||
}
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#ifdef __cplusplus
|
||||
static jsval_layout JSVAL_TO_IMPL(JS::Value);
|
||||
static JS::Value IMPL_TO_JSVAL(jsval_layout);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue