This commit is contained in:
rogerl%netscape.com 2001-08-06 21:53:33 +00:00
Родитель 151fe68669
Коммит 62c3650311
46 изменённых файлов: 16898 добавлений и 5867 удалений

Просмотреть файл

@ -36,16 +36,14 @@
namespace JavaScript
{
//
// Algorithms
//
// Assign zero to every element between first inclusive and last
// exclusive.
// This is equivalent ot fill(first, last, 0) but may be more efficient.
// Assign zero to every element between first inclusive and last exclusive.
// This is equivalent ot fill(first, last, 0) but may be more efficient.
template<class ForwardIterator>
inline void zero(ForwardIterator first, ForwardIterator last)
inline void zero(ForwardIterator first, ForwardIterator last)
{
while (first != last) {
*first = 0;
@ -53,17 +51,15 @@ namespace JavaScript
}
}
// Same as find(first, last, value) but may be more efficient because
// it doesn't use a reference for value.
template<class InputIterator, class T>
inline InputIterator findValue(InputIterator first, InputIterator last, T value)
{
while (first != last && !(*first == value))
++first;
return first;
}
// Same as find(first, last, value) but may be more efficient because
// it doesn't use a reference for value.
template<class InputIterator, class T>
inline InputIterator findValue(InputIterator first, InputIterator last, T value)
{
while (first != last && !(*first == value))
++first;
return first;
}
}
#endif /* algo_h___ */

2439
js2/src/bytecodegen.cpp Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

396
js2/src/bytecodegen.h Normal file
Просмотреть файл

@ -0,0 +1,396 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#ifndef bytecodegen_h___
#define bytecodegen_h___
#ifdef _WIN32
// Turn off warnings about identifiers too long in browser information
#pragma warning(disable: 4786)
#endif
#include <vector>
#include <map>
#include "systemtypes.h"
#include "strings.h"
#include "tracer.h"
namespace JavaScript {
namespace JS2Runtime {
typedef enum {
// 1st 2 bits specify what kind of 'this' exists
NoThis = 0x00,
Inherent = 0x01,
Explicit = 0x02,
ThisFlags = 0x03,
// bit #3 indicates presence of named arguments
NamedArguments = 0x04,
// but #4 is set for the invocation of the super constructor
// from inside a constructor
SuperInvoke = 0x08
} CallFlag;
typedef enum {
LoadConstantUndefinedOp,// --> <undefined value object>
LoadConstantTrueOp, // --> <true value object>
LoadConstantFalseOp, // --> <false value object>
LoadConstantNullOp, // --> <null value object>
LoadConstantZeroOp, // --> <+0.0 value object>
LoadConstantNumberOp, // <poolindex> --> <Number value object>
LoadConstantStringOp, // <poolindex> --> <String value object>
LoadThisOp, // --> <this object>
LoadFunctionOp, // <pointer> XXX !!! XXX
LoadTypeOp, // <pointer> XXX !!! XXX
InvokeOp, // <argc> <thisflag> <function> <args> --> [<result>]
GetTypeOp, // <object> --> <type of object>
CastOp, // <object> <type> --> <object>
DoUnaryOp, // <operation> <object> --> <result>
DoOperatorOp, // <operation> <object> <object> --> <result>
PushNullOp, // --> <Object(null)>
PushIntOp, // <int> --> <Object(int)>
PushNumOp, // <num> --> <Object(num)>
PushStringOp, // <poolindex> --> <Object(index)>
PushTypeOp, // <poolindex>
ReturnOp, // <function> <args> <result> --> <result>
ReturnVoidOp, // <function> <args> -->
GetConstructorOp, // <type> --> <function>
NewObjectOp, // --> <object>
NewThisOp, // <type> -->
NewInstanceOp, // <argc> <type> <args> --> <object>
DeleteOp, // <index> <object> --> <boolean>
TypeOfOp, // <object> --> <string>
InstanceOfOp, // <object> <object> --> <boolean>
AsOp, // <object> <type> --> <object>
IsOp, // <object> <object> --> <boolean>
ToBooleanOp, // <object> --> <boolean>
JumpFalseOp, // <target> <object> -->
JumpTrueOp, // <target> <object> -->
JumpOp, // <target>
TryOp, // <handler> <handler>
JsrOp, // <target>
RtsOp,
WithinOp, // <object> -->
WithoutOp, //
ThrowOp, // <whatever> <object> --> <object>
HandlerOp,
LogicalXorOp, // <object> <object> <boolean> <boolean> --> <object>
LogicalNotOp, // <object> --> <object>
SwapOp, // <object1> <object2> --> <object2> <object1>
DupOp, // <object> --> <object> <object>
DupInsertOp, // <object1> <object2> --> <object2> <object1> <object2>
DupNOp, // <N> <object> --> <object> { N times }
DupInsertNOp, // <N> <object> {xN} <object2> --> <object2> <object> {xN} <object2>
PopOp, // <object> -->
// for instance members
GetFieldOp, // <slot> <base> --> <object>
SetFieldOp, // <slot> <base> <object> --> <object>
// for instance methods
GetMethodOp, // <slot> <base> --> <base> <function>
GetMethodRefOp, // <slot> <base> --> <bound function>
// for argumentz
GetArgOp, // <index> --> <object>
SetArgOp, // <index> <object> --> <object>
// for local variables in the immediate scope
GetLocalVarOp, // <index> --> <object>
SetLocalVarOp, // <index> <object> --> <object>
// for local variables in the nth closure scope
GetClosureVarOp, // <depth>, <index> --> <object>
SetClosureVarOp, // <depth>, <index> <object> --> <object>
// for array elements
GetElementOp, // <base> <index> --> <object>
SetElementOp, // <base> <index> <object> --> <object>
// for properties
GetPropertyOp, // <poolindex> <base> --> <object>
GetInvokePropertyOp, // <poolindex> <base> --> <base> <object>
SetPropertyOp, // <poolindex> <base> <object> --> <object>
// for all generic names
GetNameOp, // <poolindex> --> <object>
GetTypeOfNameOp, // <poolindex> --> <object>
SetNameOp, // <poolindex> <object> --> <object>
LoadGlobalObjectOp, // --> <object>
PushScopeOp, // <pointer> XXX !!! XXX
PopScopeOp, // <pointer> XXX !!! XXX
NewClosureOp, // <function> --> <function>
ClassOp, // <object> --> <type>
JuxtaposeOp, // <attribute> <attribute> --> <attribute>
NamedArgOp, // <object> <string> --> <named arg object>
OpCodeCount
} ByteCodeOp;
struct ByteCodeData {
int8 stackImpact;
char *opName;
};
extern ByteCodeData gByteCodeData[OpCodeCount];
typedef std::pair<uint32, size_t> PC_Position;
class ByteCodeModule {
public:
ByteCodeModule(ByteCodeGen *bcg);
#ifdef DEBUG
void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("ByteCodeModule", s, t); return t; }
void operator delete(void* t) { trace_release("ByteCodeModule", t); STD::free(t); }
#endif
uint32 getLong(uint32 index) const { return *((uint32 *)&mCodeBase[index]); }
uint16 getShort(uint32 index) const { return *((uint16 *)&mCodeBase[index]); }
int32 getOffset(uint32 index) const { return *((int32 *)&mCodeBase[index]); }
const String *getString(uint32 index) const { return &mStringPoolContents[index]; }
float64 getNumber(uint32 index) const { return mNumberPoolContents[index]; }
void setSource(const String &source, const String &sourceLocation)
{
mSource = source;
mSourceLocation = sourceLocation;
}
String mSource;
String mSourceLocation;
uint32 mLocalsCount; // number of local vars to allocate space for
uint32 mStackDepth; // max. depth of execution stack
uint8 *mCodeBase;
uint32 mLength;
String *mStringPoolContents;
float64 *mNumberPoolContents;
PC_Position *mCodeMap;
uint32 mCodeMapLength;
size_t getPositionForPC(uint32 pc);
};
Formatter& operator<<(Formatter& f, const ByteCodeModule& bcm);
#define BufferIncrement (32)
#define NotALabel ((uint32)(-1))
class Label {
public:
typedef enum { InternalLabel, NamedLabel, BreakLabel, ContinueLabel } LabelKind;
Label() : mKind(InternalLabel), mHasLocation(false) { }
Label(LabelStmtNode *lbl) : mKind(NamedLabel), mHasLocation(false), mLabelStmt(lbl) { }
Label(LabelKind kind) : mKind(kind), mHasLocation(false) { }
bool matches(const StringAtom *name)
{
return ((mKind == NamedLabel) && (mLabelStmt->name.compare(*name) == 0));
}
bool matches(LabelKind kind)
{
return (mKind == kind);
}
void addFixup(ByteCodeGen *bcg, uint32 branchLocation);
void setLocation(ByteCodeGen *bcg, uint32 location);
std::vector<uint32> mFixupList;
LabelKind mKind;
bool mHasLocation;
LabelStmtNode *mLabelStmt;
uint32 mLocation;
};
class ByteCodeGen {
public:
ByteCodeGen(Context *cx, ScopeChain *scopeChain)
: mBuffer(new CodeBuffer),
mScopeChain(scopeChain),
mPC_Map(new CodeMap),
m_cx(cx),
mNamespaceList(NULL) ,
mStackTop(0),
mStackMax(0)
{ }
#ifdef DEBUG
void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("ByteCodeGen", s, t); return t; }
void operator delete(void* t) { trace_release("ByteCodeGen", t); STD::free(t); }
#endif
ByteCodeModule *genCodeForScript(StmtNode *p);
bool genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint32 finallyLabel);
void genCodeForFunction(FunctionDefinition &f,
size_t pos,
JSFunction *fnc,
bool isConstructor,
JSType *topClass);
ByteCodeModule *genCodeForExpression(ExprNode *p);
JSType *genExpr(ExprNode *p);
Reference *genReference(ExprNode *p, Access acc);
void genReferencePair(ExprNode *p, Reference *&readRef, Reference *&writeRef);
typedef std::vector<uint8> CodeBuffer;
typedef std::vector<PC_Position> CodeMap;
// this is the current code buffer
CodeBuffer *mBuffer;
ScopeChain *mScopeChain;
CodeMap *mPC_Map;
Context *m_cx;
std::vector<Label> mLabelList;
std::vector<uint32> mLabelStack;
NamespaceList *mNamespaceList;
int32 mStackTop; // keep these as signed so as to
int32 mStackMax; // track if they go negative.
bool hasContent()
{
return (mBuffer->size() > 0);
}
void addOp(uint8 op); // XXX move more outline if it helps to reduce overall .exe size
void addPosition(size_t pos) { mPC_Map->push_back(PC_Position(mBuffer->size(), pos)); }
// Add in the opcode effect as usual, but also stretch the
// execution stack by N, as the opcode has that effect during
// execution.
void addOpStretchStack(uint8 op, int32 n)
{
addByte(op);
mStackTop += gByteCodeData[op].stackImpact;
if ((mStackTop + n) > mStackMax)
mStackMax = mStackTop + n;
ASSERT(mStackTop >= 0);
}
void adjustStack(int32 n)
{
mStackTop += n;
if ((mStackTop + n) > mStackMax)
mStackMax = mStackTop + n;
ASSERT(mStackTop >= 0);
}
// Make sure there's room for n more operands on the stack
void stretchStack(int32 n)
{
if ((mStackTop + n) > mStackMax)
mStackMax = mStackTop + n;
}
// these routines assume the depth is being reduced
// i.e. they don't reset mStackMax
void addOpAdjustDepth(uint8 op, int32 depth)
{ addByte(op); mStackTop += depth; ASSERT(mStackTop >= 0); }
void addOpSetDepth(uint8 op, int32 depth)
{ addByte(op); mStackTop = depth; ASSERT(mStackTop >= 0); }
void addByte(uint8 v) { mBuffer->push_back(v); }
void addShort(uint16 v) { mBuffer->push_back((uint8)(v >> 8)); mBuffer->push_back((uint8)(v)); }
void addPointer(void *v) { ASSERT(sizeof(void *) == sizeof(uint32)); addLong((uint32)(v)); } // XXX Pointer size dependant !!!
void addLong(uint32 v)
{ mBuffer->insert(mBuffer->end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(uint32)); }
void addOffset(int32 v)
{ mBuffer->insert(mBuffer->end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(int32)); }
void setOffset(uint32 index, int32 v)
{ *((int32 *)(mBuffer->begin() + index)) = v; } // XXX
void addFixup(uint32 label)
{
mLabelList[label].addFixup(this, mBuffer->size());
}
uint32 getLabel();
uint32 getLabel(Label::LabelKind kind);
uint32 getLabel(LabelStmtNode *lbl);
uint32 getTopLabel(Label::LabelKind kind, const StringAtom *name);
uint32 getTopLabel(Label::LabelKind kind);
void setLabel(uint32 label)
{
mLabelList[label].setLocation(this, mBuffer->size());
}
uint32 currentOffset()
{
return mBuffer->size();
}
std::vector<String> mStringPoolContents;
typedef std::map<String, uint32, std::less<String> > StringPool;
StringPool mStringPool;
std::vector<float64> mNumberPoolContents;
typedef std::map<float64, uint32, std::less<double> > NumberPool;
NumberPool mNumberPool;
void addNumberRef(float64 f);
void addStringRef(const String &str);
};
uint32 printInstruction(Formatter &f, uint32 i, const ByteCodeModule& bcm);
}
}
#endif /* bytecodegen_h___ */

240
js2/src/collector.cpp Normal file
Просмотреть файл

@ -0,0 +1,240 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s): Patrick Beard <beard@netscape.com>
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#include "collector.h"
namespace JavaScript
{
Collector::Collector()
: mObjectSpace(kObjectSpaceSize),
mFloatSpace(kFloatSpaceSize)
{
}
Collector::~Collector()
{
}
void
Collector::addRoot(void* root, size_type n)
{
mRoots.push_back(RootSegment(pointer(root), n));
}
void
Collector::removeRoot(void* root)
{
for (RootSegments::iterator i = mRoots.begin(), e = mRoots.end(); i != e; ++i) {
if (i->first == root) {
mRoots.erase(i);
return;
}
}
}
inline Collector::size_type align(Collector::size_type n)
{
return (n + (kObjectAlignment - 1)) & kObjectAddressMask;
}
Collector::pointer
Collector::allocateObject(size_type n, pointer type)
{
size_type size = align(n + sizeof(ObjectHeader));
pointer ptr = mObjectSpace.mAllocPtr;
if ((ptr + size) <= mObjectSpace.mLimitPtr) {
mObjectSpace.mAllocPtr += size;
ObjectHeader* header = (ObjectHeader*) ptr;
header->mSize = size;
header->mType = type;
return (pointer) std::memset(ptr + sizeof(ObjectHeader), 0, n);
}
// need to run a garbage collection to recover more space, or double space size?
return 0;
}
float64*
Collector::allocateFloat64(float64 value)
{
float64* fptr = mFloatSpace.mAllocPtr;
if (fptr < mFloatSpace.mLimitPtr) {
mFloatSpace.mAllocPtr++;
*fptr = value;
return (float64*) (uint32(fptr) | kFloat64Tag);
}
// need to run a garbage collection to recover more space, or double space size?
return 0;
}
inline bool is_object(Collector::pointer ref)
{
return ((uint32(ref) & kObjectAddressMask) == uint32(ref));
}
inline bool is_float64(Collector::pointer ref)
{
return ((uint32(ref) & kFloat64TagMask) == kFloat64Tag);
}
void
Collector::collect()
{
// 0. swap from/to space. we now start allocating in the new toSpace.
Space<char>::pointer_type scanPtr = mObjectSpace.Swap();
mFloatSpace.Swap();
// 1. scan all registered root segments.
for (RootSegments::iterator i = mRoots.begin(), e = mRoots.end(); i != e; ++i) {
RootSegment& r = *i;
pointer* refs = (pointer*) r.first;
pointer* limit = (pointer*) (r.first + r.second);
while (refs < limit) {
pointer& ref = *refs++;
if (ref) {
if (is_object(ref))
ref = copy(ref);
else
if (is_float64(ref))
ref = copyFloat64(ref);
}
}
}
// 2. Scan through toSpace until scanPtr meets mAllocPtr.
while (scanPtr < mObjectSpace.mAllocPtr) {
ObjectHeader* header = (ObjectHeader*) scanPtr;
if (header->mType)
header->mType = copy(header->mType);
scanPtr += header->mSize;
pointer* refs = (pointer*) (header + 1);
pointer* limit = (pointer*) scanPtr;
while (refs < limit) {
pointer& ref = *refs++;
if (ref) {
if (is_object(ref))
ref = copy(ref);
else
if (is_float64(ref))
ref = copyFloat64(ref);
}
}
}
}
Collector::pointer
Collector::copy(pointer object)
{
// forwarding pointer?
ObjectHeader* oldHeader = ((ObjectHeader*)object) - 1;
if (oldHeader->mSize == kIsForwardingPointer)
return oldHeader->mType;
// copy the old object into toSpace. copy will always succeed,
// because we only call it from within collect. the problem
// is when we don't recover any space... will have to be able
// to expand the heaps.
size_type n = oldHeader->mSize;
ObjectHeader* newHeader = (ObjectHeader*) mObjectSpace.mAllocPtr;
mObjectSpace.mAllocPtr += n;
std::memcpy(newHeader, oldHeader, n);
oldHeader->mSize = kIsForwardingPointer;
oldHeader->mType = (pointer) (newHeader + 1);
return (pointer) (newHeader + 1);
}
Collector::pointer
Collector::copyFloat64(pointer object)
{
float64* fptr = mFloatSpace.mAllocPtr++;
*fptr = *(float64*) (uint32(object) & kFloat64AddressMask);
return (pointer) (uint32(fptr) | kFloat64Tag);
}
#if DEBUG
struct ConsCell {
float64* car;
ConsCell* cdr;
void* operator new(std::size_t n, Collector& gc)
{
return gc.allocateObject(n);
}
};
void testCollector()
{
Collector gc;
ConsCell* head = 0;
gc.addRoot(&head, sizeof(ConsCell*));
const uint32 kCellCount = 100;
ConsCell* cell;
ConsCell** link = &head;
for (uint32 i = 0; i < kCellCount; ++i) {
*link = cell = new (gc) ConsCell;
ASSERT(cell);
cell->car = gc.allocateFloat64(i);
ASSERT(cell->car);
link = &cell->cdr;
}
// circularly link the list.
*link = head;
// run a garbage collection.
gc.collect();
// walk the list again to verify that it is intact.
link = &head;
for (uint32 i = 0; i < kCellCount; i++) {
cell = *link;
ASSERT(cell->car);
float64 value = gc.getFloat64(cell->car);
ASSERT(value == (float64)i);
link = &cell->cdr;
}
// make sure list is still circularly linked.
ASSERT(*link == head);
}
#endif // DEBUG
}

156
js2/src/collector.h Normal file
Просмотреть файл

@ -0,0 +1,156 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s): Patrick Beard <beard@netscape.com>
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#ifndef collector_h___
#define collector_h___
#include "mem.h"
#include <deque>
#include <utility>
namespace JavaScript
{
using std::deque;
using std::pair;
// tuneable parameters of the collector.
enum {
kLogObjectAlignment = 3,
kObjectAlignment = (1 << kLogObjectAlignment),
kObjectAddressMask = (-1 << kLogObjectAlignment),
kFloat64Tag = 0x2,
kFloat64TagMask = ~(-1 << 2),
kFloat64AddressMask = (-1 << 2),
kIsForwardingPointer = 0x1,
kObjectSpaceSize = 1024 * 1024,
kFloatSpaceSize = kObjectSpaceSize / sizeof(float64)
};
// collector entry points.
class Collector {
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef char *pointer;
typedef const char *const_pointer;
struct ObjectHeader {
size_type mSize;
pointer mType;
};
Collector();
~Collector();
void addRoot(void* root, size_type n);
void removeRoot(void* root);
pointer allocateObject(size_type n, pointer type = 0);
float64* allocateFloat64(float64 value = 0.0);
void collect();
pointer getType(pointer object)
{
return ((ObjectHeader*)object)[-1].mType;
}
size_type getSize(pointer object)
{
return ((ObjectHeader*)object)[-1].mSize;
}
float64 getFloat64(float64* fptr)
{
return *(float64*)(uint32(fptr) & kFloat64AddressMask);
}
private:
template <typename T> struct Space {
typedef T value_type;
typedef T *pointer_type;
size_type mSize;
pointer_type mFromPtr;
pointer_type mToPtr;
pointer_type mAllocPtr;
pointer_type mLimitPtr;
Space(size_type n)
: mSize(n), mFromPtr(0), mToPtr(0),
mAllocPtr(0), mLimitPtr(0)
{
mFromPtr = new value_type[n];
mToPtr = new value_type[n];
mAllocPtr = mToPtr;
mLimitPtr = mToPtr + n;
}
~Space()
{
delete[] mFromPtr;
delete[] mToPtr;
}
pointer_type Swap()
{
pointer_type newToPtr = mFromPtr;
pointer_type newFromPtr = mToPtr;
mToPtr = newToPtr;
mAllocPtr = newToPtr;
mLimitPtr = newToPtr + mSize;
mFromPtr = newFromPtr;
pointer_type scanPtr = newToPtr;
return scanPtr;
}
};
Space<char> mObjectSpace;
Space<float64> mFloatSpace;
typedef pair<pointer, size_type> RootSegment;
typedef deque<RootSegment> RootSegments;
RootSegments mRoots;
pointer copy(pointer object);
pointer copyFloat64(pointer object);
Collector(const Collector&); // No copy constructor
void operator=(const Collector&); // No assignment operator
};
void testCollector();
}
#endif // collector_h___

Просмотреть файл

@ -6,7 +6,7 @@
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
@ -41,16 +41,34 @@
namespace JavaScript
{
//
// Save-Restore Pattern
//
// Use the definition
// SaveRestore<T> temp(var)
// to save the current value of var at the time of the definition into a temporary temp
// and restore var to the saved value at the end of temp's scope, regardless of whether
// temp goes out of scope due to normal execution or due to a thrown exception.
template<typename T> class SaveRestore {
const T savedValue;
T &var;
public:
SaveRestore(T &t): savedValue(t), var(t) {}
~SaveRestore() {var = savedValue;}
};
//
// Doubly Linked Lists
//
// A ListQueue provides insert and delete operations on a doubly-linked list of
// objects threaded through fields named 'next' and 'prev'. The type parameter
// E must be a class derived from ListQueueEntry.
// The ListQueue does not own its elements. They must be deleted explicitly if
// needed.
// A ListQueue provides insert and delete operations on a doubly-linked list of
// objects threaded through fields named 'next' and 'prev'. The type parameter
// E must be a class derived from ListQueueEntry.
// The ListQueue does not own its elements. They must be deleted explicitly if
// needed.
struct ListQueueEntry {
ListQueueEntry *next; // Next entry in linked list
ListQueueEntry *prev; // Previous entry in linked list
@ -65,23 +83,14 @@ namespace JavaScript
ListQueue() {next = this; prev = this;}
operator bool() const {
// Return true if the ListQueue is nonempty
return next != static_cast<const ListQueueEntry *>(this);
}
// Return true if the ListQueue is nonempty.
operator bool() const {return next != static_cast<const ListQueueEntry *>(this);}
bool operator !() const {
// Return true if the ListQueue is empty
return next == static_cast<const ListQueueEntry *>(this);
}
// Return true if the ListQueue is empty.
bool operator !() const {return next == static_cast<const ListQueueEntry *>(this);}
E &front() const {
ASSERT(operator bool()); return *static_cast<E *>(next);
}
E &back() const {
ASSERT(operator bool()); return *static_cast<E *>(prev);
}
E &front() const {ASSERT(operator bool()); return *static_cast<E *>(next);}
E &back() const {ASSERT(operator bool()); return *static_cast<E *>(prev);}
void push_front(E &elt) {
ASSERT(!elt.next && !elt.prev);
@ -107,18 +116,18 @@ namespace JavaScript
}
};
//
// Growable Arrays
//
// A Buffer initially points to inline storage of initialSize elements of type T.
// The Buffer can be expanded via the expand method to increase its size by
// allocating storage from the heap.
// A Buffer initially points to inline storage of initialSize elements of type T.
// The Buffer can be expanded via the expand method to increase its size by
// allocating storage from the heap.
template <typename T, size_t initialSize> class Buffer {
public:
T *buffer; // Pointer to the current buffer
size_t size; // Current size of the buffer
T *buffer; // Pointer to the current buffer
size_t size; // Current size of the buffer
private:
T initialBuffer[initialSize]; // Initial buffer
public:
@ -128,16 +137,15 @@ namespace JavaScript
void expand(size_t newSize);
};
// Expand the buffer to size newSize, which must be greater than the current
// size. The buffer's contents are not preserved.
// Expand the buffer to size newSize, which must be greater than the current
// size. The buffer's contents are not preserved.
template <typename T, size_t initialSize>
inline void Buffer<T, initialSize>::expand(size_t newSize) {
inline void Buffer<T, initialSize>::expand(size_t newSize) {
ASSERT(newSize > size);
if (buffer != initialBuffer) {
delete[] buffer;
buffer = 0; // For exception safety if the allocation below
// fails.
buffer = 0; // For exception safety if the allocation below fails.
}
buffer = new T[newSize];
size = newSize;
@ -146,14 +154,13 @@ namespace JavaScript
// See ArrayBuffer below.
template <typename T> class RawArrayBuffer {
T *const cache; // Pointer to a fixed-size cache for holding the buffer
// if it's small enough
T *const cache; // Pointer to a fixed-size cache for holding the buffer if it's small enough
protected:
T *buffer; // Pointer to the current buffer
size_t length; // Logical size of the buffer
size_t bufferSize; // Physical size of the buffer
T *buffer; // Pointer to the current buffer
size_t length; // Logical size of the buffer
size_t bufferSize; // Physical size of the buffer
#ifdef DEBUG
size_t maxReservedSize; // Maximum size reserved so far
size_t maxReservedSize; // Maximum size reserved so far
#endif
public:
@ -189,19 +196,16 @@ namespace JavaScript
void fast_push_back(const T &elt);
void push_back(const T &elt);
void append(const T *elts, size_t nElts);
void append(const T *begin, const T *end) {
ASSERT(end >= begin);
append(begin, static_cast<size_t>(end - begin));
}
void append(const T *begin, const T *end) {ASSERT(end >= begin); append(begin, toSize_t(end - begin));}
T &pop_back() {ASSERT(length); return buffer[--length];}
};
// Enlarge the buffer so that it can hold at least newLength elements.
// May throw an exception, in which case the buffer is left unchanged.
// Enlarge the buffer so that it can hold at least newLength elements.
// May throw an exception, in which case the buffer is left unchanged.
template <typename T>
void RawArrayBuffer<T>::enlarge(size_t newLength) {
void RawArrayBuffer<T>::enlarge(size_t newLength) {
size_t newBufferSize = bufferSize * 2;
if (newBufferSize < newLength)
newBufferSize = newLength;
@ -215,11 +219,11 @@ namespace JavaScript
bufferSize = newBufferSize;
}
// Ensure that there is room to hold nElts elements in the buffer, without
// expanding the buffer's logical length.
// May throw an exception, in which case the buffer is left unchanged.
// Ensure that there is room to hold nElts elements in the buffer, without
// expanding the buffer's logical length.
// May throw an exception, in which case the buffer is left unchanged.
template <typename T>
inline void RawArrayBuffer<T>::reserve(size_t nElts) {
inline void RawArrayBuffer<T>::reserve(size_t nElts) {
if (bufferSize < nElts)
enlarge(nElts);
#ifdef DEBUG
@ -228,58 +232,58 @@ namespace JavaScript
#endif
}
// Ensure that there is room to hold nElts more elements in the buffer, without
// expanding the buffer's logical length. Return a pointer to the first element
// just past the logical length.
// May throw an exception, in which case the buffer is left unchanged.
// Ensure that there is room to hold nElts more elements in the buffer, without
// expanding the buffer's logical length. Return a pointer to the first element
// just past the logical length.
// May throw an exception, in which case the buffer is left unchanged.
template <typename T>
inline T *RawArrayBuffer<T>::reserve_back(size_t nElts) {
inline T *RawArrayBuffer<T>::reserve_back(size_t nElts) {
reserve(length + nElts);
return buffer[length];
}
// Advance the logical length by nElts, assuming that the memory has previously
// been reserved.
// Return a pointer to the first new element.
// Advance the logical length by nElts, assuming that the memory has previously
// been reserved.
// Return a pointer to the first new element.
template <typename T>
inline T *RawArrayBuffer<T>::advance_back(size_t nElts) {
inline T *RawArrayBuffer<T>::advance_back(size_t nElts) {
ASSERT(length + nElts <= maxReservedSize);
T *p = buffer + length;
length += nElts;
return p;
}
// Combine the effects of reserve_back and advance_back.
// Combine the effects of reserve_back and advance_back.
template <typename T>
inline T *RawArrayBuffer<T>::reserve_advance_back(size_t nElts) {
inline T *RawArrayBuffer<T>::reserve_advance_back(size_t nElts) {
reserve(length + nElts);
T *p = buffer + length;
length += nElts;
return p;
}
// Same as push_back but assumes that the memory has previously been reserved.
// May throw an exception if copying elt throws one, in which case the buffer is
// left unchanged.
// Same as push_back but assumes that the memory has previously been reserved.
// May throw an exception if copying elt throws one, in which case the buffer is
// left unchanged.
template <typename T>
inline void RawArrayBuffer<T>::fast_push_back(const T &elt) {
inline void RawArrayBuffer<T>::fast_push_back(const T &elt) {
ASSERT(length < maxReservedSize);
buffer[length] = elt;
++length;
}
// Append elt to the back of the buffer.
// May throw an exception, in which case the buffer is left unchanged.
// Append elt to the back of the buffer.
// May throw an exception, in which case the buffer is left unchanged.
template <typename T>
inline void RawArrayBuffer<T>::push_back(const T &elt) {
inline void RawArrayBuffer<T>::push_back(const T &elt) {
*reserve_back() = elt;
++length;
}
// Append nElts elements elts to the back of the array buffer.
// May throw an exception, in which case the buffer is left unchanged.
// Append nElts elements elts to the back of the array buffer.
// May throw an exception, in which case the buffer is left unchanged.
template <typename T>
void RawArrayBuffer<T>::append(const T *elts, size_t nElts) {
void RawArrayBuffer<T>::append(const T *elts, size_t nElts) {
size_t newLength = length + nElts;
if (newLength > bufferSize)
enlarge(newLength);
@ -288,24 +292,25 @@ namespace JavaScript
}
// An ArrayBuffer represents an array of elements of type T. The ArrayBuffer
// contains storage for a fixed size array of cacheSize elements; if this size
// is exceeded, the ArrayBuffer allocates the array from the heap. Elements can
// be appended to the back of the array using append. An ArrayBuffer can also
// act as a stack: elements can be pushed and popped from the back.
//
// All ArrayBuffer operations are atomic with respect to exceptions -- either
// they succeed or they do not affect the ArrayBuffer's existing elements and
// length. If T has a constructor, it must have a constructor with no arguments;
// that constructor is called at the time memory for the ArrayBuffer is
// allocated, just like when allocating a regular C++ array.
// An ArrayBuffer represents an array of elements of type T. The ArrayBuffer
// contains storage for a fixed size array of cacheSize elements; if this size
// is exceeded, the ArrayBuffer allocates the array from the heap. Elements can
// be appended to the back of the array using append. An ArrayBuffer can also
// act as a stack: elements can be pushed and popped from the back.
//
// All ArrayBuffer operations are atomic with respect to exceptions -- either
// they succeed or they do not affect the ArrayBuffer's existing elements and
// length. If T has a constructor, it must have a constructor with no arguments;
// that constructor is called at the time memory for the ArrayBuffer is
// allocated, just like when allocating a regular C++ array.
template <typename T, size_t cacheSize>
class ArrayBuffer: public RawArrayBuffer<T> {
class ArrayBuffer: public RawArrayBuffer<T> {
T cacheArray[cacheSize];
public:
ArrayBuffer(): RawArrayBuffer<T>(cacheArray, cacheSize) {}
};
//
// Bit Sets
//
@ -313,13 +318,13 @@ namespace JavaScript
template<size_t size> class BitSet {
STATIC_CONST(size_t, nWords = (size+31)>>5);
STATIC_CONST(uint32, lastWordMask = (2u<<((size-1)&31)) - 1);
// Bitmap of bits. The first word contains bits 0(LSB)...31(MSB),
// the second contains bits 32...63, etc.
uint32 words[nWords];
uint32 words[nWords]; // Bitmap; the first word contains bits 0(LSB)...31(MSB), the second contains bits 32...63, etc.
public:
void clear() {zero(words, words+nWords);}
BitSet() {clear();}
// Construct a BitSet out of an array of alternating low (inclusive)
// and high (exclusive) ends of ranges of set bits.
// The array is terminated by a 0,0 range.
@ -329,10 +334,7 @@ namespace JavaScript
while (low = *a++, (high = *a++) != 0) setRange(low, high);
}
bool operator[](size_t i) const {
ASSERT(i < size);
return static_cast<bool>(words[i>>5]>>(i&31) & 1);
}
bool operator[](size_t i) const {ASSERT(i < size); return static_cast<bool>(words[i>>5]>>(i&31) & 1);}
bool none() const;
bool operator==(const BitSet &s) const;
bool operator!=(const BitSet &s) const;
@ -344,10 +346,11 @@ namespace JavaScript
void resetRange(size_t low, size_t high);
void flipRange(size_t low, size_t high);
};
// Return true if all bits are clear.
// Return true if all bits are clear.
template<size_t size>
inline bool BitSet<size>::none() const {
inline bool BitSet<size>::none() const {
if (nWords == 1)
return !words[0];
else {
@ -358,25 +361,25 @@ namespace JavaScript
return true;
}
}
// Return true if the BitSets are equal.
// Return true if the BitSets are equal.
template<size_t size>
inline bool BitSet<size>::operator==(const BitSet &s) const {
inline bool BitSet<size>::operator==(const BitSet &s) const {
if (nWords == 1)
return words[0] == s.words[0];
else
return std::equal(words, s.words);
}
// Return true if the BitSets are not equal.
// Return true if the BitSets are not equal.
template<size_t size>
inline bool BitSet<size>::operator!=(const BitSet &s) const {
inline bool BitSet<size>::operator!=(const BitSet &s) const {
return !operator==(s);
}
// Set all bits between low inclusive and high exclusive.
// Set all bits between low inclusive and high exclusive.
template<size_t size>
void BitSet<size>::setRange(size_t low, size_t high) {
void BitSet<size>::setRange(size_t low, size_t high) {
ASSERT(low <= high && high <= size);
if (low != high)
if (nWords == 1)
@ -397,10 +400,10 @@ namespace JavaScript
}
}
}
// Clear all bits between low inclusive and high exclusive.
template<size_t size>
void BitSet<size>::resetRange(size_t low, size_t high) {
void BitSet<size>::resetRange(size_t low, size_t high) {
ASSERT(low <= high && high <= size);
if (low != high)
if (nWords == 1)
@ -421,10 +424,10 @@ namespace JavaScript
}
}
}
// Invert all bits between low inclusive and high exclusive.
template<size_t size>
void BitSet<size>::flipRange(size_t low, size_t high) {
void BitSet<size>::flipRange(size_t low, size_t high) {
ASSERT(low <= high && high <= size);
if (low != high)
if (nWords == 1)
@ -445,35 +448,31 @@ namespace JavaScript
}
}
}
//
// Array Queues
//
// See ArrayQueue below.
template <typename T> class RawArrayQueue {
T *const cache; // Pointer to a fixed-size cache for holding the buffer
// if it's small enough
T *const cache; // Pointer to a fixed-size cache for holding the buffer if it's small enough
protected:
T *buffer; // Pointer to the current buffer
T *bufferEnd; // Pointer to the end of the buffer
T *f; // Front end of the circular buffer, used for reading
// elements; buffer <= f < bufferEnd
T *b; // Back end of the circular buffer, used for writing
// elements; buffer < b <= bufferEnd
size_t length; // Number of elements used in the circular buffer
size_t bufferSize; // Physical size of the buffer
T *buffer; // Pointer to the current buffer
T *bufferEnd; // Pointer to the end of the buffer
T *f; // Front end of the circular buffer, used for reading elements; buffer <= f < bufferEnd
T *b; // Back end of the circular buffer, used for writing elements; buffer < b <= bufferEnd
size_t length; // Number of elements used in the circular buffer
size_t bufferSize; // Physical size of the buffer
#ifdef DEBUG
size_t maxReservedSize; // Maximum size reserved so far
size_t maxReservedSize; // Maximum size reserved so far
#endif
public:
RawArrayQueue(T *cache, size_t cacheSize) :
cache(cache), buffer(cache), bufferEnd(cache + cacheSize),
f(cache), b(cache), length(0), bufferSize(cacheSize) {
DEBUG_ONLY(maxReservedSize = 0);
}
RawArrayQueue(T *cache, size_t cacheSize):
cache(cache), buffer(cache), bufferEnd(cache + cacheSize),
f(cache), b(cache), length(0), bufferSize(cacheSize)
{DEBUG_ONLY(maxReservedSize = 0);}
private:
RawArrayQueue(const RawArrayQueue&); // No copy constructor
void operator=(const RawArrayQueue&); // No assignment operator
@ -496,7 +495,8 @@ namespace JavaScript
T &pop_front() {
ASSERT(length);
--length; T &elt = *f++;
--length;
T &elt = *f++;
if (f == bufferEnd)
f = buffer;
return elt;
@ -524,8 +524,8 @@ namespace JavaScript
// Same as append but assumes that memory has previously been reserved.
// Does not throw exceptions. T::operator= must not throw exceptions.
template <class InputIter>
void fast_append(InputIter begin, InputIter end) {
size_t nElts = static_cast<size_t>(std::distance(begin, end));
void fast_append(InputIter begin, InputIter end) {
size_t nElts = toSize_t(std::distance(begin, end));
ASSERT(length + nElts <= maxReservedSize);
while (nElts) {
size_t nEltsAdvanced;
@ -542,7 +542,7 @@ namespace JavaScript
// reserve_back may throw an exception, in which case the queue is left
// unchanged.
template <class InputIter> void append(InputIter begin, InputIter end) {
size_t nElts = static_cast<size_t>(std::distance(begin, end));
size_t nElts = toSize_t(std::distance(begin, end));
reserve_back(nElts);
while (nElts) {
size_t nEltsAdvanced;
@ -555,15 +555,16 @@ namespace JavaScript
}
};
// Pop between one and nElts elements from the front of the queue. Set begin
// and end to an array of the first n elements, where n is the return value.
// The popped elements may be accessed until the next non-const operation.
// Does not throw exceptions.
// Pop between one and nElts elements from the front of the queue. Set begin
// and end to an array of the first n elements, where n is the return value.
// The popped elements may be accessed until the next non-const operation.
// Does not throw exceptions.
template <typename T>
size_t RawArrayQueue<T>::pop_front(size_t nElts, T *&begin, T *&end) {
size_t RawArrayQueue<T>::pop_front(size_t nElts, T *&begin, T *&end) {
ASSERT(nElts <= length);
begin = f;
size_t eltsToEnd = static_cast<size_t>(bufferEnd - f);
size_t eltsToEnd = toSize_t(bufferEnd - f);
if (nElts < eltsToEnd) {
length -= nElts;
f += nElts;
@ -576,18 +577,18 @@ namespace JavaScript
return eltsToEnd;
}
}
// Enlarge the buffer so that it can hold at least newLength elements.
// May throw an exception, in which case the queue is left unchanged.
template <typename T>
void RawArrayQueue<T>::enlarge(size_t newLength) {
void RawArrayQueue<T>::enlarge(size_t newLength) {
size_t newBufferSize = bufferSize * 2;
if (newBufferSize < newLength)
newBufferSize = newLength;
auto_ptr<T> newBuffer(new T[newBufferSize]);
T *oldBuffer = buffer;
size_t eltsToEnd = static_cast<size_t>(bufferEnd - f);
size_t eltsToEnd = toSize_t(bufferEnd - f);
if (eltsToEnd <= length)
std::copy(f, f + eltsToEnd, newBuffer.get());
else {
@ -601,12 +602,12 @@ namespace JavaScript
delete[] oldBuffer;
bufferSize = newBufferSize;
}
// Ensure that there is room to hold one more element at the back of the queue,
// without expanding the queue's logical length.
// May throw an exception, in which case the queue is left unchanged.
// Ensure that there is room to hold one more element at the back of the queue,
// without expanding the queue's logical length.
// May throw an exception, in which case the queue is left unchanged.
template <typename T>
inline void RawArrayQueue<T>::reserve_back() {
inline void RawArrayQueue<T>::reserve_back() {
if (length == bufferSize)
enlarge(length + 1);
#ifdef DEBUG
@ -615,11 +616,11 @@ namespace JavaScript
#endif
}
// Ensure that there is room to hold nElts more elements at the back of the
// queue, without expanding the queue's logical length.
// May throw an exception, in which case the queue is left unchanged.
// Ensure that there is room to hold nElts more elements at the back of the
// queue, without expanding the queue's logical length.
// May throw an exception, in which case the queue is left unchanged.
template <typename T>
inline void RawArrayQueue<T>::reserve_back(size_t nElts) {
inline void RawArrayQueue<T>::reserve_back(size_t nElts) {
nElts += length;
if (bufferSize < nElts)
enlarge(nElts);
@ -628,13 +629,13 @@ namespace JavaScript
maxReservedSize = nElts;
#endif
}
// Advance the back of the queue by one element, assuming that the memory has
// previously been reserved.
// Return a pointer to that new element.
// Does not throw exceptions.
// Advance the back of the queue by one element, assuming that the memory has
// previously been reserved.
// Return a pointer to that new element.
// Does not throw exceptions.
template <typename T>
inline T *RawArrayQueue<T>::advance_back() {
inline T *RawArrayQueue<T>::advance_back() {
ASSERT(length < maxReservedSize);
++length;
if (b == bufferEnd)
@ -642,12 +643,12 @@ namespace JavaScript
return b++;
}
// Advance the back of the queue by between one and nElts elements and return a
// pointer to them, assuming that the memory has previously been reserved.
// nEltsAdvanced gets the actual number of elements advanced.
// Does not throw exceptions.
// Advance the back of the queue by between one and nElts elements and return a
// pointer to them, assuming that the memory has previously been reserved.
// nEltsAdvanced gets the actual number of elements advanced.
// Does not throw exceptions.
template <typename T>
T *RawArrayQueue<T>::advance_back(size_t nElts, size_t &nEltsAdvanced) {
T *RawArrayQueue<T>::advance_back(size_t nElts, size_t &nEltsAdvanced) {
size_t newLength = length + nElts;
ASSERT(newLength <= maxReservedSize);
if (nElts) {
@ -655,7 +656,7 @@ namespace JavaScript
if (b2 == bufferEnd)
b2 = buffer;
size_t room = static_cast<size_t>(bufferEnd - b2);
size_t room = toSize_t(bufferEnd - b2);
if (nElts > room) {
nElts = room;
newLength = length + nElts;
@ -669,12 +670,12 @@ namespace JavaScript
return 0;
}
}
// Same as push_back but assumes that the memory has previously been reserved.
// May throw an exception if copying elt throws one, in which case the queue is
// left unchanged.
// Same as push_back but assumes that the memory has previously been reserved.
// May throw an exception if copying elt throws one, in which case the queue is
// left unchanged.
template <typename T>
inline void RawArrayQueue<T>::fast_push_back(const T &elt) {
inline void RawArrayQueue<T>::fast_push_back(const T &elt) {
ASSERT(length < maxReservedSize);
T *b2 = b;
if (b2 == bufferEnd)
@ -683,11 +684,11 @@ namespace JavaScript
b = b2 + 1;
++length;
}
// Append elt to the back of the queue.
// May throw an exception, in which case the queue is left unchanged.
// Append elt to the back of the queue.
// May throw an exception, in which case the queue is left unchanged.
template <typename T>
inline void RawArrayQueue<T>::push_back(const T &elt) {
inline void RawArrayQueue<T>::push_back(const T &elt) {
reserve_back();
T *b2 = b == bufferEnd ? buffer : b;
*b2 = elt;
@ -696,26 +697,27 @@ namespace JavaScript
}
// An ArrayQueue represents an array of elements of type T that can be written
// at its back end and read at its front or back end. In addition, arrays of
// multiple elements may be written at the back end or read at the front end.
// The ArrayQueue contains storage for a fixed size array of cacheSize elements;
// if this size is exceeded, the ArrayQueue allocates the array from the heap.
// An ArrayQueue represents an array of elements of type T that can be written
// at its back end and read at its front or back end. In addition, arrays of
// multiple elements may be written at the back end or read at the front end.
// The ArrayQueue contains storage for a fixed size array of cacheSize elements;
// if this size is exceeded, the ArrayQueue allocates the array from the heap.
template <typename T, size_t cacheSize>
class ArrayQueue: public RawArrayQueue<T> {
class ArrayQueue: public RawArrayQueue<T> {
T cacheArray[cacheSize];
public:
ArrayQueue(): RawArrayQueue<T>(cacheArray, cacheSize) {}
};
//
// Array auto_ptr's
//
// An ArrayAutoPtr holds a pointer to an array initialized by new T[x].
// A regular auto_ptr cannot be used here because it deletes its pointer using
// delete rather than delete[].
// An appropriate operator[] is also provided.
// An ArrayAutoPtr holds a pointer to an array initialized by new T[x].
// A regular auto_ptr cannot be used here because it deletes its pointer using
// delete rather than delete[].
// An appropriate operator[] is also provided.
template <typename T> class ArrayAutoPtr {
T *ptr;
@ -734,7 +736,5 @@ namespace JavaScript
};
typedef ArrayAutoPtr<char> CharAutoPtr;
}
#endif /* ds_h___ */

Просмотреть файл

@ -32,53 +32,54 @@
*/
#include <cstdio>
#include "exception.h"
namespace JavaScript
{
namespace JS = JavaScript;
//
// Exceptions
//
static const char *const kindStrings[] = {
"Syntax error", // syntaxError
"Stack overflow", // stackOverflow
"Internal error", // diabetes
"Runtime error", // runtimeError
"Reference error", // referenceError
"Range error", // burnt the beans
"Type error", // Yype error
"Uncaught exception error", // uncaught exception error
"Semantic error", // semantic error
};
static const char *const kindStrings[] = {
"Syntax error", // syntaxError
"Stack overflow" // stackOverflow
};
// Return a null-terminated string describing the exception's kind.
const char *
Exception::kindString() const
{
return kindStrings[kind];
}
const char *JS::Exception::kindString() const
{
return kindStrings[kind];
}
// Return the full error message.
String
Exception::fullMessage() const
{
String m(widenCString("In "));
m += sourceFile;
if (lineNum) {
char b[32];
sprintf(b, ", line %d:\n", lineNum);
m += b;
m += sourceLine;
m += '\n';
String sourceLine2(sourceLine);
insertChars(sourceLine2, charNum, "[ERROR]");
m += sourceLine2;
m += '\n';
} else
m += ":\n";
m += kindString();
m += ": ";
m += message;
JS::String JS::Exception::fullMessage() const
{
String m(widenCString("In "));
m += sourceFile;
if (lineNum) {
char b[32];
sprintf(b, ", line %d:\n", lineNum);
m += b;
m += sourceLine;
m += '\n';
return m;
}
String sourceLine2(sourceLine);
insertChars(sourceLine2, charNum, "[ERROR]");
m += sourceLine2;
m += '\n';
} else
m += ":\n";
m += kindString();
m += ": ";
m += message;
m += '\n';
return m;
}

Просмотреть файл

@ -38,55 +38,58 @@
namespace JavaScript
{
//
// Exceptions
//
// A JavaScript exception (other than out-of-memory, for which we use the
// standard C++ exception bad_alloc).
// A JavaScript exception (other than out-of-memory, for which we use the
// standard C++ exception bad_alloc).
struct Exception {
enum Kind {
syntaxError,
stackOverflow
stackOverflow,
internalError,
runtimeError,
referenceError,
rangeError,
typeError,
uncaughtError,
semanticError
};
Kind kind; // The exception's kind
String message; // The detailed message
String sourceFile; // A description of the source code that caused the
// error
uint32 lineNum; // Number of line that caused the error
uint32 charNum; // Character offset within the line that caused the
// error
uint32 pos; // Offset within the input of the error
String sourceLine; // The text of the source line
Kind kind; // The exception's kind
String message; // The detailed message
String sourceFile; // A description of the source code that caused the error
uint32 lineNum; // Number of line that caused the error
size_t charNum; // Character offset within the line that caused the error
size_t pos; // Offset within the input of the error
String sourceLine; // The text of the source line
Exception (Kind kind, const String &message) :
Exception (Kind kind, const char *message):
kind(kind), message(widenCString(message)), lineNum(0), charNum(0) {}
Exception (Kind kind, const String &message):
kind(kind), message(message), lineNum(0), charNum(0) {}
Exception(Kind kind, const String &message, const String &sourceFile,
uint32 lineNum, uint32 charNum, uint32 pos,
const String &sourceLine) :
kind(kind), message(message), sourceFile(sourceFile),
lineNum(lineNum), charNum(charNum), pos(pos), sourceLine(sourceLine)
{}
Exception(Kind kind, const String &message, const String &sourceFile, uint32 lineNum, size_t charNum,
size_t pos, const String &sourceLine):
kind(kind), message(message), sourceFile(sourceFile), lineNum(lineNum), charNum(charNum), pos(pos),
sourceLine(sourceLine) {}
Exception(Kind kind, const String &message, const String &sourceFile,
uint32 lineNum, uint32 charNum, uint32 pos,
const char16 *sourceLineBegin, const char16 *sourceLineEnd) :
kind(kind), message(message), sourceFile(sourceFile),
lineNum(lineNum), charNum(charNum), pos(pos),
sourceLine(sourceLineBegin, sourceLineEnd) {}
Exception(Kind kind, const String &message, const String &sourceFile, uint32 lineNum, size_t charNum,
size_t pos, const char16 *sourceLineBegin, const char16 *sourceLineEnd):
kind(kind), message(message), sourceFile(sourceFile), lineNum(lineNum), charNum(charNum), pos(pos),
sourceLine(sourceLineBegin, sourceLineEnd) {}
bool hasKind(Kind k) const {return kind == k;}
const char *kindString() const;
String fullMessage() const;
};
// Throw a stackOverflow exception if the execution stack has gotten too large.
// Throw a stackOverflow exception if the execution stack has gotten too large.
inline void checkStackSize() {}
}
#endif /* exception_h___ */

2
js2/src/fdlibm_ns.cpp Normal file
Просмотреть файл

@ -0,0 +1,2 @@
// this file intentionally left blank

140
js2/src/fdlibm_ns.h Normal file
Просмотреть файл

@ -0,0 +1,140 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Roger Lawrence <rogerl@netscape.com>
* Patrick Beard <beard@netscape.com>
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#include <math.h>
#if defined(_WIN32) && !defined(__MWERKS__)
#define __STDC__
#endif
/*
* Use math routines in fdlibm.
*/
#undef __P
#ifdef __STDC__
#define __P(p) p
#else
#define __P(p) ()
#endif
#if defined _WIN32 || defined SUNOS4
// these are functions we trust the local implementation
// to provide, so we just inline them into calls to the
// standard library.
namespace fd {
inline double floor(double x) { return ::floor(x); }
inline double acos(double x) { return ::acos(x); }
inline double asin(double x) { return ::asin(x); }
inline double atan(double x) { return ::atan(x); }
inline double cos(double x) { return ::cos(x); }
inline double sin(double x) { return ::sin(x); }
inline double tan(double x) { return ::tan(x); }
inline double exp(double x) { return ::exp(x); }
inline double log(double x) { return ::log(x); }
inline double sqrt(double x) { return ::sqrt(x); }
inline double ceil(double x) { return ::ceil(x); }
inline double fabs(double x) { return ::fabs(x); }
inline double fmod(double x, double y) { return ::fmod(x, y); }
}
// these one we get from the fdlibm library
namespace fd {
extern "C" {
double fd_atan2 __P((double, double));
double fd_copysign __P((double, double));
double fd_pow __P((double, double));
}
inline double atan2(double x, double y) { return fd_atan2(x, y); }
inline double copysign(double x, double y) { return fd_copysign(x, y); }
inline double pow(double x, double y) { return fd_pow(x, y); }
}
#elif defined(linux)
namespace fd {
inline double atan(double x) { return ::atan(x); }
inline double atan2(double x, double y) { return ::atan2(x, y); }
inline double ceil(double x) { return ::ceil(x); }
inline double cos(double x) { return ::cos(x); }
inline double fabs(double x) { return ::fabs(x); }
inline double floor(double x) { return ::floor(x); }
inline double fmod(double x, double y) { return ::fmod(x, y); }
inline double sin(double x) { return ::sin(x); }
inline double sqrt(double x) { return ::sqrt(x); }
inline double tan(double x) { return ::tan(x); }
inline double copysign(double x, double y) { return ::copysign(x, y); }
}
namespace fd {
extern "C" {
double fd_asin __P((double));
double fd_acos __P((double));
double fd_exp __P((double));
double fd_log __P((double));
double fd_pow __P((double, double));
}
inline double asin(double x) { return fd_asin(x); }
inline double acos(double x) { return fd_acos(x); }
inline double exp(double x) { return fd_exp(x); }
inline double log(double x) { return fd_log(x); }
inline double pow(double x, double y) { return fd_pow(x, y); }
}
#elif defined(macintosh)
// the macintosh MSL provides acceptable implementations for all of these.
namespace fd {
inline double atan(double x) { return ::atan(x); }
inline double atan2(double x, double y) { return ::atan2(x, y); }
inline double ceil(double x) { return ::ceil(x); }
inline double cos(double x) { return ::cos(x); }
inline double fabs(double x) { return ::fabs(x); }
inline double floor(double x) { return ::floor(x); }
inline double fmod(double x, double y) { return ::fmod(x, y); }
inline double sin(double x) { return ::sin(x); }
inline double sqrt(double x) { return ::sqrt(x); }
inline double tan(double x) { return ::tan(x); }
inline double copysign(double x, double y) { return ::copysign(x, y); }
inline double asin(double x) { return ::asin(x); }
inline double acos(double x) { return ::acos(x); }
inline double exp(double x) { return ::exp(x); }
inline double log(double x) { return ::log(x); }
inline double pow(double x, double y) { return ::pow(x, y); }
}
#endif

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -6,14 +6,14 @@
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
@ -38,9 +38,9 @@
#include <cstdarg>
#include "systemtypes.h"
#include "utilities.h"
#include "stlcfg.h"
#include "ds.h"
#include "utilities.h"
#include "strings.h"
namespace JavaScript
@ -49,273 +49,272 @@ namespace JavaScript
// Output
//
// Print the characters between begin and end to the given file. These
// characters may include nulls.
size_t printChars(FILE *file, const char *begin, const char *end);
// Print the characters between begin and end to the given file. These
// characters may include nulls.
size_t printChars(FILE *file, const char *begin, const char *end);
#ifndef XP_MAC_MPW
inline size_t printChars(FILE *file, const char *begin, const char *end) {
ASSERT(end >= begin);
return STD::fwrite(begin, 1, static_cast<size_t>(end - begin), file);
}
inline size_t printChars(FILE *file, const char *begin, const char *end) {
ASSERT(end >= begin);
return STD::fwrite(begin, 1, toSize_t(end - begin), file);
}
#endif
// A Formatter is an abstract base class representing a simplified output stream.
// One can print text to a Formatter by using << and the various global
// print... methods below. Formatters accept both char and char16 text and
// convert as appropriate to their actual stream.
class Formatter {
protected:
virtual void printChar8(char ch);
virtual void printChar16(char16 ch);
virtual void printZStr8(const char *str);
virtual void printStr8(const char *strBegin, const char *strEnd) = 0;
virtual void printStr16(const char16 *strBegin, const char16 *strEnd) = 0;
virtual void printString16(const String &s);
virtual void printVFormat8(const char *format, va_list args);
public:
// A Formatter is an abstract base class representing a simplified output stream.
// One can print text to a Formatter by using << and the various global
// print... methods below. Formatters accept both char and char16 text and
// convert as appropriate to their actual stream.
class Formatter {
protected:
virtual void printChar8(char ch);
virtual void printChar16(char16 ch);
virtual void printZStr8(const char *str);
virtual void printStr8(const char *strBegin, const char *strEnd) = 0;
virtual void printStr16(const char16 *strBegin, const char16 *strEnd) = 0;
virtual void printString16(const String &s);
virtual void printVFormat8(const char *format, va_list args);
public:
Formatter &operator<<(char ch) {printChar8(ch); return *this;}
Formatter &operator<<(char16 ch) {printChar16(ch); return *this;}
Formatter &operator<<(const char *str) {printZStr8(str); return *this;}
Formatter &operator<<(const String &s) {printString16(s); return *this;}
Formatter &operator<<(uint32 i) {
printFormat(*this, "%u", i);
return *this;
}
#ifdef __GNUC__ // Workaround for gcc pedantry. No one should be calling delete on a raw Formatter.
virtual ~Formatter() {}
#endif
friend void printString(Formatter &f, const char *strBegin, const char *strEnd) {
f.printStr8(strBegin, strEnd);
}
Formatter &operator<<(char ch) {printChar8(ch); return *this;}
Formatter &operator<<(char16 ch) {printChar16(ch); return *this;}
Formatter &operator<<(const char *str) {printZStr8(str); return *this;}
Formatter &operator<<(const String &s) {printString16(s); return *this;}
Formatter &operator<<(bool b);
Formatter &operator<<(uint8 i) {printFormat(*this, "%u", i); return *this;}
Formatter &operator<<(uint32 i) {printFormat(*this, "%u", i); return *this;}
Formatter &operator<<(int32 i) {printFormat(*this, "%d", i); return *this;}
friend void printString(Formatter &f, const char16 *strBegin, const char16 *strEnd) {
f.printStr16(strBegin, strEnd);
}
#ifndef _WIN32
// Cause compile-time undefined YOU_TRIED_TO_PRINT_A_RAW_POINTER identifier errors for accidental printing of pointers.
// The error occurs at the place where you try to instantiate this template; the compiler may or may not tell you where it is.
template<class T> Formatter &operator<<(const T *s) {YOU_TRIED_TO_PRINT_A_RAW_POINTER(s); return *this;}
#endif
friend void printFormat(Formatter &f, const char *format, ...) {
va_list args;
va_start(args, format);
f.printVFormat8(format, args);
va_end(args);
}
};
friend void printString(Formatter &f, const char *strBegin, const char *strEnd) {f.printStr8(strBegin, strEnd);}
friend void printString(Formatter &f, const char16 *strBegin, const char16 *strEnd) {f.printStr16(strBegin, strEnd);}
friend void printFormat(Formatter &f, const char *format, ...);
};
void printNum(Formatter &f, uint32 i, int nDigits, char pad, const char *format);
void printChar(Formatter &f, char ch, int count);
void printChar(Formatter &f, char16 ch, int count);
inline void printDec(Formatter &f, int32 i, int nDigits = 0, char pad = ' ') {printNum(f, (uint32)i, nDigits, pad, "%i");}
inline void printDec(Formatter &f, uint32 i, int nDigits = 0, char pad = ' ') {printNum(f, i, nDigits, pad, "%u");}
inline void printHex(Formatter &f, int32 i, int nDigits = 0, char pad = '0') {printNum(f, (uint32)i, nDigits, pad, "%X");}
inline void printHex(Formatter &f, uint32 i, int nDigits = 0, char pad = '0') {printNum(f, i, nDigits, pad, "%X");}
void printPtr(Formatter &f, void *p);
void printNum(Formatter &f, uint32 i, int nDigits, char pad, const char *format);
void printChar(Formatter &f, char ch, int count);
void printChar(Formatter &f, char16 ch, int count);
inline void printDec(Formatter &f, int32 i, int nDigits = 0, char pad = ' ') {printNum(f, (uint32)i, nDigits, pad, "%i");}
inline void printDec(Formatter &f, uint32 i, int nDigits = 0, char pad = ' ') {printNum(f, i, nDigits, pad, "%u");}
inline void printHex(Formatter &f, int32 i, int nDigits = 0, char pad = '0') {printNum(f, (uint32)i, nDigits, pad, "%X");}
inline void printHex(Formatter &f, uint32 i, int nDigits = 0, char pad = '0') {printNum(f, i, nDigits, pad, "%X");}
void printPtr(Formatter &f, void *p);
// An AsciiFileFormatter is a Formatter that prints to a standard ASCII
// file or stream. Characters with Unicode values of 256 or higher are
// converted to escape sequences. Selected lower characters can also be
// converted to escape sequences; these are specified by set bits in the
// BitSet passed to the constructor.
class AsciiFileFormatter: public Formatter {
FILE *file;
BitSet<256> filter; // Set of first 256 characters that are to be converted to escape sequences
bool filterEmpty; // True if filter passes all 256 characters
public:
static BitSet<256> defaultFilter; // Default value of filter when not given in the constructor
// An AsciiFileFormatter is a Formatter that prints to a standard ASCII
// file or stream. Characters with Unicode values of 256 or higher are
// converted to escape sequences. Selected lower characters can also be
// converted to escape sequences; these are specified by set bits in the
// BitSet passed to the constructor.
class AsciiFileFormatter: public Formatter {
FILE *file;
BitSet<256> filter; // Set of first 256 characters that are to be converted to escape sequences
bool filterEmpty; // True if filter passes all 256 characters
public:
static BitSet<256> defaultFilter; // Default value of filter when not given in the constructor
explicit AsciiFileFormatter(FILE *file, BitSet<256> *filter = 0);
explicit AsciiFileFormatter(FILE *file, BitSet<256> *filter = 0);
private:
bool filterChar(char ch) {return filter[static_cast<uchar>(ch)];}
bool filterChar(char16 ch) {
return char16Value(ch) >= 0x100 || filter[char16Value(ch)];
}
private:
bool filterChar(char ch) {return filter[static_cast<uchar>(ch)];}
bool filterChar(char16 ch) {
return char16Value(ch) >= 0x100 || filter[char16Value(ch)];
}
protected:
void printChar8(char ch);
void printChar16(char16 ch);
void printZStr8(const char *str);
void printStr8(const char *strBegin, const char *strEnd);
void printStr16(const char16 *strBegin, const char16 *strEnd);
};
protected:
void printChar8(char ch);
void printChar16(char16 ch);
void printZStr8(const char *str);
void printStr8(const char *strBegin, const char *strEnd);
void printStr16(const char16 *strBegin, const char16 *strEnd);
};
extern AsciiFileFormatter stdOut;
extern AsciiFileFormatter stdErr;
extern AsciiFileFormatter stdOut;
extern AsciiFileFormatter stdErr;
// A StringFormatter is a Formatter that prints to a String.
class StringFormatter: public Formatter {
String s;
// A StringFormatter is a Formatter that prints to a String.
class StringFormatter: public Formatter {
String s;
public:
const String& getString() { return s; }
void clear() {JavaScript::clear(s);}
protected:
void printChar8(char ch);
void printChar16(char16 ch);
void printZStr8(const char *str);
void printStr8(const char *strBegin, const char *strEnd);
void printStr16(const char16 *strBegin, const char16 *strEnd);
void printString16(const String &str);
};
public:
const String& getString() { return s; }
void clear() {JavaScript::clear(s);}
protected:
void printChar8(char ch);
void printChar16(char16 ch);
void printZStr8(const char *str);
void printStr8(const char *strBegin, const char *strEnd);
void printStr16(const char16 *strBegin, const char16 *strEnd);
void printString16(const String &str);
};
//
// Formatted Output
//
class PrettyPrinter: public Formatter {
public:
STATIC_CONST(uint32, unlimitedLineWidth = 0x7FFFFFFF);
class Region;
class Indent;
class Block;
class PrettyPrinter: public Formatter {
public:
STATIC_CONST(uint32, unlimitedLineWidth = 0x7FFFFFFF);
class Region;
class Indent;
class Block;
private:
STATIC_CONST(uint32, infiniteLength = 0x80000000);
const uint32 lineWidth; // Current maximum desired line width
private:
STATIC_CONST(uint32, infiniteLength = 0x80000000);
const uint32 lineWidth; // Current maximum desired line width
struct BlockInfo {
uint32 margin; // Saved margin before this block's beginning
uint32 lastBreak; // Saved lastBreak before this block's beginning
bool fits; // True if this entire block fits on one line
};
struct BlockInfo {
uint32 margin; // Saved margin before this block's beginning
uint32 lastBreak; // Saved lastBreak before this block's beginning
bool fits; // True if this entire block fits on one line
};
// Variables for the back end that prints to the destination
Formatter &outputFormatter; // Destination formatter on which the result should be printed
uint32 outputPos; // Number of characters printed on current output line
uint32 lineNum; // Serial number of current line
uint32 lastBreak; // Number of line just after the last break that occurred in this block
uint32 margin; // Current left margin in spaces
ArrayBuffer<BlockInfo, 20> savedBlocks; // Stack of saved information about partially printed blocks
// Variables for the back end that prints to the destination
Formatter &outputFormatter; // Destination formatter on which the result should be printed
uint32 outputPos; // Number of characters printed on current output line
uint32 lineNum; // Serial number of current line
uint32 lastBreak; // Number of line just after the last break that occurred in this block
uint32 margin; // Current left margin in spaces
ArrayBuffer<BlockInfo, 20> savedBlocks; // Stack of saved information about partially printed blocks
// Variables for the front end that calculates block sizes
struct Item: ListQueueEntry {
enum Kind {text, blockBegin, indentBlockBegin, blockEnd, indent, linearBreak, fillBreak};
// Variables for the front end that calculates block sizes
struct Item: ListQueueEntry {
enum Kind {text, blockBegin, indentBlockBegin, blockEnd, indent, linearBreak, fillBreak};
const Kind kind; // The kind of this text sequence
bool lengthKnown; // True if totalLength is known; always true for text, blockEnd, and indent Items
uint32 length; // Length of this text sequence, number of spaces for this break, or delta for indent or indentBlockBegin
uint32 totalLength; // Total length of this block (for blockBegin) or length of this break plus following clump (for breaks);
// If lengthKnown is false, this is the serialPos of this Item instead of a length
bool hasKind(Kind k) const {return kind == k;}
const Kind kind; // The kind of this text sequence
bool lengthKnown; // True if totalLength is known; always true for text, blockEnd, and indent Items
uint32 length; // Length of this text sequence, number of spaces for this break, or delta for indent or indentBlockBegin
uint32 totalLength; // Total length of this block (for blockBegin) or length of this break plus following clump (for breaks);
// If lengthKnown is false, this is the serialPos of this Item instead of a length
bool hasKind(Kind k) const {return kind == k;}
explicit Item(Kind kind): kind(kind), lengthKnown(true) {}
Item(Kind kind, uint32 length): kind(kind), lengthKnown(true), length(length) {}
Item(Kind kind, uint32 length, uint32 beginSerialPos):
kind(kind), lengthKnown(false), length(length), totalLength(beginSerialPos) {}
explicit Item(Kind kind): kind(kind), lengthKnown(true) {}
Item(Kind kind, uint32 length): kind(kind), lengthKnown(true), length(length) {}
Item(Kind kind, uint32 length, uint32 beginSerialPos):
kind(kind), lengthKnown(false), length(length), totalLength(beginSerialPos) {}
void computeTotalLength(uint32 endSerialPos) {
ASSERT(!lengthKnown);
lengthKnown = true;
totalLength = endSerialPos - totalLength;
}
void computeTotalLength(uint32 endSerialPos) {
ASSERT(!lengthKnown);
lengthKnown = true;
totalLength = endSerialPos - totalLength;
}
};
};
#ifdef DEBUG
Region *topRegion; // Most deeply nested Region
Region *topRegion; // Most deeply nested Region
#endif
uint32 nNestedBlocks; // Number of nested Blocks
uint32 nNestedBlocks; // Number of nested Blocks
uint32 leftSerialPos; // The difference rightSerialPos-
uint32 rightSerialPos; // leftSerialPos is always the number of characters that would be output by
// printing activeItems if they all fit on one line; only the difference
// matters -- the absolute values are irrelevant and may wrap around 2^32.
uint32 leftSerialPos; // The difference rightSerialPos-
uint32 rightSerialPos; // leftSerialPos is always the number of characters that would be output by
// printing activeItems if they all fit on one line; only the difference
// matters -- the absolute values are irrelevant and may wrap around 2^32.
ArrayQueue<Item *, 20> itemStack; // Stack of enclosing nested Items whose lengths have not yet been determined;
// itemStack always has room for at least nNestedBlocks extra entries so that end Items
// may be added without throwing an exception.
Pool<Item> itemPool; // Pool from which to allocate activeItems
ListQueue<Item> activeItems; // Queue of items left to be printed
ArrayQueue<char16, 256> itemText; // Text of text items in activeItems, in the same order as in activeItems
ArrayQueue<Item *, 20> itemStack; // Stack of enclosing nested Items whose lengths have not yet been determined;
// itemStack always has room for at least nNestedBlocks extra entries so that end Items
// may be added without throwing an exception.
Pool<Item> itemPool; // Pool from which to allocate activeItems
ListQueue<Item> activeItems; // Queue of items left to be printed
ArrayQueue<char16, 256> itemText; // Text of text items in activeItems, in the same order as in activeItems
public:
static uint32 defaultLineWidth; // Default for lineWidth if not given to the constructor
public:
static uint32 defaultLineWidth; // Default for lineWidth if not given to the constructor
explicit PrettyPrinter(Formatter &f, uint32 lineWidth = defaultLineWidth);
private:
PrettyPrinter(const PrettyPrinter&); // No copy constructor
void operator=(const PrettyPrinter&); // No assignment operator
public:
~PrettyPrinter();
explicit PrettyPrinter(Formatter &f, uint32 lineWidth = defaultLineWidth);
private:
PrettyPrinter(const PrettyPrinter&); // No copy constructor
void operator=(const PrettyPrinter&); // No assignment operator
public:
virtual ~PrettyPrinter();
private:
void outputBreak(bool sameLine, uint32 nSpaces);
bool reduceLeftActiveItems(uint32 rightOffset);
void reduceRightActiveItems();
private:
void outputBreak(bool sameLine, uint32 nSpaces);
bool reduceLeftActiveItems(uint32 rightOffset);
void reduceRightActiveItems();
Item &beginIndent(int32 offset);
void endIndent(Item &i);
Item &beginIndent(int32 offset);
void endIndent(Item &i);
Item &beginBlock(Item::Kind kind, int32 offset);
void endBlock(Item &i);
Item &beginBlock(Item::Kind kind, int32 offset);
void endBlock(Item &i);
void conditionalBreak(uint32 nSpaces, Item::Kind kind);
void conditionalBreak(uint32 nSpaces, Item::Kind kind);
protected:
void printStr8(const char *strBegin, const char *strEnd);
void printStr16(const char16 *strBegin, const char16 *strEnd);
public:
protected:
void printStr8(const char *strBegin, const char *strEnd);
void printStr16(const char16 *strBegin, const char16 *strEnd);
public:
void requiredBreak();
void linearBreak(uint32 nSpaces) {conditionalBreak(nSpaces, Item::linearBreak);}
void linearBreak(uint32 nSpaces, bool required);
void fillBreak(uint32 nSpaces) {conditionalBreak(nSpaces, Item::fillBreak);}
void requiredBreak();
void linearBreak(uint32 nSpaces) {conditionalBreak(nSpaces, Item::linearBreak);}
void linearBreak(uint32 nSpaces, bool required);
void fillBreak(uint32 nSpaces) {conditionalBreak(nSpaces, Item::fillBreak);}
void end();
void end();
friend class Region;
friend class Indent;
friend class Block;
friend class Region;
friend class Indent;
friend class Block;
class Region {
class Region {
#ifdef DEBUG
Region *next; // Link to next most deeply nested Region
Region *next; // Link to next most deeply nested Region
#endif
protected:
PrettyPrinter &pp;
protected:
PrettyPrinter &pp;
Region(PrettyPrinter &pp): pp(pp) {DEBUG_ONLY(next = pp.topRegion; pp.topRegion = this;);}
private:
Region(const Region&); // No copy constructor
void operator=(const Region&); // No assignment operator
protected:
Region(PrettyPrinter &pp): pp(pp) {DEBUG_ONLY(next = pp.topRegion; pp.topRegion = this;);}
private:
Region(const Region&); // No copy constructor
void operator=(const Region&); // No assignment operator
protected:
#ifdef DEBUG
~Region() {pp.topRegion = next;}
~Region() {pp.topRegion = next;}
#endif
};
};
// Use an Indent object to temporarily indent a PrettyPrinter by the
// offset given to the Indent's constructor. The PrettyPrinter's margin
// is set back to its original value when the Indent object is destroyed.
// Using an Indent object is exception-safe; no matter how control
// leaves an Indent scope, the indent is undone.
// Scopes of Indent and Block objects must be properly nested.
class Indent: public Region {
Item &endItem; // The Item returned by beginIndent
public:
Indent(PrettyPrinter &pp, int32 offset): Region(pp), endItem(pp.beginIndent(offset)) {}
~Indent() {pp.endIndent(endItem);}
};
// Use an Indent object to temporarily indent a PrettyPrinter by the
// offset given to the Indent's constructor. The PrettyPrinter's margin
// is set back to its original value when the Indent object is destroyed.
// Using an Indent object is exception-safe; no matter how control
// leaves an Indent scope, the indent is undone.
// Scopes of Indent and Block objects must be properly nested.
class Indent: public Region {
Item &endItem; // The Item returned by beginIndent
public:
Indent(PrettyPrinter &pp, int32 offset): Region(pp), endItem(pp.beginIndent(offset)) {}
~Indent() {pp.endIndent(endItem);}
};
// Use a Block object to temporarily enter a PrettyPrinter block. If an
// offset is provided, line breaks inside the block are indented by that
// offset relative to the existing indent; otherwise, line breaks inside
// the block are indented to the current output position. The block
// lasts until the Block object is destroyed.
// Scopes of Indent and Block objects must be properly nested.
class Block: public Region {
Item &endItem; // The Item returned by beginBlock
public:
explicit Block(PrettyPrinter &pp): Region(pp), endItem(pp.beginBlock(Item::blockBegin, 0)) {}
Block(PrettyPrinter &pp, int32 offset): Region(pp), endItem(pp.beginBlock(Item::indentBlockBegin, offset)) {}
~Block() {pp.endBlock(endItem);}
};
};
// Use a Block object to temporarily enter a PrettyPrinter block. If an
// offset is provided, line breaks inside the block are indented by that
// offset relative to the existing indent; otherwise, line breaks inside
// the block are indented to the current output position. The block
// lasts until the Block object is destroyed.
// Scopes of Indent and Block objects must be properly nested.
class Block: public Region {
Item &endItem; // The Item returned by beginBlock
public:
explicit Block(PrettyPrinter &pp): Region(pp), endItem(pp.beginBlock(Item::blockBegin, 0)) {}
Block(PrettyPrinter &pp, int32 offset): Region(pp), endItem(pp.beginBlock(Item::indentBlockBegin, offset)) {}
~Block() {pp.endBlock(endItem);}
};
};
void escapeString(Formatter &f, const char16 *begin, const char16 *end, char16 quote);
void quoteString(Formatter &f, const String &s, char16 quote);
void escapeString(Formatter &f, const char16 *begin, const char16 *end, char16 quote);
void quoteString(Formatter &f, const String &s, char16 quote);
}
#endif /* formatter_h___ */

Просмотреть файл

@ -119,7 +119,7 @@ int main(int /* argc */, char* /* argv[] */)
int value = rand() % 32767;
values.push_back(value);
// allocate a random amount of garbage.
if (!GC_malloc(static_cast<size_t>(value)))
if (!GC_malloc(toSize_t(value)))
cerr << "GC_malloc failed." << endl;
// allocate an object that has a finalizer to call its destructor.
A* a = new A();

Просмотреть файл

@ -6,7 +6,7 @@
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
@ -33,158 +33,153 @@
#include "hash.h"
#include <new>
namespace JavaScript
{
namespace JS = JavaScript;
//
// Hash Codes
//
// General-purpose null-terminated C string hash function
HashNumber
hashString(const char *s)
{
HashNumber h = 0;
uchar ch;
while ((ch = (uchar)*s++) != 0)
h = (h >> 28) ^ (h << 4) ^ ch;
return h;
}
JS::HashNumber JS::hashString(const char *s)
{
HashNumber h = 0;
uchar ch;
while ((ch = (uchar)*s++) != 0)
h = (h >> 28) ^ (h << 4) ^ ch;
return h;
}
// General-purpose String hash function
HashNumber
hashString(const String &s)
{
HashNumber h = 0;
String::const_iterator p = s.begin();
String::size_type n = s.size();
if (n < 16)
// Hash every character in a short string.
while (n--)
h = (h >> 28) ^ (h << 4) ^ *p++;
else
// Sample a la java.lang.String.hash().
for (String::size_type m = n / 8; n >= m; p += m, n -= m)
h = (h >> 28) ^ (h << 4) ^ *p;
return h;
}
JS::HashNumber JS::hashString(const String &s)
{
HashNumber h = 0;
String::const_iterator p = s.begin();
String::size_type n = s.size();
if (n < 16)
// Hash every character in a short string.
while (n--)
h = (h >> 28) ^ (h << 4) ^ *p++;
else
// Sample a la java.lang.String.hash().
for (String::size_type m = n / 8; n >= m; p += m, n -= m)
h = (h >> 28) ^ (h << 4) ^ *p;
return h;
}
//
// Hash Tables
//
const uint minLgNBuckets = 4;
const uint minLgNBuckets = 4;
GenericHashTableIterator::GenericHashTableIterator(GenericHashTable &ht):
ht(ht), entry(0), nextBucket(ht.buckets)
{
DEBUG_ONLY(++ht.nReferences);
operator++();
JS::GenericHashTableIterator::GenericHashTableIterator(GenericHashTable &ht):
ht(ht), entry(0), nextBucket(ht.buckets)
{
DEBUG_ONLY(++ht.nReferences);
operator++();
}
JS::GenericHashTableIterator &JS::GenericHashTableIterator::operator++()
{
GenericHashEntry *e = entry;
if (e) {
backpointer = &e->next;
e = e->next;
}
if (!e) {
GenericHashEntry **const bucketsEnd = ht.bucketsEnd;
GenericHashEntry **bucket = nextBucket;
GenericHashTableIterator &
GenericHashTableIterator::operator++()
{
GenericHashEntry *e = entry;
if (e) {
backpointer = &e->next;
e = e->next;
}
if (!e) {
GenericHashEntry **const bucketsEnd = ht.bucketsEnd;
GenericHashEntry **bucket = nextBucket;
while (bucket != bucketsEnd) {
e = *bucket++;
if (e) {
backpointer = bucket-1;
break;
}
while (bucket != bucketsEnd) {
e = *bucket++;
if (e) {
backpointer = bucket-1;
break;
}
nextBucket = bucket;
}
entry = e;
return *this;
nextBucket = bucket;
}
GenericHashTable::GenericHashTable(uint32 nEntriesDefault) :
nEntries(0)
{
DEBUG_ONLY(nReferences = 0);
entry = e;
return *this;
}
uint lgNBuckets = ceilingLog2(nEntriesDefault);
if (lgNBuckets < minLgNBuckets)
lgNBuckets = minLgNBuckets;
defaultLgNBuckets = lgNBuckets;
recomputeMinMaxNEntries(lgNBuckets);
uint32 nBuckets = JS_BIT(lgNBuckets);
buckets = new GenericHashEntry*[nBuckets];
// No exceptions after this point unless buckets is deleted.
JS::GenericHashTable::GenericHashTable(uint32 nEntriesDefault):
nEntries(0)
{
DEBUG_ONLY(nReferences = 0);
bucketsEnd = buckets + nBuckets;
zero(buckets, bucketsEnd);
}
uint lgNBuckets = ceilingLog2(nEntriesDefault);
if (lgNBuckets < minLgNBuckets)
lgNBuckets = minLgNBuckets;
defaultLgNBuckets = lgNBuckets;
recomputeMinMaxNEntries(lgNBuckets);
uint32 nBuckets = JS_BIT(lgNBuckets);
buckets = new GenericHashEntry*[nBuckets];
// No exceptions after this point unless buckets is deleted.
bucketsEnd = buckets + nBuckets;
zero(buckets, bucketsEnd);
}
// Initialize shift, minNEntries, and maxNEntries based on the lg2 of the
// number of buckets.
void
GenericHashTable::recomputeMinMaxNEntries(uint lgNBuckets)
{
uint32 nBuckets = JS_BIT(lgNBuckets);
shift = 32 - lgNBuckets;
maxNEntries = nBuckets; // Maximum ratio is 100%
// Minimum ratio is 37.5%
minNEntries = lgNBuckets <= defaultLgNBuckets ? 0 : 3*(nBuckets>>3);
}
void JS::GenericHashTable::recomputeMinMaxNEntries(uint lgNBuckets)
{
uint32 nBuckets = JS_BIT(lgNBuckets);
shift = 32 - lgNBuckets;
maxNEntries = nBuckets; // Maximum ratio is 100%
// Minimum ratio is 37.5%
minNEntries = lgNBuckets <= defaultLgNBuckets ? 0 : 3*(nBuckets>>3);
}
// Rehash the table. This method cannot throw out-of-memory exceptions, so it is
// safe to call from a destructor.
void
GenericHashTable::rehash()
{
uint32 newLgNBuckets = ceilingLog2(nEntries);
if (newLgNBuckets < defaultLgNBuckets)
newLgNBuckets = defaultLgNBuckets;
uint32 newNBuckets = JS_BIT(newLgNBuckets);
try {
GenericHashEntry **newBuckets = new GenericHashEntry*[newNBuckets];
// No exceptions after this point.
void JS::GenericHashTable::rehash()
{
uint32 newLgNBuckets = ceilingLog2(nEntries);
if (newLgNBuckets < defaultLgNBuckets)
newLgNBuckets = defaultLgNBuckets;
uint32 newNBuckets = JS_BIT(newLgNBuckets);
try {
GenericHashEntry **newBuckets = new GenericHashEntry*[newNBuckets];
// No exceptions after this point.
GenericHashEntry **newBucketsEnd = newBuckets + newNBuckets;
zero(newBuckets, newBucketsEnd);
recomputeMinMaxNEntries(newLgNBuckets);
GenericHashEntry **be = bucketsEnd;
for (GenericHashEntry **b = buckets; b != be; b++) {
GenericHashEntry *e = *b;
while (e) {
GenericHashEntry *next = e->next;
// Place e in the new set of buckets.
GenericHashEntry **nb =
newBuckets + (e->keyHash*goldenRatio >> shift);
e->next = *nb;
*nb = e;
e = next;
}
GenericHashEntry **newBucketsEnd = newBuckets + newNBuckets;
zero(newBuckets, newBucketsEnd);
recomputeMinMaxNEntries(newLgNBuckets);
GenericHashEntry **be = bucketsEnd;
for (GenericHashEntry **b = buckets; b != be; b++) {
GenericHashEntry *e = *b;
while (e) {
GenericHashEntry *next = e->next;
// Place e in the new set of buckets.
GenericHashEntry **nb = newBuckets + (e->keyHash*goldenRatio >> shift);
e->next = *nb;
*nb = e;
e = next;
}
delete[] buckets;
buckets = newBuckets;
bucketsEnd = newBucketsEnd;
} catch (std::bad_alloc) {
// Out of memory. Ignore the error and just relax the resizing
// boundaries.
if (buckets + JS_BIT(newLgNBuckets) > bucketsEnd)
maxNEntries >>= 1;
else
minNEntries <<= 1;
}
delete[] buckets;
buckets = newBuckets;
bucketsEnd = newBucketsEnd;
} catch (std::bad_alloc) {
// Out of memory. Ignore the error and just relax the resizing boundaries.
if (buckets + JS_BIT(newLgNBuckets) > bucketsEnd)
maxNEntries >>= 1;
else
minNEntries <<= 1;
}
}

Просмотреть файл

@ -6,7 +6,7 @@
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
@ -61,9 +61,9 @@ namespace JavaScript {
return hashString(key);
}
const HashNumber goldenRatio = 0x9E3779B9U;
//
// Private
//
@ -76,35 +76,30 @@ namespace JavaScript {
const HashNumber keyHash; // This entry's hash value
protected:
explicit GenericHashEntry(HashNumber keyHash) :
next(0), keyHash(keyHash) {}
explicit GenericHashEntry(HashNumber keyHash): next(0), keyHash(keyHash) {}
friend class GenericHashTable;
};
// private
// private
class GenericHashTableIterator;
class GenericHashTable {
protected:
protected:
GenericHashEntry **buckets; // Vector of hash buckets
GenericHashEntry **bucketsEnd; // Pointer past end of vector of hash
// buckets
uint defaultLgNBuckets; // lg2 of minimum number of buckets for
// which to size the table
GenericHashEntry **bucketsEnd; // Pointer past end of vector of hash buckets
uint defaultLgNBuckets; // lg2 of minimum number of buckets for which to size the table
uint32 nEntries; // Number of entries in table
uint32 minNEntries; // Minimum number of entries without
// rehashing
uint32 maxNEntries; // Maximum number of entries without
// rehashing
uint32 minNEntries; // Minimum number of entries without rehashing
uint32 maxNEntries; // Maximum number of entries without rehashing
uint32 shift; // 32 - lg2(number of buckets)
#ifdef DEBUG
public:
public:
uint32 nReferences; // Number of iterators and references
// currently pointing to this hash table
#endif
public:
public:
explicit GenericHashTable(uint32 nEntriesDefault);
~GenericHashTable() {
#ifndef _WIN32
@ -123,20 +118,18 @@ namespace JavaScript {
typedef GenericHashTableIterator Iterator;
};
// This ought to be GenericHashTable::Iterator, but this doesn't work
// due to a Microsoft VC6 bug.
// This ought to be GenericHashTable::Iterator, but this doesn't work
// due to a Microsoft VC6 bug.
class GenericHashTableIterator {
protected:
protected:
GenericHashTable &ht; // Hash table being iterated
GenericHashEntry *entry; // Current entry; nil if done
GenericHashEntry **backpointer; // Pointer to pointer to current entry
GenericHashEntry **nextBucket; // Next bucket; pointer past end of
// vector of hash buckets if done
GenericHashEntry **nextBucket; // Next bucket; pointer past end of vector of hash buckets if done
public:
explicit GenericHashTableIterator(GenericHashTable &ht);
~GenericHashTableIterator() {
ht.maybeShrink(); DEBUG_ONLY(--ht.nReferences);
}
~GenericHashTableIterator() {ht.maybeShrink(); DEBUG_ONLY(--ht.nReferences);}
// Return true if there are entries left.
operator bool() const {return entry != 0;}
@ -156,35 +149,29 @@ namespace JavaScript {
struct Entry: public GenericHashEntry {
Data data;
Entry(HashNumber keyHash, Key key) :
GenericHashEntry(keyHash), data(key) {}
Entry(HashNumber keyHash, Key key): GenericHashEntry(keyHash), data(key) {}
template<class Value>
Entry(HashNumber keyHash, Key key, Value value) :
GenericHashEntry(keyHash), data(key, value) {}
Entry(HashNumber keyHash, Key key, Value value): GenericHashEntry(keyHash), data(key, value) {}
};
public:
public:
class Reference {
#ifdef _WIN32
// Microsoft VC6 bug: friend declarations to inner classes don't work
public:
public:
#endif
Entry *entry; // Current entry; nil if done
GenericHashEntry **backpointer; // Pointer to pointer to current
// entry
GenericHashEntry **backpointer; // Pointer to pointer to current entry
const HashNumber keyHash; // This entry's key's hash value
#ifdef DEBUG
GenericHashTable *ht; // Hash table to which this
// Reference points
GenericHashTable *ht; // Hash table to which this Reference points
#endif
public:
public:
#ifndef _WIN32
Reference(HashTable &ht, Key key); // Search for an entry with the
// given key.
Reference(HashTable &ht, Key key); // Search for an entry with the given key.
#else
// Microsoft VC6 bug: VC6 doesn't allow this to be defined outside
// the class
// Microsoft VC6 bug: VC6 doesn't allow this to be defined outside the class
Reference(HashTable &ht, Key key): keyHash(ht.hasher(key)) {
#ifdef DEBUG
Reference::ht = &ht;
@ -195,17 +182,16 @@ namespace JavaScript {
GenericHashEntry **bp = ht.buckets + h;
Entry *e;
while ((e = static_cast<Entry *>(*bp)) != 0 &&
!(e->keyHash == kh && e->data == key))
while ((e = static_cast<Entry *>(*bp)) != 0 && !(e->keyHash == kh && e->data == key))
bp = &e->next;
entry = e;
backpointer = bp;
}
#endif
private:
private:
Reference(const Reference&); // No copy constructor
void operator=(const Reference&); // No assignment operator
public:
public:
#if defined(DEBUG) && !defined(_WIN32)
~Reference() {if (ht) --ht->nReferences;}
#endif
@ -219,29 +205,23 @@ namespace JavaScript {
};
class Iterator: public GenericHashTableIterator {
public:
public:
explicit Iterator(HashTable &ht): GenericHashTableIterator(ht) {}
private:
private:
Iterator(const Iterator&); // No copy constructor
void operator=(const Iterator&); // No assignment operator
public:
public:
// Go to next entry.
Iterator &operator++() {
return *static_cast<Iterator*>(&GenericHashTableIterator::operator++());
}
Data &operator*() const {
// Return current entry's data.
ASSERT(entry);
return static_cast<Entry *>(entry)->data;
}
// Go to next entry.
Iterator &operator++() {return *static_cast<Iterator*>(&GenericHashTableIterator::operator++());}
// Return current entry's data.
Data &operator*() const {ASSERT(entry); return static_cast<Entry *>(entry)->data;}
void erase();
};
HashTable(uint32 nEntriesDefault = 0, const H &hasher = H()) :
GenericHashTable(nEntriesDefault), hasher(hasher) {}
HashTable(uint32 nEntriesDefault = 0, const H &hasher = H()): GenericHashTable(nEntriesDefault), hasher(hasher) {}
~HashTable();
template<class Value> Data &insert(Reference &r, Key key, Value value);

2188
js2/src/js2execution.cpp Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

2159
js2/src/js2runtime.cpp Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

1669
js2/src/js2runtime.h Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

550
js2/src/jsarray.cpp Normal file
Просмотреть файл

@ -0,0 +1,550 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#ifdef _WIN32
// Turn off warnings about identifiers too long in browser information
#pragma warning(disable: 4786)
#pragma warning(disable: 4711)
#pragma warning(disable: 4710)
#endif
#include <algorithm>
#include "parser.h"
#include "numerics.h"
#include "js2runtime.h"
// this is the IdentifierList passed to the name lookup routines
#define CURRENT_ATTR (NULL)
#include "jsarray.h"
namespace JavaScript {
namespace JS2Runtime {
JSValue Array_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
JSValue thatValue = thisValue;
if (thatValue.isNull())
thatValue = Array_Type->newInstance(cx);
ASSERT(thatValue.isObject());
JSObject *thisObj = thatValue.object;
ASSERT(dynamic_cast<JSArrayInstance *>(thisObj));
JSArrayInstance *arrInst = (JSArrayInstance *)thisObj;
if (argc > 0) {
if (argc == 1) {
arrInst->mLength = (uint32)(argv[0].toNumber(cx).f64);
}
else {
arrInst->mLength = argc;
for (uint32 i = 0; i < argc; i++) {
String *id = numberToString(i);
arrInst->defineVariable(cx, *id, (NamespaceList *)(NULL), Object_Type, argv[i]);
delete id;
}
}
}
return thatValue;
}
static JSValue Array_toString(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
ASSERT(dynamic_cast<JSArrayInstance *>(thisObj));
JSArrayInstance *arrInst = (JSArrayInstance *)thisObj;
ContextStackReplacement csr(cx);
if (arrInst->mLength == 0)
return JSValue(new String(widenCString("")));
else {
String *s = new String();
for (uint32 i = 0; i < arrInst->mLength; i++) {
String *id = numberToString(i);
arrInst->getProperty(cx, *id, NULL);
JSValue result = cx->popValue();
s->append(*result.toString(cx).string);
if (i < (arrInst->mLength - 1))
s->append(widenCString(","));
}
return JSValue(s);
}
}
static JSValue Array_toSource(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
ASSERT(dynamic_cast<JSArrayInstance *>(thisObj));
JSArrayInstance *arrInst = (JSArrayInstance *)thisObj;
ContextStackReplacement csr(cx);
if (arrInst->mLength == 0)
return JSValue(new String(widenCString("[]")));
else {
String *s = new String(widenCString("["));
for (uint32 i = 0; i < arrInst->mLength; i++) {
String *id = numberToString(i);
arrInst->getProperty(cx, *id, NULL);
JSValue result = cx->popValue();
if (!result.isUndefined())
s->append(*result.toString(cx).string);
if (i < (arrInst->mLength - 1))
s->append(widenCString(", "));
}
s->append(widenCString("]"));
return JSValue(s);
}
}
static JSValue Array_push(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
ASSERT(dynamic_cast<JSArrayInstance *>(thisObj));
JSArrayInstance *arrInst = (JSArrayInstance *)thisObj;
for (uint32 i = 0; i < argc; i++) {
String *id = numberToString(i + arrInst->mLength);
arrInst->defineVariable(cx, *id, (NamespaceList *)(NULL), Object_Type, argv[i]);
delete id;
}
arrInst->mLength += argc;
return JSValue((float64)arrInst->mLength);
}
static JSValue Array_pop(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
ASSERT(dynamic_cast<JSArrayInstance *>(thisObj));
JSArrayInstance *arrInst = (JSArrayInstance *)thisObj;
ContextStackReplacement csr(cx);
if (arrInst->mLength > 0) {
String *id = numberToString(arrInst->mLength - 1);
arrInst->getProperty(cx, *id, NULL);
JSValue result = cx->popValue();
arrInst->deleteProperty(*id, NULL);
--arrInst->mLength;
delete id;
return result;
}
else
return kUndefinedValue;
}
JSValue Array_concat(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
JSValue E = thisValue;
JSArrayInstance *A = (JSArrayInstance *)(Array_Type->newInstance(cx));
uint32 n = 0;
uint32 i = 0;
ContextStackReplacement csr(cx);
do {
if (E.getType() != Array_Type) {
String *id = numberToString(n++);
A->setProperty(cx, *id, CURRENT_ATTR, E);
}
else {
ASSERT(E.isObject() && dynamic_cast<JSArrayInstance *>(E.object));
JSArrayInstance *arrInst = (JSArrayInstance *)(E.object);
for (uint32 k = 0; k < arrInst->mLength; k++) {
String *id = numberToString(k);
arrInst->getProperty(cx, *id, NULL);
JSValue result = cx->popValue();
id = numberToString(n++);
A->setProperty(cx, *id, CURRENT_ATTR, result);
}
}
E = argv[i++];
} while (i <= argc);
return JSValue(A);
}
static JSValue Array_join(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ContextStackReplacement csr(cx);
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
thisObj->getProperty(cx, widenCString("length"), CURRENT_ATTR);
JSValue result = cx->popValue();
uint32 length = (uint32)(result.toUInt32(cx).f64);
const String *separator;
if (argc == 0)
separator = new String(',', 1);
else
separator = argv[0].toString(cx).string;
thisObj->getProperty(cx, *numberToString(0), CURRENT_ATTR);
result = cx->popValue();
String *S = new String();
for (uint32 k = 0; k < length; k++) {
thisObj->getProperty(cx, *numberToString(0), CURRENT_ATTR);
result = cx->popValue();
if (!result.isUndefined() && !result.isNull())
*S += *result.toString(cx).string;
if (k < (length - 1))
*S += *separator;
}
return JSValue(S);
}
static JSValue Array_reverse(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
ContextStackReplacement csr(cx);
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
thisObj->getProperty(cx, widenCString("length"), CURRENT_ATTR);
JSValue result = cx->popValue();
uint32 length = (uint32)(result.toUInt32(cx).f64);
uint32 halfway = length / 2;
for (uint32 k = 0; k < halfway; k++) {
String *id1 = numberToString(k);
String *id2 = numberToString(length - k - 1);
PropertyIterator it;
if (thisObj->hasOwnProperty(*id1, CURRENT_ATTR, Read, &it)) {
if (thisObj->hasOwnProperty(*id2, CURRENT_ATTR, Read, &it)) {
thisObj->getProperty(cx, *id1, CURRENT_ATTR);
thisObj->getProperty(cx, *id2, CURRENT_ATTR);
thisObj->setProperty(cx, *id1, CURRENT_ATTR, cx->popValue());
thisObj->setProperty(cx, *id2, CURRENT_ATTR, cx->popValue());
}
else {
thisObj->getProperty(cx, *id1, CURRENT_ATTR);
thisObj->setProperty(cx, *id2, CURRENT_ATTR, cx->popValue());
thisObj->deleteProperty(*id1, CURRENT_ATTR);
}
}
else {
if (thisObj->hasOwnProperty(*id2, CURRENT_ATTR, Read, &it)) {
thisObj->getProperty(cx, *id2, CURRENT_ATTR);
thisObj->setProperty(cx, *id1, CURRENT_ATTR, cx->popValue());
thisObj->deleteProperty(*id2, CURRENT_ATTR);
}
else {
thisObj->deleteProperty(*id1, CURRENT_ATTR);
thisObj->deleteProperty(*id2, CURRENT_ATTR);
}
}
}
return thisValue;
}
static JSValue Array_shift(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
ContextStackReplacement csr(cx);
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
thisObj->getProperty(cx, widenCString("length"), CURRENT_ATTR);
JSValue result = cx->popValue();
uint32 length = (uint32)(result.toUInt32(cx).f64);
if (length == 0) {
thisObj->setProperty(cx, widenCString("length"), CURRENT_ATTR, result);
return kUndefinedValue;
}
thisObj->getProperty(cx, *numberToString(0), CURRENT_ATTR);
result = cx->popValue();
for (uint32 k = 1; k < length; k++) {
String *id1 = numberToString(k);
String *id2 = numberToString(k - 1);
PropertyIterator it;
if (thisObj->hasOwnProperty(*id1, CURRENT_ATTR, Read, &it)) {
thisObj->getProperty(cx, *id1, CURRENT_ATTR);
thisObj->setProperty(cx, *id2, CURRENT_ATTR, cx->popValue());
}
else
thisObj->deleteProperty(*id2, CURRENT_ATTR);
}
thisObj->deleteProperty(*numberToString(length - 1), CURRENT_ATTR);
thisObj->setProperty(cx, widenCString("length"), CURRENT_ATTR, JSValue((float64)(length - 1)) );
return result;
}
static JSValue Array_slice(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ContextStackReplacement csr(cx);
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
JSArrayInstance *A = (JSArrayInstance *)Array_Type->newInstance(cx);
thisObj->getProperty(cx, widenCString("length"), CURRENT_ATTR);
JSValue result = cx->popValue();
uint32 length = (uint32)(result.toUInt32(cx).f64);
uint32 start, end;
if (argc < 1)
start = 0;
else {
int32 arg0 = (int32)(argv[0].toInt32(cx).f64);
if (arg0 < 0) {
arg0 += length;
if (arg0 < 0)
start = 0;
else
start = toUInt32(arg0);
}
else {
if (toUInt32(arg0) >= length) // cast ok since > 0
start = length;
else
start = toUInt32(arg0);
}
}
if (argc < 2)
end = length;
else {
int32 arg1 = (int32)(argv[1].toInt32(cx).f64);
if (arg1 < 0) {
arg1 += length;
if (arg1 < 0)
end = 0;
else
end = toUInt32(arg1);
}
else {
if (toUInt32(arg1) >= length)
end = length;
else
end = toUInt32(arg1);
}
}
uint32 n = 0;
while (start < end) {
String *id1 = numberToString(start);
PropertyIterator it;
if (thisObj->hasOwnProperty(*id1, CURRENT_ATTR, Read, &it)) {
String *id2 = numberToString(n);
thisObj->getProperty(cx, *id1, CURRENT_ATTR);
A->setProperty(cx, *id2, CURRENT_ATTR, cx->popValue());
}
n++;
start++;
}
A->setProperty(cx, widenCString("length"), CURRENT_ATTR, JSValue((float64)n) );
return JSValue(A);
}
static JSValue Array_sort(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue * /*argv*/, uint32 /*argc*/)
{
return kUndefinedValue;
}
static JSValue Array_splice(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
if (argc > 1) {
uint32 k;
ContextStackReplacement csr(cx);
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
thisObj->getProperty(cx, widenCString("length"), CURRENT_ATTR);
JSValue result = cx->popValue();
uint32 length = (uint32)(result.toUInt32(cx).f64);
JSArrayInstance *A = (JSArrayInstance *)Array_Type->newInstance(cx);
int32 arg0 = (int32)(argv[0].toInt32(cx).f64);
uint32 start;
if (arg0 < 0) {
arg0 += length;
if (arg0 < 0)
start = 0;
else
start = toUInt32(arg0);
}
else {
if (toUInt32(arg0) >= length)
start = length;
else
start = toUInt32(arg0);
}
uint32 deleteCount;
int32 arg1 = (int32)(argv[1].toInt32(cx).f64);
if (arg1 < 0)
deleteCount = 0;
else
if (toUInt32(arg1) >= (length - start))
deleteCount = length - start;
else
deleteCount = toUInt32(arg1);
for (k = 0; k < deleteCount; k++) {
String *id1 = numberToString(start + k);
PropertyIterator it;
if (thisObj->hasOwnProperty(*id1, CURRENT_ATTR, Read, &it)) {
String *id2 = numberToString(k);
thisObj->getProperty(cx, *id1, CURRENT_ATTR);
A->setProperty(cx, *id2, CURRENT_ATTR, cx->popValue());
}
}
A->setProperty(cx, widenCString("length"), CURRENT_ATTR, JSValue((float64)deleteCount) );
uint32 newItemCount = argc - 2;
if (newItemCount < deleteCount) {
for (k = start; k < (length - deleteCount); k++) {
String *id1 = numberToString(k + deleteCount);
String *id2 = numberToString(k + newItemCount);
PropertyIterator it;
if (thisObj->hasOwnProperty(*id1, CURRENT_ATTR, Read, &it)) {
thisObj->getProperty(cx, *id1, CURRENT_ATTR);
thisObj->setProperty(cx, *id2, CURRENT_ATTR, cx->popValue());
}
else
thisObj->deleteProperty(*id2, CURRENT_ATTR);
}
for (k = length; k > (length - deleteCount + newItemCount); k--) {
String *id1 = numberToString(k - 1);
thisObj->deleteProperty(*id1, CURRENT_ATTR);
}
}
else {
if (newItemCount > deleteCount) {
for (k = length - deleteCount; k > start; k--) {
String *id1 = numberToString(k + deleteCount - 1);
String *id2 = numberToString(k + newItemCount - 1);
PropertyIterator it;
if (thisObj->hasOwnProperty(*id1, CURRENT_ATTR, Read, &it)) {
thisObj->getProperty(cx, *id1, CURRENT_ATTR);
thisObj->setProperty(cx, *id2, CURRENT_ATTR, cx->popValue());
}
else
thisObj->deleteProperty(*id2, CURRENT_ATTR);
}
}
}
k = start;
for (uint32 i = 2; i < argc; i++) {
String *id1 = numberToString(k++);
thisObj->setProperty(cx, *id1, CURRENT_ATTR, argv[i]);
}
thisObj->setProperty(cx, widenCString("length"), CURRENT_ATTR, JSValue((float64)(length - deleteCount + newItemCount)) );
return JSValue(A);
}
return kUndefinedValue;
}
static JSValue Array_unshift(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ContextStackReplacement csr(cx);
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
thisObj->getProperty(cx, widenCString("length"), CURRENT_ATTR);
JSValue result = cx->popValue();
uint32 length = (uint32)(result.toUInt32(cx).f64);
uint32 k;
for (k = length; k > 0; k--) {
String *id1 = numberToString(k - 1);
String *id2 = numberToString(k + argc - 1);
PropertyIterator it;
if (thisObj->hasOwnProperty(*id1, CURRENT_ATTR, Read, &it)) {
thisObj->getProperty(cx, *id1, CURRENT_ATTR);
thisObj->setProperty(cx, *id2, CURRENT_ATTR, cx->popValue());
}
else
thisObj->deleteProperty(*id2, CURRENT_ATTR);
}
for (k = 0; k < argc; k++) {
String *id1 = numberToString(k);
thisObj->setProperty(cx, *id1, CURRENT_ATTR, argv[k]);
}
thisObj->setProperty(cx, widenCString("length"), CURRENT_ATTR, JSValue((float64)(length + argc)) );
return thisValue;
}
Context::PrototypeFunctions *getArrayProtos()
{
Context::ProtoFunDef arrayProtos[] =
{
{ "toString", String_Type, 0, Array_toString },
{ "toLocaleString", String_Type, 0, Array_toString }, // XXX
{ "toSource", String_Type, 0, Array_toSource },
{ "push", Number_Type, 1, Array_push },
{ "pop", Object_Type, 0, Array_pop },
{ "concat", Array_Type, 1, Array_concat },
{ "join", String_Type, 1, Array_join },
{ "reverse", Array_Type, 0, Array_reverse },
{ "shift", Object_Type, 0, Array_shift },
{ "slice", Array_Type, 2, Array_slice },
{ "sort", Array_Type, 1, Array_sort },
{ "splice", Array_Type, 2, Array_splice },
{ "unshift", Number_Type, 1, Array_unshift },
{ NULL }
};
return new Context::PrototypeFunctions(&arrayProtos[0]);
}
}
}

48
js2/src/jsarray.h Normal file
Просмотреть файл

@ -0,0 +1,48 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
namespace JavaScript {
namespace JS2Runtime {
extern JSValue Array_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc);
extern JSValue Array_concat(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc);
Context::PrototypeFunctions *getArrayProtos();
}
}

Просмотреть файл

@ -31,178 +31,231 @@
* file under either the NPL or the GPL.
*/
#include <math.h>
#ifdef _WIN32
// Turn off warnings about identifiers too long in browser information
#pragma warning(disable: 4786)
#pragma warning(disable: 4711)
#pragma warning(disable: 4710)
#endif
#include <algorithm>
#include "parser.h"
#include "numerics.h"
#include "js2runtime.h"
#include "jsmath.h"
namespace JavaScript {
namespace JSMathClass {
#include "fdlibm_ns.h"
using namespace JSTypes;
namespace JavaScript {
namespace JS2Runtime {
#ifndef M_E
#define M_E 2.7182818284590452354
#define M_E 2.7182818284590452354
#endif
#ifndef M_LOG2E
#define M_LOG2E 1.4426950408889634074
#define M_LOG2E 1.4426950408889634074
#endif
#ifndef M_LOG10E
#define M_LOG10E 0.43429448190325182765
#define M_LOG10E 0.43429448190325182765
#endif
#ifndef M_LN2
#define M_LN2 0.69314718055994530942
#define M_LN2 0.69314718055994530942
#endif
#ifndef M_LN10
#define M_LN10 2.30258509299404568402
#define M_LN10 2.30258509299404568402
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846
#define M_PI 3.14159265358979323846
#endif
#ifndef M_SQRT2
#define M_SQRT2 1.41421356237309504880
#define M_SQRT2 1.41421356237309504880
#endif
#ifndef M_SQRT1_2
#define M_SQRT1_2 0.70710678118654752440
#define M_SQRT1_2 0.70710678118654752440
#endif
#define M_CONSTANTS_COUNT 8
/*
Concept copied from SpiderMonkey -
fd_XXX needs to be defined either as a call to the fdlibm routine
or the native C library routine depending on the platform
*/
#define JS_USE_FDLIBM_MATH 0
#if !JS_USE_FDLIBM_MATH
/*
* Use system provided math routines.
*/
#define fd_acos acos
#define fd_asin asin
#define fd_atan atan
#define fd_atan2 atan2
#define fd_ceil ceil
#define fd_copysign copysign
#define fd_cos cos
#define fd_exp exp
#define fd_fabs fabs
#define fd_floor floor
#define fd_fmod fmod
#define fd_log log
#define fd_pow pow
#define fd_sin sin
#define fd_sqrt sqrt
#define fd_tan tan
#endif
static JSValue math_abs(Context *, const JSValues& argv)
static JSValue Math_abs(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
if (argv.size() > 0) {
JSValue num = argv[1].toNumber();
if (num.isNaN()) return num;
if (num.isNegativeZero()) return kPositiveZero;
if (num.isNegativeInfinity()) return kPositiveInfinity;
if (num.f64 < 0) return JSValue(-num.f64);
return num;
if (argc == 0)
return kNaNValue;
else
return JSValue(fd::fabs(argv[0].toNumber(cx).f64));
}
static JSValue Math_acos(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
if (argc == 0)
return kNaNValue;
return JSValue(fd::acos(argv[0].toNumber(cx).f64));
}
static JSValue Math_asin(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
if (argc == 0)
return kNaNValue;
return JSValue(fd::asin(argv[0].toNumber(cx).f64));
}
static JSValue Math_atan(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
if (argc == 0)
return kNaNValue;
return JSValue(fd::atan(argv[0].toNumber(cx).f64));
}
static JSValue Math_atan2(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
if (argc <= 1)
return kNaNValue;
float64 y = argv[0].toNumber(cx).f64;
float64 x = argv[1].toNumber(cx).f64;
return JSValue(fd::atan2(y, x));
}
static JSValue Math_ceil(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
if (argc == 0)
return kNaNValue;
return JSValue(fd::ceil(argv[0].toNumber(cx).f64));
}
static JSValue Math_cos(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
if (argc == 0)
return kNaNValue;
return JSValue(fd::cos(argv[0].toNumber(cx).f64));
}
static JSValue Math_exp(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
if (argc == 0)
return kNaNValue;
return JSValue(fd::exp(argv[0].toNumber(cx).f64));
}
static JSValue Math_floor(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
if (argc == 0)
return kNaNValue;
else
return JSValue(fd::floor(argv[0].toNumber(cx).f64));
}
static JSValue Math_log(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
if (argc == 0)
return kNaNValue;
return JSValue(fd::log(argv[0].toNumber(cx).f64));
}
static JSValue Math_max(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
if (argc == 0)
return kNaNValue;
float64 result = argv[0].toNumber(cx).f64;
for (uint32 i = 1; i < argc; ++i) {
float64 arg = argv[i].toNumber(cx).f64;
if (arg > result)
result = arg;
}
return kUndefinedValue;
return JSValue(result);
}
static JSValue Math_min(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
if (argc == 0)
return kNaNValue;
float64 result = argv[0].toNumber(cx).f64;
for (uint32 i = 1; i < argc; ++i) {
float64 arg = argv[i].toNumber(cx).f64;
if (arg < result)
result = arg;
}
return JSValue(result);
}
static JSValue Math_pow(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
if (argc < 1)
return kNaNValue;
return JSValue(fd::pow(argv[0].toNumber(cx).f64, argv[1].toNumber(cx).f64));
}
static JSValue Math_random(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue * /*argv*/, uint32 /*argc*/)
{
return JSValue(42.0);
}
static JSValue Math_round(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
if (argc == 0)
return kNaNValue;
float64 x = argv[0].toNumber(cx).f64;
return JSValue( fd::copysign( fd::floor(x + 0.5), x ) );
}
static JSValue Math_sin(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
if (argc == 0)
return kNaNValue;
return JSValue(fd::sin(argv[0].toNumber(cx).f64));
}
static JSValue Math_sqrt(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
if (argc == 0)
return kNaNValue;
return JSValue(fd::sqrt(argv[0].toNumber(cx).f64));
}
static JSValue Math_tan(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
if (argc == 0)
return kNaNValue;
return JSValue(fd::tan(argv[0].toNumber(cx).f64));
}
static JSValue math_acos(Context *, const JSValues& argv)
{
if (argv.size() > 0) {
JSValue num = argv[1].toNumber();
return JSValue(fd_acos(num.f64));
}
return kUndefinedValue;
}
static JSValue math_asin(Context *, const JSValues& argv)
{
if (argv.size() > 0) {
JSValue num = argv[1].toNumber();
return JSValue(fd_asin(num.f64));
}
return kUndefinedValue;
}
static JSValue math_atan(Context *, const JSValues& argv)
{
if (argv.size() > 0) {
JSValue num = argv[1].toNumber();
return JSValue(fd_atan(num.f64));
}
return kUndefinedValue;
}
static JSValue math_atan2(Context *, const JSValues& argv)
{
if (argv.size() > 1) {
JSValue num1 = argv[1].toNumber();
JSValue num2 = argv[1].toNumber();
return JSValue(fd_atan2(num1.f64, num2.f64));
}
return kUndefinedValue;
}
static JSValue math_ceil(Context *, const JSValues& argv)
{
if (argv.size() > 0) {
JSValue num = argv[1].toNumber();
return JSValue(fd_ceil(num.f64));
}
return kUndefinedValue;
}
struct MathFunctionEntry {
struct {
char *name;
JSNativeFunction::JSCode fn;
} MathFunctions[] = {
{ "abs", math_abs },
{ "acos", math_acos },
{ "asin", math_asin },
{ "atan", math_atan },
{ "atan2", math_atan2 },
{ "ceil", math_ceil },
{ "acos", math_acos },
{ "acos", math_acos }
float64 value;
} MathObjectConstants[M_CONSTANTS_COUNT] = {
{ "E", M_E },
{ "LOG2E", M_LOG2E },
{ "LOG10E", M_LOG10E },
{ "LN2", M_LN2 },
{ "LN10", M_LN10 },
{ "PI", M_PI },
{ "SQRT2", M_SQRT2 },
{ "SQRT1_2",M_SQRT1_2 }
};
struct MathConstantEntry {
struct MathObjectFunctionDef {
char *name;
double value;
} MathConstants[] = {
{ "E", M_E },
{ "LOG2E", M_LOG2E },
{ "LOG10E", M_LOG10E },
{ "LN2", M_LN2 },
{ "LN10", M_LN10 },
{ "PI", M_PI },
{ "SQRT2", M_SQRT2 },
{ "SQRT1_2", M_SQRT1_2 }
JSFunction::NativeCode *imp;
} MathObjectFunctions[] = {
{ "abs", Math_abs },
{ "acos", Math_acos },
{ "asin", Math_asin },
{ "atan", Math_atan },
{ "atan2", Math_atan2 },
{ "ceil", Math_ceil },
{ "cos", Math_cos },
{ "exp", Math_exp },
{ "floor", Math_floor },
{ "log", Math_log },
{ "max", Math_max },
{ "min", Math_min },
{ "pow", Math_pow },
{ "random", Math_random },
{ "round", Math_round },
{ "sin", Math_sin },
{ "sqrt", Math_sqrt },
{ "tan", Math_tan },
};
// There is no constructor for Math, we simply initialize
// the properties of the Math object
void JSMath::initMathObject(JSScope *g)
void initMathObject(Context *cx, JSObject *mathObj)
{
uint i;
JSMath *m = new JSMath();
m->setClass(new JSString("Math"));
uint32 i;
for (i = 0; i < M_CONSTANTS_COUNT; i++)
mathObj->defineVariable(cx, widenCString(MathObjectConstants[i].name),
(NamespaceList *)(NULL), Number_Type, JSValue(MathObjectConstants[i].value));
for (i = 0; i < sizeof(MathObjectFunctions) / sizeof(MathObjectFunctionDef); i++) {
JSFunction *f = new JSFunction(MathObjectFunctions[i].imp, Number_Type);
mathObj->defineVariable(cx, widenCString(MathObjectFunctions[i].name),
(NamespaceList *)(NULL), Number_Type, JSValue(f));
}
}
for (i = 0; i < sizeof(MathFunctions) / sizeof(MathFunctionEntry); i++)
m->setProperty(widenCString(MathFunctions[i].name), JSValue(new JSNativeFunction(MathFunctions[i].fn) ) );
for (i = 0; i < sizeof(MathConstants) / sizeof(MathConstantEntry); i++)
m->setProperty(widenCString(MathConstants[i].name), JSValue(MathConstants[i].value) );
g->setProperty(widenCString("Math"), JSValue(m));
}
} /* JSMathClass */
} /* JavaScript */
}

Просмотреть файл

@ -31,28 +31,11 @@
* file under either the NPL or the GPL.
*/
#ifndef jsmath_h
#define jsmath_h
namespace JavaScript {
namespace JS2Runtime {
#include "jstypes.h"
namespace JavaScript {
namespace JSMathClass {
using JSTypes::JSObject;
using JSTypes::JSString;
using JSTypes::JSScope;
class JSMath : public JSObject {
private:
JSMath() { }
public:
static void initMathObject(JSScope *g);
};
} /* JSMathClass */
} /* JavaScript */
void initMathObject(Context *cx, JSObject *mathObj);
#endif jsmath_h
}
}

444
js2/src/jsstring.cpp Normal file
Просмотреть файл

@ -0,0 +1,444 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#ifdef _WIN32
// Turn off warnings about identifiers too long in browser information
#pragma warning(disable: 4786)
#pragma warning(disable: 4711)
#pragma warning(disable: 4710)
#endif
#include <algorithm>
#include "parser.h"
#include "numerics.h"
#include "js2runtime.h"
#include "jsstring.h"
namespace JavaScript {
namespace JS2Runtime {
JSValue String_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
JSValue thatValue = thisValue;
if (thatValue.isNull())
thatValue = String_Type->newInstance(cx);
ASSERT(thatValue.isObject());
JSObject *thisObj = thatValue.object;
ASSERT(dynamic_cast<JSStringInstance *>(thisObj));
JSStringInstance *strInst = (JSStringInstance *)thisObj;
if (argc > 0)
thisObj->mPrivate = (void *)(new String(*argv[0].toString(cx).string));
else
thisObj->mPrivate = (void *)(new String(widenCString("")));
strInst->mLength = ((String *)(thisObj->mPrivate))->size();
return thatValue;
}
JSValue String_fromCharCode(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
String *resultStr = new String();
resultStr->reserve(argc);
for (uint32 i = 0; i < argc; i++)
*resultStr += (char16)(argv[i].toUInt16(cx).f64);
return JSValue(resultStr);
}
static JSValue String_toString(Context * /*cx*/, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
return JSValue((String *)thisObj->mPrivate);
}
struct MatchResult {
bool failure;
uint32 endIndex;
String **captures;
};
static void splitMatch(const String *S, uint32 q, const String *R, MatchResult &result)
{
result.failure = true;
result.captures = NULL;
uint32 r = R->size();
uint32 s = S->size();
if ((q + r) > s)
return;
for (uint32 i = 0; i < r; i++) {
if ((*S)[q + i] != (*R)[i])
return;
}
result.endIndex = q + r;
result.failure = false;
}
static JSValue String_split(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ContextStackReplacement csr(cx);
ASSERT(thisValue.isObject());
JSValue S = thisValue.toString(cx);
JSArrayInstance *A = (JSArrayInstance *)Array_Type->newInstance(cx);
uint32 lim;
JSValue separatorV = (argc > 0) ? argv[0] : kUndefinedValue;
JSValue limitV = (argc > 1) ? argv[1] : kUndefinedValue;
if (limitV.isUndefined())
lim = (uint32)(two32minus1);
else
lim = (uint32)(limitV.toUInt32(cx).f64);
uint32 s = S.string->size();
uint32 p = 0;
// XXX if separatorV.isRegExp() -->
const String *R = separatorV.toString(cx).string;
if (lim == 0)
return JSValue(A);
if (separatorV.isUndefined()) {
A->setProperty(cx, widenCString("0"), NULL, S);
return JSValue(A);
}
if (s == 0) {
MatchResult z;
splitMatch(S.string, 0, R, z);
if (!z.failure)
return JSValue(A);
A->setProperty(cx, widenCString("0"), NULL, S);
return JSValue(A);
}
while (true) {
uint32 q = p;
step11:
if (q == s) {
String *T = new String(*S.string, p, (s - p));
JSValue v(T);
A->setProperty(cx, *numberToString(A->mLength), NULL, v);
return JSValue(A);
}
MatchResult z;
splitMatch(S.string, q, R, z);
if (z.failure) {
q = q + 1;
goto step11;
}
uint32 e = z.endIndex;
if (e == p) {
q = q + 1;
goto step11;
}
String *T = new String(*S.string, p, (q - p));
JSValue v(T);
A->setProperty(cx, *numberToString(A->mLength), NULL, v);
if (A->mLength == lim)
return JSValue(A);
p = e;
// step 20 --> 27, handle captures array (we know it's empty for non regexp)
}
}
static JSValue String_valueOf(Context * /*cx*/, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
ASSERT(thisValue.isObject());
if (thisValue.isString())
return thisValue;
else
throw Exception(Exception::typeError, "String.valueOf called on");
return kUndefinedValue;
}
static JSValue String_charAt(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ASSERT(thisValue.isObject());
const String *str = thisValue.toString(cx).string;
uint32 pos = 0;
if (argc > 0)
pos = (uint32)(argv[0].toInt32(cx).f64);
if ((pos < 0) || (pos >= str->size()))
return JSValue(new String()); // have an empty string kValue somewhere?
else
return JSValue(new String(1, (*str)[pos]));
}
static JSValue String_charCodeAt(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ASSERT(thisValue.isObject());
const String *str = thisValue.toString(cx).string;
uint32 pos = 0;
if (argc > 0)
pos = (uint32)(argv[0].toInt32(cx).f64);
if ((pos < 0) || (pos >= str->size()))
return kNaNValue;
else
return JSValue((float64)(*str)[pos]);
}
static JSValue String_concat(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ASSERT(thisValue.isObject());
const String *str = thisValue.toString(cx).string;
String *result = new String(*str);
for (uint32 i = 0; i < argc; i++) {
*result += *argv[i].toString(cx).string;
}
return JSValue(result);
}
static JSValue String_indexOf(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ASSERT(thisValue.isObject());
if (argc == 0)
return JSValue(-1.0);
const String *str = thisValue.toString(cx).string;
const String *searchStr = argv[0].toString(cx).string;
uint32 pos = 0;
if (argc > 1) {
int32 arg1 = (int32)(argv[1].toInt32(cx).f64);
if (arg1 < 0)
pos = 0;
else
if (toUInt32(arg1) >= str->size())
pos = str->size();
else
pos = toUInt32(arg1);
}
pos = str->find(*searchStr, pos);
if (pos == String::npos)
return JSValue(-1.0);
return JSValue((float64)pos);
}
static JSValue String_lastIndexOf(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ASSERT(thisValue.isObject());
if (argc == 0)
return JSValue(-1.0);
const String *str = thisValue.toString(cx).string;
const String *searchStr = argv[0].toString(cx).string;
uint32 pos = 0;
if (argc > 1) {
float64 fpos = argv[1].toNumber(cx).f64;
if (fpos != fpos)
pos = str->size();
else {
int32 arg1 = (int32)(fpos);
if (arg1 < 0)
pos = 0;
else
if (toUInt32(arg1) >= str->size())
pos = str->size();
else
pos = toUInt32(arg1);
}
}
pos = str->rfind(*searchStr, pos);
if (pos == String::npos)
return JSValue(-1.0);
return JSValue((float64)pos);
}
static JSValue String_localeCompare(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue * /*argv*/, uint32 /*argc*/)
{
return kUndefinedValue;
}
static JSValue String_toLowerCase(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
ASSERT(thisValue.isObject());
JSValue S = thisValue.toString(cx);
String *result = new String(*S.string);
for (String::iterator i = result->begin(), end = result->end(); i != end; i++)
*i = toLower(*i);
return JSValue(result);
}
static JSValue String_toUpperCase(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
ASSERT(thisValue.isObject());
JSValue S = thisValue.toString(cx);
String *result = new String(*S.string);
for (String::iterator i = result->begin(), end = result->end(); i != end; i++)
*i = toUpper(*i);
return JSValue(result);
}
static JSValue String_slice(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ASSERT(thisValue.isObject());
const String *sourceString = thisValue.toString(cx).string;
uint32 sourceLength = sourceString->size();
uint32 start, end;
if (argc > 0) {
int32 arg0 = (int32)(argv[0].toInt32(cx).f64);
if (arg0 < 0) {
arg0 += sourceLength;
if (arg0 < 0)
start = 0;
else
start = toUInt32(arg0);
}
else {
if (toUInt32(arg0) < sourceLength)
start = toUInt32(arg0);
else
start = sourceLength;
}
}
else
start = 0;
if (argc > 1) {
int32 arg1 = (int32)(argv[1].toInt32(cx).f64);
if (arg1 < 0) {
arg1 += sourceLength;
if (arg1 < 0)
end = 0;
else
end = toUInt32(arg1);
}
else {
if (toUInt32(arg1) < sourceLength)
end = toUInt32(arg1);
else
end = sourceLength;
}
}
else
end = sourceLength;
if (start > end)
return JSValue(new String());
return JSValue(new String(sourceString->substr(start, end - start)));
}
static JSValue String_substring(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ASSERT(thisValue.isObject());
const String *sourceString = thisValue.toString(cx).string;
uint32 sourceLength = sourceString->size();
uint32 start, end;
if (argc > 0) {
int32 arg0 = (int32)(argv[0].toInt32(cx).f64);
if (arg0 < 0)
start = 0;
else
if (toUInt32(arg0) < sourceLength)
start = toUInt32(arg0);
else
start = sourceLength;
}
else
start = 0;
if (argc > 1) {
int32 arg1 = (int32)(argv[1].toInt32(cx).f64);
if (arg1 < 0)
end = 0;
else
if (toUInt32(arg1) < sourceLength)
end = toUInt32(arg1);
else
end = sourceLength;
}
else
end = sourceLength;
if (start > end) {
uint32 t = start;
start = end;
end = t;
}
return JSValue(new String(sourceString->substr(start, end - start)));
}
Context::PrototypeFunctions *getStringProtos()
{
Context::ProtoFunDef stringProtos[] =
{
{ "toString", String_Type, 0, String_toString },
{ "valueof", String_Type, 0, String_valueOf },
{ "charAt", String_Type, 1, String_charAt },
{ "charCodeAt", Number_Type, 1, String_charCodeAt },
{ "concat", String_Type, 1, String_concat },
{ "indexOf", Number_Type, 1, String_indexOf },
{ "lastIndexOf", Number_Type, 1, String_lastIndexOf },
{ "localeCompare", Number_Type, 1, String_localeCompare },
{ "slice", String_Type, 2, String_slice },
{ "split", Array_Type, 2, String_split },
{ "substring", String_Type, 2, String_substring },
{ "toSource", String_Type, 0, String_toString },
{ "toLocaleUpperCase", String_Type, 0, String_toUpperCase }, // (sic)
{ "toLocaleLowerCase", String_Type, 0, String_toLowerCase }, // (sic)
{ "toUpperCase", String_Type, 0, String_toUpperCase },
{ "toLowerCase", String_Type, 0, String_toLowerCase },
{ NULL }
};
return new Context::PrototypeFunctions(&stringProtos[0]);
}
}
}

45
js2/src/jsstring.h Normal file
Просмотреть файл

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
namespace JavaScript {
namespace JS2Runtime {
extern JSValue String_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc);
extern JSValue String_fromCharCode(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc);
Context::PrototypeFunctions *getStringProtos();
}
}

Просмотреть файл

@ -6,7 +6,7 @@
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
@ -52,6 +52,18 @@ JS::Lexer::Lexer(World &world, const String &source, const String &sourceLocatio
}
// Skip past the next token, which must have been either peeked or read and then unread.
// skip is faster than get but must not be called if the next token has not been seen yet.
void JS::Lexer::skip()
{
ASSERT(nTokensFwd);
if (++nextToken == tokens + tokenBufferSize)
nextToken = tokens;
--nTokensFwd;
DEBUG_ONLY(++nTokensBack);
}
// Get and return the next token. The token remains valid until the next
// call to this Lexer. If the Reader reached the end of file, return a
// Token whose Kind is end. The caller may alter the value of this Token
@ -333,7 +345,7 @@ bool JS::Lexer::lexNumeral()
reader.recordChar('0');
ch = getChar();
if ((ch&~0x20) == 'X') {
uint32 pos = reader.getPos();
size_t pos = reader.getPos();
char16 ch2 = getChar();
if (isASCIIHexDigit(ch2, digit)) {
reader.recordChar(ch);
@ -354,7 +366,7 @@ bool JS::Lexer::lexNumeral()
ch = getChar();
}
if ((ch&~0x20) == 'E') {
uint32 pos = reader.getPos();
size_t pos = reader.getPos();
char16 ch2 = getChar();
char16 sign = 0;
if (ch2 == '+' || ch2 == '-') {

Просмотреть файл

@ -6,7 +6,7 @@
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
@ -66,12 +66,13 @@ namespace JavaScript
Lexer(World &world, const String &source, const String &sourceLocation, uint32 initialLineNum = 1);
void skip();
const Token &get(bool preferRegExp);
const Token *eat(bool preferRegExp, Token::Kind kind);
const Token &peek(bool preferRegExp);
void redesignate(bool preferRegExp);
void unget();
uint32 getPos() const;
size_t getPos() const;
private:
void syntaxError(const char *message, uint backUp = 1);
@ -95,7 +96,7 @@ namespace JavaScript
#endif
// Return the position of the first character of the next token, which must have been peeked.
inline uint32 Lexer::getPos() const
inline size_t Lexer::getPos() const
{
ASSERT(nTokensFwd);
return nextToken->getPos();

Просмотреть файл

@ -1,43 +1,43 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#include <memory>
#include "mem.h"
namespace JavaScript
{
namespace JS = JavaScript;
//
// Zones
//
@ -45,137 +45,133 @@ namespace JavaScript
// #define DEBUG_ZONE to allocate each object in its own malloc block.
// This allows tools such as Purify to do bounds checking on all blocks.
// Construct a Zone that allocates memory in chunks of the given size.
Zone::Zone(size_t blockSize):
headers(0), freeBegin(0), freeEnd(0), blockSize(blockSize)
{
ASSERT(blockSize && !(blockSize & basicAlignment-1));
}
JS::Zone::Zone(size_t blockSize):
headers(0), freeBegin(0), freeEnd(0), blockSize(blockSize)
{
ASSERT(blockSize && !(blockSize & basicAlignment-1));
}
// Deallocate the Zone's blocks.
void
Zone::clear()
{
Header *h = headers;
while (h) {
Header *next = h->next;
STD::free(h);
h = next;
}
headers = 0;
void JS::Zone::clear()
{
Header *h = headers;
while (h) {
Header *next = h->next;
STD::free(h);
h = next;
}
headers = 0;
}
// Allocate a fully aligned block of the given size.
// Throw bad_alloc if out of memory, without corrupting any of the Zone data
// structures.
void *
Zone::newBlock(size_t size)
{
Header *h = static_cast<Header *>(STD::malloc(sizeof(Header) + size));
h->next = headers;
headers = h;
return h+1;
}
// Allocate a naturally-aligned object of the given size (in bytes). Throw
// bad_alloc if out of memory, without corrupting any of the Zone data
// structures.
void *
Zone::allocate(size_t size)
{
ASSERT(size); // Can't allocate zero-size blocks.
#ifdef DEBUG_ZONE
return newBlock(size);
#else
// Round up to natural alignment if necessary
size = size + (basicAlignment-1) & -basicAlignment;
char *p = freeBegin;
size_t freeBytes = static_cast<size_t>(freeEnd - p);
void *JS::Zone::newBlock(size_t size)
{
Header *h = static_cast<Header *>(STD::malloc(sizeof(Header) + size));
h->next = headers;
headers = h;
return h+1;
}
if (size > freeBytes) {
// If freeBytes is at least a quarter of blockSize, allocate
//a separate block.
if (freeBytes<<2 >= blockSize || size >= blockSize)
return newBlock(size);
p = static_cast<char *>(newBlock(blockSize));
freeEnd = p + blockSize;
}
freeBegin = p + size;
return p;
#endif
// Allocate a naturally-aligned object of the given size (in bytes). Throw
// bad_alloc if out of memory, without corrupting any of the Zone data structures.
void *JS::Zone::allocate(size_t size)
{
ASSERT(size); // Can't allocate zero-size blocks.
#ifdef DEBUG_ZONE
return newBlock(size);
#else
// Round up to natural alignment if necessary
size = size + (basicAlignment-1) & -basicAlignment;
char *p = freeBegin;
size_t freeBytes = toSize_t(freeEnd - p);
if (size > freeBytes) {
// If freeBytes is at least a quarter of blockSize, allocate a separate block.
if (freeBytes<<2 >= blockSize || size >= blockSize)
return newBlock(size);
p = static_cast<char *>(newBlock(blockSize));
freeEnd = p + blockSize;
}
freeBegin = p + size;
return p;
#endif
}
// Same as allocate but does not align size up to basicAlignment. Thus, the
// next object allocated in the zone will immediately follow this one if it
// falls in the same zone block.
// Use this when all objects in the zone have the same size.
void *
Zone::allocateUnaligned(size_t size)
{
ASSERT(size); // Can't allocate zero-size blocks.
void *JS::Zone::allocateUnaligned(size_t size)
{
ASSERT(size); // Can't allocate zero-size blocks.
#ifdef DEBUG_ZONE
return newBlock(size);
return newBlock(size);
#else
char *p = freeBegin;
size_t freeBytes = static_cast<size_t>(freeEnd - p);
if (size > freeBytes) {
// If freeBytes is at least a quarter of blockSize, allocate a
// separate block.
if (freeBytes<<2 >= blockSize || size >= blockSize)
return newBlock(size);
p = static_cast<char *>(newBlock(blockSize));
freeEnd = p + blockSize;
}
freeBegin = p + size;
return p;
char *p = freeBegin;
size_t freeBytes = toSize_t(freeEnd - p);
if (size > freeBytes) {
// If freeBytes is at least a quarter of blockSize, allocate a separate block.
if (freeBytes<<2 >= blockSize || size >= blockSize)
return newBlock(size);
p = static_cast<char *>(newBlock(blockSize));
freeEnd = p + blockSize;
}
freeBegin = p + size;
return p;
#endif
}
}
//
// Arenas
//
struct Arena::DestructorEntry : ArenaObject {
DestructorEntry *next; // Next destructor registration in linked list
void (*destructor)(void *); // Destructor function
void *object; // Object on which to call the destructor
DestructorEntry (void (*destructor)(void *), void *object) :
destructor(destructor), object(object) {}
};
struct JS::Arena::DestructorEntry: JS::ArenaObject {
DestructorEntry *next; // Next destructor registration in linked list
void (*destructor)(void *); // Destructor function
void *object; // Object on which to call the destructor
DestructorEntry (void (*destructor)(void *), void *object) :
destructor(destructor), object(object) {}
};
// Call the Arena's registered destructors.
void
Arena::runDestructors()
{
DestructorEntry *e = destructorEntries;
while (e) {
e->destructor(e->object);
e = e->next;
}
destructorEntries = 0;
void JS::Arena::runDestructors()
{
DestructorEntry *e = destructorEntries;
while (e) {
e->destructor(e->object);
e = e->next;
}
destructorEntries = 0;
}
// Ensure that object's destructor is called at the time the arena is
// deallocated or cleared. The destructors will be called in reverse order of
// being registered. registerDestructor might itself runs out of memory, in
// which case it immediately calls object's destructor before throwing
// bad_alloc.
void
Arena::newDestructorEntry(void (*destructor)(void *), void *object)
{
try {
DestructorEntry *e = new(*this) DestructorEntry(destructor, object);
e->next = destructorEntries;
destructorEntries = e;
} catch (...) {
destructor(object);
throw;
}
void JS::Arena::newDestructorEntry(void (*destructor)(void *), void *object)
{
try {
DestructorEntry *e = new(*this) DestructorEntry(destructor, object);
e->next = destructorEntries;
destructorEntries = e;
} catch (...) {
destructor(object);
throw;
}
}

Просмотреть файл

@ -6,7 +6,7 @@
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
@ -17,7 +17,7 @@
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
@ -40,28 +40,26 @@
namespace JavaScript
{
//
// Zones
//
// A zone is a region of memory from which objects can be allocated
// individually.
// The memory in a zone is deallocated when the zone is deallocated or its
// clear method called.
// A zone is a region of memory from which objects can be allocated
// individually.
// The memory in a zone is deallocated when the zone is deallocated or its
// clear method called.
class Zone {
union Header {
Header *next; // Next block header in linked list
// Padding to ensure following block is fully aligned
char padding[basicAlignment];
Header *next; // Next block header in linked list
char padding[basicAlignment];// Padding to ensure following block is fully aligned
};// Block data follows header
Header *headers; // Linked list of allocated blocks
char *freeBegin; // Pointer to free bytes left in current block
char *freeEnd; // Pointer to end of free bytes left in current block
size_t blockSize; // Size of individual arena blocks
Header *headers; // Linked list of allocated blocks
char *freeBegin; // Pointer to free bytes left in current block
char *freeEnd; // Pointer to end of free bytes left in current block
size_t blockSize; // Size of individual arena blocks
public:
explicit Zone(size_t blockSize = 1024);
private:
@ -70,7 +68,7 @@ namespace JavaScript
public:
void clear();
~Zone() {clear();}
private:
void *newBlock(size_t size);
public:
@ -78,6 +76,7 @@ namespace JavaScript
void *allocateUnaligned(size_t size);
};
//
// Arenas
//
@ -97,80 +96,68 @@ namespace JavaScript
};
#endif
// An arena is a region of memory from which objects either derived from
// ArenaObject or allocated using a ArenaAllocator can be allocated. Deleting
// these objects individually runs the destructors, if any, but does not
// deallocate the memory. On the other hand, the entire arena can be
// deallocated as a whole.
//
// One may also allocate other objects in an arena by using the Arena
// specialization of the global operator new. However, be careful not to
// delete any such objects explicitly!
//
// Destructors can be registered for objects (or parts of objects) allocated
// in the arena. These destructors are called, in reverse order of being
// registered, at the time the arena is deallocated or cleared. When
// registering destructors for an object O be careful not to delete O manually
// because that would run its destructor twice.
// An arena is a region of memory from which objects either derived from
// ArenaObject or allocated using a ArenaAllocator can be allocated. Deleting
// these objects individually runs the destructors, if any, but does not
// deallocate the memory. On the other hand, the entire arena can be
// deallocated as a whole.
//
// One may also allocate other objects in an arena by using the Arena
// specialization of the global operator new. However, be careful not to
// delete any such objects explicitly!
//
// Destructors can be registered for objects (or parts of objects) allocated
// in the arena. These destructors are called, in reverse order of being
// registered, at the time the arena is deallocated or cleared. When
// registering destructors for an object O be careful not to delete O manually
// because that would run its destructor twice.
class Arena: public Zone {
struct DestructorEntry;
// Linked list of destructor registrations, ordered from most to
// least recently registered
DestructorEntry *destructorEntries;
DestructorEntry *destructorEntries;// Linked list of destructor registrations, ordered from most to least recently registered
public:
explicit Arena(size_t blockSize = 1024):
Zone(blockSize), destructorEntries(0) {}
explicit Arena(size_t blockSize = 1024): Zone(blockSize), destructorEntries(0) {}
private:
void runDestructors();
public:
void clear() {runDestructors(); Zone::clear();}
~Arena() {runDestructors();}
private:
void newDestructorEntry(void (*destructor)(void *), void *object);
public:
// Ensure that object's destructor is called at the time the arena is
// deallocated or cleared.
// Ensure that object's destructor is called at the time the arena is deallocated or cleared.
// The destructors will be called in reverse order of being registered.
// registerDestructor might itself runs out of memory, in which case
// it immediately
// registerDestructor might itself runs out of memory, in which case it immediately
// calls object's destructor before throwing bad_alloc.
#ifndef _WIN32
template<class T> void registerDestructor(T *object) {
newDestructorEntry(&classDestructor<T>, object);
}
template<class T> void registerDestructor(T *object) {newDestructorEntry(&classDestructor<T>, object);}
#else
template<class T> void registerDestructor(T *object) {
newDestructorEntry(&DestructorHolder<T>::destroy, object);
}
template<class T> void registerDestructor(T *object) {newDestructorEntry(&DestructorHolder<T>::destroy, object);}
#endif
};
};
// Objects derived from this class will be contained in the Arena
// passed to the new operator.
// Objects derived from this class will be contained in the Arena
// passed to the new operator.
struct ArenaObject {
void *operator new(size_t size, Arena &arena) {
return arena.allocate(size);
}
void *operator new[](size_t size, Arena &arena) {
return arena.allocate(size);
}
void *operator new(size_t size, Arena &arena) {return arena.allocate(size);}
void *operator new[](size_t size, Arena &arena) {return arena.allocate(size);}
void operator delete(void *, Arena &) {}
void operator delete[](void *, Arena &) {}
private:
private:
void operator delete(void *, size_t) {}
void operator delete[](void *) {}
};
// Objects allocated by passing this class to standard containers will
// be contained in the Arena passed to the ArenaAllocator's constructor.
// Objects allocated by passing this class to standard containers will
// be contained in the Arena passed to the ArenaAllocator's constructor.
template<class T> class ArenaAllocator {
Arena &arena;
public:
typedef T value_type;
typedef size_t size_type;
@ -179,58 +166,51 @@ namespace JavaScript
typedef const T *const_pointer;
typedef T &reference;
typedef const T &const_reference;
static pointer address(reference r) {return &r;}
static const_pointer address(const_reference r) {return &r;}
ArenaAllocator(Arena &arena): arena(arena) {}
template<class U> ArenaAllocator(const ArenaAllocator<U> &u) :
arena(u.arena) {}
pointer allocate(size_type n, const void *hint = 0) {
return static_cast<pointer>(arena.allocate(n*sizeof(T)));
}
template<class U> ArenaAllocator(const ArenaAllocator<U> &u): arena(u.arena) {}
pointer allocate(size_type n, const void *hint = 0) {return static_cast<pointer>(arena.allocate(n*sizeof(T)));}
static void deallocate(pointer, size_type) {}
static void construct(pointer p, const T &val) {new(p) T(val);}
static void destroy(pointer p) {p->~T();}
#ifdef __GNUC__ // why doesn't g++ support numeric_limits<T>?
static size_type max_size() {return size_type(-1) / sizeof(T);}
#else
static size_type max_size() {
return std::numeric_limits<size_type>::max() / sizeof(T);
}
static size_type max_size() {return std::numeric_limits<size_type>::max() / sizeof(T);}
#endif
template<class U> struct rebind {typedef ArenaAllocator<U> other;};
};
//
// Pools
//
// A Pool holds a collection of objects of the same type. These
// objects can be allocated and deallocated inexpensively.
// To allocate a T, use new(pool) T(...), where pool has type Pool<T>.
// To deallocate a T, use pool.destroy(t), where t has type T*.
// A Pool holds a collection of objects of the same type. These
// objects can be allocated and deallocated inexpensively.
// To allocate a T, use new(pool) T(...), where pool has type Pool<T>.
// To deallocate a T, use pool.destroy(t), where t has type T*.
template <typename T> class Pool: public Zone {
struct FreeList {
FreeList *next; // Next item in linked list of freed objects
FreeList *next; // Next item in linked list of freed objects
};
STATIC_CONST(size_t, entrySize = sizeof(T) >= sizeof(FreeList *) ?
sizeof(T) : sizeof(FreeList *));
FreeList *freeList; // Head of linked list of freed objects
STATIC_CONST(size_t, entrySize = sizeof(T) >= sizeof(FreeList *) ? sizeof(T) : sizeof(FreeList *));
FreeList *freeList; // Head of linked list of freed objects
public:
// clumpSize is the number of T's that are allocated at a time.
explicit Pool(size_t clumpSize) :
Zone(clumpSize * entrySize), freeList(0) {}
explicit Pool(size_t clumpSize): Zone(clumpSize * entrySize), freeList(0) {}
// Allocate memory for a single T. Use this with a placement new
// operator to create a new T.
// Allocate memory for a single T. Use this with a placement new operator to create a new T.
void *allocate() {
if (freeList) {
FreeList *p = freeList;
@ -239,6 +219,7 @@ namespace JavaScript
}
return allocateUnaligned(entrySize);
}
void deallocate(void *t) {
FreeList *p = static_cast<FreeList *>(t);
p->next = freeList;
@ -249,6 +230,7 @@ namespace JavaScript
};
}
inline void *operator new(size_t size, JavaScript::Arena &arena) {
return arena.allocate(size);
}
@ -259,6 +241,7 @@ inline void *operator new[](size_t size, JavaScript::Arena &arena) {
}
#endif
// Global delete operators. These are only called in the rare cases that a
// constructor throws an exception and has to undo an operator new.
// An explicit delete statement will never invoke these.
@ -276,6 +259,4 @@ template <typename T>
inline void operator delete(void *t, JavaScript::Pool<T> &pool) {
pool.deallocate(t);
}
//#endif
#endif /* mem_h___ */

Просмотреть файл

@ -35,11 +35,14 @@
#include <cstring>
#include <cfloat>
#include "numerics.h"
#include "jstypes.h"
#include "parser.h"
#include "js2runtime.h"
#include "fdlibm_ns.h"
namespace JavaScript
{
using namespace JSTypes;
using namespace JS2Runtime;
//
// Portable double-precision floating point to string and back conversions
@ -243,15 +246,15 @@ namespace JavaScript
// had to move these here since they depend upon the values
// initialized above, and we can't guarantee order other than
// lexically in a single file.
const JSValue JSTypes::kUndefinedValue;
const JSValue JSTypes::kNaNValue = JSValue(nan);
const JSValue JSTypes::kTrueValue = JSValue(true);
const JSValue JSTypes::kFalseValue = JSValue(false);
const JSValue JSTypes::kNullValue = JSValue(JSValue::null_tag);
const JSValue JSTypes::kNegativeZero = JSValue(-0.0);
const JSValue JSTypes::kPositiveZero = JSValue(0.0);
const JSValue JSTypes::kNegativeInfinity = JSValue(negativeInfinity);
const JSValue JSTypes::kPositiveInfinity = JSValue(positiveInfinity);
const JSValue JS2Runtime::kUndefinedValue;
const JSValue JS2Runtime::kNaNValue = JSValue(nan);
const JSValue JS2Runtime::kTrueValue = JSValue(true);
const JSValue JS2Runtime::kFalseValue = JSValue(false);
const JSValue JS2Runtime::kNullValue = JSValue(JSValue::null_tag);
const JSValue JS2Runtime::kNegativeZero = JSValue(-0.0);
const JSValue JS2Runtime::kPositiveZero = JSValue(0.0);
const JSValue JS2Runtime::kNegativeInfinity = JSValue(negativeInfinity);
const JSValue JS2Runtime::kPositiveInfinity = JSValue(positiveInfinity);
//
// Portable double-precision floating point to string and back conversions
@ -2644,7 +2647,7 @@ namespace JavaScript
// Output the integer part of value with the digits in reverse order.
char *pInt = p; // Pointer to the beginning of the integer part of the string
double valueInt = floor(value); // value truncated to an integer
double valueInt = fd::floor(value); // value truncated to an integer
uint32 digit;
if (valueInt <= 4294967295.0) {
uint32 n = (uint32)valueInt;

Просмотреть файл

@ -34,8 +34,6 @@
#ifndef numerics_h
#define numerics_h
#include <cmath>
#include "systemtypes.h"
#include "utilities.h"
#include "strings.h"

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

166
js2/src/property.h Normal file
Просмотреть файл

@ -0,0 +1,166 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#ifndef property_h___
#define property_h___
#include <map>
namespace JavaScript {
struct ExprNode;
namespace JS2Runtime {
class JSFunction;
class JSValue;
class JSType;
typedef enum { ValuePointer, FunctionPair, IndexPair, Slot, Method, Constructor } PropertyFlag;
typedef uint32 PropertyAttribute;
class Property {
public:
Property() { }
// a pair (or just one) of getter & setter methods - specify the vtable indices
Property(uint32 g, uint32 s, JSType *type, PropertyAttribute attr)
: mType(type), mAttributes(attr), mFlag(IndexPair)
{
mData.iPair.getterI = g;
mData.iPair.setterI = s;
}
// a pair (or just one) of getter & setter functions
Property(JSType *type, JSFunction *g, JSFunction *s, PropertyAttribute attr)
// XXX the type is the return
// type of the getter function.
: mType(type), mAttributes(attr), mFlag(FunctionPair)
{
mData.fPair.getterF = g;
mData.fPair.setterF = s;
}
// a member - either a vtable index or a slot index
Property(uint32 i, JSType *type, PropertyFlag flag, PropertyAttribute attr)
: mType(type), mAttributes(attr), mFlag(flag)
{
mData.index = i;
}
// a generic property
Property(JSValue *p, JSType *type, PropertyAttribute attr)
: mType(type), mAttributes(attr), mFlag(ValuePointer)
{
mData.vp = p;
}
enum {
NoAttribute = 0x00000000,
Indexable = 0x00000001,
Static = 0x00000002,
Dynamic = 0x00000004,
Constructor = 0x00000008,
Operator = 0x00000010,
Prototype = 0x00000020,
Extend = 0x00000040,
Virtual = 0x00000080,
True = 0x00000100,
Abstract = 0x00000200,
Override = 0x00000400,
MayOverride = 0x00000800,
Enumerable = 0x00001000,
Public = 0x00002000,
Private = 0x00004000,
Final = 0x00008000,
Const = 0x00010000
};
union {
JSValue *vp; // straightforward value
struct { // getter & setter functions
JSFunction *getterF;
JSFunction *setterF;
} fPair;
struct { // getter & setter methods (in base->mMethods)
uint32 getterI;
uint32 setterI;
} iPair;
uint32 index; // method (in base->mMethods) or
// slot (in base->mInstanceValues)
} mData;
JSType *mType;
PropertyAttribute mAttributes;
PropertyFlag mFlag;
};
Formatter& operator<<(Formatter& f, const Property& prop);
struct NamespaceList {
NamespaceList(const String *name, NamespaceList *next) : mName(*name), mNext(next) { }
const String mName;
NamespaceList *mNext;
};
typedef std::pair<Property *, NamespaceList *> NamespacedProperty;
typedef std::multimap<String, NamespacedProperty *, std::less<const String> > PropertyMap;
typedef PropertyMap::iterator PropertyIterator;
#define PROPERTY_KIND(it) ((it)->second->first->mFlag)
#define PROPERTY_ATTR(it) ((it)->second->first->mAttributes)
#define PROPERTY(it) ((it)->second->first)
#define NAMESPACED_PROPERTY(it) ((it)->second)
#define PROPERTY_NAMESPACELIST(it) ((it)->second->second)
#define PROPERTY_VALUEPOINTER(it) ((it)->second->first->mData.vp)
#define PROPERTY_INDEX(it) ((it)->second->first->mData.index)
#define PROPERTY_NAME(it) ((it)->first)
#define PROPERTY_TYPE(it) ((it)->second->first->mType)
#define PROPERTY_GETTERF(it) ((it)->second->first->mData.fPair.getterF)
#define PROPERTY_SETTERF(it) ((it)->second->first->mData.fPair.setterF)
#define PROPERTY_GETTERI(it) ((it)->second->first->mData.iPair.getterI)
#define PROPERTY_SETTERI(it) ((it)->second->first->mData.iPair.setterI)
}
}
#endif

Просмотреть файл

@ -62,18 +62,27 @@ void JS::Reader::beginLine()
linePositions.push_back(p);
}
// Fully process the source in order to fill in the line start table.
void JS::Reader::fillLineStartsTable()
{
char16 ch;
do {
ch = get();
if (isLineBreak(ch))
beginLine();
} while (!getEof(ch));
}
// Return the number of the line containing the given character position.
// The line starts should have been recorded by calling beginLine.
uint32 JS::Reader::posToLineNum(uint32 pos) const
uint32 JS::Reader::posToLineNum(size_t pos) const
{
ASSERT(pos <= getPos());
std::vector<const char16 *>::const_iterator i =
std::upper_bound(linePositions.begin(), linePositions.end(), begin + pos);
ASSERT(i != linePositions.begin());
return static_cast<uint32>(i-1 - linePositions.begin()) +
initialLineNum;
return static_cast<uint32>(i-1 - linePositions.begin()) + initialLineNum;
}
@ -84,7 +93,7 @@ uint32 JS::Reader::posToLineNum(uint32 pos) const
// manually finds the line ending by searching for a line break; otherwise,
// getLine assumes that the line ends one character before the beginning
// of the next line.
uint32 JS::Reader::getLine(uint32 lineNum, const char16 *&lineBegin, const char16 *&lineEnd) const
size_t JS::Reader::getLine(uint32 lineNum, const char16 *&lineBegin, const char16 *&lineEnd) const
{
lineBegin = 0;
lineEnd = 0;
@ -106,7 +115,7 @@ uint32 JS::Reader::getLine(uint32 lineNum, const char16 *&lineBegin, const char1
++e;
}
lineEnd = e;
return static_cast<uint32>(lineBegin - begin);
return toSize_t(lineBegin - begin);
}
@ -156,12 +165,12 @@ JS::String &JS::Reader::endRecording()
// Report an error at the given character position in the source code.
void JS::Reader::error(Exception::Kind kind, const String &message, uint32 pos)
void JS::Reader::error(Exception::Kind kind, const String &message, size_t pos)
{
uint32 lineNum = posToLineNum(pos);
const char16 *lineBegin;
const char16 *lineEnd;
uint32 linePos = getLine(lineNum, lineBegin, lineEnd);
size_t linePos = getLine(lineNum, lineBegin, lineEnd);
ASSERT(lineBegin && lineEnd && linePos <= pos);
throw Exception(kind, message, sourceLocation, lineNum, pos - linePos, pos, lineBegin, lineEnd);

Просмотреть файл

@ -69,9 +69,9 @@ namespace JavaScript {
char16 get() {ASSERT(p <= end);return *p++;}
char16 peek() {ASSERT(p <= end); return *p;}
void unget(uint32 n = 1) {ASSERT(p >= begin + n); p -= n;}
uint32 getPos() const {return static_cast<uint32>(p - begin);}
void setPos(uint32 pos) {ASSERT(pos <= getPos()); p = begin + pos;}
void unget(size_t n = 1) {ASSERT(p >= begin + n); p -= n;}
size_t getPos() const {return toSize_t(p - begin);}
void setPos(size_t pos) {ASSERT(pos <= getPos()); p = begin + pos;}
bool eof() const {ASSERT(p <= end); return p == end;}
bool peekEof(char16 ch) const {
@ -85,13 +85,14 @@ namespace JavaScript {
ASSERT(p[-1] == ch); return !ch && p == end+1;
}
void beginLine();
uint32 posToLineNum(uint32 pos) const;
uint32 getLine(uint32 lineNum, const char16 *&lineBegin, const char16 *&lineEnd) const;
void fillLineStartsTable();
uint32 posToLineNum(size_t pos) const;
size_t getLine(uint32 lineNum, const char16 *&lineBegin, const char16 *&lineEnd) const;
void beginRecording(String &recordString);
void recordChar(char16 ch);
String &endRecording();
void error(Exception::Kind kind, const String &message, uint32 pos);
void error(Exception::Kind kind, const String &message, size_t pos);
};
@ -107,5 +108,4 @@ namespace JavaScript {
};
}
#endif /* reader_h___ */

Просмотреть файл

@ -40,8 +40,6 @@
#ifndef _WIN32
// Microsoft Visual C++ 6.0 bug: standard identifiers should be in std namespace
using std::size_t;
using std::ptrdiff_t;
using std::va_list;
using std::strlen;
using std::strcpy;
@ -55,15 +53,12 @@
using std::vsnprintf;
using std::fprintf;
# define STD std
# define STATIC_CONST(type, expr) static const type expr
#else
# define STD
// Microsoft Visual C++ 6.0 bug: these identifiers should not begin with
// underscores
# define snprintf _snprintf
# define vsnprintf _vsnprintf
// Microsoft Visual C++ 6.0 bug: constants not supported
# define STATIC_CONST(type, expr) enum {expr}
#endif
using std::string;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -6,7 +6,7 @@
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
@ -17,7 +17,7 @@
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
@ -39,30 +39,8 @@
#include "utilities.h"
#include "mem.h"
namespace JavaScript
namespace JavaScript
{
// A string of UTF-16 characters. Nulls are allowed just like any other
// character. The string is not null-terminated.
// Use wstring if char16 is wchar_t. Otherwise use basic_string<uint16>.
//
// Eventually we'll want to use a custom class better suited for JavaScript that
// generates less code bloat and separates the concepts of a fixed, read-only
// string from a mutable buffer that is expanding. For now, though, we use the
// standard basic_string.
typedef std::basic_string<char16> String;
typedef String string16;
typedef string16::const_iterator string16_citer;
typedef string string8;
typedef string8::const_iterator string8_citer;
String &newArenaString(Arena &arena);
String &newArenaString(Arena &arena, const String &str);
//
// Unicode UTF-16 characters and strings
//
// Special char16s
namespace uni {
const char16 null = '\0';
@ -73,11 +51,9 @@ namespace JavaScript
const char16 ps = 0x2029;
}
const uint16 firstFormatChar = 0x200C; // Lowest Unicode Cf character
inline char16 widen(char ch) {
return static_cast<char16>(static_cast<uchar>(ch));
}
inline char16 widen(char ch) {return static_cast<char16>(static_cast<uchar>(ch));}
// Use char16Value to compare char16's for inequality because an
// implementation may have char16's be either signed or unsigned.
inline uint16 char16Value(char16 ch) {return static_cast<uint16>(ch);}
@ -86,15 +62,38 @@ namespace JavaScript
typedef uint32 char16orEOF;
const char16orEOF char16eof = static_cast<char16orEOF>(-1);
// If c is a char16, return it; if c is char16eof, return the character
// \uFFFF.
inline char16 char16orEOFToChar16(char16orEOF c) {
return static_cast<char16>(c);
}
// If c is a char16, return it; if c is char16eof, return the character \uFFFF.
inline char16 char16orEOFToChar16(char16orEOF c) {return static_cast<char16>(c);}
//
// Unicode UTF-16 characters and strings
//
// A string of UTF-16 characters. Nulls are allowed just like any other
// character. The string is not null-terminated.
// Use wstring if char16 is wchar_t. Otherwise use basic_string<uint16>.
//
// Eventually we'll want to use a custom class better suited for JavaScript that
// generates less code bloat and separates the concepts of a fixed, read-only
// string from a mutable buffer that is expanding. For now, though, we use the
// standard basic_string.
typedef std::basic_string<char16> String;
typedef String string16;
typedef string16::const_iterator string16_citer;
typedef string string8;
typedef string8::const_iterator string8_citer;
String &newArenaString(Arena &arena);
String &newArenaString(Arena &arena, const String &str);
#ifndef _WIN32
// Return a String containing the characters of the null-terminated C
// string cstr (without the trailing null).
//
// This function is inline in the vain hope that some compiler would do a return
// value optimization and avoid creating and destroying a temporary String when
// widenCString is called. We can still hope....
inline String widenCString(const char *cstr) {
size_t len = strlen(cstr);
const uchar *ucstr = reinterpret_cast<const uchar *>(cstr);
@ -110,32 +109,28 @@ namespace JavaScript
// Widen and append characters between begin and end to the end of str.
inline void appendChars(String &str, const char *begin, const char *end) {
ASSERT(begin <= end);
str.append(reinterpret_cast<const uchar *>(begin),
reinterpret_cast<const uchar *>(end));
str.append(reinterpret_cast<const uchar *>(begin), reinterpret_cast<const uchar *>(end));
}
// Widen and insert length characters starting at chars into the given
// position of str.
inline void insertChars(String &str, String::size_type pos,
const char *chars, size_t length) {
inline void insertChars(String &str, String::size_type pos, const char *chars, size_t length) {
ASSERT(pos <= str.size());
const uchar *uchars = reinterpret_cast<const uchar *>(chars);
str.insert(str.begin() + pos, uchars, uchars + length);
}
#else
// Microsoft VC6 bug: String constructor and append limited to char16
// iterators
// Microsoft VC6 bug: String constructor and append limited to char16 iterators
String widenCString(const char *cstr);
void appendChars(String &str, const char *chars, size_t length);
inline void appendChars(String &str, const char *begin, const char *end) {
ASSERT(begin <= end);
appendChars(str, begin, static_cast<size_t>(end - begin));
appendChars(str, begin, toSize_t(end - begin));
}
void insertChars(String &str, String::size_type pos, const char *chars,
size_t length);
void insertChars(String &str, String::size_type pos, const char *chars, size_t length);
#endif
void insertChars(String &str, String::size_type pos, const char *cstr);
@ -147,14 +142,14 @@ namespace JavaScript
class CharInfo {
uint32 info; // Word from table a.
uint32 info; // Word from table a.
// Unicode character attribute lookup tables
static const uint8 x[];
static const uint8 y[];
static const uint32 a[];
public:
public:
// Enumerated Unicode general category types
enum Type {
Unassigned = 0, // Cn
@ -190,48 +185,40 @@ namespace JavaScript
enum Group {
NonIdGroup, // 0 May not be part of an identifier
FormatGroup, // 1 Format control
IdGroup, // 2 May start or continue a JS identifier
// (includes $ and _)
IdContinueGroup, // 3 May continue a JS identifier
// [(IdContinueGroup & -2) == IdGroup]
IdGroup, // 2 May start or continue a JS identifier (includes $ and _)
IdContinueGroup, // 3 May continue a JS identifier [(IdContinueGroup & -2) == IdGroup]
WhiteGroup, // 4 White space character (but not line break)
LineBreakGroup // 5 Line break character
// [(LineBreakGroup & -2) == WhiteGroup]
LineBreakGroup // 5 Line break character [(LineBreakGroup & -2) == WhiteGroup]
};
CharInfo() {}
CharInfo(char16 c) :
info(a[y[x[static_cast<uint16>(c)>>6]<<6 | c&0x3F]]) {}
CharInfo(char16 c): info(a[y[x[static_cast<uint16>(c)>>6]<<6 | c&0x3F]]) {}
CharInfo(const CharInfo &ci): info(ci.info) {}
friend Type cType(const CharInfo &ci) {return static_cast<Type>(ci.info & 0x1F);}
friend Group cGroup(const CharInfo &ci) {return static_cast<Group>(ci.info >> 16 & 7);}
friend bool isAlpha(const CharInfo &ci)
{
return ((1<<UppercaseLetter | 1<<LowercaseLetter | 1<<TitlecaseLetter | 1<<ModifierLetter | 1<<OtherLetter)
>> cType(ci) & 1) != 0;
}
friend bool isAlpha(const CharInfo &ci) {
return ((1<<UppercaseLetter | 1<<LowercaseLetter | 1<<TitlecaseLetter | 1<<ModifierLetter | 1<<OtherLetter) >> cType(ci) & 1) != 0;
}
friend bool isAlphanumeric(const CharInfo &ci)
{
return ((1<<UppercaseLetter | 1<<LowercaseLetter | 1<<TitlecaseLetter | 1<<ModifierLetter | 1<<OtherLetter |
1<<DecimalDigitNumber | 1<<LetterNumber)
>> cType(ci) & 1) != 0;
}
friend bool isAlphanumeric(const CharInfo &ci) {
return ((1<<UppercaseLetter | 1<<LowercaseLetter | 1<<TitlecaseLetter | 1<<ModifierLetter | 1<<OtherLetter |
1<<DecimalDigitNumber | 1<<LetterNumber) >> cType(ci) & 1) != 0;
}
// Return true if this character can start a JavaScript identifier
// Return true if this character can start a JavaScript identifier
friend bool isIdLeading(const CharInfo &ci) {return cGroup(ci) == IdGroup;}
// Return true if this character can continue a JavaScript identifier
// Return true if this character can continue a JavaScript identifier
friend bool isIdContinuing(const CharInfo &ci) {return (cGroup(ci) & -2) == IdGroup;}
// Return true if this character is a Unicode decimal digit (Nd) character
// Return true if this character is a Unicode decimal digit (Nd) character
friend bool isDecimalDigit(const CharInfo &ci) {return cType(ci) == DecimalDigitNumber;}
// Return true if this character is a Unicode white space or line break character
// Return true if this character is a Unicode white space or line break character
friend bool isSpace(const CharInfo &ci) {return (cGroup(ci) & -2) == WhiteGroup;}
// Return true if this character is a Unicode line break character (LF, CR, LS, or PS)
// Return true if this character is a Unicode line break character (LF, CR, LS, or PS)
friend bool isLineBreak(const CharInfo &ci) {return cGroup(ci) == LineBreakGroup;}
// Return true if this character is a Unicode format control character (Cf)
// Return true if this character is a Unicode format control character (Cf)
friend bool isFormat(const CharInfo &ci) {return cGroup(ci) == FormatGroup;}
friend bool isUpper(const CharInfo &ci) {return cType(ci) == UppercaseLetter;}
@ -240,12 +227,10 @@ namespace JavaScript
friend char16 toUpper(char16 c);
friend char16 toLower(char16 c);
};
inline bool isASCIIDecimalDigit(char16 c) {return c >= '0' && c <= '9';}
bool isASCIIHexDigit(char16 c, uint &digit);
const char16 *skipWhiteSpace(const char16 *str, const char16 *strEnd);
}
#endif /* strings_h___ */

Просмотреть файл

@ -41,6 +41,8 @@
#pragma warning(disable: 4786)
#endif
#define MAX_UINT16 (65535)
// Define int8, int16, int32, int64, uint8, uint16, uint32, uint64, and uint.
typedef unsigned int uint;
typedef unsigned char uchar;
@ -49,19 +51,18 @@ typedef signed char int8;
typedef unsigned char uint8;
typedef short int16;
typedef unsigned short uint16;
#if !defined(XP_MAC) && !defined(_WIN32)
typedef int int32;
typedef unsigned int uint32;
#else
#ifdef _WIN32
typedef long int32;
typedef unsigned long uint32;
#endif
#ifdef _WIN32
typedef __int64 int64;
typedef unsigned __int64 uint64;
#else
typedef int int32;
typedef unsigned int uint32;
typedef long long int64;
typedef unsigned long long uint64;
using std::size_t;
using std::ptrdiff_t;
#endif
// Define this if the machine natively supports 64-bit integers
@ -81,11 +82,7 @@ typedef float float32;
typedef uint16 uchar16;
#else
typedef wchar_t char16;
#ifndef _WIN32 // Microsoft VC6 bug: wchar_t should be a built-in type, not a typedef
typedef wchar_t uchar16;
#else
typedef wchar_t uchar16;
#endif
typedef wchar_t uchar16;
#endif
#ifdef _WIN32

Просмотреть файл

@ -6,7 +6,7 @@
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
@ -136,6 +136,7 @@ const char *const JS::Token::kindNames[kindsEnd] = {
"in", // In
"instanceof", // Instanceof
"interface", // Interface
"is", // Is
"namespace", // Namespace
"native", // Native
"new", // New
@ -164,18 +165,22 @@ const char *const JS::Token::kindNames[kindsEnd] = {
"with", // With
// Non-reserved words
"ecmascript", // Ecmascript
"eval", // Eval
"exclude", // Exclude
"get", // Get
"include", // Include
"set" // Set
"javascript", // Javascript
"set", // Set
"strict" // Strict
};
static const uchar followRet = 1<<JS::Token::canFollowReturn;
static const uchar isAttr = 1<<JS::Token::isAttribute | 1<<JS::Token::canFollowAttribute;
static const uchar nonreserved = 1<<JS::Token::isNonreserved;
static const uchar followAttr = 1<<JS::Token::canFollowAttribute;
static const uchar followGet = 1<<JS::Token::canFollowGet;
static const uchar isAttr = 1<<JS::Token::isAttribute | followAttr;
static const uchar isNEAttr = 1<<JS::Token::isNonExpressionAttribute | isAttr;
static const uchar followRet = 1<<JS::Token::canFollowReturn;
const uchar JS::Token::kindFlags[kindsEnd] = {
// Special
@ -246,7 +251,7 @@ const uchar JS::Token::kindFlags[kindsEnd] = {
0, // question
// Reserved words
isAttr, // Abstract
isNEAttr, // Abstract
0, // As
0, // Break
0, // Case
@ -263,27 +268,28 @@ const uchar JS::Token::kindFlags[kindsEnd] = {
followAttr, // Export
0, // Extends
isAttr, // False
isAttr, // Final
isNEAttr, // Final
0, // Finally
0, // For
followAttr, // Function
0, // Goto
0, // If
0, // Implements
0, // Import
followAttr, // Import
0, // In
0, // Instanceof
followAttr, // Interface
0, // Is
followAttr, // Namespace
followAttr, // Native
0, // New
0, // Null
isAttr, // Package
0, // Package
isAttr, // Private
followAttr, // Protected
isAttr, // Public
0, // Return
isAttr, // Static
isNEAttr, // Static
0, // Super
0, // Switch
followAttr, // Synchronized
@ -294,21 +300,24 @@ const uchar JS::Token::kindFlags[kindsEnd] = {
isAttr, // True
0, // Try
0, // Typeof
0, // Use
followAttr, // Use
followAttr, // Var
0, // Void
isAttr, // Volatile
isNEAttr, // Volatile
followRet, // While
0, // With
// Non-reserved words
isAttr|followGet, // Eval
isAttr|followGet, // Exclude
isAttr|followGet, // Get
isAttr|followGet, // Include
isAttr|followGet, // Set
isAttr|nonreserved, // Ecmascript
isAttr|nonreserved, // Eval
isAttr|nonreserved, // Exclude
isAttr|nonreserved, // Get
isAttr|nonreserved, // Include
isAttr|nonreserved, // Javascript
isAttr|nonreserved, // Set
isAttr|nonreserved, // Strict
isAttr|followGet // identifier
isAttr|nonreserved // identifier
};
@ -316,8 +325,7 @@ const uchar JS::Token::kindFlags[kindsEnd] = {
void JS::Token::initKeywords(World &world)
{
const char *const*keywordName = kindNames + keywordsBegin;
for (Kind kind = keywordsBegin; kind != keywordsEnd;
kind = Kind(kind+1))
for (Kind kind = keywordsBegin; kind != keywordsEnd; kind = Kind(kind+1))
world.identifiers[widenCString(*keywordName++)].tokenKind = kind;
}

Просмотреть файл

@ -6,7 +6,7 @@
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
@ -47,7 +47,7 @@ namespace JavaScript
class Token {
public:
enum Kind {
// Keep synchronized with kindNames, kindFlags, and tokenBinaryOperatorInfos tables
// Keep synchronized with the kindNames, kindFlags, and tokenBinaryOperatorInfos tables
// Special
end, // End of token stream
@ -151,6 +151,7 @@ namespace JavaScript
In, // in
Instanceof, // instanceof
Interface, // interface
Is, // is
Namespace, // namespace
Native, // native
New, // new
@ -179,44 +180,61 @@ namespace JavaScript
With, // with
// Non-reserved words
Ecmascript, // ecmascript
Eval, // eval
Exclude, // exclude
Get, // get
Include, // include
Javascript, // javascript
Set, // set
Strict, // strict
identifier, // Non-keyword identifier (may be same as a keyword if it contains an escape code)
kindsEnd, // End of token kinds
kindsEnd, // End of token kinds
keywordsBegin = Abstract, // Beginning of range of special identifier tokens
keywordsEnd = identifier, // End of range of special identifier tokens
nonreservedBegin = Eval, // Beginning of range of non-reserved words
keywordsBegin = Abstract, // Beginning of range of special identifier tokens
keywordsEnd = identifier, // End of range of special identifier tokens
nonreservedBegin = Ecmascript,// Beginning of range of non-reserved words
nonreservedEnd = identifier, // End of range of non-reserved words
kindsWithCharsBegin = number, // Beginning of range of tokens for which the chars field (below) is valid
kindsWithCharsEnd = regExp+1 // End of range of tokens for which the chars field (below) is valid
};
#define CASE_TOKEN_ATTRIBUTE_IDENTIFIER \
Token::Eval: \
// Keep synchronized with isNonreserved below
#define CASE_TOKEN_NONRESERVED \
Token::Ecmascript: \
case Token::Eval: \
case Token::Exclude: \
case Token::Get: \
case Token::Include: \
case Token::Javascript: \
case Token::Set: \
case Token::Strict: \
case Token::identifier
#define CASE_TOKEN_NONRESERVED \
Token::Eval: \
#define CASE_TOKEN_NONRESERVED_NONINCLUDE \
Token::Ecmascript: \
case Token::Eval: \
case Token::Exclude: \
case Token::Get: \
case Token::Include: \
case Token::Javascript: \
case Token::Set: \
case Token::Strict: \
case Token::identifier
// Keep synchronized with isNonExpressionAttribute below
#define CASE_TOKEN_NONEXPRESSION_ATTRIBUTE \
Token::Abstract: \
case Token::Final: \
case Token::Static: \
case Token::Volatile
enum Flag {
isNonreserved, // True if this token is a non-reserved identifier
isAttribute, // True if this token is an attribute
isNonExpressionAttribute, // True if this token is an attribute but not an expression
canFollowAttribute, // True if this token is an attribute or can follow an attribute
canFollowReturn, // True if this token can follow a return without an expression
canFollowGet // True if this token can follow a get or set in a FunctionName
canFollowReturn // True if this token can follow a return without an expression
};
private:
@ -228,7 +246,7 @@ namespace JavaScript
#endif
Kind kind; // The token's kind
bool lineBreak; // True if line break precedes this token
uint32 pos; // Source position of this token
size_t pos; // Source position of this token
const StringAtom *id; // The token's characters; non-nil for identifiers, keywords, and regular expressions only
String chars; // The token's characters; valid for strings, units, numbers, and regular expression flags only
float64 value; // The token's value (numbers only)
@ -246,7 +264,7 @@ namespace JavaScript
bool hasIdentifierKind() const {ASSERT(nonreservedEnd == identifier && kindsEnd == identifier+1); return kind >= nonreservedBegin;}
bool getFlag(Flag f) const {ASSERT(valid); return (kindFlags[kind] & 1<<f) != 0;}
bool getLineBreak() const {ASSERT(valid); return lineBreak;}
uint32 getPos() const {ASSERT(valid); return pos;}
size_t getPos() const {ASSERT(valid); return pos;}
const StringAtom &getIdentifier() const {ASSERT(valid && id); return *id;}
const String &getChars() const {ASSERT(valid && kind >= kindsWithCharsBegin && kind < kindsWithCharsEnd); return chars;}
float64 getValue() const {ASSERT(valid && kind == number); return value;}

166
js2/src/tracer.cpp Normal file
Просмотреть файл

@ -0,0 +1,166 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#include "systemtypes.h"
#include "tracer.h"
// for each owner, we maintain a simple linked list of
// the pointers that have been allocated
struct PointerData {
PointerData(void *p, size_t s, PointerData *n)
: mPointer(p), mSize(s), mNext(n) { }
void *mPointer;
size_t mSize;
PointerData *mNext;
};
struct AllocData {
AllocData(char *owner)
{
mOwner = (char *)STD::malloc(strlen(owner) + 1);
strcpy(mOwner, owner);
mData = NULL;
mTotalAllocatedCount = 0;
mTotalReleasedCount = 0;
mTotalAllocatedSize = 0;
mTotalReleasedSize = 0;
}
uint32 mTotalAllocatedCount;
uint32 mTotalReleasedCount;
uint32 mTotalAllocatedSize;
uint32 mTotalReleasedSize;
char *mOwner;
PointerData *mData;
};
AllocData **gAllocations = NULL;
uint32 gAllocationsCount = 0;
static AllocData *findOwner(char *owner)
{
for (uint32 i = 0; i < gAllocationsCount; i++) {
if (STD::strcmp(gAllocations[i]->mOwner, owner) == 0)
return gAllocations[i];
}
gAllocations = (AllocData **)STD::realloc(gAllocations, (gAllocationsCount + 1) * sizeof(AllocData));
gAllocations[gAllocationsCount] = new AllocData(owner);
return gAllocations[gAllocationsCount++];
}
void trace_alloc(char *owner, size_t s, void *p)
{
AllocData *ad = findOwner(owner);
ad->mData = new PointerData(p, s, ad->mData);
ad->mTotalAllocatedCount++;
ad->mTotalAllocatedSize += s;
// ?? check for duplicate or overlapping allocation ??
}
void trace_release(char *owner, void *p)
{
AllocData *ad = findOwner(owner);
PointerData *pd = ad->mData;
PointerData **back = &ad->mData;
ad->mTotalReleasedCount++;
while (pd) {
if (pd->mPointer == p) {
*back = pd->mNext;
ad->mTotalReleasedSize += pd->mSize;
delete pd;
return;
}
back = &pd->mNext;
pd = pd->mNext;
}
NOT_REACHED("released pointer not found");
}
void trace_dump(JavaScript::Formatter& f)
{
for (uint32 i = 0; i < gAllocationsCount; i++) {
AllocData *ad = gAllocations[i];
f << "For '" << ad->mOwner << "':" << "\n";
f << "\t" << "Total Allocated Count = " << ad->mTotalAllocatedCount << "\n";
f << "\t" << "Total Allocated Size = " << ad->mTotalAllocatedSize << "\n";
f << "\t" << "Total Released Count = " << ad->mTotalReleasedCount << "\n";
f << "\t" << "Total Released Size = " << ad->mTotalReleasedSize << "\n";
/*
if we could get stack traces, it might be fun to dump those here
from each un-released chunk.
PointerData *pd = ad->mData;
while (pd) {
f << "Unreleased data, allocated from " << pd->stackTrace << "\n";
pd = pd->mNext;
}
*/
f << "\n";
}
}
#include "formatter.h"
namespace JavaScript {
namespace Shell {
void do_dikdik(JavaScript::Formatter &f)
{
f << " \\ / \n";
f << " \\ __/ _______ \n";
f << " / \\ / \\ \n";
f << " / + + \\/ \\ \n";
f << " | | \\------* \n";
f << " \\ / | \n";
f << " \\ /\\ / \n";
f << " | | \\ / \n";
f << " \\_/ \\ ___ /|| \n";
f << " || || \n";
f << " || || \n";
f << " || || \n";
f << " || \n";
f << "\n";
}
}
}

52
js2/src/tracer.h Normal file
Просмотреть файл

@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#ifndef tracer_h___
#define tracer_h___
#include "formatter.h"
void trace_alloc(char *owner, size_t s, void *p);
void trace_release(char *owner, void *p);
void trace_dump(JavaScript::Formatter& f);
namespace JavaScript {
namespace Shell {
void do_dikdik(JavaScript::Formatter &f);
}
}
#endif

Просмотреть файл

@ -34,16 +34,19 @@
#ifndef utilities_h___
#define utilities_h___
#ifdef MSC_VER
// disable long identifier warnings
# pragma warning(disable: 4786)
#endif
#include "systemtypes.h"
namespace JavaScript
{
#ifndef _WIN32
#define STATIC_CONST(type, expr) static const type expr
#else
// Microsoft Visual C++ 6.0 bug: constants not supported
#define STATIC_CONST(type, expr) enum {expr}
#endif
//
// Assertions
//
@ -51,15 +54,27 @@ namespace JavaScript
#ifdef DEBUG
void Assert(const char *s, const char *file, int line);
# define ASSERT(_expr) \
((_expr) ? (void)0 : JavaScript::Assert(#_expr, __FILE__, __LINE__))
# define NOT_REACHED(_reasonStr) \
JavaScript::Assert(_reasonStr, __FILE__, __LINE__)
# define DEBUG_ONLY(_stmt) _stmt
#define ASSERT(_expr) ((_expr) ? (void)0 : JavaScript::Assert(#_expr, __FILE__, __LINE__))
#define NOT_REACHED(_reasonStr) JavaScript::Assert(_reasonStr, __FILE__, __LINE__)
#define DEBUG_ONLY(_stmt) _stmt
#else
# define ASSERT(expr)
# define NOT_REACHED(reasonStr)
# define DEBUG_ONLY(_stmt)
#define ASSERT(expr) (void)0
#define NOT_REACHED(reasonStr) (void)0
#define DEBUG_ONLY(_stmt)
#endif
// A checked_cast acts as a static_cast that is checked in DEBUG mode.
// It can only be used to downcast a class hierarchy that has at least one virtual function.
#ifdef DEBUG
template <class Target, class Source> inline Target checked_cast(Source *s)
{
Target t = dynamic_cast<Target>(s);
ASSERT(t);
return t;
}
#else
#define checked_cast static_cast
#endif
@ -67,10 +82,33 @@ namespace JavaScript
// Mathematics
//
template<class N> N min(N v1, N v2) {return v1 <= v2 ? v1 : v2;}
template<class N> N max(N v1, N v2) {return v1 >= v2 ? v1 : v2;}
template<class N> inline N min(N v1, N v2) {return v1 <= v2 ? v1 : v2;}
template<class N> inline N max(N v1, N v2) {return v1 >= v2 ? v1 : v2;}
uint ceilingLog2(uint32 n);
uint floorLog2(uint32 n);
//
// Flag Bitmaps
//
template<class F> inline F setFlag(F flags, F flag) {return static_cast<F>(flags | flag);}
template<class F> inline F clearFlag(F flags, F flag) {return static_cast<F>(flags & ~flag);}
template<class F> inline bool testFlag(F flags, F flag) {return (flags & flag) != 0;}
//
// Signed/Unsigned Conversions
//
// Use these instead of type casts to safely convert between signed and unsigned
// integers of the same size.
inline uint32 toUInt32(int32 x) {return static_cast<uint32>(x);}
inline int32 toInt32(uint32 x) {return static_cast<int32>(x);}
inline size_t toSize_t(ptrdiff_t x) {return static_cast<size_t>(x);}
inline ptrdiff_t toPtrdiff_t(size_t x) {return static_cast<ptrdiff_t>(x);}
}
#endif /* utilities_h___ */

Просмотреть файл

@ -34,26 +34,28 @@
#ifdef _WIN32
// Turn off warnings about identifiers too long in browser information
#pragma warning(disable: 4786)
//#pragma warning(disable: 4711)
//#pragma warning(disable: 4710)
#endif
#include "world.h"
namespace JavaScript
{
// Return an existing StringAtom corresponding to the String s if there is
// one; if not, create a new StringAtom with String s and return that StringAtom.
StringAtom &
StringAtomTable::operator[](const String &s)
{
HT::Reference r(ht, s);
if (r)
return *r;
else
return ht.insert(r, s);
}
namespace JS = JavaScript;
World::World()
{
Token::initKeywords(*this);
}
// Return an existing StringAtom corresponding to the String s if there is one;
// if not, create a new StringAtom with String s and return that StringAtom.
JS::StringAtom &JS::StringAtomTable::operator[](const String &s)
{
HT::Reference r(ht, s);
if (r)
return *r;
else
return ht.insert(r, s);
}
JS::World::World()
{
Token::initKeywords(*this);
}

Просмотреть файл

@ -39,44 +39,43 @@
#include "hash.h"
namespace JavaScript {
//
// String atom management
//
// A StringAtom is a String for which the following guarantee applies:
// StringAtoms A and B have the same character sequences if and only if A and
// B are the same StringAtom.
// A StringAtom is a String for which the following guarantee applies:
// StringAtoms A and B have the same character sequences if and only if A and
// B are the same StringAtom.
class StringAtom: public String {
public:
// Token::Kind if this is a keyword; Token::identifier if not
Token::Kind tokenKind;
Token::Kind tokenKind; // Token::Kind if this is a keyword; Token::identifier if not
explicit StringAtom(const String &s): String(s), tokenKind(Token::identifier) {}
private:
StringAtom(const StringAtom&); // No copy constructor
void operator=(const StringAtom&); // No assignment operator
StringAtom(const StringAtom &); // No copy constructor
void operator=(const StringAtom &); // No assignment operator
};
inline bool operator==(const StringAtom &s1, const StringAtom &s2) {return &s1 == &s2;}
inline bool operator!=(const StringAtom &s1, const StringAtom &s2) {return &s1 != &s2;}
class StringAtomTable {
typedef HashTable<StringAtom, const String&> HT;
typedef HashTable<StringAtom, const String &> HT;
HT ht;
public:
StringAtom &operator[](const String &s);
StringAtom &operator[](const char *s) {return operator[](widenCString(s));}
};
};
class World {
public:
public:
StringAtomTable identifiers;
World();
};
}
#endif