Compare commits
2 Commits
Bugzilla_P
...
STLPORT_FU
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90ec25ad49 | ||
|
|
cc0938739a |
44
mozilla/js/js2/Makefile
Normal file
44
mozilla/js/js2/Makefile
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
STLPORT = /usr/local/include/stlport
|
||||||
|
|
||||||
|
CC = gcc
|
||||||
|
CFLAGS = -g -ggdb -DDEBUG -DXP_UNIX -Wall -W -Wpointer-arith \
|
||||||
|
-Wbad-function-cast -Wstrict-prototypes -Wmissing-prototypes \
|
||||||
|
-Wno-non-virtual-dtor -I$(STLPORT)
|
||||||
|
|
||||||
|
objs = hash.o \
|
||||||
|
icodegenerator.o \
|
||||||
|
interpreter.o \
|
||||||
|
js2.o \
|
||||||
|
jsmath.o \
|
||||||
|
jstypes.o \
|
||||||
|
numerics.o \
|
||||||
|
parser.o \
|
||||||
|
utilities.o \
|
||||||
|
world.o \
|
||||||
|
vmtypes.o \
|
||||||
|
debugger.o
|
||||||
|
|
||||||
|
gc_path = ../../gc/boehm/
|
||||||
|
|
||||||
|
libs = gc.a -lstdc++ -lm
|
||||||
|
|
||||||
|
%.o : %.cpp
|
||||||
|
$(CC) -c $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
js2: $(objs) gc.a
|
||||||
|
$(CC) -o $@ -ggdb $(objs) $(libs)
|
||||||
|
|
||||||
|
gc.a:
|
||||||
|
(cd $(gc_path) ; ln -f -s Makefile.unix Makefile ; make gc.a)
|
||||||
|
ln -f -s $(gc_path)gc.a ./gc.a
|
||||||
|
|
||||||
|
gctest: gc_allocator.o
|
||||||
|
$(CC) -o $@ -ggdb $^ $(libs)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(objs)
|
||||||
|
|
||||||
|
depend:
|
||||||
|
gcc -MM *.cpp > dependencies
|
||||||
|
|
||||||
|
include dependencies
|
||||||
111
mozilla/js/js2/cplusplustests/CPlusPlusTests.dsp
Normal file
111
mozilla/js/js2/cplusplustests/CPlusPlusTests.dsp
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
# Microsoft Developer Studio Project File - Name="CPlusPlusTests" - Package Owner=<4>
|
||||||
|
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||||
|
# ** DO NOT EDIT **
|
||||||
|
|
||||||
|
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||||
|
|
||||||
|
CFG=CPlusPlusTests - Win32 Debug
|
||||||
|
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||||
|
!MESSAGE use the Export Makefile command and run
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "CPlusPlusTests.mak".
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE You can specify a configuration when running NMAKE
|
||||||
|
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "CPlusPlusTests.mak" CFG="CPlusPlusTests - Win32 Debug"
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE Possible choices for configuration are:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE "CPlusPlusTests - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||||
|
!MESSAGE "CPlusPlusTests - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||||
|
!MESSAGE
|
||||||
|
|
||||||
|
# Begin Project
|
||||||
|
# PROP AllowPerConfigDependencies 0
|
||||||
|
# PROP Scc_ProjName ""
|
||||||
|
# PROP Scc_LocalPath ""
|
||||||
|
CPP=cl.exe
|
||||||
|
RSC=rc.exe
|
||||||
|
|
||||||
|
!IF "$(CFG)" == "CPlusPlusTests - Win32 Release"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 0
|
||||||
|
# PROP BASE Output_Dir "Release"
|
||||||
|
# PROP BASE Intermediate_Dir "Release"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 0
|
||||||
|
# PROP Output_Dir "Release"
|
||||||
|
# PROP Intermediate_Dir "Release"
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||||
|
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||||
|
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=link.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "CPlusPlusTests - Win32 Debug"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 1
|
||||||
|
# PROP BASE Output_Dir "Debug"
|
||||||
|
# PROP BASE Intermediate_Dir "Debug"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 1
|
||||||
|
# PROP Output_Dir "Debug"
|
||||||
|
# PROP Intermediate_Dir "Debug"
|
||||||
|
# PROP Ignore_Export_Lib 0
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||||
|
# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||||
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=link.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||||
|
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
|
# Begin Target
|
||||||
|
|
||||||
|
# Name "CPlusPlusTests - Win32 Release"
|
||||||
|
# Name "CPlusPlusTests - Win32 Debug"
|
||||||
|
# Begin Group "Source Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\cplusplustests.cpp
|
||||||
|
|
||||||
|
!IF "$(CFG)" == "CPlusPlusTests - Win32 Release"
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "CPlusPlusTests - Win32 Debug"
|
||||||
|
|
||||||
|
# ADD CPP /Ob1 /FR
|
||||||
|
# SUBTRACT CPP /O<none> /YX
|
||||||
|
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
|
# End Source File
|
||||||
|
# End Group
|
||||||
|
# Begin Group "Header Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||||
|
# End Group
|
||||||
|
# Begin Group "Resource Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||||
|
# End Group
|
||||||
|
# End Target
|
||||||
|
# End Project
|
||||||
29
mozilla/js/js2/cplusplustests/CPlusPlusTests.dsw
Normal file
29
mozilla/js/js2/cplusplustests/CPlusPlusTests.dsw
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||||
|
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
Project: "CPlusPlusTests"=.\CPlusPlusTests.dsp - Package Owner=<4>
|
||||||
|
|
||||||
|
Package=<5>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
Package=<4>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
Global:
|
||||||
|
|
||||||
|
Package=<5>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
Package=<3>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
BIN
mozilla/js/js2/cplusplustests/CPlusPlusTests.mcp
Normal file
BIN
mozilla/js/js2/cplusplustests/CPlusPlusTests.mcp
Normal file
Binary file not shown.
129
mozilla/js/js2/cplusplustests/cplusplustests.cpp
Normal file
129
mozilla/js/js2/cplusplustests/cplusplustests.cpp
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
#include <cstddef>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
struct Arena {
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
Arena(const char *name): name(name) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void *operator new(size_t size, Arena &arena);
|
||||||
|
void operator delete(void *p);
|
||||||
|
|
||||||
|
void *operator new(size_t size, Arena &arena)
|
||||||
|
{
|
||||||
|
void *p = malloc(size);
|
||||||
|
printf("Allocating %d bytes at %p using arena \"%s\"\n", size, p, arena.name);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef __MWERKS__
|
||||||
|
void operator delete(void *p, Arena &arena)
|
||||||
|
{
|
||||||
|
printf("Deleting object at %p using arena \"%s\"\n", p, arena.name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void operator delete(void *p)
|
||||||
|
{
|
||||||
|
printf("Deleting object at %p\n", p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct C {
|
||||||
|
int n;
|
||||||
|
|
||||||
|
C(int n, bool bad = false);
|
||||||
|
~C();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Exception {
|
||||||
|
int num;
|
||||||
|
|
||||||
|
explicit Exception(int n): num(n) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
C::C(int n, bool bad): n(n)
|
||||||
|
{
|
||||||
|
printf("Constructing C #%d at %p\n", n, this);
|
||||||
|
if (bad) {
|
||||||
|
printf("Throwing %d; constructor aborted\n", n);
|
||||||
|
throw Exception(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
C::~C()
|
||||||
|
{
|
||||||
|
printf("Destroying C #%d at %p\n", n, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void constructorTest1(int n, bool bad)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
printf("Calling C(%d,%d)\n", n, (int)bad);
|
||||||
|
{
|
||||||
|
C c(n, bad);
|
||||||
|
printf("We have C #%d\n", c.n);
|
||||||
|
}
|
||||||
|
printf("C is out of scope\n");
|
||||||
|
} catch (Exception &e) {
|
||||||
|
printf("Caught exception %d\n", e.num);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void constructorTest2(int n, bool bad)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
printf("Calling new C(%d,%d)\n", n, (int)bad);
|
||||||
|
{
|
||||||
|
C *c = new C(n, bad);
|
||||||
|
printf("We have C #%d\n", c->n);
|
||||||
|
delete c;
|
||||||
|
}
|
||||||
|
printf("C is out of scope\n");
|
||||||
|
} catch (Exception &e) {
|
||||||
|
printf("Caught exception %d\n", e.num);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void constructorTest3(int n, bool bad)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
printf("Calling new(arena) C(%d,%d)\n", n, (int)bad);
|
||||||
|
{
|
||||||
|
Arena arena("My arena");
|
||||||
|
C *c = new(arena) C(n, bad);
|
||||||
|
printf("We have C #%d\n", c->n);
|
||||||
|
}
|
||||||
|
printf("C is out of scope\n");
|
||||||
|
} catch (Exception &e) {
|
||||||
|
printf("Caught exception %d\n", e.num);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
printf("Beginning constructor tests\n\n");
|
||||||
|
constructorTest1(1, false);
|
||||||
|
constructorTest1(2, true);
|
||||||
|
constructorTest2(3, false);
|
||||||
|
constructorTest2(4, true);
|
||||||
|
constructorTest3(5, false);
|
||||||
|
constructorTest3(6, true);
|
||||||
|
printf("Ending constructor tests\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
191
mozilla/js/js2/cpucfg.h
Normal file
191
mozilla/js/js2/cpucfg.h
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
/* -*- 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 Mozilla Communicator client code, released
|
||||||
|
* March 31, 1998.
|
||||||
|
*
|
||||||
|
* 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 cpucfg_h
|
||||||
|
#define cpucfg_h
|
||||||
|
|
||||||
|
#define JS_HAVE_LONG_LONG
|
||||||
|
|
||||||
|
#ifdef XP_MAC
|
||||||
|
#undef IS_LITTLE_ENDIAN
|
||||||
|
#define IS_BIG_ENDIAN 1
|
||||||
|
|
||||||
|
#define JS_BYTES_PER_BYTE 1L
|
||||||
|
#define JS_BYTES_PER_SHORT 2L
|
||||||
|
#define JS_BYTES_PER_INT 4L
|
||||||
|
#define JS_BYTES_PER_INT64 8L
|
||||||
|
#define JS_BYTES_PER_LONG 4L
|
||||||
|
#define JS_BYTES_PER_FLOAT 4L
|
||||||
|
#define JS_BYTES_PER_DOUBLE 8L
|
||||||
|
#define JS_BYTES_PER_WORD 4L
|
||||||
|
#define JS_BYTES_PER_DWORD 8L
|
||||||
|
|
||||||
|
#define JS_BITS_PER_BYTE 8L
|
||||||
|
#define JS_BITS_PER_SHORT 16L
|
||||||
|
#define JS_BITS_PER_INT 32L
|
||||||
|
#define JS_BITS_PER_INT64 64L
|
||||||
|
#define JS_BITS_PER_LONG 32L
|
||||||
|
#define JS_BITS_PER_FLOAT 32L
|
||||||
|
#define JS_BITS_PER_DOUBLE 64L
|
||||||
|
#define JS_BITS_PER_WORD 32L
|
||||||
|
|
||||||
|
#define JS_BITS_PER_BYTE_LOG2 3L
|
||||||
|
#define JS_BITS_PER_SHORT_LOG2 4L
|
||||||
|
#define JS_BITS_PER_INT_LOG2 5L
|
||||||
|
#define JS_BITS_PER_INT64_LOG2 6L
|
||||||
|
#define JS_BITS_PER_LONG_LOG2 5L
|
||||||
|
#define JS_BITS_PER_FLOAT_LOG2 5L
|
||||||
|
#define JS_BITS_PER_DOUBLE_LOG2 6L
|
||||||
|
#define JS_BITS_PER_WORD_LOG2 5L
|
||||||
|
|
||||||
|
#define JS_ALIGN_OF_SHORT 2L
|
||||||
|
#define JS_ALIGN_OF_INT 4L
|
||||||
|
#define JS_ALIGN_OF_LONG 4L
|
||||||
|
#define JS_ALIGN_OF_INT64 2L
|
||||||
|
#define JS_ALIGN_OF_FLOAT 4L
|
||||||
|
#define JS_ALIGN_OF_DOUBLE 4L
|
||||||
|
#define JS_ALIGN_OF_POINTER 4L
|
||||||
|
#define JS_ALIGN_OF_WORD 4L
|
||||||
|
|
||||||
|
#define JS_BYTES_PER_WORD_LOG2 2L
|
||||||
|
#define JS_BYTES_PER_DWORD_LOG2 3L
|
||||||
|
#define PR_WORDS_PER_DWORD_LOG2 1L
|
||||||
|
|
||||||
|
#elif defined(XP_PC)
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define IS_LITTLE_ENDIAN 1
|
||||||
|
#undef IS_BIG_ENDIAN
|
||||||
|
|
||||||
|
#define JS_BYTES_PER_BYTE 1L
|
||||||
|
#define JS_BYTES_PER_SHORT 2L
|
||||||
|
#define JS_BYTES_PER_INT 4L
|
||||||
|
#define JS_BYTES_PER_INT64 8L
|
||||||
|
#define JS_BYTES_PER_LONG 4L
|
||||||
|
#define JS_BYTES_PER_FLOAT 4L
|
||||||
|
#define JS_BYTES_PER_DOUBLE 8L
|
||||||
|
#define JS_BYTES_PER_WORD 4L
|
||||||
|
#define JS_BYTES_PER_DWORD 8L
|
||||||
|
|
||||||
|
#define JS_BITS_PER_BYTE 8L
|
||||||
|
#define JS_BITS_PER_SHORT 16L
|
||||||
|
#define JS_BITS_PER_INT 32L
|
||||||
|
#define JS_BITS_PER_INT64 64L
|
||||||
|
#define JS_BITS_PER_LONG 32L
|
||||||
|
#define JS_BITS_PER_FLOAT 32L
|
||||||
|
#define JS_BITS_PER_DOUBLE 64L
|
||||||
|
#define JS_BITS_PER_WORD 32L
|
||||||
|
|
||||||
|
#define JS_BITS_PER_BYTE_LOG2 3L
|
||||||
|
#define JS_BITS_PER_SHORT_LOG2 4L
|
||||||
|
#define JS_BITS_PER_INT_LOG2 5L
|
||||||
|
#define JS_BITS_PER_INT64_LOG2 6L
|
||||||
|
#define JS_BITS_PER_LONG_LOG2 5L
|
||||||
|
#define JS_BITS_PER_FLOAT_LOG2 5L
|
||||||
|
#define JS_BITS_PER_DOUBLE_LOG2 6L
|
||||||
|
#define JS_BITS_PER_WORD_LOG2 5L
|
||||||
|
|
||||||
|
#define JS_ALIGN_OF_SHORT 2L
|
||||||
|
#define JS_ALIGN_OF_INT 4L
|
||||||
|
#define JS_ALIGN_OF_LONG 4L
|
||||||
|
#define JS_ALIGN_OF_INT64 8L
|
||||||
|
#define JS_ALIGN_OF_FLOAT 4L
|
||||||
|
#define JS_ALIGN_OF_DOUBLE 4L
|
||||||
|
#define JS_ALIGN_OF_POINTER 4L
|
||||||
|
#define JS_ALIGN_OF_WORD 4L
|
||||||
|
|
||||||
|
#define JS_BYTES_PER_WORD_LOG2 2L
|
||||||
|
#define JS_BYTES_PER_DWORD_LOG2 3L
|
||||||
|
#define PR_WORDS_PER_DWORD_LOG2 1L
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
#if defined(_WINDOWS) && !defined(_WIN32) /* WIN16 */
|
||||||
|
#define IS_LITTLE_ENDIAN 1
|
||||||
|
#undef IS_BIG_ENDIAN
|
||||||
|
|
||||||
|
#define JS_BYTES_PER_BYTE 1L
|
||||||
|
#define JS_BYTES_PER_SHORT 2L
|
||||||
|
#define JS_BYTES_PER_INT 2L
|
||||||
|
#define JS_BYTES_PER_INT64 8L
|
||||||
|
#define JS_BYTES_PER_LONG 4L
|
||||||
|
#define JS_BYTES_PER_FLOAT 4L
|
||||||
|
#define JS_BYTES_PER_DOUBLE 8L
|
||||||
|
#define JS_BYTES_PER_WORD 4L
|
||||||
|
#define JS_BYTES_PER_DWORD 8L
|
||||||
|
|
||||||
|
#define JS_BITS_PER_BYTE 8L
|
||||||
|
#define JS_BITS_PER_SHORT 16L
|
||||||
|
#define JS_BITS_PER_INT 16L
|
||||||
|
#define JS_BITS_PER_INT64 64L
|
||||||
|
#define JS_BITS_PER_LONG 32L
|
||||||
|
#define JS_BITS_PER_FLOAT 32L
|
||||||
|
#define JS_BITS_PER_DOUBLE 64L
|
||||||
|
#define JS_BITS_PER_WORD 32L
|
||||||
|
|
||||||
|
#define JS_BITS_PER_BYTE_LOG2 3L
|
||||||
|
#define JS_BITS_PER_SHORT_LOG2 4L
|
||||||
|
#define JS_BITS_PER_INT_LOG2 4L
|
||||||
|
#define JS_BITS_PER_INT64_LOG2 6L
|
||||||
|
#define JS_BITS_PER_LONG_LOG2 5L
|
||||||
|
#define JS_BITS_PER_FLOAT_LOG2 5L
|
||||||
|
#define JS_BITS_PER_DOUBLE_LOG2 6L
|
||||||
|
#define JS_BITS_PER_WORD_LOG2 5L
|
||||||
|
|
||||||
|
#define JS_ALIGN_OF_SHORT 2L
|
||||||
|
#define JS_ALIGN_OF_INT 2L
|
||||||
|
#define JS_ALIGN_OF_LONG 2L
|
||||||
|
#define JS_ALIGN_OF_INT64 2L
|
||||||
|
#define JS_ALIGN_OF_FLOAT 2L
|
||||||
|
#define JS_ALIGN_OF_DOUBLE 2L
|
||||||
|
#define JS_ALIGN_OF_POINTER 2L
|
||||||
|
#define JS_ALIGN_OF_WORD 2L
|
||||||
|
|
||||||
|
#define JS_BYTES_PER_WORD_LOG2 2L
|
||||||
|
#define JS_BYTES_PER_DWORD_LOG2 3L
|
||||||
|
#define PR_WORDS_PER_DWORD_LOG2 1L
|
||||||
|
#endif /* defined(_WINDOWS) && !defined(_WIN32) */
|
||||||
|
|
||||||
|
#elif defined(XP_UNIX) || defined(XP_BEOS)
|
||||||
|
|
||||||
|
#error "This file is supposed to be auto-generated on UNIX platforms, but the"
|
||||||
|
#error "static version for Mac and Windows platforms is being used."
|
||||||
|
#error "Something's probably wrong with paths/headers/dependencies/Makefiles."
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#error "Must define one of XP_MAC, XP_PC, or XP_UNIX"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
466
mozilla/js/js2/debugger.cpp
Normal file
466
mozilla/js/js2/debugger.cpp
Normal file
@@ -0,0 +1,466 @@
|
|||||||
|
/* -*- 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 "world.h"
|
||||||
|
#include "debugger.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
namespace Debugger {
|
||||||
|
|
||||||
|
using namespace Interpreter;
|
||||||
|
|
||||||
|
/* keep in sync with list in debugger.h */
|
||||||
|
static const char *shell_cmds[][3] = {
|
||||||
|
{"assemble", "", 0},
|
||||||
|
{"ambiguous", "", "Test command for ambiguous command detection"},
|
||||||
|
{"ambiguous2", "", "Test command for ambiguous command detection"},
|
||||||
|
{"continue", "", "Continue execution until complete."},
|
||||||
|
{"dissassemble", "[start_pc] [end_pc]", "Dissassemble entire module, or subset of module."},
|
||||||
|
{"exit", "", 0},
|
||||||
|
{"help", "", "Display this message."},
|
||||||
|
{"istep", "", "Execute the current opcode and stop."},
|
||||||
|
{"let", "", "Set a debugger environment variable."},
|
||||||
|
{"print", "", 0},
|
||||||
|
{"register", "", "(nyi) Show the value of a single register or all registers, or set the value of a single register."},
|
||||||
|
{"step", "", "Execute the current JS statement and stop."},
|
||||||
|
{0, 0} /* sentry */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ShellVariable {
|
||||||
|
TRACE_SOURCE,
|
||||||
|
TRACE_ICODE,
|
||||||
|
VARIABLE_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *shell_vars[][3] = {
|
||||||
|
{"tracesource", "", "(bool) Show JS source while executing."},
|
||||||
|
{"traceicode", " ", "(bool) Show opcodes while executing."},
|
||||||
|
{0, 0} /* sentry */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* return true if str2 starts with/is str1
|
||||||
|
* XXX ignore case */
|
||||||
|
static bool
|
||||||
|
startsWith (const String &str1, const String &str2)
|
||||||
|
{
|
||||||
|
uint n;
|
||||||
|
size_t m = str1.size();
|
||||||
|
|
||||||
|
if (m > str2.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (n = 0; n < m; ++n)
|
||||||
|
if (str1[n] != str2[n])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* locate the best match for |partial| in the command list |list|.
|
||||||
|
* if no matches are found, return |length|, if multiple matches are found,
|
||||||
|
* return |length| plus the number of ambiguous matches
|
||||||
|
*/
|
||||||
|
static uint32
|
||||||
|
matchElement (const String &partial, const char *list[][3], size_t length)
|
||||||
|
{
|
||||||
|
uint32 ambig_matches = 0;
|
||||||
|
uint32 match = length;
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < length ; ++i)
|
||||||
|
{
|
||||||
|
String possibleMatch (widenCString(list[i][0]));
|
||||||
|
if (startsWith(partial, possibleMatch))
|
||||||
|
{
|
||||||
|
if (partial.size() == possibleMatch.size())
|
||||||
|
{
|
||||||
|
/* exact match */
|
||||||
|
ambig_matches = 0;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
else if (match == COMMAND_COUNT) /* no match yet */
|
||||||
|
match = i;
|
||||||
|
else
|
||||||
|
++ambig_matches; /* something already matched,
|
||||||
|
* ambiguous command */
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ambig_matches == 0)
|
||||||
|
return match;
|
||||||
|
else
|
||||||
|
return length + ambig_matches;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
showHelp(Formatter &out)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
out << "JavaScript 2.0 Debugger Help...\n\n";
|
||||||
|
|
||||||
|
for (i = 0; shell_cmds[i][0] != 0; i++)
|
||||||
|
{
|
||||||
|
out << "Command : " << shell_cmds[i][0] << " " <<
|
||||||
|
shell_cmds[i][1] << "\n";
|
||||||
|
|
||||||
|
if (shell_cmds[i][2])
|
||||||
|
out << "Help : " << shell_cmds[i][2] << "\n";
|
||||||
|
else
|
||||||
|
out << "Help : (probably) Not Implemented.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32
|
||||||
|
getClosestSourcePosForPC (Context *cx, InstructionIterator pc)
|
||||||
|
{
|
||||||
|
ICodeModule *iCode = cx->getICode();
|
||||||
|
|
||||||
|
if (iCode->mInstructionMap->begin() == iCode->mInstructionMap->end())
|
||||||
|
return NotABanana;
|
||||||
|
/*NOT_REACHED ("Instruction map is empty, waah.");*/
|
||||||
|
|
||||||
|
InstructionMap::iterator pos_iter =
|
||||||
|
iCode->mInstructionMap->upper_bound (pc - iCode->its_iCode->begin());
|
||||||
|
if (pos_iter != iCode->mInstructionMap->begin())
|
||||||
|
--pos_iter;
|
||||||
|
|
||||||
|
return pos_iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Shell::showSourceAtPC (Context *cx, InstructionIterator pc)
|
||||||
|
{
|
||||||
|
if (!mResolveFileCallback)
|
||||||
|
{
|
||||||
|
mErr << "Source not available (Debugger was improperly initialized.)\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ICodeModule *iCode = cx->getICode();
|
||||||
|
|
||||||
|
String fn = iCode->getFileName();
|
||||||
|
const Reader *reader = mResolveFileCallback(fn);
|
||||||
|
if (!reader)
|
||||||
|
{
|
||||||
|
mErr << "Source not available.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 pos = getClosestSourcePosForPC(cx, pc);
|
||||||
|
if (pos == NotABanana)
|
||||||
|
{
|
||||||
|
mErr << "Map is empty, cannot display source.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 lineNum = reader->posToLineNum (pos);
|
||||||
|
const char16 *lineBegin, *lineEnd;
|
||||||
|
|
||||||
|
uint32 lineStartPos = reader->getLine (lineNum, lineBegin, lineEnd);
|
||||||
|
String sourceLine (lineBegin, lineEnd);
|
||||||
|
|
||||||
|
mOut << fn << ":" << lineNum << " " << sourceLine << "\n";
|
||||||
|
|
||||||
|
uint padding = fn.length() + (uint32)(lineNum / 10) + 3;
|
||||||
|
uint i;
|
||||||
|
|
||||||
|
for (i = 0; i < padding; i++)
|
||||||
|
mOut << " ";
|
||||||
|
|
||||||
|
padding = (pos - lineStartPos);
|
||||||
|
for (i = 0; i < padding; i++)
|
||||||
|
mOut << ".";
|
||||||
|
|
||||||
|
mOut << "^\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Shell::showOpAtPC(Context* cx, InstructionIterator pc)
|
||||||
|
{
|
||||||
|
ICodeModule *iCode = cx->getICode();
|
||||||
|
|
||||||
|
if ((pc < iCode->its_iCode->begin()) ||
|
||||||
|
(pc >= iCode->its_iCode->end()))
|
||||||
|
{
|
||||||
|
mErr << "PC Out Of Range.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValues ®isters = cx->getRegisters();
|
||||||
|
|
||||||
|
printFormat(mOut, "trace [%02u:%04u]: ",
|
||||||
|
iCode->mID, (pc - iCode->its_iCode->begin()));
|
||||||
|
Instruction* i = *pc;
|
||||||
|
stdOut << *i;
|
||||||
|
if (i->op() != BRANCH && i->count() > 0) {
|
||||||
|
mOut << " [";
|
||||||
|
i->printOperands(stdOut, registers);
|
||||||
|
mOut << "]\n";
|
||||||
|
} else {
|
||||||
|
mOut << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Shell::listen(Context* cx, Context::Event event)
|
||||||
|
{
|
||||||
|
InstructionIterator pc = cx->getPC();
|
||||||
|
|
||||||
|
if (mTraceSource)
|
||||||
|
showSourceAtPC (cx, pc);
|
||||||
|
if (mTraceICode)
|
||||||
|
showOpAtPC (cx, pc);
|
||||||
|
|
||||||
|
if (!(mStopMask & event))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((mLastCommand == STEP) && (mLastICodeID == cx->getICode()->mID) &&
|
||||||
|
(mLastSourcePos == getClosestSourcePosForPC (cx, cx->getPC())))
|
||||||
|
/* we're in source-step mode, and the source position hasn't
|
||||||
|
* changed yet */
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!mTraceSource && !mTraceICode)
|
||||||
|
showSourceAtPC (cx, pc);
|
||||||
|
|
||||||
|
static String lastLine(widenCString("help\n"));
|
||||||
|
String line;
|
||||||
|
LineReader reader(mIn);
|
||||||
|
|
||||||
|
do {
|
||||||
|
stdOut << "jsd";
|
||||||
|
if (mLastCommand != COMMAND_COUNT)
|
||||||
|
stdOut << " (" << shell_cmds[mLastCommand][0] << ") ";
|
||||||
|
stdOut << "> ";
|
||||||
|
|
||||||
|
reader.readLine(line);
|
||||||
|
|
||||||
|
if (line[0] == uni::lf)
|
||||||
|
line = lastLine;
|
||||||
|
else
|
||||||
|
lastLine = line;
|
||||||
|
|
||||||
|
} while (doCommand(cx, line));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lex and execute the debugger command in |source|, return true if the
|
||||||
|
* command does not require the script being debugged to continue (eg, ask
|
||||||
|
* for more debugger input.)
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
Shell::doCommand (Interpreter::Context *cx, const String &source)
|
||||||
|
{
|
||||||
|
Lexer lex (mWorld, source, widenCString("debugger console"), 0);
|
||||||
|
const String *cmd;
|
||||||
|
uint32 match;
|
||||||
|
bool rv = true;
|
||||||
|
|
||||||
|
const Token &t = lex.get(true);
|
||||||
|
|
||||||
|
if (t.hasKind(Token::identifier))
|
||||||
|
cmd = &(t.getIdentifier());
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mErr << "you idiot.\n";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
match = matchElement (*cmd, shell_cmds, (size_t)COMMAND_COUNT);
|
||||||
|
|
||||||
|
if (match <= (uint32)COMMAND_COUNT)
|
||||||
|
{
|
||||||
|
switch ((ShellCommand)match)
|
||||||
|
{
|
||||||
|
case COMMAND_COUNT:
|
||||||
|
mErr << "Unknown command '" << *cmd << "'.\n";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AMBIGUOUS:
|
||||||
|
case AMBIGUOUS2:
|
||||||
|
mErr << "I pity the foogoo.\n";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONTINUE:
|
||||||
|
mStopMask &= (Context::EV_ALL ^ Context::EV_STEP);
|
||||||
|
rv = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DISSASSEMBLE:
|
||||||
|
mOut << *cx->getICode();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HELP:
|
||||||
|
showHelp (mOut);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PRINT:
|
||||||
|
doPrint (cx, lex);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STEP:
|
||||||
|
mStopMask |= Context::EV_STEP;
|
||||||
|
rv = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LET:
|
||||||
|
doSetVariable (lex);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
mErr << "Input '" << *cmd << "' matched unimplemented " <<
|
||||||
|
"command '" << shell_cmds[match][0] << "'.\n";
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mLastSourcePos = getClosestSourcePosForPC (cx, cx->getPC());
|
||||||
|
mLastICodeID = cx->getICode()->mID;
|
||||||
|
mLastCommand = (ShellCommand)match;
|
||||||
|
|
||||||
|
} else
|
||||||
|
mErr << "Ambiguous command '" << *cmd << "', " <<
|
||||||
|
(match - (uint32)COMMAND_COUNT + 1) << " similar commands.\n";
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Shell::doSetVariable (Lexer &lex)
|
||||||
|
{
|
||||||
|
uint32 match;
|
||||||
|
const String *varname;
|
||||||
|
const Token *t = &(lex.get(true));
|
||||||
|
|
||||||
|
if (t->hasKind(Token::identifier))
|
||||||
|
varname = &(t->getIdentifier());
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mErr << "invalid variable name.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match = matchElement (*varname, shell_vars, (size_t)VARIABLE_COUNT);
|
||||||
|
|
||||||
|
if (match <= (uint32)VARIABLE_COUNT)
|
||||||
|
switch ((ShellVariable)match)
|
||||||
|
{
|
||||||
|
case VARIABLE_COUNT:
|
||||||
|
mErr << "Unknown variable '" << *varname << "'.\n";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TRACE_SOURCE:
|
||||||
|
t = &(lex.get(true));
|
||||||
|
if (t->hasKind(Token::assignment))
|
||||||
|
t = &(lex.get(true)); /* optional = */
|
||||||
|
|
||||||
|
if (t->hasKind(Token::True))
|
||||||
|
mTraceSource = true;
|
||||||
|
else if (t->hasKind(Token::False))
|
||||||
|
mTraceSource = false;
|
||||||
|
else
|
||||||
|
goto badval;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TRACE_ICODE:
|
||||||
|
t = &(lex.get(true));
|
||||||
|
if (t->hasKind(Token::assignment))
|
||||||
|
t = &(lex.get(true)); /* optional = */
|
||||||
|
|
||||||
|
if (t->hasKind(Token::True))
|
||||||
|
mTraceICode = true;
|
||||||
|
else if (t->hasKind(Token::False))
|
||||||
|
mTraceICode = false;
|
||||||
|
else
|
||||||
|
goto badval;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
mErr << "Variable '" << *varname <<
|
||||||
|
"' matched unimplemented variable '" <<
|
||||||
|
shell_vars[match][0] << "'.\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mErr << "Ambiguous variable '" << *varname << "', " <<
|
||||||
|
(match - (uint32)COMMAND_COUNT + 1) << " similar variables.\n";
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
badval:
|
||||||
|
mErr << "Invalid value for variable '" <<
|
||||||
|
shell_vars[(ShellVariable)match][0] << "'\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Shell::doPrint (Context *, Lexer &lex)
|
||||||
|
{
|
||||||
|
const Token *t = &(lex.get(true));
|
||||||
|
|
||||||
|
if (!(t->hasKind(Token::identifier)))
|
||||||
|
{
|
||||||
|
mErr << "Invalid register name.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
const StringAtom *name = &(t->getIdentifier());
|
||||||
|
|
||||||
|
VariableMap::iterator i = ((cx->getICode())->itsVariables)->find(*name);
|
||||||
|
// if (i)
|
||||||
|
mOut << (*i).first << " = " << (*i).second << "\n";
|
||||||
|
// else
|
||||||
|
// mOut << "No " << *name << " defined.\n";
|
||||||
|
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace Debugger */
|
||||||
|
} /* namespace JavaScript */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
163
mozilla/js/js2/debugger.h
Normal file
163
mozilla/js/js2/debugger.h
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
/* -*- 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* this is all vapor, don't take it to serious yet */
|
||||||
|
|
||||||
|
#ifndef debugger_h
|
||||||
|
#define debugger_h
|
||||||
|
|
||||||
|
#include "utilities.h"
|
||||||
|
#include "interpreter.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
namespace Debugger {
|
||||||
|
|
||||||
|
using namespace Interpreter;
|
||||||
|
|
||||||
|
class Shell;
|
||||||
|
|
||||||
|
typedef const Reader *ResolveFileCallback (const String &fileName);
|
||||||
|
typedef bool DebuggerCommandCallback (Shell &debugger, const Lexer &lex);
|
||||||
|
|
||||||
|
class Breakpoint {
|
||||||
|
public:
|
||||||
|
/* representation of a breakpoint */
|
||||||
|
void set();
|
||||||
|
void clear();
|
||||||
|
bool getState();
|
||||||
|
InstructionIterator getPC();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DebuggerCommand
|
||||||
|
{
|
||||||
|
DebuggerCommand(String aName, String aParamDesc, String aShortHelp,
|
||||||
|
String aLongHelp = widenCString("No more help available."),
|
||||||
|
DebuggerCommandCallback *aCommandFunction = 0)
|
||||||
|
: mName(aName), mParamDesc(aParamDesc), mShortHelp(aShortHelp),
|
||||||
|
mLongHelp(aLongHelp), mCommandFunction(aCommandFunction) {}
|
||||||
|
|
||||||
|
String mName;
|
||||||
|
String mParamDesc;
|
||||||
|
String mShortHelp;
|
||||||
|
String mLongHelp;
|
||||||
|
DebuggerCommandCallback *mCommandFunction;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* keep in sync with list in debugger.cpp */
|
||||||
|
enum ShellCommand {
|
||||||
|
ASSEMBLE,
|
||||||
|
AMBIGUOUS,
|
||||||
|
AMBIGUOUS2,
|
||||||
|
CONTINUE,
|
||||||
|
DISSASSEMBLE,
|
||||||
|
EXIT,
|
||||||
|
HELP,
|
||||||
|
ISTEP,
|
||||||
|
LET,
|
||||||
|
PRINT,
|
||||||
|
REGISTER,
|
||||||
|
STEP,
|
||||||
|
COMMAND_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
class Shell : public Context::Listener {
|
||||||
|
public:
|
||||||
|
Shell (World &aWorld, FILE *aIn, Formatter &aOut, Formatter &aErr,
|
||||||
|
ResolveFileCallback *aCallback = 0) :
|
||||||
|
mWorld(aWorld), mIn(aIn), mOut(aOut), mErr(aErr),
|
||||||
|
mResolveFileCallback(aCallback), mStopMask(Context::EV_DEBUG),
|
||||||
|
mTraceSource(false), mTraceICode(false), mLastSourcePos(0),
|
||||||
|
mLastICodeID(NotABanana), mLastCommand(COMMAND_COUNT)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Shell ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ResolveFileCallback
|
||||||
|
*setResolveFileCallback (ResolveFileCallback *aCallback)
|
||||||
|
{
|
||||||
|
ResolveFileCallback *rv = mResolveFileCallback;
|
||||||
|
mResolveFileCallback = aCallback;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void listen(Context *context, Context::Event event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* install on a context
|
||||||
|
*/
|
||||||
|
bool attachToContext (Context *aContext)
|
||||||
|
{
|
||||||
|
aContext->addListener (this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* detach an icdebugger from a context
|
||||||
|
*/
|
||||||
|
bool detachFromContext (Context *aContext)
|
||||||
|
{
|
||||||
|
aContext->removeListener (this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *getIStream() { return mIn; }
|
||||||
|
Formatter &getOStream() { return mOut; }
|
||||||
|
Formatter &getEStream() { return mErr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool doCommand (Context *cx, const String &aSource);
|
||||||
|
void doSetVariable (Lexer &lex);
|
||||||
|
void doPrint (Context *cx, Lexer &lex);
|
||||||
|
|
||||||
|
void showOpAtPC(Context* cx, InstructionIterator pc);
|
||||||
|
void showSourceAtPC(Context* cx, InstructionIterator pc);
|
||||||
|
|
||||||
|
World &mWorld;
|
||||||
|
FILE *mIn;
|
||||||
|
Formatter &mOut, &mErr;
|
||||||
|
ResolveFileCallback *mResolveFileCallback;
|
||||||
|
uint32 mStopMask;
|
||||||
|
bool mTraceSource, mTraceICode;
|
||||||
|
uint32 mLastSourcePos, mLastICodeID;
|
||||||
|
ShellCommand mLastCommand;
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace Debugger */
|
||||||
|
} /* namespace JavaScript */
|
||||||
|
|
||||||
|
#endif /* debugger_h */
|
||||||
26
mozilla/js/js2/dependencies
Normal file
26
mozilla/js/js2/dependencies
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
debugger.o: debugger.cpp world.h utilities.h systemtypes.h hash.h \
|
||||||
|
parser.h debugger.h interpreter.h jstypes.h gc_allocator.h vmtypes.h \
|
||||||
|
numerics.h jsclasses.h icode.h icodegenerator.h
|
||||||
|
gc_allocator.o: gc_allocator.cpp gc_allocator.h gc_container.h
|
||||||
|
hash.o: hash.cpp hash.h utilities.h systemtypes.h
|
||||||
|
icodegenerator.o: icodegenerator.cpp numerics.h utilities.h \
|
||||||
|
systemtypes.h world.h hash.h parser.h vmtypes.h jstypes.h \
|
||||||
|
gc_allocator.h jsclasses.h icode.h icodegenerator.h interpreter.h
|
||||||
|
interpreter.o: interpreter.cpp interpreter.h utilities.h systemtypes.h \
|
||||||
|
jstypes.h gc_allocator.h vmtypes.h numerics.h jsclasses.h world.h \
|
||||||
|
hash.h parser.h icode.h icodegenerator.h jsmath.h
|
||||||
|
js2.o: js2.cpp world.h utilities.h systemtypes.h hash.h parser.h \
|
||||||
|
interpreter.h jstypes.h gc_allocator.h vmtypes.h numerics.h \
|
||||||
|
jsclasses.h icode.h icodegenerator.h debugger.h
|
||||||
|
jsmath.o: jsmath.cpp jsmath.h jstypes.h utilities.h systemtypes.h \
|
||||||
|
gc_allocator.h
|
||||||
|
jstypes.o: jstypes.cpp jstypes.h utilities.h systemtypes.h \
|
||||||
|
gc_allocator.h jsclasses.h numerics.h icodegenerator.h parser.h \
|
||||||
|
vmtypes.h world.h hash.h icode.h
|
||||||
|
numerics.o: numerics.cpp numerics.h utilities.h systemtypes.h
|
||||||
|
parser.o: parser.cpp numerics.h utilities.h systemtypes.h parser.h \
|
||||||
|
world.h hash.h
|
||||||
|
utilities.o: utilities.cpp utilities.h systemtypes.h
|
||||||
|
vmtypes.o: vmtypes.cpp utilities.h systemtypes.h vmtypes.h numerics.h \
|
||||||
|
jstypes.h gc_allocator.h jsclasses.h world.h hash.h parser.h icode.h
|
||||||
|
world.o: world.cpp world.h utilities.h systemtypes.h hash.h parser.h
|
||||||
150
mozilla/js/js2/gc_allocator.cpp
Normal file
150
mozilla/js/js2/gc_allocator.cpp
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
// -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; 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) 2000 Netscape Communications Corporation. All
|
||||||
|
// Rights Reserved.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "gc_allocator.h"
|
||||||
|
#include "gc_container.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
namespace JavaScript {
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
typename gc_allocator<T>::pointer
|
||||||
|
gc_allocator<T>::allocate(gc_allocator<T>::size_type n, const void*)
|
||||||
|
{
|
||||||
|
return static_cast<pointer>(GC_malloc(n*sizeof(T)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void gc_allocator<T>::deallocate(gc_allocator<T>::pointer ptr, gc_allocator<T>::size_type)
|
||||||
|
{
|
||||||
|
// this can really be a NO-OP with the GC.
|
||||||
|
// ::GC_free(static_cast<void*>(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// test driver for standalone GC development.
|
||||||
|
|
||||||
|
namespace JS = JavaScript;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void* operator new(std::size_t, const JS::gc_allocator<T>& alloc)
|
||||||
|
{
|
||||||
|
return alloc.allocate(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a C++ class that is garbage collectable, and wants to have its destructor
|
||||||
|
* called when it is finalized.
|
||||||
|
*/
|
||||||
|
class A {
|
||||||
|
public:
|
||||||
|
typedef JS::gc_traits_finalizable<A> traits;
|
||||||
|
typedef JS::gc_allocator<A, traits> allocator;
|
||||||
|
friend struct traits;
|
||||||
|
|
||||||
|
static int instances;
|
||||||
|
|
||||||
|
void* operator new(std::size_t)
|
||||||
|
{
|
||||||
|
return allocator::allocate(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
A()
|
||||||
|
{
|
||||||
|
++instances;
|
||||||
|
std::cout << "A::A() here." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~A()
|
||||||
|
{
|
||||||
|
--instances;
|
||||||
|
std::cout << "A::~A() here." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// void operator delete(void*) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
int A::instances = 0;
|
||||||
|
|
||||||
|
int main(int /* argc */, char* /* argv[] */)
|
||||||
|
{
|
||||||
|
using namespace std;
|
||||||
|
using namespace JS;
|
||||||
|
|
||||||
|
cout << "testing the GC allocator." << endl;
|
||||||
|
|
||||||
|
#ifdef XP_MAC
|
||||||
|
// allocate a string, using the GC, and owned by an auto_ptr, that knows how to correctly destroy the string.
|
||||||
|
typedef gc_container<char>::string char_string;
|
||||||
|
typedef gc_allocator<char_string> char_string_alloc;
|
||||||
|
auto_ptr<char_string, char_string_alloc> ptr(new(char_string_alloc()) char_string("This is a garbage collectable string."));
|
||||||
|
const char_string& str = *ptr;
|
||||||
|
cout << str << endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// question, how can we partially evaluate a template?
|
||||||
|
// can we say, typedef template <class T> vector<typename T>.
|
||||||
|
// typedef vector<int, gc_allocator<int> > int_vector;
|
||||||
|
typedef gc_container<int>::vector int_vector;
|
||||||
|
|
||||||
|
// generate 1000 random values.
|
||||||
|
int_vector values;
|
||||||
|
for (int i = 0; i < 1000; ++i) {
|
||||||
|
int value = rand() % 32767;
|
||||||
|
values.push_back(value);
|
||||||
|
// allocate a random amount of garbage.
|
||||||
|
if (!GC_malloc(static_cast<size_t>(value)))
|
||||||
|
cerr << "GC_malloc failed." << endl;
|
||||||
|
// allocate an object that has a finalizer to call its destructor.
|
||||||
|
A* a = new A();
|
||||||
|
}
|
||||||
|
|
||||||
|
// run a collection.
|
||||||
|
// gc_allocator<void>::collect();
|
||||||
|
GC_gcollect();
|
||||||
|
|
||||||
|
// print out instance count.
|
||||||
|
cout << "A::instances = " << A::instances << endl;
|
||||||
|
|
||||||
|
// sort the values.
|
||||||
|
sort(values.begin(), values.end());
|
||||||
|
|
||||||
|
// print the values.
|
||||||
|
int_vector::iterator iter = values.begin(), last = values.end();
|
||||||
|
cout << *iter++;
|
||||||
|
while (iter < last)
|
||||||
|
cout << ' ' << *iter++;
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
#ifdef XP_MAC
|
||||||
|
// finally, print the string again.
|
||||||
|
cout << str << endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
178
mozilla/js/js2/gc_allocator.h
Normal file
178
mozilla/js/js2/gc_allocator.h
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
// -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; 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) 2000 Netscape Communications Corporation. All
|
||||||
|
// Rights Reserved.
|
||||||
|
|
||||||
|
#ifndef gc_allocator_h
|
||||||
|
#define gc_allocator_h
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#ifndef _WIN32 // Microsoft VC6 bug: standard identifiers should be in std namespace
|
||||||
|
using std::size_t;
|
||||||
|
using std::ptrdiff_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
extern "C" {
|
||||||
|
void* GC_malloc(size_t bytes);
|
||||||
|
void* GC_malloc_atomic(size_t bytes);
|
||||||
|
void GC_free(void* ptr);
|
||||||
|
void GC_gcollect(void);
|
||||||
|
|
||||||
|
typedef void (*GC_finalization_proc) (void* obj, void* client_data);
|
||||||
|
void GC_register_finalizer(void* obj, GC_finalization_proc proc, void* client_data,
|
||||||
|
GC_finalization_proc *old_proc, void* *old_client_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0 && !defined(XP_MAC)
|
||||||
|
// for platforms where GC doesn't exist yet.
|
||||||
|
inline void* GC_malloc(size_t bytes) { return ::operator new(bytes); }
|
||||||
|
inline void* GC_malloc_atomic(size_t bytes) { return ::operator new(bytes); }
|
||||||
|
inline void GC_free(void* ptr) { operator delete(ptr); }
|
||||||
|
inline void GC_gcollect() {}
|
||||||
|
inline void GC_register_finalizer(void* obj, GC_finalization_proc proc, void* client_data,
|
||||||
|
GC_finalization_proc *old_proc, void* *old_client_data) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* General case: memory for type must be allocated as a conservatively
|
||||||
|
* scanned block of memory.
|
||||||
|
*/
|
||||||
|
template <class T> struct gc_traits {
|
||||||
|
static T* allocate(size_t n) { return static_cast<T*>(GC_malloc(n * sizeof(T))); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specializations for blocks of atomic types: the macro define_atomic_type(_type)
|
||||||
|
* specializes gc_traits<T> for types that need not be scanned by the
|
||||||
|
* GC. Implementors are free to define other types as atomic, if they are
|
||||||
|
* guaranteed not to contain pointers.
|
||||||
|
*/
|
||||||
|
#define define_atomic_type(_type) \
|
||||||
|
template <> struct gc_traits<_type> { \
|
||||||
|
static _type* allocate(size_t n) \
|
||||||
|
{ \
|
||||||
|
return static_cast<_type*>(GC_malloc_atomic(n * sizeof(_type))); \
|
||||||
|
} \
|
||||||
|
};
|
||||||
|
|
||||||
|
define_atomic_type(char)
|
||||||
|
define_atomic_type(unsigned char)
|
||||||
|
define_atomic_type(short)
|
||||||
|
define_atomic_type(unsigned short)
|
||||||
|
define_atomic_type(int)
|
||||||
|
define_atomic_type(unsigned int)
|
||||||
|
define_atomic_type(long)
|
||||||
|
define_atomic_type(unsigned long)
|
||||||
|
define_atomic_type(float)
|
||||||
|
define_atomic_type(double)
|
||||||
|
|
||||||
|
#undef define_atomic_type
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traits for classes that need to have their destructor called
|
||||||
|
* when reclaimed by the garbage collector.
|
||||||
|
*/
|
||||||
|
template <class T> struct gc_traits_finalizable {
|
||||||
|
static void finalizer(void* obj, void* client_data)
|
||||||
|
{
|
||||||
|
T* t = static_cast<T*>(obj);
|
||||||
|
size_t n = reinterpret_cast<size_t>(client_data);
|
||||||
|
for (size_t i = 0; i < n; ++i)
|
||||||
|
t[i].~T();
|
||||||
|
}
|
||||||
|
|
||||||
|
static T* allocate(size_t n)
|
||||||
|
{
|
||||||
|
T* t = gc_traits<T>::allocate(n);
|
||||||
|
GC_finalization_proc old_proc; void* old_client_data;
|
||||||
|
GC_register_finalizer(t, &finalizer, reinterpret_cast<void*>(n), &old_proc, &old_client_data);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An allocator that can be used to allocate objects in the garbage collected heap.
|
||||||
|
*/
|
||||||
|
template <class T, class traits = gc_traits<T> > class gc_allocator {
|
||||||
|
public:
|
||||||
|
typedef T value_type;
|
||||||
|
typedef size_t size_type;
|
||||||
|
typedef ptrdiff_t difference_type;
|
||||||
|
typedef T *pointer;
|
||||||
|
typedef const T *const_pointer;
|
||||||
|
typedef T &reference;
|
||||||
|
typedef const T &const_reference;
|
||||||
|
|
||||||
|
gc_allocator() {}
|
||||||
|
template<typename U, typename UTraits> gc_allocator(const gc_allocator<U, UTraits>&) {}
|
||||||
|
// ~gc_allocator() {}
|
||||||
|
|
||||||
|
static pointer address(reference r) { return &r; }
|
||||||
|
static const_pointer address(const_reference r) { return &r; }
|
||||||
|
|
||||||
|
static pointer allocate(size_type n, const void* /* hint */ = 0) { return traits::allocate(n); }
|
||||||
|
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(); }
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(_WIN32)
|
||||||
|
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); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<class U> struct rebind { typedef gc_allocator<U> other; };
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// raw byte allocator used on some platforms (grrr).
|
||||||
|
typedef char _Char[1];
|
||||||
|
static char* _Charalloc(size_type n) { return (char*) rebind<_Char>::other::allocate(n); }
|
||||||
|
|
||||||
|
// funky operator required for calling basic_string<T> constructor (grrr).
|
||||||
|
template<typename U, typename UTraits> int operator==(const gc_allocator<U, UTraits>&) { return 0; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// void* deallocate used on some platforms (grrr).
|
||||||
|
static void deallocate(void*, size_type) {}
|
||||||
|
|
||||||
|
static void collect() { GC_gcollect(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic base class for objects allocated using a gc_allocator. How they are allocated
|
||||||
|
* can be controlled by specializing gc_traits for the specific class.
|
||||||
|
*/
|
||||||
|
template <typename T> class gc_object {
|
||||||
|
public:
|
||||||
|
void* operator new(size_t) { return gc_allocator<T>::allocate(1, 0); }
|
||||||
|
void operator delete(void* /* ptr */) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simpler base class for classes that have no need to specialize allocation behavior.
|
||||||
|
*/
|
||||||
|
class gc_base {
|
||||||
|
public:
|
||||||
|
void* operator new(size_t n) { return GC_malloc(n); }
|
||||||
|
void operator delete(void*) {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* gc_allocator_h */
|
||||||
71
mozilla/js/js2/gc_container.h
Normal file
71
mozilla/js/js2/gc_container.h
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
// -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; 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) 2000 Netscape Communications Corporation. All
|
||||||
|
// Rights Reserved.
|
||||||
|
|
||||||
|
#ifndef gc_container_h
|
||||||
|
#define gc_container_h
|
||||||
|
|
||||||
|
#include "gc_allocator.h"
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define LIST std::list
|
||||||
|
#define VECTOR std::vector
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
// grr, what kind of standard is this?
|
||||||
|
#define STRING basic_string
|
||||||
|
#define CHAR_TRAITS string_char_traits
|
||||||
|
#else
|
||||||
|
#define STRING std::basic_string
|
||||||
|
#define CHAR_TRAITS std::char_traits
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
/**
|
||||||
|
* Rebind some of the basic container types to use a GC_allocator.
|
||||||
|
* What I really want is something more general, something like:
|
||||||
|
* template <typename Container, typename T> class gc_rebind {
|
||||||
|
* typedef typename Container<T, gc_allocator<T> > other;
|
||||||
|
* };
|
||||||
|
* But I can't figure out how to do that with C++ templates.
|
||||||
|
*/
|
||||||
|
template <class T> struct gc_container {
|
||||||
|
typedef typename LIST<T, gc_allocator<T> > list;
|
||||||
|
typedef typename VECTOR<T, gc_allocator<T> > vector;
|
||||||
|
typedef typename STRING<T, CHAR_TRAITS<T>, gc_allocator<T> > string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* But, it's pretty easy to do with macros:
|
||||||
|
*/
|
||||||
|
#define GC_CONTAINER(container, type) container<T, gc_allocator<T> >
|
||||||
|
|
||||||
|
/*
|
||||||
|
// this gives an "unimplemented C++ feature" error using CWPro5.
|
||||||
|
// maybe someday.
|
||||||
|
template <template<class, class> typename Container, typename T>
|
||||||
|
struct gc_rebind {
|
||||||
|
typedef typename Container<T, gc_allocator<T> > container;
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* gc_container_h */
|
||||||
173
mozilla/js/js2/hash.cpp
Normal file
173
mozilla/js/js2/hash.cpp
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
// -*- 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.
|
||||||
|
|
||||||
|
#include "hash.h"
|
||||||
|
#include <new>
|
||||||
|
namespace JS = JavaScript;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Hash Codes
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
// General-purpose null-terminated C string hash function
|
||||||
|
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
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
while (bucket != bucketsEnd) {
|
||||||
|
e = *bucket++;
|
||||||
|
if (e) {
|
||||||
|
backpointer = bucket-1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nextBucket = bucket;
|
||||||
|
}
|
||||||
|
entry = e;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JS::GenericHashTable::GenericHashTable(uint32 nEntriesDefault):
|
||||||
|
nEntries(0)
|
||||||
|
{
|
||||||
|
DEBUG_ONLY(nReferences = 0);
|
||||||
|
|
||||||
|
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 JS::GenericHashTable::recomputeMinMaxNEntries(uint lgNBuckets)
|
||||||
|
{
|
||||||
|
uint32 nBuckets = JS_BIT(lgNBuckets);
|
||||||
|
shift = 32 - lgNBuckets;
|
||||||
|
maxNEntries = nBuckets; // Maximum ratio is 100%
|
||||||
|
minNEntries = lgNBuckets <= defaultLgNBuckets ? 0 : 3*(nBuckets>>3); // Minimum ratio is 37.5%
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Rehash the table. This method cannot throw out-of-memory exceptions, so it is
|
||||||
|
// safe to call from a destructor.
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
373
mozilla/js/js2/hash.h
Normal file
373
mozilla/js/js2/hash.h
Normal file
@@ -0,0 +1,373 @@
|
|||||||
|
// -*- 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.
|
||||||
|
|
||||||
|
#ifndef hash_h
|
||||||
|
#define hash_h
|
||||||
|
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Hash Codes
|
||||||
|
//
|
||||||
|
|
||||||
|
typedef uint32 HashNumber;
|
||||||
|
|
||||||
|
HashNumber hashString(const char *s);
|
||||||
|
HashNumber hashString(const String &s);
|
||||||
|
|
||||||
|
|
||||||
|
template<class Key>
|
||||||
|
struct Hash {
|
||||||
|
HashNumber operator()(Key key) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Key>
|
||||||
|
inline HashNumber Hash<Key>::operator()(Key key) const
|
||||||
|
{
|
||||||
|
return hashString(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const HashNumber goldenRatio = 0x9E3779B9U;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Private
|
||||||
|
//
|
||||||
|
|
||||||
|
// Base class for user-defined hash entries.
|
||||||
|
// private
|
||||||
|
class GenericHashEntry {
|
||||||
|
public:
|
||||||
|
GenericHashEntry *next; // Link to next entry in the same bucket
|
||||||
|
const HashNumber keyHash; // This entry's hash value
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit GenericHashEntry(HashNumber keyHash): next(0), keyHash(keyHash) {}
|
||||||
|
|
||||||
|
friend class GenericHashTable;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// private
|
||||||
|
class GenericHashTableIterator;
|
||||||
|
class GenericHashTable {
|
||||||
|
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
|
||||||
|
uint32 nEntries; // Number of entries in table
|
||||||
|
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:
|
||||||
|
uint32 nReferences; // Number of iterators and references currently pointing to this hash table
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit GenericHashTable(uint32 nEntriesDefault);
|
||||||
|
~GenericHashTable() {
|
||||||
|
#ifndef _WIN32
|
||||||
|
ASSERT(nReferences == 0);
|
||||||
|
#endif
|
||||||
|
delete[] buckets;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recomputeMinMaxNEntries(uint lgNBuckets);
|
||||||
|
void rehash();
|
||||||
|
void maybeGrow() {if (nEntries > maxNEntries) rehash();}
|
||||||
|
void maybeShrink() {if (nEntries < minNEntries) rehash();}
|
||||||
|
|
||||||
|
friend class GenericHashTableIterator;
|
||||||
|
|
||||||
|
typedef GenericHashTableIterator Iterator;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This ought to be GenericHashTable::Iterator, but this doesn't work due to a
|
||||||
|
// Microsoft VC6 bug.
|
||||||
|
class GenericHashTableIterator {
|
||||||
|
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
|
||||||
|
public:
|
||||||
|
explicit GenericHashTableIterator(GenericHashTable &ht);
|
||||||
|
~GenericHashTableIterator() {ht.maybeShrink(); DEBUG_ONLY(--ht.nReferences);}
|
||||||
|
|
||||||
|
operator bool() const {return entry != 0;} // Return true if there are entries left.
|
||||||
|
GenericHashTableIterator &operator++();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Hash Tables
|
||||||
|
//
|
||||||
|
|
||||||
|
template<class Data, class Key, class H = Hash<Key> >
|
||||||
|
class HashTable: private GenericHashTable {
|
||||||
|
H hasher; // Hash function
|
||||||
|
|
||||||
|
struct Entry: public GenericHashEntry {
|
||||||
|
Data data;
|
||||||
|
|
||||||
|
Entry(HashNumber keyHash, Key key): GenericHashEntry(keyHash), data(key) {}
|
||||||
|
template<class Value>
|
||||||
|
Entry(HashNumber keyHash, Key key, Value value): GenericHashEntry(keyHash), data(key, value) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
class Reference {
|
||||||
|
#ifdef _WIN32 // Microsoft VC6 bug: friend declarations to inner classes don't work
|
||||||
|
public:
|
||||||
|
#endif
|
||||||
|
Entry *entry; // Current entry; nil if done
|
||||||
|
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
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
#ifndef _WIN32
|
||||||
|
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
|
||||||
|
Reference(HashTable &ht, Key key): keyHash(ht.hasher(key)) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
Reference::ht = &ht;
|
||||||
|
++ht.nReferences;
|
||||||
|
#endif
|
||||||
|
HashNumber kh = keyHash;
|
||||||
|
HashNumber h = kh*goldenRatio >> ht.shift;
|
||||||
|
GenericHashEntry **bp = ht.buckets + h;
|
||||||
|
Entry *e;
|
||||||
|
|
||||||
|
while ((e = static_cast<Entry *>(*bp)) != 0 && !(e->keyHash == kh && e->data == key))
|
||||||
|
bp = &e->next;
|
||||||
|
entry = e;
|
||||||
|
backpointer = bp;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
private:
|
||||||
|
Reference(const Reference&); // No copy constructor
|
||||||
|
void operator=(const Reference&); // No assignment operator
|
||||||
|
public:
|
||||||
|
#if defined(DEBUG) && !defined(_WIN32)
|
||||||
|
~Reference() {if (ht) --ht->nReferences;}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
operator bool() const {return entry != 0;} // Return true if an entry was found.
|
||||||
|
Data &operator*() const {ASSERT(entry); return entry->data;} // Return the data of the entry that was found.
|
||||||
|
|
||||||
|
friend class HashTable;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Iterator: public GenericHashTableIterator {
|
||||||
|
public:
|
||||||
|
explicit Iterator(HashTable &ht): GenericHashTableIterator(ht) {}
|
||||||
|
private:
|
||||||
|
Iterator(const Iterator&); // No copy constructor
|
||||||
|
void operator=(const Iterator&); // No assignment operator
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Go to next entry.
|
||||||
|
Iterator &operator++() {return *static_cast<Iterator*>(&GenericHashTableIterator::operator++());}
|
||||||
|
Data &operator*() const {ASSERT(entry); return static_cast<Entry *>(entry)->data;} // Return current entry's data.
|
||||||
|
void erase();
|
||||||
|
};
|
||||||
|
|
||||||
|
HashTable(uint32 nEntriesDefault = 0, const H &hasher = H()): GenericHashTable(nEntriesDefault), hasher(hasher) {}
|
||||||
|
~HashTable();
|
||||||
|
|
||||||
|
template<class Value> Data &insert(Reference &r, Key key, Value value);
|
||||||
|
Data &insert(Reference &r, Key key);
|
||||||
|
Data &insert(Key key);
|
||||||
|
void erase(Reference &r);
|
||||||
|
void erase(Key key);
|
||||||
|
Data *operator[](Key key);
|
||||||
|
|
||||||
|
friend class Reference;
|
||||||
|
friend class Iterator;
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
template<class Value> Data &insert(Key key, Value value);
|
||||||
|
#else // Microsoft VC6 bug: VC6 doesn't allow this to be defined outside the class
|
||||||
|
template<class Value> Data &insert(Key key, Value value) {
|
||||||
|
Reference r(*this, key);
|
||||||
|
if (r)
|
||||||
|
return *r = value;
|
||||||
|
else
|
||||||
|
return insert(r, key, value);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Implementation
|
||||||
|
//
|
||||||
|
|
||||||
|
template<class Data, class Key, class H>
|
||||||
|
HashTable<Data, Key, H>::~HashTable()
|
||||||
|
{
|
||||||
|
GenericHashEntry **be = bucketsEnd;
|
||||||
|
for (GenericHashEntry **b = buckets; b != be; b++) {
|
||||||
|
Entry *e = static_cast<Entry *>(*b);
|
||||||
|
while (e) {
|
||||||
|
Entry *next = static_cast<Entry *>(e->next);
|
||||||
|
delete e;
|
||||||
|
e = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
template<class Data, class Key, class H>
|
||||||
|
HashTable<Data, Key, H>::Reference::Reference(HashTable &ht, Key key):
|
||||||
|
keyHash(ht.hasher(key))
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
Reference::ht = &ht;
|
||||||
|
++ht.nReferences;
|
||||||
|
#endif
|
||||||
|
HashNumber kh = keyHash;
|
||||||
|
HashNumber h = kh*goldenRatio >> ht.shift;
|
||||||
|
GenericHashEntry **bp = ht.buckets + h;
|
||||||
|
Entry *e;
|
||||||
|
|
||||||
|
while ((e = static_cast<Entry *>(*bp)) != 0 && !(e->keyHash == kh && e->data == key))
|
||||||
|
bp = &e->next;
|
||||||
|
entry = e;
|
||||||
|
backpointer = bp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Insert the given key/value pair into the hash table. Reference must
|
||||||
|
// be the result of an unsuccessful search for that key in the table.
|
||||||
|
// The reference is not valid after this method is called.
|
||||||
|
// Return a reference to the new entry's value.
|
||||||
|
template<class Data, class Key, class H> template<class Value>
|
||||||
|
inline Data &HashTable<Data, Key, H>::insert(Reference &r, Key key, Value value)
|
||||||
|
{
|
||||||
|
ASSERT(r.ht == this && !r.entry);
|
||||||
|
Entry *e = new Entry(r.keyHash, key, value);
|
||||||
|
*r.backpointer = e;
|
||||||
|
++nEntries;
|
||||||
|
maybeGrow();
|
||||||
|
#ifdef DEBUG
|
||||||
|
--r.ht->nReferences;
|
||||||
|
r.ht = 0;
|
||||||
|
#endif
|
||||||
|
return e->data;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Same as above but without a Value argument.
|
||||||
|
template<class Data, class Key, class H>
|
||||||
|
inline Data &HashTable<Data, Key, H>::insert(Reference &r, Key key)
|
||||||
|
{
|
||||||
|
ASSERT(r.ht == this && !r.entry);
|
||||||
|
Entry *e = new Entry(r.keyHash, key);
|
||||||
|
*r.backpointer = e;
|
||||||
|
++nEntries;
|
||||||
|
maybeGrow();
|
||||||
|
#ifdef DEBUG
|
||||||
|
--r.ht->nReferences;
|
||||||
|
r.ht = 0;
|
||||||
|
#endif
|
||||||
|
return e->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Insert the given key/value pair into the hash table. If an entry with a
|
||||||
|
// matching key already exists, replace that entry's value.
|
||||||
|
// Return a reference to the new entry's value.
|
||||||
|
#ifndef _WIN32 // Microsoft VC6 bug: VC6 doesn't allow this to be defined outside the class
|
||||||
|
template<class Data, class Key, class H> template<class Value>
|
||||||
|
Data &HashTable<Data, Key, H>::insert(Key key, Value value)
|
||||||
|
{
|
||||||
|
Reference r(*this, key);
|
||||||
|
if (r)
|
||||||
|
return *r = value;
|
||||||
|
else
|
||||||
|
return insert(r, key, value);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Same as above but without a Value argument.
|
||||||
|
template<class Data, class Key, class H>
|
||||||
|
Data &HashTable<Data, Key, H>::insert(Key key)
|
||||||
|
{
|
||||||
|
Reference r(*this, key);
|
||||||
|
if (r)
|
||||||
|
return *r;
|
||||||
|
else
|
||||||
|
return insert(r, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Reference r must point to an existing entry. Delete that entry.
|
||||||
|
// The reference is not valid after this method is called.
|
||||||
|
template<class Data, class Key, class H>
|
||||||
|
inline void HashTable<Data, Key, H>::erase(Reference &r)
|
||||||
|
{
|
||||||
|
Entry *e = r.entry;
|
||||||
|
ASSERT(r.ht == this && e);
|
||||||
|
*r.backpointer = e->next;
|
||||||
|
--nEntries;
|
||||||
|
delete e;
|
||||||
|
#ifdef DEBUG
|
||||||
|
--r.ht->nReferences;
|
||||||
|
r.ht = 0;
|
||||||
|
#endif
|
||||||
|
maybeShrink();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Remove the hash table entry, if any, matching the given key.
|
||||||
|
template<class Data, class Key, class H>
|
||||||
|
void HashTable<Data, Key, H>::erase(Key key)
|
||||||
|
{
|
||||||
|
Reference r(*this, key);
|
||||||
|
if (r)
|
||||||
|
erase(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Return a pointer to the value of the hash table entry matching the given key.
|
||||||
|
// Return nil if no entry matches.
|
||||||
|
template<class Data, class Key, class H>
|
||||||
|
Data *HashTable<Data, Key, H>::operator[](Key key)
|
||||||
|
{
|
||||||
|
Reference r(*this, key);
|
||||||
|
if (r)
|
||||||
|
return &*r;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
1104
mozilla/js/js2/icode.h
Normal file
1104
mozilla/js/js2/icode.h
Normal file
File diff suppressed because it is too large
Load Diff
2138
mozilla/js/js2/icodegenerator.cpp
Normal file
2138
mozilla/js/js2/icodegenerator.cpp
Normal file
File diff suppressed because it is too large
Load Diff
306
mozilla/js/js2/icodegenerator.h
Normal file
306
mozilla/js/js2/icodegenerator.h
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
/* -*- 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 icodegenerator_h
|
||||||
|
#define icodegenerator_h
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
|
#include "utilities.h"
|
||||||
|
#include "parser.h"
|
||||||
|
#include "vmtypes.h"
|
||||||
|
#include "jsclasses.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
namespace ICG {
|
||||||
|
|
||||||
|
using namespace VM;
|
||||||
|
using namespace JSTypes;
|
||||||
|
using namespace JSClasses;
|
||||||
|
|
||||||
|
typedef std::map<String, TypedRegister, std::less<String> > VariableList;
|
||||||
|
typedef std::map<uint32, uint32, std::less<uint32> > InstructionMap;
|
||||||
|
|
||||||
|
|
||||||
|
class ICodeModule {
|
||||||
|
public:
|
||||||
|
ICodeModule(InstructionStream *iCode, VariableList *variables,
|
||||||
|
uint32 maxRegister, uint32 maxParameter,
|
||||||
|
InstructionMap *instructionMap) :
|
||||||
|
its_iCode(iCode), itsVariables(variables),
|
||||||
|
itsParameterCount(maxParameter), itsMaxRegister(maxRegister),
|
||||||
|
mID(++sMaxID), mInstructionMap(instructionMap) { }
|
||||||
|
~ICodeModule()
|
||||||
|
{
|
||||||
|
delete its_iCode;
|
||||||
|
delete itsVariables;
|
||||||
|
delete mInstructionMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
Formatter& print(Formatter& f);
|
||||||
|
void setFileName (String aFileName) { mFileName = aFileName; }
|
||||||
|
String getFileName () { return mFileName; }
|
||||||
|
|
||||||
|
InstructionStream *its_iCode;
|
||||||
|
VariableList *itsVariables;
|
||||||
|
uint32 itsParameterCount;
|
||||||
|
uint32 itsMaxRegister;
|
||||||
|
uint32 mID;
|
||||||
|
InstructionMap *mInstructionMap;
|
||||||
|
String mFileName;
|
||||||
|
|
||||||
|
static uint32 sMaxID;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<const StringAtom *> LabelSet;
|
||||||
|
class LabelEntry {
|
||||||
|
public:
|
||||||
|
LabelEntry(LabelSet *labelSet, Label *breakLabel)
|
||||||
|
: labelSet(labelSet), breakLabel(breakLabel), continueLabel(NULL) { }
|
||||||
|
LabelEntry(LabelSet *labelSet, Label *breakLabel, Label *continueLabel)
|
||||||
|
: labelSet(labelSet), breakLabel(breakLabel), continueLabel(continueLabel) { }
|
||||||
|
|
||||||
|
bool containsLabel(const StringAtom *label);
|
||||||
|
|
||||||
|
LabelSet *labelSet;
|
||||||
|
Label *breakLabel;
|
||||||
|
Label *continueLabel;
|
||||||
|
};
|
||||||
|
typedef std::vector<LabelEntry *> LabelStack;
|
||||||
|
|
||||||
|
Formatter& operator<<(Formatter &f, ICodeModule &i);
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
|
||||||
|
// An ICodeGenerator provides the interface between the parser and the
|
||||||
|
// interpreter. The parser constructs one of these for each
|
||||||
|
// function/script, adds statements and expressions to it and then
|
||||||
|
// converts it into an ICodeModule, ready for execution.
|
||||||
|
|
||||||
|
class ICodeGenerator {
|
||||||
|
public:
|
||||||
|
typedef enum { kNoFlags = 0, kIsTopLevel = 0x01, kIsStaticMethod = 0x02, kIsWithinWith = 0x04 } ICodeGeneratorFlags;
|
||||||
|
private:
|
||||||
|
InstructionStream *iCode;
|
||||||
|
bool iCodeOwner;
|
||||||
|
LabelList labels;
|
||||||
|
|
||||||
|
Register mTopRegister; // highest (currently) alloacated register
|
||||||
|
uint32 mParameterCount; // number of parameters declared for the function
|
||||||
|
// these must come before any variables declared.
|
||||||
|
TypedRegister mExceptionRegister; // reserved to carry the exception object.
|
||||||
|
VariableList *variableList; // name|register pair for each variable
|
||||||
|
|
||||||
|
World *mWorld; // used to register strings
|
||||||
|
JSScope *mGlobal; // the scope for compiling within
|
||||||
|
LabelStack mLabelStack; // stack of LabelEntry objects, one per nested looping construct
|
||||||
|
// maps source position to instruction index
|
||||||
|
InstructionMap *mInstructionMap;
|
||||||
|
|
||||||
|
JSClass *mClass; // enclosing class when generating code for methods
|
||||||
|
ICodeGeneratorFlags mFlags; // assorted flags
|
||||||
|
|
||||||
|
std::vector<bool> mPermanentRegister;
|
||||||
|
|
||||||
|
Register getTempRegister()
|
||||||
|
{
|
||||||
|
while (mTopRegister < mPermanentRegister.size())
|
||||||
|
if (!mPermanentRegister[mTopRegister])
|
||||||
|
return mTopRegister++;
|
||||||
|
else
|
||||||
|
++mTopRegister;
|
||||||
|
mPermanentRegister.resize(mTopRegister + 1);
|
||||||
|
mPermanentRegister[mTopRegister] = false;
|
||||||
|
return mTopRegister++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetTopRegister() { mTopRegister = mParameterCount; }
|
||||||
|
void resetStatement() { resetTopRegister(); }
|
||||||
|
|
||||||
|
TypedRegister allocateRegister(const StringAtom& name, JSType *type);
|
||||||
|
|
||||||
|
void setRegisterForVariable(const StringAtom& name, TypedRegister r) { (*variableList)[name] = r; }
|
||||||
|
|
||||||
|
JSType *findType(const StringAtom& typeName);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void setLabel(Label *label);
|
||||||
|
|
||||||
|
void jsr(Label *label) { iCode->push_back(new Jsr(label)); }
|
||||||
|
void rts() { iCode->push_back(new Rts()); }
|
||||||
|
void branch(Label *label);
|
||||||
|
GenericBranch *branchTrue(Label *label, TypedRegister condition);
|
||||||
|
GenericBranch *branchFalse(Label *label, TypedRegister condition);
|
||||||
|
|
||||||
|
void beginTry(Label *catchLabel, Label *finallyLabel)
|
||||||
|
{ iCode->push_back(new Tryin(catchLabel, finallyLabel)); }
|
||||||
|
void endTry() { iCode->push_back(new Tryout()); }
|
||||||
|
|
||||||
|
void beginWith(TypedRegister obj) { iCode->push_back(new Within(obj)); }
|
||||||
|
void endWith() { iCode->push_back(new Without()); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void startStatement(uint32 pos) { (*mInstructionMap)[iCode->size()] = pos; }
|
||||||
|
|
||||||
|
ICodeOp mapExprNodeToICodeOp(ExprNode::Kind kind);
|
||||||
|
|
||||||
|
|
||||||
|
bool isTopLevel() { return (mFlags & kIsTopLevel) != 0; }
|
||||||
|
bool isWithinWith() { return (mFlags & kIsWithinWith) != 0; }
|
||||||
|
bool isStaticMethod() { return (mFlags & kIsStaticMethod) != 0; }
|
||||||
|
|
||||||
|
void setFlag(uint32 flag, bool v) { mFlags = (ICodeGeneratorFlags)((v) ? mFlags | flag : mFlags & ~flag); }
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {Var, Property, Slot, Static, Constructor, Name, Method} LValueKind;
|
||||||
|
|
||||||
|
LValueKind resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex);
|
||||||
|
TypedRegister handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args);
|
||||||
|
TypedRegister handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args);
|
||||||
|
ICodeModule *genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superClass);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
ICodeGenerator(World *world, JSScope *global, JSClass *aClass = NULL, ICodeGeneratorFlags flags = kIsTopLevel);
|
||||||
|
|
||||||
|
~ICodeGenerator()
|
||||||
|
{
|
||||||
|
if (iCodeOwner) {
|
||||||
|
delete iCode;
|
||||||
|
delete mInstructionMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ICodeModule *complete();
|
||||||
|
|
||||||
|
TypedRegister genExpr(ExprNode *p,
|
||||||
|
bool needBoolValueInBranch = false,
|
||||||
|
Label *trueBranch = NULL,
|
||||||
|
Label *falseBranch = NULL);
|
||||||
|
TypedRegister genStmt(StmtNode *p, LabelSet *currentLabelSet = NULL);
|
||||||
|
|
||||||
|
void returnStmt(TypedRegister r);
|
||||||
|
void returnStmt();
|
||||||
|
void throwStmt(TypedRegister r) { iCode->push_back(new Throw(r)); }
|
||||||
|
void debuggerStmt() { iCode->push_back(new Debugger()); }
|
||||||
|
|
||||||
|
TypedRegister allocateVariable(const StringAtom& name);
|
||||||
|
TypedRegister allocateVariable(const StringAtom& name, const StringAtom& typeName);
|
||||||
|
|
||||||
|
TypedRegister findVariable(const StringAtom& name)
|
||||||
|
{
|
||||||
|
VariableList::iterator i = variableList->find(name);
|
||||||
|
return (i == variableList->end()) ? TypedRegister(NotARegister, &None_Type) : (*i).second;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypedRegister allocateParameter(const StringAtom& name) { mParameterCount++; return allocateRegister(name, &Any_Type); }
|
||||||
|
TypedRegister allocateParameter(const StringAtom& name, const StringAtom& typeName)
|
||||||
|
{ mParameterCount++; return allocateRegister(name, findType(typeName)); }
|
||||||
|
TypedRegister allocateParameter(const StringAtom& name, JSType *type)
|
||||||
|
{ mParameterCount++; return allocateRegister(name, type); }
|
||||||
|
|
||||||
|
Formatter& print(Formatter& f);
|
||||||
|
|
||||||
|
TypedRegister op(ICodeOp op, TypedRegister source);
|
||||||
|
TypedRegister op(ICodeOp op, TypedRegister source1, TypedRegister source2);
|
||||||
|
TypedRegister binaryOp(ICodeOp op, TypedRegister source1, TypedRegister source2);
|
||||||
|
TypedRegister call(TypedRegister base, TypedRegister target, RegisterList *args);
|
||||||
|
TypedRegister getMethod(TypedRegister thisArg, uint32 slotIndex);
|
||||||
|
|
||||||
|
void move(TypedRegister destination, TypedRegister source);
|
||||||
|
TypedRegister logicalNot(TypedRegister source);
|
||||||
|
TypedRegister test(TypedRegister source);
|
||||||
|
|
||||||
|
TypedRegister loadBoolean(bool value);
|
||||||
|
TypedRegister loadImmediate(double value);
|
||||||
|
TypedRegister loadString(const String &value);
|
||||||
|
TypedRegister loadString(const StringAtom &name);
|
||||||
|
|
||||||
|
TypedRegister newObject(TypedRegister constructor);
|
||||||
|
TypedRegister newArray();
|
||||||
|
TypedRegister newFunction(ICodeModule *icm);
|
||||||
|
TypedRegister newClass(JSClass *clazz);
|
||||||
|
|
||||||
|
TypedRegister cast(TypedRegister arg, JSType *toType);
|
||||||
|
|
||||||
|
TypedRegister super();
|
||||||
|
TypedRegister loadName(const StringAtom &name, JSType *t = &Any_Type);
|
||||||
|
void saveName(const StringAtom &name, TypedRegister value);
|
||||||
|
TypedRegister nameXcr(const StringAtom &name, ICodeOp op);
|
||||||
|
|
||||||
|
TypedRegister deleteProperty(TypedRegister base, const StringAtom &name);
|
||||||
|
TypedRegister getProperty(TypedRegister base, const StringAtom &name);
|
||||||
|
void setProperty(TypedRegister base, const StringAtom &name, TypedRegister value);
|
||||||
|
TypedRegister propertyXcr(TypedRegister base, const StringAtom &name, ICodeOp op);
|
||||||
|
|
||||||
|
TypedRegister getStatic(JSClass *base, const String &name);
|
||||||
|
void setStatic(JSClass *base, const StringAtom &name, TypedRegister value);
|
||||||
|
TypedRegister staticXcr(JSClass *base, const StringAtom &name, ICodeOp op);
|
||||||
|
|
||||||
|
TypedRegister getElement(TypedRegister base, TypedRegister index);
|
||||||
|
void setElement(TypedRegister base, TypedRegister index, TypedRegister value);
|
||||||
|
TypedRegister elementXcr(TypedRegister base, TypedRegister index, ICodeOp op);
|
||||||
|
|
||||||
|
TypedRegister getSlot(TypedRegister base, uint32 slot);
|
||||||
|
void setSlot(TypedRegister base, uint32 slot, TypedRegister value);
|
||||||
|
TypedRegister slotXcr(TypedRegister base, uint32 slot, ICodeOp op);
|
||||||
|
|
||||||
|
TypedRegister varXcr(TypedRegister var, ICodeOp op);
|
||||||
|
|
||||||
|
InstructionStream *getICode() { return iCode; }
|
||||||
|
|
||||||
|
Label *getLabel();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Formatter& operator<<(Formatter &f, ICodeGenerator &i);
|
||||||
|
Formatter& operator<<(Formatter &f, ICodeModule &i);
|
||||||
|
/*
|
||||||
|
std::ostream &operator<<(std::ostream &s, ICodeGenerator &i);
|
||||||
|
std::ostream &operator<<(std::ostream &s, StringAtom &str);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace IGC */
|
||||||
|
} /* namespace JavaScript */
|
||||||
|
|
||||||
|
#endif /* icodegenerator_h */
|
||||||
1361
mozilla/js/js2/interpreter.cpp
Normal file
1361
mozilla/js/js2/interpreter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
113
mozilla/js/js2/interpreter.h
Normal file
113
mozilla/js/js2/interpreter.h
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
// -*- 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) 2000 Netscape Communications Corporation. All
|
||||||
|
// Rights Reserved.
|
||||||
|
|
||||||
|
#ifndef interpreter_h
|
||||||
|
#define interpreter_h
|
||||||
|
|
||||||
|
#include "utilities.h"
|
||||||
|
#include "jstypes.h"
|
||||||
|
#include "vmtypes.h"
|
||||||
|
#include "icodegenerator.h"
|
||||||
|
#include "gc_allocator.h"
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
namespace Interpreter {
|
||||||
|
|
||||||
|
using namespace ICG;
|
||||||
|
using namespace JSTypes;
|
||||||
|
|
||||||
|
struct Activation;
|
||||||
|
|
||||||
|
struct Linkage;
|
||||||
|
|
||||||
|
class Context : public gc_base {
|
||||||
|
void initContext();
|
||||||
|
public:
|
||||||
|
explicit Context(World& world, JSScope* aGlobal)
|
||||||
|
: mWorld(world), mGlobal(aGlobal), mLinkage(0), mActivation(0), mHasOperatorsPackageLoaded(false) { initContext(); }
|
||||||
|
|
||||||
|
World& getWorld() { return mWorld; }
|
||||||
|
JSScope* getGlobalObject() { return mGlobal; }
|
||||||
|
InstructionIterator getPC() { return mPC; }
|
||||||
|
|
||||||
|
JSValues& getRegisters();
|
||||||
|
ICodeModule* getICode();
|
||||||
|
|
||||||
|
enum Event {
|
||||||
|
EV_NONE = 0x0000,
|
||||||
|
EV_STEP = 0x0001,
|
||||||
|
EV_THROW = 0x0002,
|
||||||
|
EV_DEBUG = 0x0004,
|
||||||
|
EV_ALL = 0xffff
|
||||||
|
};
|
||||||
|
|
||||||
|
class Listener {
|
||||||
|
public:
|
||||||
|
virtual void listen(Context *context, Event event) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void addListener(Listener* listener);
|
||||||
|
void removeListener(Listener* listener);
|
||||||
|
|
||||||
|
class Frame {
|
||||||
|
public:
|
||||||
|
virtual Frame* getNext() = 0;
|
||||||
|
virtual void getState(InstructionIterator& pc, JSValues*& registers,
|
||||||
|
ICodeModule*& iCode) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
Frame* getFrames();
|
||||||
|
|
||||||
|
JSValue interpret(ICodeModule* iCode, const JSValues& args);
|
||||||
|
void doCall(JSFunction *target, Instruction *pc);
|
||||||
|
|
||||||
|
ICodeModule* compile(const String &source);
|
||||||
|
ICodeModule* genCode(StmtNode *p, const String &fileName);
|
||||||
|
JSValue readEvalFile(FILE* in, const String& fileName);
|
||||||
|
|
||||||
|
void addBinaryOperator(BinaryOperator::BinaryOp op, BinaryOperator *fn) { mBinaryOperators[op].push_back(fn); }
|
||||||
|
const JSValue findBinaryOverride(JSValue &operand1, JSValue &operand2, BinaryOperator::BinaryOp op);
|
||||||
|
|
||||||
|
|
||||||
|
bool hasOperatorsPackageLoaded() { return mHasOperatorsPackageLoaded; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void broadcast(Event event);
|
||||||
|
void initOperatorsPackage();
|
||||||
|
|
||||||
|
private:
|
||||||
|
World& mWorld;
|
||||||
|
JSScope* mGlobal;
|
||||||
|
Linkage* mLinkage;
|
||||||
|
typedef std::vector<Listener*, gc_allocator<Listener*> > ListenerList;
|
||||||
|
typedef ListenerList::iterator ListenerIterator;
|
||||||
|
ListenerList mListeners;
|
||||||
|
Activation* mActivation;
|
||||||
|
bool mHasOperatorsPackageLoaded;
|
||||||
|
|
||||||
|
InstructionIterator mPC;
|
||||||
|
|
||||||
|
BinaryOperatorList mBinaryOperators[BinaryOperator::BinaryOperatorCount];
|
||||||
|
|
||||||
|
}; /* class Context */
|
||||||
|
|
||||||
|
} /* namespace Interpreter */
|
||||||
|
} /* namespace JavaScript */
|
||||||
|
|
||||||
|
#endif /* interpreter_h */
|
||||||
33
mozilla/js/js2/java/ArithmeticNode.java
Normal file
33
mozilla/js/js2/java/ArithmeticNode.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
class ArithmeticNode extends BinaryNode {
|
||||||
|
|
||||||
|
ArithmeticNode(String aOp, ExpressionNode aLeft, ExpressionNode aRight)
|
||||||
|
{
|
||||||
|
super(aOp, aLeft, aRight);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
JSValue lV = left.eval(theEnv);
|
||||||
|
JSValue rV = right.eval(theEnv);
|
||||||
|
|
||||||
|
if (op == "+")
|
||||||
|
return lV.add(theEnv, rV);
|
||||||
|
else
|
||||||
|
if (op == "-")
|
||||||
|
return lV.subtract(theEnv, rV);
|
||||||
|
else
|
||||||
|
if (op == "*")
|
||||||
|
return lV.multiply(theEnv, rV);
|
||||||
|
else
|
||||||
|
if (op == "/")
|
||||||
|
return lV.divide(theEnv, rV);
|
||||||
|
else
|
||||||
|
if (op == "%")
|
||||||
|
return lV.remainder(theEnv, rV);
|
||||||
|
else {
|
||||||
|
System.out.println("missing arithmetic op " + op);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
16
mozilla/js/js2/java/AssignmentNode.java
Normal file
16
mozilla/js/js2/java/AssignmentNode.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
class AssignmentNode extends BinaryNode {
|
||||||
|
|
||||||
|
AssignmentNode(String aOp, ExpressionNode aLeft, ExpressionNode aRight)
|
||||||
|
{
|
||||||
|
super(aOp, aLeft, aRight);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
JSReference lV = left.evalLHS(theEnv);
|
||||||
|
JSValue rV = right.eval(theEnv);
|
||||||
|
|
||||||
|
return lV.base.putProp(theEnv, lV.id, rV);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
72
mozilla/js/js2/java/BinaryNode.java
Normal file
72
mozilla/js/js2/java/BinaryNode.java
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
class BinaryNode extends ExpressionNode {
|
||||||
|
|
||||||
|
BinaryNode(String aOp, ExpressionNode aLeft, ExpressionNode aRight)
|
||||||
|
{
|
||||||
|
left = aLeft;
|
||||||
|
right = aRight;
|
||||||
|
op = aOp;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSReference evalLHS(Environment theEnv)
|
||||||
|
{
|
||||||
|
if (op == ".") {
|
||||||
|
JSValue lV = left.eval(theEnv);
|
||||||
|
JSString id;
|
||||||
|
if (right instanceof JSIdentifier)
|
||||||
|
id = (JSString)right;
|
||||||
|
else
|
||||||
|
id = right.eval(theEnv).toJSString(theEnv);
|
||||||
|
return new JSReference(lV, id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new RuntimeException("bad lValue operator " + op);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
JSValue lV = left.eval(theEnv);
|
||||||
|
JSValue rV = right.eval(theEnv);
|
||||||
|
|
||||||
|
if (op == ".")
|
||||||
|
return lV.getProp(theEnv, rV.toJSString(theEnv));
|
||||||
|
else
|
||||||
|
if (op == "()")
|
||||||
|
return lV.call(theEnv, rV);
|
||||||
|
else
|
||||||
|
if (op == ",")
|
||||||
|
return JSValueList.buildList(lV, rV);
|
||||||
|
else {
|
||||||
|
System.out.println("missing binary op " + op);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
String print(String indent)
|
||||||
|
{
|
||||||
|
StringBuffer result = new StringBuffer(indent);
|
||||||
|
result.append(getClass().toString());
|
||||||
|
result.append(" ");
|
||||||
|
result.append(op);
|
||||||
|
result.append("\n");
|
||||||
|
indent += " ";
|
||||||
|
if (left == null) {
|
||||||
|
result.append(indent);
|
||||||
|
result.append("null\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result.append(left.print(indent));
|
||||||
|
if (right == null) {
|
||||||
|
result.append(indent);
|
||||||
|
result.append("null\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result.append(right.print(indent));
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ExpressionNode left;
|
||||||
|
protected ExpressionNode right;
|
||||||
|
protected String op;
|
||||||
|
|
||||||
|
}
|
||||||
36
mozilla/js/js2/java/BitwiseNode.java
Normal file
36
mozilla/js/js2/java/BitwiseNode.java
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
class BitwiseNode extends BinaryNode {
|
||||||
|
|
||||||
|
BitwiseNode(String aOp, ExpressionNode aLeft, ExpressionNode aRight)
|
||||||
|
{
|
||||||
|
super(aOp, aLeft, aRight);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
JSInteger lV = left.eval(theEnv).toJSInteger(theEnv);
|
||||||
|
JSValue rV = right.eval(theEnv);
|
||||||
|
|
||||||
|
if (op == "&")
|
||||||
|
return lV.and(theEnv, rV);
|
||||||
|
else
|
||||||
|
if (op == "|")
|
||||||
|
return lV.or(theEnv, rV);
|
||||||
|
else
|
||||||
|
if (op == "^")
|
||||||
|
return lV.xor(theEnv, rV);
|
||||||
|
else
|
||||||
|
if (op == "<<")
|
||||||
|
return lV.shr(theEnv, rV);
|
||||||
|
else
|
||||||
|
if (op == ">>")
|
||||||
|
return lV.shl(theEnv, rV);
|
||||||
|
else
|
||||||
|
if (op == ">>>")
|
||||||
|
return lV.ushl(theEnv, rV);
|
||||||
|
else {
|
||||||
|
System.out.println("missing bitwise op " + op);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
24
mozilla/js/js2/java/Brenda.java
Normal file
24
mozilla/js/js2/java/Brenda.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
class Brenda {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try {
|
||||||
|
JSLexer lexer = new JSLexer((args != null) ? new DataInputStream(new FileInputStream(args[0])) : new DataInputStream(System.in));
|
||||||
|
JSParser parser = new JSParser(lexer);
|
||||||
|
ControlNodeGroup tree = new ControlNodeGroup();
|
||||||
|
parser.statements(0, tree);
|
||||||
|
System.out.println(ControlNode.printAll());
|
||||||
|
|
||||||
|
Environment theEnv = new Environment();
|
||||||
|
ControlNode c = tree.getHead();
|
||||||
|
while (c != null) c = c.eval(theEnv);
|
||||||
|
|
||||||
|
System.out.println("After eval :\n" + theEnv.print());
|
||||||
|
|
||||||
|
} catch(Exception e) {
|
||||||
|
System.err.println("exception: "+e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
59
mozilla/js/js2/java/ConditionalNode.java
Normal file
59
mozilla/js/js2/java/ConditionalNode.java
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
class ConditionalNode extends ControlNode {
|
||||||
|
|
||||||
|
ConditionalNode(ExpressionNode aCondition)
|
||||||
|
{
|
||||||
|
super(aCondition);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConditionalNode(ExpressionNode aCondition, ControlNode aTrueCode)
|
||||||
|
{
|
||||||
|
super(aCondition);
|
||||||
|
trueCode = aTrueCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConditionalNode(ExpressionNode aCondition, ControlNode aTrueCode, ControlNode aFalseCode)
|
||||||
|
{
|
||||||
|
super(aCondition);
|
||||||
|
trueCode = aTrueCode;
|
||||||
|
setNext(aFalseCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moveNextToTrue()
|
||||||
|
{
|
||||||
|
trueCode = next;
|
||||||
|
setNext(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlNode eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
JSBoolean b = expr.eval(theEnv).toJSBoolean(theEnv);
|
||||||
|
if (b.isTrue())
|
||||||
|
return trueCode;
|
||||||
|
else
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
String print()
|
||||||
|
{
|
||||||
|
StringBuffer result = new StringBuffer("ConditionalNode ");
|
||||||
|
result.append(index);
|
||||||
|
result.append("\nexpr:\n");
|
||||||
|
if (expr == null)
|
||||||
|
result.append("expr = null\n");
|
||||||
|
else
|
||||||
|
result.append(expr.print(""));
|
||||||
|
result.append("true branch:\n");
|
||||||
|
if (trueCode == null)
|
||||||
|
result.append("true branch = null\n");
|
||||||
|
else
|
||||||
|
result.append("true branch->" + trueCode.index + "\n");
|
||||||
|
result.append("false branch:\n");
|
||||||
|
if (next == null)
|
||||||
|
result.append("false branch = null\n");
|
||||||
|
else
|
||||||
|
result.append("false branch->" + next.index + "\n");
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ControlNode trueCode;
|
||||||
|
}
|
||||||
67
mozilla/js/js2/java/ControlNode.java
Normal file
67
mozilla/js/js2/java/ControlNode.java
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
class ControlNode {
|
||||||
|
|
||||||
|
private static Vector gList = new Vector();
|
||||||
|
|
||||||
|
static String printAll()
|
||||||
|
{
|
||||||
|
StringBuffer result = new StringBuffer();
|
||||||
|
for (int i = 0; i < gList.size(); i++) {
|
||||||
|
result.append(((ControlNode)(gList.elementAt(i))).print());
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlNode(ExpressionNode anExpr)
|
||||||
|
{
|
||||||
|
expr = anExpr;
|
||||||
|
index = gList.size();
|
||||||
|
gList.addElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionNode getExpression()
|
||||||
|
{
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setNext(ControlNode aNext)
|
||||||
|
{
|
||||||
|
next = aNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlNode eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
if (expr != null) theEnv.resultValue = expr.eval(theEnv);
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
String print()
|
||||||
|
{
|
||||||
|
StringBuffer result = new StringBuffer(getClass().toString().substring(6));
|
||||||
|
result.append(" #");
|
||||||
|
result.append(index);
|
||||||
|
result.append("\nexpr: \n");
|
||||||
|
if (expr == null)
|
||||||
|
result.append("expr = null\n");
|
||||||
|
else
|
||||||
|
result.append(expr.print(""));
|
||||||
|
result.append("next: ");
|
||||||
|
if (next == null)
|
||||||
|
result.append("next = null\n");
|
||||||
|
else
|
||||||
|
result.append("next->" + next.index + "\n");
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ExpressionNode expr;
|
||||||
|
protected ControlNode next;
|
||||||
|
protected int index;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
153
mozilla/js/js2/java/ControlNodeGroup.java
Normal file
153
mozilla/js/js2/java/ControlNodeGroup.java
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
class ControlNodeGroup {
|
||||||
|
|
||||||
|
ControlNodeGroup()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlNodeGroup(ControlNode aHead)
|
||||||
|
{
|
||||||
|
head = aHead;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(ControlNodeGroup aGroup)
|
||||||
|
{
|
||||||
|
if (head == null) {
|
||||||
|
head = aGroup.head;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fixTails(aGroup.getHead());
|
||||||
|
}
|
||||||
|
addTails(aGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(ControlNode aNode)
|
||||||
|
{
|
||||||
|
fixTails(aNode);
|
||||||
|
addTail(aNode);
|
||||||
|
if (head == null) head = aNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addBreak(ControlNode aNode)
|
||||||
|
{
|
||||||
|
fixTails(aNode);
|
||||||
|
addBreakTail(aNode);
|
||||||
|
if (head == null) head = aNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addContinue(ControlNode aNode)
|
||||||
|
{
|
||||||
|
fixTails(aNode);
|
||||||
|
addContinueTail(aNode);
|
||||||
|
if (head == null) head = aNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fixTails(ControlNode butt)
|
||||||
|
{
|
||||||
|
int count = tails.size();
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
ControlNode aNode = (ControlNode)(tails.elementAt(i));
|
||||||
|
aNode.setNext(butt);
|
||||||
|
}
|
||||||
|
tails.removeAllElements();
|
||||||
|
}
|
||||||
|
|
||||||
|
void fixContinues(ControlNode butt, String label)
|
||||||
|
{
|
||||||
|
int count = continueTails.size();
|
||||||
|
int i = 0;
|
||||||
|
while (i < count) {
|
||||||
|
ControlNode c = (ControlNode)(continueTails.elementAt(i));
|
||||||
|
ExpressionNode e = c.getExpression();
|
||||||
|
String tgt = (e == null) ? null : ((JSIdentifier)e).s;
|
||||||
|
if ((tgt == null) || tgt.equals(label)) {
|
||||||
|
c.setNext(butt);
|
||||||
|
continueTails.removeElementAt(i);
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setHead(ControlNode aHead)
|
||||||
|
{
|
||||||
|
head = aHead;
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlNode getHead()
|
||||||
|
{
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addTail(ControlNode aTail)
|
||||||
|
{
|
||||||
|
tails.addElement(aTail);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addBreakTail(ControlNode aTail)
|
||||||
|
{
|
||||||
|
breakTails.addElement(aTail);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addContinueTail(ControlNode aTail)
|
||||||
|
{
|
||||||
|
continueTails.addElement(aTail);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeTail(ControlNode aTail)
|
||||||
|
{
|
||||||
|
tails.removeElement(aTail);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addTails(ControlNodeGroup aGroup)
|
||||||
|
{
|
||||||
|
int count = aGroup.tails.size();
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
tails.addElement(aGroup.tails.elementAt(i));
|
||||||
|
}
|
||||||
|
aGroup.tails.removeAllElements();
|
||||||
|
|
||||||
|
count = aGroup.breakTails.size();
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
breakTails.addElement(aGroup.breakTails.elementAt(i));
|
||||||
|
}
|
||||||
|
aGroup.breakTails.removeAllElements();
|
||||||
|
|
||||||
|
count = aGroup.continueTails.size();
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
continueTails.addElement(aGroup.continueTails.elementAt(i));
|
||||||
|
}
|
||||||
|
aGroup.continueTails.removeAllElements();
|
||||||
|
}
|
||||||
|
|
||||||
|
void shiftBreakTails(String label)
|
||||||
|
{
|
||||||
|
int count = breakTails.size();
|
||||||
|
int i = 0;
|
||||||
|
while (i < count) {
|
||||||
|
ControlNode c = (ControlNode)(breakTails.elementAt(i));
|
||||||
|
ExpressionNode e = c.getExpression();
|
||||||
|
String tgt = (e == null) ? null : ((JSIdentifier)e).s;
|
||||||
|
if ((tgt == null) || tgt.equals(label)) {
|
||||||
|
tails.addElement(c);
|
||||||
|
breakTails.removeElementAt(i);
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlNode head;
|
||||||
|
Vector tails = new Vector();
|
||||||
|
Vector breakTails = new Vector();
|
||||||
|
Vector continueTails = new Vector();
|
||||||
|
|
||||||
|
}
|
||||||
30
mozilla/js/js2/java/Environment.java
Normal file
30
mozilla/js/js2/java/Environment.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
import java.util.Hashtable;
|
||||||
|
|
||||||
|
class Environment {
|
||||||
|
|
||||||
|
JSScope scope = new JSScope("globals");
|
||||||
|
JSScope globalScope = scope;
|
||||||
|
|
||||||
|
|
||||||
|
void enterNewScope(JSScope newScope)
|
||||||
|
{
|
||||||
|
newScope.parent = scope;
|
||||||
|
scope = newScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
void leaveScope()
|
||||||
|
{
|
||||||
|
scope = scope.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
String print()
|
||||||
|
{
|
||||||
|
StringBuffer result = new StringBuffer("Globals contents :\n");
|
||||||
|
result.append(scope.toString());
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue resultValue;
|
||||||
|
|
||||||
|
}
|
||||||
24
mozilla/js/js2/java/ExpressionNode.java
Normal file
24
mozilla/js/js2/java/ExpressionNode.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
class ExpressionNode {
|
||||||
|
|
||||||
|
ExpressionNode()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
String print(String indent)
|
||||||
|
{
|
||||||
|
return indent + "ExpressionNode(" + getClass().toString() + ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
JSReference evalLHS(Environment theEnv)
|
||||||
|
{
|
||||||
|
System.out.println("Unimplemented evalLHS for " + print(""));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
System.out.println("Unimplemented eval for " + print(""));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
36
mozilla/js/js2/java/FunctionNode.java
Normal file
36
mozilla/js/js2/java/FunctionNode.java
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
class FunctionNode extends ExpressionNode {
|
||||||
|
|
||||||
|
FunctionNode(JSIdentifier aName, ControlNodeGroup aBody, ExpressionNode parameterList)
|
||||||
|
{
|
||||||
|
fn = new NativeFunction(aBody.getHead());
|
||||||
|
name = aName;
|
||||||
|
if (parameterList != null) {
|
||||||
|
if (parameterList instanceof BinaryNode)
|
||||||
|
buildParameterVector((BinaryNode)parameterList);
|
||||||
|
else
|
||||||
|
fn.parameters.addElement(parameterList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void buildParameterVector(BinaryNode x)
|
||||||
|
{
|
||||||
|
if (x.left instanceof BinaryNode) {
|
||||||
|
buildParameterVector((BinaryNode)(x.left));
|
||||||
|
fn.parameters.addElement(x.right);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fn.parameters.addElement(x.left);
|
||||||
|
fn.parameters.addElement(x.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
theEnv.scope.putProp(theEnv, name, fn);
|
||||||
|
return fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSString name;
|
||||||
|
NativeFunction fn;
|
||||||
|
|
||||||
|
}
|
||||||
52
mozilla/js/js2/java/JSBoolean.java
Normal file
52
mozilla/js/js2/java/JSBoolean.java
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
class JSBoolean extends JSValue {
|
||||||
|
|
||||||
|
static JSBoolean JSTrue = new JSBoolean(true);
|
||||||
|
static JSBoolean JSFalse = new JSBoolean(false);
|
||||||
|
|
||||||
|
private JSBoolean(boolean p)
|
||||||
|
{
|
||||||
|
b = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isTrue()
|
||||||
|
{
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isFalse()
|
||||||
|
{
|
||||||
|
return !b;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue bang(Environment theEnv) {
|
||||||
|
return (b) ? JSFalse : JSTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue typeof(Environment theEnv) {
|
||||||
|
return new JSString("boolean");
|
||||||
|
}
|
||||||
|
|
||||||
|
JSBoolean toJSBoolean(Environment theEnv) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue toPrimitive(Environment theEnv, String hint) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSString toJSString(Environment theEnv) {
|
||||||
|
return (b) ? new JSString("true") : new JSString("false");
|
||||||
|
}
|
||||||
|
|
||||||
|
JSDouble toJSDouble(Environment theEnv) {
|
||||||
|
return (b) ? new JSDouble(1) : new JSDouble(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean b;
|
||||||
|
|
||||||
|
}
|
||||||
111
mozilla/js/js2/java/JSDouble.java
Normal file
111
mozilla/js/js2/java/JSDouble.java
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
class JSDouble extends JSNumber {
|
||||||
|
|
||||||
|
JSDouble(double p)
|
||||||
|
{
|
||||||
|
d = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSDouble(String s)
|
||||||
|
{
|
||||||
|
d = new Double(s).doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
String print(String indent)
|
||||||
|
{
|
||||||
|
return indent + "JSDouble " + d + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return Double.toString(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue plus(Environment theEnv) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue minus(Environment theEnv) {
|
||||||
|
return new JSDouble(-d);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue add(Environment theEnv, JSValue rV) {
|
||||||
|
if (rV instanceof JSString)
|
||||||
|
return toJSString(theEnv).add(theEnv, rV);
|
||||||
|
else
|
||||||
|
return new JSDouble(d + rV.toJSDouble(theEnv).d);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue subtract(Environment theEnv, JSValue rV) {
|
||||||
|
return new JSDouble(d - rV.toJSDouble(theEnv).d);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue multiply(Environment theEnv, JSValue rV) {
|
||||||
|
return new JSDouble(d * rV.toJSDouble(theEnv).d);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue divide(Environment theEnv, JSValue rV) {
|
||||||
|
return new JSDouble(d / rV.toJSDouble(theEnv).d);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue remainder(Environment theEnv, JSValue rV) {
|
||||||
|
return new JSDouble(d % rV.toJSDouble(theEnv).d);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue gt(Environment theEnv, JSValue rV) {
|
||||||
|
return (d > rV.toJSDouble(theEnv).d) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue ge(Environment theEnv, JSValue rV) {
|
||||||
|
return (d >= rV.toJSDouble(theEnv).d) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue lt(Environment theEnv, JSValue rV) {
|
||||||
|
return (d < rV.toJSDouble(theEnv).d) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue le(Environment theEnv, JSValue rV) {
|
||||||
|
return (d <= rV.toJSDouble(theEnv).d) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eq(Environment theEnv, JSValue rV) {
|
||||||
|
return (d == rV.toJSDouble(theEnv).d) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue ne(Environment theEnv, JSValue rV) {
|
||||||
|
return (d != rV.toJSDouble(theEnv).d) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSDouble toJSDouble(Environment theEnv) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue toPrimitive(Environment theEnv, String hint) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSInteger toJSInteger(Environment theEnv) {
|
||||||
|
return new JSInteger((int)d);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSBoolean toJSBoolean(Environment theEnv) {
|
||||||
|
return ((d == d) && (d != 0.0)) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSString toJSString(Environment theEnv) {
|
||||||
|
return new JSString(Double.toString(d));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSObject toJSObject(Environment theEnv) {
|
||||||
|
return new NativeNumber(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
double d;
|
||||||
|
|
||||||
|
}
|
||||||
22
mozilla/js/js2/java/JSException.java
Normal file
22
mozilla/js/js2/java/JSException.java
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
|
||||||
|
class JSException extends RuntimeException {
|
||||||
|
|
||||||
|
JSException(JSValue x)
|
||||||
|
{
|
||||||
|
value = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue getValue()
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return value.toJSString(null).s;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue value;
|
||||||
|
|
||||||
|
}
|
||||||
1117
mozilla/js/js2/java/JSGrammar.g
Normal file
1117
mozilla/js/js2/java/JSGrammar.g
Normal file
File diff suppressed because it is too large
Load Diff
23
mozilla/js/js2/java/JSIdentifier.java
Normal file
23
mozilla/js/js2/java/JSIdentifier.java
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
class JSIdentifier extends JSString {
|
||||||
|
|
||||||
|
JSIdentifier(String s)
|
||||||
|
{
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
String print(String indent)
|
||||||
|
{
|
||||||
|
return indent + "JSIdentifier : " + s + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
return theEnv.scope.getProp(theEnv, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSReference evalLHS(Environment theEnv)
|
||||||
|
{
|
||||||
|
return new JSReference(theEnv.scope, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
68
mozilla/js/js2/java/JSInteger.java
Normal file
68
mozilla/js/js2/java/JSInteger.java
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
class JSInteger extends JSNumber {
|
||||||
|
|
||||||
|
JSInteger(String s)
|
||||||
|
{
|
||||||
|
i = new Integer(s).intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSInteger(int p)
|
||||||
|
{
|
||||||
|
i = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSBoolean toJSBoolean(Environment theEnv) {
|
||||||
|
return (i != 0) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSDouble toJSDouble(Environment theEnv) {
|
||||||
|
return new JSDouble(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSInteger toJSInteger(Environment theEnv) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue toPrimitive(Environment theEnv, String hint) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSString toJSString(Environment theEnv) {
|
||||||
|
return new JSString(Integer.toString(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue twiddle(Environment theEnv) {
|
||||||
|
return new JSInteger(~i);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue and(Environment theEnv, JSValue rV) {
|
||||||
|
return new JSInteger(i & rV.toJSInteger(theEnv).i);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue or(Environment theEnv, JSValue rV) {
|
||||||
|
return new JSInteger(i | rV.toJSInteger(theEnv).i);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue xor(Environment theEnv, JSValue rV) {
|
||||||
|
return new JSInteger(i ^ rV.toJSInteger(theEnv).i);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue shl(Environment theEnv, JSValue rV) {
|
||||||
|
return new JSInteger(i >> rV.toJSInteger(theEnv).i);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue shr(Environment theEnv, JSValue rV) {
|
||||||
|
return new JSInteger(i << rV.toJSInteger(theEnv).i);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue ushl(Environment theEnv, JSValue rV) {
|
||||||
|
return new JSInteger(i >>> rV.toJSInteger(theEnv).i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
}
|
||||||
41
mozilla/js/js2/java/JSName.java
Normal file
41
mozilla/js/js2/java/JSName.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
class JSName extends ExpressionNode {
|
||||||
|
|
||||||
|
JSName(JSIdentifier anID, int aScope)
|
||||||
|
{
|
||||||
|
id = anID;
|
||||||
|
scope = aScope; // this is the scope that the name was used in
|
||||||
|
}
|
||||||
|
|
||||||
|
String print(String indent)
|
||||||
|
{
|
||||||
|
return indent + "JSName : " + id.s + ", scope : " + scope + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
JSReference evalLHS(Environment theEnv)
|
||||||
|
{
|
||||||
|
JSScope scope = theEnv.scope;
|
||||||
|
while (scope != null) {
|
||||||
|
if (scope.hasProp(theEnv, id))
|
||||||
|
return new JSReference(scope, id);
|
||||||
|
else
|
||||||
|
scope = scope.parent;
|
||||||
|
}
|
||||||
|
return new JSReference(theEnv.globalScope, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
JSScope scope = theEnv.scope;
|
||||||
|
while (scope != null) {
|
||||||
|
if (scope.hasProp(theEnv, id))
|
||||||
|
return scope.getProp(theEnv, id);
|
||||||
|
else
|
||||||
|
scope = scope.parent;
|
||||||
|
}
|
||||||
|
throw new JSException(new JSString(id.s + " undefined"));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSIdentifier id;
|
||||||
|
int scope;
|
||||||
|
|
||||||
|
}
|
||||||
8
mozilla/js/js2/java/JSNumber.java
Normal file
8
mozilla/js/js2/java/JSNumber.java
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
abstract class JSNumber extends JSValue {
|
||||||
|
|
||||||
|
JSValue typeof(Environment theEnv) {
|
||||||
|
return new JSString("number");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
84
mozilla/js/js2/java/JSObject.java
Normal file
84
mozilla/js/js2/java/JSObject.java
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
|
||||||
|
import java.util.Hashtable;
|
||||||
|
|
||||||
|
class JSObject extends JSValue {
|
||||||
|
|
||||||
|
static JSObject objectPrototype = new JSObject("Object");
|
||||||
|
static JSObject JSUndefined = new JSObject("undefined");
|
||||||
|
|
||||||
|
JSObject(String aClass)
|
||||||
|
{
|
||||||
|
oClass = aClass;
|
||||||
|
prototype = objectPrototype;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPrototype(JSObject aPrototype)
|
||||||
|
{
|
||||||
|
prototype = aPrototype;
|
||||||
|
}
|
||||||
|
|
||||||
|
String print(String indent)
|
||||||
|
{
|
||||||
|
return indent + "JSObject : " + oClass + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return oClass + contents.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue typeof(Environment theEnv) {
|
||||||
|
if (this == JSUndefined)
|
||||||
|
return new JSString("undefined");
|
||||||
|
else
|
||||||
|
return new JSString("object");
|
||||||
|
}
|
||||||
|
|
||||||
|
JSBoolean toJSBoolean(Environment theEnv) {
|
||||||
|
return JSBoolean.JSTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSDouble toJSDouble(Environment theEnv) {
|
||||||
|
return toPrimitive(theEnv, "Number").toJSDouble(theEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue getProp(Environment theEnv, JSString id)
|
||||||
|
{
|
||||||
|
Object v = contents.get(id.s);
|
||||||
|
if (v == null)
|
||||||
|
if (prototype == null)
|
||||||
|
return JSUndefined;
|
||||||
|
else
|
||||||
|
return prototype.getProp(theEnv, id);
|
||||||
|
else
|
||||||
|
return (JSValue)v;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasProp(Environment theEnv, JSString id)
|
||||||
|
{
|
||||||
|
Object v = contents.get(id.s);
|
||||||
|
if (v == null)
|
||||||
|
if (prototype == null)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return prototype.hasProp(theEnv, id);
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue putProp(Environment theEnv, JSString id, JSValue rV) {
|
||||||
|
contents.put(id.s, rV);
|
||||||
|
return rV;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Hashtable contents = new Hashtable();
|
||||||
|
|
||||||
|
String oClass;
|
||||||
|
|
||||||
|
JSObject prototype;
|
||||||
|
}
|
||||||
12
mozilla/js/js2/java/JSReference.java
Normal file
12
mozilla/js/js2/java/JSReference.java
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
class JSReference {
|
||||||
|
|
||||||
|
JSReference(JSValue aBase, JSString aID)
|
||||||
|
{
|
||||||
|
base = aBase;
|
||||||
|
id = aID;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue base;
|
||||||
|
JSString id;
|
||||||
|
|
||||||
|
}
|
||||||
10
mozilla/js/js2/java/JSScope.java
Normal file
10
mozilla/js/js2/java/JSScope.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
class JSScope extends JSObject {
|
||||||
|
|
||||||
|
JSScope(String s)
|
||||||
|
{
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSScope parent;
|
||||||
|
|
||||||
|
}
|
||||||
83
mozilla/js/js2/java/JSString.java
Normal file
83
mozilla/js/js2/java/JSString.java
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
class JSString extends JSValue {
|
||||||
|
|
||||||
|
JSString(String p)
|
||||||
|
{
|
||||||
|
s = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue typeof(Environment theEnv) {
|
||||||
|
return new JSString("string");
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue add(Environment theEnv, JSValue rV)
|
||||||
|
{
|
||||||
|
return new JSString(s + rV.toJSString(theEnv).s);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue gt(Environment theEnv, JSValue rV) {
|
||||||
|
if (rV instanceof JSString)
|
||||||
|
return (s.compareTo(rV.toJSString(theEnv).s) == 1) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
|
||||||
|
else
|
||||||
|
return toJSDouble(theEnv).gt(theEnv, rV);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue ge(Environment theEnv, JSValue rV) {
|
||||||
|
if (rV instanceof JSString)
|
||||||
|
return (s.compareTo(rV.toJSString(theEnv).s) != -1) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
|
||||||
|
else
|
||||||
|
return toJSDouble(theEnv).ge(theEnv, rV);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue lt(Environment theEnv, JSValue rV) {
|
||||||
|
if (rV instanceof JSString)
|
||||||
|
return (s.compareTo(rV.toJSString(theEnv).s) == -1) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
|
||||||
|
else
|
||||||
|
return toJSDouble(theEnv).lt(theEnv, rV);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue le(Environment theEnv, JSValue rV) {
|
||||||
|
if (rV instanceof JSString)
|
||||||
|
return (s.compareTo(rV.toJSString(theEnv).s) != 1) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
|
||||||
|
else
|
||||||
|
return toJSDouble(theEnv).le(theEnv, rV);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eq(Environment theEnv, JSValue rV) {
|
||||||
|
if (rV instanceof JSString)
|
||||||
|
return (s.compareTo(rV.toJSString(theEnv).s) == 0) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
|
||||||
|
else
|
||||||
|
return toJSDouble(theEnv).eq(theEnv, rV);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue ne(Environment theEnv, JSValue rV) {
|
||||||
|
if (rV instanceof JSString)
|
||||||
|
return (s.compareTo(rV.toJSString(theEnv).s) != 0) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
|
||||||
|
else
|
||||||
|
return toJSDouble(theEnv).ne(theEnv, rV);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSDouble toJSDouble(Environment theEnv) {
|
||||||
|
return new JSDouble(s); // XXX Way More To Do, see Rhino ScriptRuntime.java
|
||||||
|
}
|
||||||
|
|
||||||
|
JSString toJSString(Environment theEnv) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue toPrimitive(Environment theEnv, String hint) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String print(String indent)
|
||||||
|
{
|
||||||
|
return indent + "JSString : " + s + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String s;
|
||||||
|
|
||||||
|
}
|
||||||
222
mozilla/js/js2/java/JSValue.java
Normal file
222
mozilla/js/js2/java/JSValue.java
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
class JSValue extends ExpressionNode {
|
||||||
|
|
||||||
|
String print(String indent)
|
||||||
|
{
|
||||||
|
return indent + "JSValue\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
JSReference evalLHS(Environment theEnv)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("EvalLHS on non-lvalue");
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Eval on JSValue");
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue unimplemented(String op)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("unimplemented " + op + " called");
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue gt(Environment theEnv, JSValue rV) {
|
||||||
|
JSValue lV = toPrimitive(theEnv, "Number");
|
||||||
|
rV = rV.toPrimitive(theEnv, "Number");
|
||||||
|
if ((lV instanceof JSString) && (rV instanceof JSString))
|
||||||
|
return lV.gt(theEnv, rV);
|
||||||
|
else
|
||||||
|
return lV.toJSDouble(theEnv).gt(theEnv, rV.toJSDouble(theEnv));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue ge(Environment theEnv, JSValue rV) {
|
||||||
|
JSValue lV = toPrimitive(theEnv, "Number");
|
||||||
|
rV = rV.toPrimitive(theEnv, "Number");
|
||||||
|
if ((lV instanceof JSString) && (rV instanceof JSString))
|
||||||
|
return lV.ge(theEnv, rV);
|
||||||
|
else
|
||||||
|
return lV.toJSDouble(theEnv).ge(theEnv, rV.toJSDouble(theEnv));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue lt(Environment theEnv, JSValue rV) {
|
||||||
|
JSValue lV = toPrimitive(theEnv, "Number");
|
||||||
|
rV = rV.toPrimitive(theEnv, "Number");
|
||||||
|
if ((lV instanceof JSString) && (rV instanceof JSString))
|
||||||
|
return lV.lt(theEnv, rV);
|
||||||
|
else
|
||||||
|
return lV.toJSDouble(theEnv).lt(theEnv, rV.toJSDouble(theEnv));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue le(Environment theEnv, JSValue rV) {
|
||||||
|
JSValue lV = toPrimitive(theEnv, "Number");
|
||||||
|
rV = rV.toPrimitive(theEnv, "Number");
|
||||||
|
if ((lV instanceof JSString) && (rV instanceof JSString))
|
||||||
|
return lV.le(theEnv, rV);
|
||||||
|
else
|
||||||
|
return lV.toJSDouble(theEnv).le(theEnv, rV.toJSDouble(theEnv));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eq(Environment theEnv, JSValue rV) {
|
||||||
|
JSValue lV = toPrimitive(theEnv, "Number");
|
||||||
|
rV = rV.toPrimitive(theEnv, "Number");
|
||||||
|
if ((lV instanceof JSString) && (rV instanceof JSString))
|
||||||
|
return lV.eq(theEnv, rV);
|
||||||
|
else
|
||||||
|
return lV.toJSDouble(theEnv).eq(theEnv, rV.toJSDouble(theEnv));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue ne(Environment theEnv, JSValue rV) {
|
||||||
|
JSValue lV = toPrimitive(theEnv, "Number");
|
||||||
|
rV = rV.toPrimitive(theEnv, "Number");
|
||||||
|
if ((lV instanceof JSString) && (rV instanceof JSString))
|
||||||
|
return lV.ne(theEnv, rV);
|
||||||
|
else
|
||||||
|
return lV.toJSDouble(theEnv).ne(theEnv, rV.toJSDouble(theEnv));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue plus(Environment theEnv) {
|
||||||
|
return toJSDouble(theEnv).plus(theEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue minus(Environment theEnv) {
|
||||||
|
return toJSDouble(theEnv).minus(theEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue twiddle(Environment theEnv) {
|
||||||
|
return toJSInteger(theEnv).twiddle(theEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue bang(Environment theEnv) {
|
||||||
|
return toJSBoolean(theEnv).bang(theEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue typeof(Environment theEnv) {
|
||||||
|
return unimplemented("typeof");
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue add(Environment theEnv, JSValue rV) {
|
||||||
|
JSValue lV = toPrimitive(theEnv, "");
|
||||||
|
rV = rV.toPrimitive(theEnv, "");
|
||||||
|
if ((lV instanceof JSString) || (rV instanceof JSString))
|
||||||
|
return lV.add(theEnv, rV);
|
||||||
|
else
|
||||||
|
return lV.toJSDouble(theEnv).add(theEnv, rV);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue subtract(Environment theEnv, JSValue rV) {
|
||||||
|
return toJSDouble(theEnv).subtract(theEnv, rV.toJSDouble(theEnv));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue multiply(Environment theEnv, JSValue rV) {
|
||||||
|
return toJSDouble(theEnv).multiply(theEnv, rV.toJSDouble(theEnv));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue divide(Environment theEnv, JSValue rV) {
|
||||||
|
return toJSDouble(theEnv).divide(theEnv, rV.toJSDouble(theEnv));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue remainder(Environment theEnv, JSValue rV) {
|
||||||
|
return toJSDouble(theEnv).remainder(theEnv, rV.toJSDouble(theEnv));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue and(Environment theEnv, JSValue rV) {
|
||||||
|
return toJSInteger(theEnv).and(theEnv, rV.toJSInteger(theEnv));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue or(Environment theEnv, JSValue rV) {
|
||||||
|
return toJSInteger(theEnv).or(theEnv, rV.toJSInteger(theEnv));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue xor(Environment theEnv, JSValue rV) {
|
||||||
|
return toJSInteger(theEnv).xor(theEnv, rV.toJSInteger(theEnv));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue shl(Environment theEnv, JSValue rV) {
|
||||||
|
return toJSInteger(theEnv).shl(theEnv, rV.toJSInteger(theEnv));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue shr(Environment theEnv, JSValue rV) {
|
||||||
|
return toJSInteger(theEnv).shr(theEnv, rV.toJSInteger(theEnv));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue ushl(Environment theEnv, JSValue rV) {
|
||||||
|
return toJSInteger(theEnv).ushl(theEnv, rV.toJSInteger(theEnv));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue getProp(Environment theEnv, JSString id) {
|
||||||
|
return toJSObject(theEnv).getProp(theEnv, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasProp(Environment theEnv, JSString id) {
|
||||||
|
return toJSObject(theEnv).hasProp(theEnv, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue putProp(Environment theEnv, JSString id, JSValue rV) {
|
||||||
|
return toJSObject(theEnv).putProp(theEnv, id, rV);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue call(Environment theEnv, JSValue rV) {
|
||||||
|
throw new JSException(new JSString("[[call]] not implemented"));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue defaultValue(Environment theEnv, String hint) {
|
||||||
|
/*
|
||||||
|
When the [[DefaultValue]] method of O is called with hint String, the following steps are taken:
|
||||||
|
1. Call the [[Get]] method of object O with argument "toString".
|
||||||
|
2. If Result(1) is not an object, go to step 5.
|
||||||
|
3. Call the [[Call]] method of Result(1), with O as the this value and an empty argument list.
|
||||||
|
4. If Result(3) is a primitive value, return Result(3).
|
||||||
|
5. Call the [[Get]] method of object O with argument "valueOf".
|
||||||
|
6. If Result(5) is not an object, go to step 9.
|
||||||
|
7. Call the [[Call]] method of Result(5), with O as the this value and an empty argument list.
|
||||||
|
8. If Result(7) is a primitive value, return Result(7).
|
||||||
|
9. Generate a runtime error.
|
||||||
|
*/
|
||||||
|
JSValue v = null;
|
||||||
|
if (hint.equals("String")) {
|
||||||
|
v = getProp(theEnv, new JSString("toString"));
|
||||||
|
if (v instanceof JSObject) {
|
||||||
|
// invoke 'v.Call' with 'this' as the JS this
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
v = getProp(theEnv, new JSString("valueOf"));
|
||||||
|
if (v instanceof JSObject) {
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new JSException(new JSString("No default value"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // hint.equals("Number")
|
||||||
|
/*
|
||||||
|
When the [[DefaultValue]] method of O is called with hint Number, the following steps are taken:
|
||||||
|
1. Call the [[Get]] method of object O with argument "valueOf".
|
||||||
|
2. If Result(1) is not an object, go to step 5.
|
||||||
|
3. Call the [[Call]] method of Result(1), with O as the this value and an empty argument list.
|
||||||
|
4. If Result(3) is a primitive value, return Result(3).
|
||||||
|
5. Call the [[Get]] method of object O with argument "toString".
|
||||||
|
6. If Result(5) is not an object, go to step 9.
|
||||||
|
7. Call the [[Call]] method of Result(5), with O as the this value and an empty argument list.
|
||||||
|
8. If Result(7) is a primitive value, return Result(7).
|
||||||
|
9. Generate a runtime error.
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue toPrimitive(Environment theEnv, String hint) {
|
||||||
|
JSValue result = defaultValue(theEnv, hint);
|
||||||
|
if (result instanceof JSObject)
|
||||||
|
throw new JSException(new JSString("default value returned object"));
|
||||||
|
else
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JSObject toJSObject(Environment theEnv) { unimplemented("toJSObjet"); return null; }
|
||||||
|
JSDouble toJSDouble(Environment theEnv) { unimplemented("toJSDouble"); return null; }
|
||||||
|
JSInteger toJSInteger(Environment theEnv) { unimplemented("toJSInteger"); return null; }
|
||||||
|
JSString toJSString(Environment theEnv) { unimplemented("toJSString"); return null; }
|
||||||
|
JSBoolean toJSBoolean(Environment theEnv) { unimplemented("toJSBoolean"); return null; }
|
||||||
|
|
||||||
|
}
|
||||||
40
mozilla/js/js2/java/JSValueList.java
Normal file
40
mozilla/js/js2/java/JSValueList.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
class JSValueList extends JSValue {
|
||||||
|
|
||||||
|
static JSValueList buildList(JSValue left, JSValue right)
|
||||||
|
{
|
||||||
|
JSValueList theList;
|
||||||
|
if (left instanceof JSValueList) {
|
||||||
|
theList = (JSValueList)left;
|
||||||
|
theList.add(right);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (right instanceof JSValueList) {
|
||||||
|
theList = (JSValueList)right;
|
||||||
|
theList.add(left);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
theList = new JSValueList();
|
||||||
|
theList.add(left);
|
||||||
|
theList.add(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
return theList;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(JSValue v)
|
||||||
|
{
|
||||||
|
if (v instanceof JSValueList) {
|
||||||
|
JSValueList vl = (JSValueList)v;
|
||||||
|
for (int i = 0; i < vl.contents.size(); i++)
|
||||||
|
contents.addElement((JSValue)(vl.contents.elementAt(i)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
contents.addElement(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector contents = new Vector();
|
||||||
|
|
||||||
|
}
|
||||||
39
mozilla/js/js2/java/LogicalNode.java
Normal file
39
mozilla/js/js2/java/LogicalNode.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
class LogicalNode extends BinaryNode {
|
||||||
|
|
||||||
|
LogicalNode(String aOp, ExpressionNode aLeft, ExpressionNode aRight)
|
||||||
|
{
|
||||||
|
super(aOp, aLeft, aRight);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
JSBoolean b = left.eval(theEnv).toJSBoolean(theEnv);
|
||||||
|
if (op == "&&") {
|
||||||
|
if (b.isFalse())
|
||||||
|
return b;
|
||||||
|
else {
|
||||||
|
b = right.eval(theEnv).toJSBoolean(theEnv);
|
||||||
|
if (b.isFalse())
|
||||||
|
return b;
|
||||||
|
else
|
||||||
|
return JSBoolean.JSTrue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (op == "||") {
|
||||||
|
if (b.isTrue())
|
||||||
|
return b;
|
||||||
|
else {
|
||||||
|
b = right.eval(theEnv).toJSBoolean(theEnv);
|
||||||
|
if (b.isTrue())
|
||||||
|
return b;
|
||||||
|
else
|
||||||
|
return JSBoolean.JSFalse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
System.out.println("missing logical op " + op);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
35
mozilla/js/js2/java/NativeFunction.java
Normal file
35
mozilla/js/js2/java/NativeFunction.java
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
class NativeFunction extends JSObject {
|
||||||
|
|
||||||
|
NativeFunction(ControlNode aBody)
|
||||||
|
{
|
||||||
|
super("Function");
|
||||||
|
body = aBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue call(Environment theEnv, JSValue rV)
|
||||||
|
{
|
||||||
|
|
||||||
|
JSScope args = new JSScope("Arguments");
|
||||||
|
theEnv.enterNewScope(args);
|
||||||
|
|
||||||
|
for (int i = 0; i < parameters.size(); i++) {
|
||||||
|
if (rV instanceof JSValueList)
|
||||||
|
args.putProp(theEnv, (JSString)(parameters.elementAt(i)), (JSValue) ( ((JSValueList)rV).contents.elementAt(i)) );
|
||||||
|
else
|
||||||
|
args.putProp(theEnv, (JSString)(parameters.elementAt(i)), rV );
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlNode c = body;
|
||||||
|
while (c != null) c = c.eval(theEnv);
|
||||||
|
|
||||||
|
theEnv.leaveScope();
|
||||||
|
return theEnv.resultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlNode body;
|
||||||
|
Vector parameters = new Vector();
|
||||||
|
|
||||||
|
}
|
||||||
18
mozilla/js/js2/java/NativeNumber.java
Normal file
18
mozilla/js/js2/java/NativeNumber.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
class NativeNumber extends JSObject {
|
||||||
|
|
||||||
|
NativeNumber(double p) {
|
||||||
|
super("Number");
|
||||||
|
d = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue defaultValue(Environment theEnv, String hint) {
|
||||||
|
if (hint.equals("String"))
|
||||||
|
return new JSString(Double.toString(d));
|
||||||
|
else
|
||||||
|
return new JSDouble(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
double d;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
35
mozilla/js/js2/java/RelationalNode.java
Normal file
35
mozilla/js/js2/java/RelationalNode.java
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
class RelationalNode extends BinaryNode {
|
||||||
|
|
||||||
|
RelationalNode(String aOp, ExpressionNode aLeft, ExpressionNode aRight)
|
||||||
|
{
|
||||||
|
super(aOp, aLeft, aRight);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
JSValue lV = left.eval(theEnv);
|
||||||
|
JSValue rV = right.eval(theEnv);
|
||||||
|
|
||||||
|
if (op == ">")
|
||||||
|
return lV.gt(theEnv, rV);
|
||||||
|
else
|
||||||
|
if (op == ">=")
|
||||||
|
return lV.ge(theEnv, rV);
|
||||||
|
else
|
||||||
|
if (op == "<")
|
||||||
|
return lV.lt(theEnv, rV);
|
||||||
|
else
|
||||||
|
if (op == "<=")
|
||||||
|
return lV.le(theEnv, rV);
|
||||||
|
else
|
||||||
|
if (op == "==")
|
||||||
|
return lV.eq(theEnv, rV);
|
||||||
|
else
|
||||||
|
if (op == "!=")
|
||||||
|
return lV.ne(theEnv, rV);
|
||||||
|
else {
|
||||||
|
System.out.println("missing relational op");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
43
mozilla/js/js2/java/SwitchNode.java
Normal file
43
mozilla/js/js2/java/SwitchNode.java
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
class SwitchNode extends ControlNode {
|
||||||
|
|
||||||
|
|
||||||
|
SwitchNode(ExpressionNode e)
|
||||||
|
{
|
||||||
|
super(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addCase(ExpressionNode e, ControlNode c)
|
||||||
|
{
|
||||||
|
if (e == null)
|
||||||
|
defaultCode = c;
|
||||||
|
else {
|
||||||
|
caseExpr.addElement(e);
|
||||||
|
caseCode.addElement(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlNode eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
JSValue v = expr.eval(theEnv);
|
||||||
|
int count = caseExpr.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
ExpressionNode e = (ExpressionNode)(caseExpr.elementAt(i));
|
||||||
|
JSBoolean b = v.eq(theEnv, e.eval(theEnv)).toJSBoolean(theEnv);
|
||||||
|
if (b.isTrue())
|
||||||
|
return (ControlNode)(caseCode.elementAt(i));
|
||||||
|
}
|
||||||
|
if (defaultCode != null)
|
||||||
|
return defaultCode;
|
||||||
|
else
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector caseExpr = new Vector();
|
||||||
|
Vector caseCode = new Vector();
|
||||||
|
|
||||||
|
ControlNode defaultCode;
|
||||||
|
|
||||||
|
}
|
||||||
13
mozilla/js/js2/java/ThrowNode.java
Normal file
13
mozilla/js/js2/java/ThrowNode.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
class ThrowNode extends ControlNode {
|
||||||
|
|
||||||
|
ThrowNode(ExpressionNode e)
|
||||||
|
{
|
||||||
|
super(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlNode eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
throw new JSException(expr.eval(theEnv));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
47
mozilla/js/js2/java/TryNode.java
Normal file
47
mozilla/js/js2/java/TryNode.java
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
class TryNode extends ControlNode {
|
||||||
|
|
||||||
|
TryNode(ControlNode tryCode)
|
||||||
|
{
|
||||||
|
super(null);
|
||||||
|
tryBody = tryCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addFinally(ControlNode finallyCode)
|
||||||
|
{
|
||||||
|
finallyBody = finallyCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addCatchClause(ExpressionNode e, ControlNode c)
|
||||||
|
{
|
||||||
|
catchExpr.addElement(e);
|
||||||
|
catchCode.addElement(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlNode eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
ControlNode c = tryBody;
|
||||||
|
while (c != null) c = c.eval(theEnv);
|
||||||
|
}
|
||||||
|
catch (JSException x) {
|
||||||
|
int count = catchExpr.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
ExpressionNode e = (ExpressionNode)(catchExpr.elementAt(i));
|
||||||
|
String id = ((JSObject)e).oClass;
|
||||||
|
theEnv.scope.contents.put(id, x.getValue()); // XXX YAARGH !!!
|
||||||
|
return (ControlNode)(catchCode.elementAt(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector catchExpr = new Vector();
|
||||||
|
Vector catchCode = new Vector();
|
||||||
|
|
||||||
|
ControlNode tryBody;
|
||||||
|
ControlNode finallyBody;
|
||||||
|
|
||||||
|
}
|
||||||
62
mozilla/js/js2/java/UnaryNode.java
Normal file
62
mozilla/js/js2/java/UnaryNode.java
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
class UnaryNode extends ExpressionNode {
|
||||||
|
|
||||||
|
UnaryNode(String aOp, ExpressionNode aChild)
|
||||||
|
{
|
||||||
|
child = aChild;
|
||||||
|
op = aOp;
|
||||||
|
}
|
||||||
|
|
||||||
|
String print(String indent)
|
||||||
|
{
|
||||||
|
StringBuffer result = new StringBuffer(indent);
|
||||||
|
result.append("UnaryNode ");
|
||||||
|
result.append(op);
|
||||||
|
result.append("\n");
|
||||||
|
indent += " ";
|
||||||
|
if (child == null) {
|
||||||
|
result.append(indent);
|
||||||
|
result.append("null\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result.append(child.print(indent));
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue eval(Environment theEnv)
|
||||||
|
{
|
||||||
|
JSValue cV = child.eval(theEnv);
|
||||||
|
|
||||||
|
if (op == "+")
|
||||||
|
return cV.plus(theEnv);
|
||||||
|
else
|
||||||
|
if (op == "-")
|
||||||
|
return cV.minus(theEnv);
|
||||||
|
else
|
||||||
|
if (op == "~")
|
||||||
|
return cV.twiddle(theEnv);
|
||||||
|
else
|
||||||
|
if (op == "!")
|
||||||
|
return cV.bang(theEnv);
|
||||||
|
else
|
||||||
|
if (op == "typeof")
|
||||||
|
return cV.typeof(theEnv);
|
||||||
|
else {
|
||||||
|
System.out.println("missing unary op " + op);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String getOperator()
|
||||||
|
{
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionNode getChild()
|
||||||
|
{
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ExpressionNode child;
|
||||||
|
protected String op;
|
||||||
|
|
||||||
|
}
|
||||||
343
mozilla/js/js2/js2.cpp
Normal file
343
mozilla/js/js2/js2.cpp
Normal file
@@ -0,0 +1,343 @@
|
|||||||
|
// -*- 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.
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// JS2 shell.
|
||||||
|
//
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
#define DEBUGGER_FOO
|
||||||
|
#define INTERPRET_INPUT
|
||||||
|
#else
|
||||||
|
#undef DEBUGGER_FOO
|
||||||
|
#undef INTERPRET_INPUT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "world.h"
|
||||||
|
#include "interpreter.h"
|
||||||
|
#include "icodegenerator.h"
|
||||||
|
|
||||||
|
#ifdef DEBUGGER_FOO
|
||||||
|
#include "debugger.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(XP_MAC) && !defined(XP_MAC_MPW)
|
||||||
|
#include <SIOUX.h>
|
||||||
|
#include <MacTypes.h>
|
||||||
|
|
||||||
|
static char *mac_argv[] = {"js2", 0};
|
||||||
|
|
||||||
|
static void initConsole(StringPtr consoleName,
|
||||||
|
const char* startupMessage,
|
||||||
|
int &argc, char **&argv)
|
||||||
|
{
|
||||||
|
SIOUXSettings.autocloseonquit = false;
|
||||||
|
SIOUXSettings.asktosaveonclose = false;
|
||||||
|
SIOUXSetTitle(consoleName);
|
||||||
|
|
||||||
|
// Set up a buffer for stderr (otherwise it's a pig).
|
||||||
|
static char buffer[BUFSIZ];
|
||||||
|
setvbuf(stderr, buffer, _IOLBF, BUFSIZ);
|
||||||
|
|
||||||
|
JavaScript::stdOut << startupMessage;
|
||||||
|
|
||||||
|
argc = 1;
|
||||||
|
argv = mac_argv;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
namespace Shell {
|
||||||
|
|
||||||
|
using namespace ICG;
|
||||||
|
using namespace JSTypes;
|
||||||
|
using namespace Interpreter;
|
||||||
|
|
||||||
|
// Interactively read a line from the input stream in and put it into
|
||||||
|
// s. Return false if reached the end of input before reading anything.
|
||||||
|
static bool promptLine(LineReader &inReader, string &s, const char *prompt)
|
||||||
|
{
|
||||||
|
if (prompt) {
|
||||||
|
stdOut << prompt;
|
||||||
|
#ifdef XP_MAC_MPW
|
||||||
|
// Print a CR after the prompt because MPW grabs the entire
|
||||||
|
// line when entering an interactive command.
|
||||||
|
stdOut << '\n';
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return inReader.readLine(s) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
World world;
|
||||||
|
|
||||||
|
/* "filename" of the console */
|
||||||
|
const String ConsoleName = widenCString("<console>");
|
||||||
|
const bool showTokens = false;
|
||||||
|
|
||||||
|
#ifdef DEBUGGER_FOO
|
||||||
|
Reader *sourceReader; /* Reader for console file */
|
||||||
|
|
||||||
|
static
|
||||||
|
const Reader *ResolveFile (const String& fileName)
|
||||||
|
{
|
||||||
|
if (fileName == ConsoleName)
|
||||||
|
return sourceReader;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stdErr << "Could not locate source for file '" << fileName << "'\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
JavaScript::Debugger::Shell jsd(world, stdin, JavaScript::stdOut,
|
||||||
|
JavaScript::stdOut, &ResolveFile);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static JSValue print(Context *cx, const JSValues &argv)
|
||||||
|
{
|
||||||
|
size_t n = argv.size();
|
||||||
|
if (n > 1) { // the 'this' parameter is un-interesting
|
||||||
|
stdOut << argv[1];
|
||||||
|
for (size_t i = 2; i < n; ++i)
|
||||||
|
stdOut << ' ' << argv[i];
|
||||||
|
}
|
||||||
|
stdOut << "\n";
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSValue dump(Context *cx, const JSValues &argv)
|
||||||
|
{
|
||||||
|
size_t n = argv.size();
|
||||||
|
if (n > 1) { // the 'this' parameter is un-interesting
|
||||||
|
if (argv[1].isFunction()) {
|
||||||
|
JSFunction *f = static_cast<JSFunction *>(argv[1].function);
|
||||||
|
if (f->isNative())
|
||||||
|
stdOut << "Native function";
|
||||||
|
else
|
||||||
|
stdOut << *f->getICode();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
stdOut << "Not a function";
|
||||||
|
}
|
||||||
|
stdOut << "\n";
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline char narrow(char16 ch) { return char(ch); }
|
||||||
|
|
||||||
|
static JSValue load(Context *cx, const JSValues &argv)
|
||||||
|
{
|
||||||
|
|
||||||
|
JSValue result;
|
||||||
|
size_t n = argv.size();
|
||||||
|
if (n > 1) {
|
||||||
|
for (size_t i = 1; i < n; ++i) {
|
||||||
|
JSValue val = argv[i].toString();
|
||||||
|
if (val.isString()) {
|
||||||
|
String fileName(*val.string);
|
||||||
|
std::string str(fileName.length(), char());
|
||||||
|
std::transform(fileName.begin(), fileName.end(), str.begin(), narrow);
|
||||||
|
FILE* f = fopen(str.c_str(), "r");
|
||||||
|
if (f) {
|
||||||
|
result = cx->readEvalFile(f, fileName);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0 // need a XP version of this, rip off from Monkey?
|
||||||
|
#include <sys/timeb.h>
|
||||||
|
static JSValue time(Context *cx, const JSValues &argv)
|
||||||
|
{
|
||||||
|
struct _timeb timebuffer;
|
||||||
|
_ftime(&timebuffer);
|
||||||
|
|
||||||
|
return JSValue((double)timebuffer.time * 1000 + timebuffer.millitm);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void readEvalPrint(FILE *in, World &world)
|
||||||
|
{
|
||||||
|
JSScope global;
|
||||||
|
Context cx(world, &global);
|
||||||
|
#ifdef DEBUGGER_FOO
|
||||||
|
jsd.attachToContext (&cx);
|
||||||
|
#endif
|
||||||
|
global.defineNativeFunction(world.identifiers["print"], print);
|
||||||
|
global.defineNativeFunction(world.identifiers["dump"], dump);
|
||||||
|
global.defineNativeFunction(world.identifiers["load"], load);
|
||||||
|
// global.defineNativeFunction(world.identifiers["time"], time);
|
||||||
|
|
||||||
|
String buffer;
|
||||||
|
string line;
|
||||||
|
LineReader inReader(in);
|
||||||
|
|
||||||
|
while (promptLine(inReader, line, buffer.empty() ? "js> " : "> ")) {
|
||||||
|
appendChars(buffer, line.data(), line.size());
|
||||||
|
try {
|
||||||
|
Arena a;
|
||||||
|
Parser p(world, a, buffer, ConsoleName);
|
||||||
|
|
||||||
|
if (showTokens) {
|
||||||
|
Lexer &l = p.lexer;
|
||||||
|
while (true) {
|
||||||
|
const Token &t = l.get(true);
|
||||||
|
if (t.hasKind(Token::end))
|
||||||
|
break;
|
||||||
|
stdOut << ' ';
|
||||||
|
t.print(stdOut, true);
|
||||||
|
}
|
||||||
|
stdOut << '\n';
|
||||||
|
} else {
|
||||||
|
StmtNode *parsedStatements = p.parseProgram();
|
||||||
|
ASSERT(p.lexer.peek(true).hasKind(Token::end));
|
||||||
|
{
|
||||||
|
PrettyPrinter f(stdOut, 30);
|
||||||
|
{
|
||||||
|
PrettyPrinter::Block b(f, 2);
|
||||||
|
f << "Program =";
|
||||||
|
f.linearBreak(1);
|
||||||
|
StmtNode::printStatements(f, parsedStatements);
|
||||||
|
}
|
||||||
|
f.end();
|
||||||
|
}
|
||||||
|
stdOut << '\n';
|
||||||
|
#ifdef INTERPRET_INPUT
|
||||||
|
#ifdef DEBUGGER_FOO
|
||||||
|
sourceReader = &(p.lexer.reader);
|
||||||
|
#endif
|
||||||
|
// Generate code for parsedStatements, which is a linked
|
||||||
|
// list of zero or more statements
|
||||||
|
ICodeModule* icm = cx.genCode(parsedStatements, ConsoleName);
|
||||||
|
if (icm) {
|
||||||
|
stdOut << *icm;
|
||||||
|
JSValue result = cx.interpret(icm, JSValues());
|
||||||
|
stdOut << "result = " << result << "\n";
|
||||||
|
delete icm;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
clear(buffer);
|
||||||
|
} catch (Exception &e) {
|
||||||
|
/* If we got a syntax error on the end of input,
|
||||||
|
* then wait for a continuation
|
||||||
|
* of input rather than printing the error message. */
|
||||||
|
if (!(e.hasKind(Exception::syntaxError) &&
|
||||||
|
e.lineNum && e.pos == buffer.size() &&
|
||||||
|
e.sourceFile == ConsoleName)) {
|
||||||
|
stdOut << '\n' << e.fullMessage();
|
||||||
|
clear(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stdOut << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Poor man's instruction tracing facility.
|
||||||
|
*/
|
||||||
|
class Tracer : public Context::Listener {
|
||||||
|
typedef InstructionStream::difference_type InstructionOffset;
|
||||||
|
void listen(Context* context, Context::Event event)
|
||||||
|
{
|
||||||
|
if (event & Context::EV_STEP) {
|
||||||
|
ICodeModule *iCode = context->getICode();
|
||||||
|
JSValues ®isters = context->getRegisters();
|
||||||
|
InstructionIterator pc = context->getPC();
|
||||||
|
|
||||||
|
|
||||||
|
InstructionOffset offset = (pc - iCode->its_iCode->begin());
|
||||||
|
printFormat(stdOut, "trace [%02u:%04u]: ",
|
||||||
|
iCode->mID, offset);
|
||||||
|
|
||||||
|
Instruction* i = *pc;
|
||||||
|
stdOut << *i;
|
||||||
|
if (i->op() != BRANCH && i->count() > 0) {
|
||||||
|
stdOut << " [";
|
||||||
|
i->printOperands(stdOut, registers);
|
||||||
|
stdOut << "]\n";
|
||||||
|
} else {
|
||||||
|
stdOut << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
char * tests[] = {
|
||||||
|
"function fact(n) { if (n > 1) return n * fact(n-1); else return 1; } print(fact(6), \" should be 720\"); return;" ,
|
||||||
|
"a = { f1: 1, f2: 2}; print(a.f2++, \" should be 2\"); print(a.f2 <<= 1, \" should be 6\"); return;" ,
|
||||||
|
"class A { static var b = 3; static function s() { return b++; }function x() { return \"Ax\"; } function y() { return \"Ay\"; } } var a:A = new A; print(a.s(), \" should be 3\"); print(A.b, \" should be 4\"); return;",
|
||||||
|
"class B extends A { function x() { return \"Bx\"; } } var b:B = new B; print(b.x(), \" should be Bx\"); print(b.y(), \" should be Ay\"); return;"
|
||||||
|
};
|
||||||
|
|
||||||
|
static void testCompile()
|
||||||
|
{
|
||||||
|
JSScope glob;
|
||||||
|
Context cx(world, &glob);
|
||||||
|
glob.defineNativeFunction(world.identifiers["print"], print);
|
||||||
|
for (uint i = 0; i < sizeof(tests) / sizeof(char *); i++) {
|
||||||
|
String testScript = widenCString(tests[i]);
|
||||||
|
Arena a;
|
||||||
|
Parser p(world, a, testScript, widenCString("testCompile"));
|
||||||
|
StmtNode *parsedStatements = p.parseProgram();
|
||||||
|
ICodeGenerator icg(&world, &glob);
|
||||||
|
StmtNode *s = parsedStatements;
|
||||||
|
while (s) {
|
||||||
|
icg.genStmt(s);
|
||||||
|
s = s->next;
|
||||||
|
}
|
||||||
|
cx.interpret(icg.complete(), JSValues());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace Shell */
|
||||||
|
} /* namespace JavaScript */
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(XP_MAC) && !defined(XP_MAC_MPW)
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
initConsole("\pJavaScript Shell", "Welcome to the js2 shell.\n", argc, argv);
|
||||||
|
#else
|
||||||
|
int main(int , char **)
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace JavaScript;
|
||||||
|
using namespace Shell;
|
||||||
|
#if 1
|
||||||
|
testCompile();
|
||||||
|
#endif
|
||||||
|
readEvalPrint(stdin, world);
|
||||||
|
return 0;
|
||||||
|
// return ProcessArgs(argv + 1, argc - 1);
|
||||||
|
}
|
||||||
316
mozilla/js/js2/jsclasses.h
Normal file
316
mozilla/js/js2/jsclasses.h
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
/* -*- 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 jsclasses_h
|
||||||
|
#define jsclasses_h
|
||||||
|
|
||||||
|
#include "jstypes.h"
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
namespace JSClasses {
|
||||||
|
|
||||||
|
using JSTypes::JSValue;
|
||||||
|
using JSTypes::JSObject;
|
||||||
|
using JSTypes::JSType;
|
||||||
|
using JSTypes::JSScope;
|
||||||
|
using JSTypes::JSFunction;
|
||||||
|
using ICG::ICodeModule;
|
||||||
|
|
||||||
|
|
||||||
|
struct JSSlot {
|
||||||
|
typedef enum { kNoFlag = 0, kIsConstructor = 0x01 } SlotFlags; // <-- readonly, enumerable etc
|
||||||
|
|
||||||
|
JSType* mType;
|
||||||
|
uint32 mIndex;
|
||||||
|
SlotFlags mFlags;
|
||||||
|
|
||||||
|
JSSlot() : mType(0), mFlags(kNoFlag)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isConstructor() const { return (mFlags & kIsConstructor) != 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(XP_MAC)
|
||||||
|
// copied from default template parameters in map.
|
||||||
|
typedef gc_allocator<std::pair<const String, JSSlot> > gc_slot_allocator;
|
||||||
|
#elif defined(XP_UNIX)
|
||||||
|
typedef JSTypes::gc_map_allocator gc_slot_allocator;
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
typedef gc_allocator<JSSlot> gc_slot_allocator;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef std::map<String, JSSlot, std::less<const String>, gc_slot_allocator> JSSlots;
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::pair<String, JSFunction*> MethodEntry;
|
||||||
|
typedef std::vector<MethodEntry> JSMethods;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a class in the JavaScript 2 (ECMA 4) language.
|
||||||
|
* Since a class defines a scope, and is defined in a scope,
|
||||||
|
* a new scope is created whose parent scope is the scope of
|
||||||
|
* class definition.
|
||||||
|
*/
|
||||||
|
class JSClass : public JSType {
|
||||||
|
protected:
|
||||||
|
JSScope* mScope;
|
||||||
|
uint32 mSlotCount;
|
||||||
|
JSSlots mSlots;
|
||||||
|
uint32 mStaticCount;
|
||||||
|
JSSlots mStaticSlots;
|
||||||
|
JSValue* mStaticData;
|
||||||
|
JSMethods mMethods;
|
||||||
|
public:
|
||||||
|
JSClass(JSScope* scope, const String& name, JSClass* superClass = 0)
|
||||||
|
: JSType(name, superClass),
|
||||||
|
mScope(new JSScope(scope)),
|
||||||
|
mSlotCount(superClass ? superClass->mSlotCount : 0),
|
||||||
|
mStaticCount(0),
|
||||||
|
mStaticData(0)
|
||||||
|
{
|
||||||
|
if (superClass) {
|
||||||
|
// inherit superclass methods
|
||||||
|
JSMethods::iterator end = superClass->mMethods.end();
|
||||||
|
for (JSMethods::iterator i = superClass->mMethods.begin(); i != end; i++)
|
||||||
|
mMethods.push_back(*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSClass* getSuperClass()
|
||||||
|
{
|
||||||
|
return static_cast<JSClass*>(mBaseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSScope* getScope()
|
||||||
|
{
|
||||||
|
return mScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSSlot& defineSlot(const String& name, JSType* type)
|
||||||
|
{
|
||||||
|
JSSlot& slot = mSlots[name];
|
||||||
|
ASSERT(slot.mType == 0);
|
||||||
|
slot.mType = type;
|
||||||
|
slot.mIndex = mSlotCount++; // starts at 0.
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSSlot& getSlot(const String& name)
|
||||||
|
{
|
||||||
|
return mSlots[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasSlot(const String& name)
|
||||||
|
{
|
||||||
|
return (mSlots.find(name) != mSlots.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
JSSlots& getSlots()
|
||||||
|
{
|
||||||
|
return mSlots;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 getSlotCount()
|
||||||
|
{
|
||||||
|
return mSlotCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a static/class variable.
|
||||||
|
*/
|
||||||
|
const JSSlot& defineStatic(const String& name, JSType* type)
|
||||||
|
{
|
||||||
|
JSSlot& slot = mStaticSlots[name];
|
||||||
|
ASSERT(slot.mType == 0);
|
||||||
|
slot.mType = type;
|
||||||
|
slot.mIndex = mStaticCount++;
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSSlot& defineConstructor(const String& name)
|
||||||
|
{
|
||||||
|
JSSlot& slot = mStaticSlots[name];
|
||||||
|
ASSERT(slot.mType == 0);
|
||||||
|
slot.mType = &JSTypes::Function_Type;
|
||||||
|
slot.mIndex = mStaticCount++;
|
||||||
|
slot.mFlags = JSSlot::kIsConstructor;
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSSlot& getStatic(const String& name)
|
||||||
|
{
|
||||||
|
return mStaticSlots[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasStatic(const String& name, JSType*& type, bool &isConstructor)
|
||||||
|
{
|
||||||
|
JSSlots::const_iterator i = mStaticSlots.find(name);
|
||||||
|
if (i != mStaticSlots.end()) {
|
||||||
|
type = i->second.mType;
|
||||||
|
isConstructor = i->second.isConstructor();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasStatic(const String& name)
|
||||||
|
{
|
||||||
|
return (mStaticSlots.find(name) != mStaticSlots.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool complete()
|
||||||
|
{
|
||||||
|
mStaticData = new JSValue[mStaticCount];
|
||||||
|
return (mStaticData != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue& operator[] (uint32 index)
|
||||||
|
{
|
||||||
|
return mStaticData[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void printProperties(Formatter& f)
|
||||||
|
{
|
||||||
|
f << "Properties:\n";
|
||||||
|
JSObject::printProperties(f);
|
||||||
|
f << "Statics:\n";
|
||||||
|
printStatics(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printStatics(Formatter& f)
|
||||||
|
{
|
||||||
|
JSClass* superClass = getSuperClass();
|
||||||
|
if (superClass) superClass->printStatics(f);
|
||||||
|
for (JSSlots::iterator i = mStaticSlots.begin(), end = mStaticSlots.end(); i != end; ++i) {
|
||||||
|
f << i->first << " : " << mStaticData[i->second.mIndex] << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void defineMethod(const String& name, JSFunction *f)
|
||||||
|
{
|
||||||
|
uint32 slot;
|
||||||
|
if (hasMethod(name, slot))
|
||||||
|
mMethods[slot] = MethodEntry(name, f);
|
||||||
|
else
|
||||||
|
mMethods.push_back(MethodEntry(name, f));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasMethod(const String& name, uint32& index)
|
||||||
|
{
|
||||||
|
JSMethods::iterator end = mMethods.end();
|
||||||
|
for (JSMethods::iterator i = mMethods.begin(); i != end; i++) {
|
||||||
|
if (i->first == name) {
|
||||||
|
index = i - mMethods.begin();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSFunction* getMethod(uint32 index)
|
||||||
|
{
|
||||||
|
return mMethods[index].second;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an instance of a JSClass.
|
||||||
|
*/
|
||||||
|
class JSInstance : public JSObject {
|
||||||
|
protected:
|
||||||
|
JSValue mSlots[1];
|
||||||
|
public:
|
||||||
|
void* operator new(size_t n, JSClass* thisClass)
|
||||||
|
{
|
||||||
|
uint32 slotCount = thisClass->getSlotCount();
|
||||||
|
if (slotCount > 0) n += sizeof(JSValue) * (slotCount - 1);
|
||||||
|
return gc_base::operator new(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(XP_MAC)
|
||||||
|
void operator delete(void* /*ptr*/, JSClass* /*thisClass*/) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JSInstance(JSClass* thisClass)
|
||||||
|
{
|
||||||
|
mType = thisClass;
|
||||||
|
// initialize extra slots with undefined.
|
||||||
|
uint32 slotCount = thisClass->getSlotCount();
|
||||||
|
if (slotCount > 0) {
|
||||||
|
std::uninitialized_fill(&mSlots[1], &mSlots[1] + (slotCount - 1),
|
||||||
|
JSTypes::kUndefinedValue);
|
||||||
|
}
|
||||||
|
// for grins, use the prototype link to access methods.
|
||||||
|
setPrototype(thisClass->getScope());
|
||||||
|
}
|
||||||
|
|
||||||
|
JSFunction* getMethod(uint32 index)
|
||||||
|
{
|
||||||
|
return getClass()->getMethod(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSClass* getClass()
|
||||||
|
{
|
||||||
|
return static_cast<JSClass*>(mType);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue& operator[] (uint32 index)
|
||||||
|
{
|
||||||
|
return mSlots[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void printProperties(Formatter& f)
|
||||||
|
{
|
||||||
|
f << "Properties:\n";
|
||||||
|
JSObject::printProperties(f);
|
||||||
|
f << "Slots:\n";
|
||||||
|
printSlots(f, getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void printSlots(Formatter& f, JSClass* thisClass)
|
||||||
|
{
|
||||||
|
JSClass* superClass = thisClass->getSuperClass();
|
||||||
|
if (superClass) printSlots(f, superClass);
|
||||||
|
JSSlots& slots = thisClass->getSlots();
|
||||||
|
for (JSSlots::iterator i = slots.begin(), end = slots.end(); i != end; ++i) {
|
||||||
|
f << i->first << " : " << mSlots[i->second.mIndex] << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace JSClasses */
|
||||||
|
} /* namespace JavaScript */
|
||||||
|
|
||||||
|
#endif /* jsclasses_h */
|
||||||
208
mozilla/js/js2/jsmath.cpp
Normal file
208
mozilla/js/js2/jsmath.cpp
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
/* -*- 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 <math.h>
|
||||||
|
#include "jsmath.h"
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
namespace JSMathClass {
|
||||||
|
|
||||||
|
using namespace JSTypes;
|
||||||
|
|
||||||
|
#ifndef M_E
|
||||||
|
#define M_E 2.7182818284590452354
|
||||||
|
#endif
|
||||||
|
#ifndef M_LOG2E
|
||||||
|
#define M_LOG2E 1.4426950408889634074
|
||||||
|
#endif
|
||||||
|
#ifndef M_LOG10E
|
||||||
|
#define M_LOG10E 0.43429448190325182765
|
||||||
|
#endif
|
||||||
|
#ifndef M_LN2
|
||||||
|
#define M_LN2 0.69314718055994530942
|
||||||
|
#endif
|
||||||
|
#ifndef M_LN10
|
||||||
|
#define M_LN10 2.30258509299404568402
|
||||||
|
#endif
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI 3.14159265358979323846
|
||||||
|
#endif
|
||||||
|
#ifndef M_SQRT2
|
||||||
|
#define M_SQRT2 1.41421356237309504880
|
||||||
|
#endif
|
||||||
|
#ifndef M_SQRT1_2
|
||||||
|
#define M_SQRT1_2 0.70710678118654752440
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
JSValue math_abs(Context *cx, const JSValues& argv)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue math_acos(Context *cx, const JSValues& argv)
|
||||||
|
{
|
||||||
|
if (argv.size() > 0) {
|
||||||
|
JSValue num = argv[1].toNumber();
|
||||||
|
return JSValue(fd_acos(num.f64));
|
||||||
|
}
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue math_asin(Context *cx, const JSValues& argv)
|
||||||
|
{
|
||||||
|
if (argv.size() > 0) {
|
||||||
|
JSValue num = argv[1].toNumber();
|
||||||
|
return JSValue(fd_asin(num.f64));
|
||||||
|
}
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue math_atan(Context *cx, const JSValues& argv)
|
||||||
|
{
|
||||||
|
if (argv.size() > 0) {
|
||||||
|
JSValue num = argv[1].toNumber();
|
||||||
|
return JSValue(fd_atan(num.f64));
|
||||||
|
}
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue math_atan2(Context *cx, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue math_ceil(Context *cx, const JSValues& argv)
|
||||||
|
{
|
||||||
|
if (argv.size() > 0) {
|
||||||
|
JSValue num = argv[1].toNumber();
|
||||||
|
return JSValue(fd_ceil(num.f64));
|
||||||
|
}
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MathFunctionEntry {
|
||||||
|
char *name;
|
||||||
|
JSNativeFunction::JSCode fn;
|
||||||
|
} MathFunctions[] = {
|
||||||
|
{ "abs", math_abs },
|
||||||
|
{ "acos", math_acos },
|
||||||
|
{ "asin", math_asin },
|
||||||
|
{ "atan", math_atan },
|
||||||
|
{ "atan2", math_atan2 },
|
||||||
|
{ "ceil", math_acos },
|
||||||
|
{ "acos", math_acos },
|
||||||
|
{ "acos", math_acos }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MathConstantEntry {
|
||||||
|
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 }
|
||||||
|
};
|
||||||
|
|
||||||
|
// There is no constructor for Math, we simply initialize
|
||||||
|
// the properties of the Math object
|
||||||
|
void JSMath::initMathObject(JSScope *g)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
JSMath *m = new JSMath();
|
||||||
|
m->setClass(new JSString("Math"));
|
||||||
|
|
||||||
|
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 */
|
||||||
58
mozilla/js/js2/jsmath.h
Normal file
58
mozilla/js/js2/jsmath.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/* -*- 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 jsmath_h
|
||||||
|
#define jsmath_h
|
||||||
|
|
||||||
|
#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 */
|
||||||
|
|
||||||
|
|
||||||
|
#endif jsmath_h
|
||||||
775
mozilla/js/js2/jstypes.cpp
Normal file
775
mozilla/js/js2/jstypes.cpp
Normal file
@@ -0,0 +1,775 @@
|
|||||||
|
/* -*- 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 "jstypes.h"
|
||||||
|
#include "jsclasses.h"
|
||||||
|
#include "numerics.h"
|
||||||
|
#include "icodegenerator.h"
|
||||||
|
#include "interpreter.h"
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
namespace JSTypes {
|
||||||
|
|
||||||
|
using namespace JSClasses;
|
||||||
|
using namespace Interpreter;
|
||||||
|
|
||||||
|
/********** Object Object Stuff **************************/
|
||||||
|
|
||||||
|
JSValue object_toString(Context *cx, const JSValues& argv)
|
||||||
|
{
|
||||||
|
if (argv.size() > 0) {
|
||||||
|
JSString *s = new JSString("[object ");
|
||||||
|
JSValue theThis = argv[0];
|
||||||
|
ASSERT(theThis.isObject());
|
||||||
|
s->append(theThis.object->getClass());
|
||||||
|
s->append("]");
|
||||||
|
return JSValue(s);
|
||||||
|
}
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue objectConstructor(Context *cx, const JSValues& argv)
|
||||||
|
{
|
||||||
|
ASSERT(argv.size() > 0);
|
||||||
|
JSValue theThis = argv[0];
|
||||||
|
|
||||||
|
// the prototype and class have been established already
|
||||||
|
|
||||||
|
return theThis;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ObjectFunctionEntry {
|
||||||
|
char *name;
|
||||||
|
JSNativeFunction::JSCode fn;
|
||||||
|
} ObjectFunctions[] = {
|
||||||
|
{ "toString", object_toString },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
JSObject *JSObject::objectPrototypeObject = JSObject::initJSObject();
|
||||||
|
String JSObject::ObjectString = widenCString("Object");
|
||||||
|
|
||||||
|
// This establishes the ur-prototype, there's a timing issue
|
||||||
|
// here - the JSObject static initializers have to run before
|
||||||
|
// any other JSObject objects are constructed.
|
||||||
|
JSObject *JSObject::initJSObject()
|
||||||
|
{
|
||||||
|
JSObject *result = new JSObject();
|
||||||
|
|
||||||
|
for (int i = 0; i < sizeof(ObjectFunctions) / sizeof(ObjectFunctionEntry); i++)
|
||||||
|
result->setProperty(widenCString(ObjectFunctions[i].name), JSValue(new JSNativeFunction(ObjectFunctions[i].fn) ) );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install the 'Object' constructor into the scope, mostly irrelevant since making
|
||||||
|
// a new JSObject does all the work of setting the prototype and [[class]] values.
|
||||||
|
void JSObject::initObjectObject(JSScope *g)
|
||||||
|
{
|
||||||
|
JSNativeFunction *objCon = new JSNativeFunction(objectConstructor);
|
||||||
|
|
||||||
|
objCon->setProperty(widenCString("prototype"), JSValue(objectPrototypeObject));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
g->setProperty(ObjectString, JSValue(objCon));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/********** Function Object Stuff **************************/
|
||||||
|
|
||||||
|
// An empty function that returns undefined
|
||||||
|
JSValue functionPrototypeFunction(Context *cx, const JSValues& argv)
|
||||||
|
{
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JSValue function_constructor(Context *cx, const JSValues& argv)
|
||||||
|
{
|
||||||
|
// build a function from the arguments into the this.
|
||||||
|
ASSERT(argv.size() > 0);
|
||||||
|
JSValue theThis = argv[0];
|
||||||
|
ASSERT(theThis.isObject());
|
||||||
|
|
||||||
|
if (argv.size() == 2) {
|
||||||
|
JSValue s = JSValue::valueToString(argv[1]);
|
||||||
|
theThis = new JSFunction(cx->compile((String)(*s.string)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return theThis;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue function_toString(Context *cx, const JSValues& argv)
|
||||||
|
{
|
||||||
|
return JSValue(new JSString("function XXX() { }" ));
|
||||||
|
}
|
||||||
|
JSValue function_apply(Context *cx, const JSValues& argv)
|
||||||
|
{
|
||||||
|
// XXX
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
JSValue function_call(Context *cx, const JSValues& argv)
|
||||||
|
{
|
||||||
|
// XXX
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
String JSFunction::FunctionString = widenCString("Function");
|
||||||
|
JSObject *JSFunction::functionPrototypeObject = NULL; // the 'original Function prototype object'
|
||||||
|
|
||||||
|
struct FunctionFunctionEntry {
|
||||||
|
char *name;
|
||||||
|
JSNativeFunction::JSCode fn;
|
||||||
|
} FunctionFunctions[] = {
|
||||||
|
{ "constructor", function_constructor },
|
||||||
|
{ "toString", function_toString },
|
||||||
|
{ "apply", function_apply },
|
||||||
|
{ "call", function_call },
|
||||||
|
};
|
||||||
|
|
||||||
|
void JSFunction::initFunctionObject(JSScope *g)
|
||||||
|
{
|
||||||
|
// first build the Function Prototype Object
|
||||||
|
functionPrototypeObject = new JSNativeFunction(functionPrototypeFunction);
|
||||||
|
for (int i = 0; i < sizeof(FunctionFunctions) / sizeof(FunctionFunctionEntry); i++)
|
||||||
|
functionPrototypeObject->setProperty(widenCString(FunctionFunctions[i].name), JSValue(new JSNativeFunction(FunctionFunctions[i].fn) ) );
|
||||||
|
|
||||||
|
// now the Function Constructor Object
|
||||||
|
JSNativeFunction *functionConstructorObject = new JSNativeFunction(function_constructor);
|
||||||
|
functionConstructorObject->setPrototype(functionPrototypeObject);
|
||||||
|
functionConstructorObject->setProperty(widenCString("length"), JSValue((int32)1));
|
||||||
|
functionConstructorObject->setProperty(widenCString("prototype"), JSValue(functionPrototypeObject));
|
||||||
|
|
||||||
|
// This is interesting - had to use defineVariable here to specify a type because
|
||||||
|
// when left as Any_Type (via setProperty), the Function predefined type interacted
|
||||||
|
// badly with this value. (I think setProperty perhaps should have reset the entry
|
||||||
|
// in mTypes) (?)
|
||||||
|
g->defineVariable(FunctionString, &Function_Type, JSValue(functionConstructorObject));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************************/
|
||||||
|
|
||||||
|
JSType Any_Type = JSType(widenCString("any"), NULL);
|
||||||
|
JSType Integer_Type = JSType(widenCString("Integer"), &Any_Type);
|
||||||
|
JSType Number_Type = JSType(widenCString("Number"), &Integer_Type);
|
||||||
|
JSType Character_Type = JSType(widenCString("Character"), &Any_Type);
|
||||||
|
JSType String_Type = JSType(widenCString("String"), &Character_Type);
|
||||||
|
JSType Function_Type = JSType(widenCString("Function"), &Any_Type);
|
||||||
|
JSType Array_Type = JSType(widenCString("Array"), &Any_Type);
|
||||||
|
JSType Type_Type = JSType(widenCString("Type"), &Any_Type);
|
||||||
|
JSType Boolean_Type = JSType(widenCString("Boolean"), &Any_Type);
|
||||||
|
JSType Null_Type = JSType(widenCString("Null"), &Any_Type);
|
||||||
|
JSType Void_Type = JSType(widenCString("void"), &Any_Type);
|
||||||
|
JSType None_Type = JSType(widenCString("none"), &Any_Type);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef IS_LITTLE_ENDIAN
|
||||||
|
#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[1])
|
||||||
|
#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[0])
|
||||||
|
#else
|
||||||
|
#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[0])
|
||||||
|
#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[1])
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define JSDOUBLE_HI32_SIGNBIT 0x80000000
|
||||||
|
#define JSDOUBLE_HI32_EXPMASK 0x7ff00000
|
||||||
|
#define JSDOUBLE_HI32_MANTMASK 0x000fffff
|
||||||
|
|
||||||
|
#define JSDOUBLE_IS_NaN(x) \
|
||||||
|
((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) == JSDOUBLE_HI32_EXPMASK && \
|
||||||
|
(JSDOUBLE_LO32(x) || (JSDOUBLE_HI32(x) & JSDOUBLE_HI32_MANTMASK)))
|
||||||
|
|
||||||
|
#define JSDOUBLE_IS_INFINITE(x) \
|
||||||
|
((JSDOUBLE_HI32(x) & ~JSDOUBLE_HI32_SIGNBIT) == JSDOUBLE_HI32_EXPMASK && \
|
||||||
|
!JSDOUBLE_LO32(x))
|
||||||
|
|
||||||
|
#define JSDOUBLE_IS_FINITE(x) \
|
||||||
|
((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) != JSDOUBLE_HI32_EXPMASK)
|
||||||
|
|
||||||
|
#define JSDOUBLE_IS_NEGZERO(d) (JSDOUBLE_HI32(d) == JSDOUBLE_HI32_SIGNBIT && \
|
||||||
|
JSDOUBLE_LO32(d) == 0)
|
||||||
|
|
||||||
|
|
||||||
|
// the canonical undefined value, etc.
|
||||||
|
const JSValue kUndefinedValue;
|
||||||
|
const JSValue kNaNValue = JSValue(nan);
|
||||||
|
const JSValue kTrueValue = JSValue(true);
|
||||||
|
const JSValue kFalseValue = JSValue(false);
|
||||||
|
const JSValue kNullValue = JSValue((JSObject*)NULL);
|
||||||
|
const JSValue kNegativeZero = JSValue(-0.0);
|
||||||
|
const JSValue kPositiveZero = JSValue(0.0);
|
||||||
|
const JSValue kNegativeInfinity = JSValue(negativeInfinity);
|
||||||
|
const JSValue kPositiveInfinity = JSValue(positiveInfinity);
|
||||||
|
|
||||||
|
|
||||||
|
const JSType *JSValue::getType() const
|
||||||
|
{
|
||||||
|
switch (tag) {
|
||||||
|
case JSValue::i32_tag:
|
||||||
|
return &Integer_Type;
|
||||||
|
case JSValue::u32_tag:
|
||||||
|
return &Integer_Type;
|
||||||
|
case JSValue::integer_tag:
|
||||||
|
return &Integer_Type;
|
||||||
|
case JSValue::f64_tag:
|
||||||
|
return &Number_Type;
|
||||||
|
case JSValue::object_tag:
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// XXX why isn't there a class for Object? XXX
|
||||||
|
//
|
||||||
|
JSClass *clazz = dynamic_cast<JSClass *>(object->getType());
|
||||||
|
if (clazz)
|
||||||
|
return clazz;
|
||||||
|
else
|
||||||
|
return &Any_Type;
|
||||||
|
}
|
||||||
|
case JSValue::array_tag:
|
||||||
|
return &Array_Type;
|
||||||
|
case JSValue::function_tag:
|
||||||
|
return &Function_Type;
|
||||||
|
case JSValue::string_tag:
|
||||||
|
return &String_Type;
|
||||||
|
case JSValue::boolean_tag:
|
||||||
|
return &Boolean_Type;
|
||||||
|
case JSValue::undefined_tag:
|
||||||
|
return &Void_Type;
|
||||||
|
case JSValue::type_tag:
|
||||||
|
return &Type_Type;
|
||||||
|
default:
|
||||||
|
NOT_REACHED("Bad tag");
|
||||||
|
return &None_Type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JSValue::isNaN() const
|
||||||
|
{
|
||||||
|
ASSERT(isNumber());
|
||||||
|
switch (tag) {
|
||||||
|
case i32_tag:
|
||||||
|
case u32_tag:
|
||||||
|
return false;
|
||||||
|
case integer_tag:
|
||||||
|
case f64_tag:
|
||||||
|
return JSDOUBLE_IS_NaN(f64);
|
||||||
|
default:
|
||||||
|
NOT_REACHED("Broken compiler?");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JSValue::isNegativeInfinity() const
|
||||||
|
{
|
||||||
|
ASSERT(isNumber());
|
||||||
|
switch (tag) {
|
||||||
|
case i32_tag:
|
||||||
|
case u32_tag:
|
||||||
|
return false;
|
||||||
|
case integer_tag:
|
||||||
|
case f64_tag:
|
||||||
|
return (f64 < 0) && JSDOUBLE_IS_INFINITE(f64);
|
||||||
|
default:
|
||||||
|
NOT_REACHED("Broken compiler?");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JSValue::isPositiveInfinity() const
|
||||||
|
{
|
||||||
|
ASSERT(isNumber());
|
||||||
|
switch (tag) {
|
||||||
|
case i32_tag:
|
||||||
|
case u32_tag:
|
||||||
|
return false;
|
||||||
|
case integer_tag:
|
||||||
|
case f64_tag:
|
||||||
|
return (f64 > 0) && JSDOUBLE_IS_INFINITE(f64);
|
||||||
|
default:
|
||||||
|
NOT_REACHED("Broken compiler?");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JSValue::isNegativeZero() const
|
||||||
|
{
|
||||||
|
ASSERT(isNumber());
|
||||||
|
switch (tag) {
|
||||||
|
case i32_tag:
|
||||||
|
case u32_tag:
|
||||||
|
return false;
|
||||||
|
case integer_tag:
|
||||||
|
case f64_tag:
|
||||||
|
return JSDOUBLE_IS_NEGZERO(f64);
|
||||||
|
default:
|
||||||
|
NOT_REACHED("Broken compiler?");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JSValue::isPositiveZero() const
|
||||||
|
{
|
||||||
|
ASSERT(isNumber());
|
||||||
|
switch (tag) {
|
||||||
|
case i32_tag:
|
||||||
|
return (i32 == 0);
|
||||||
|
case u32_tag:
|
||||||
|
return (u32 == 0);
|
||||||
|
case integer_tag:
|
||||||
|
case f64_tag:
|
||||||
|
return (f64 == 0.0) && !JSDOUBLE_IS_NEGZERO(f64);
|
||||||
|
default:
|
||||||
|
NOT_REACHED("Broken compiler?");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int JSValue::operator==(const JSValue& value) const
|
||||||
|
{
|
||||||
|
if (this->tag == value.tag) {
|
||||||
|
#define CASE(T) case T##_tag: return (this->T == value.T)
|
||||||
|
switch (tag) {
|
||||||
|
CASE(i8); CASE(u8);
|
||||||
|
CASE(i16); CASE(u16);
|
||||||
|
CASE(i32); CASE(u32); CASE(f32);
|
||||||
|
CASE(i64); CASE(u64); CASE(f64);
|
||||||
|
CASE(object); CASE(array); CASE(function); CASE(string);
|
||||||
|
CASE(type); CASE(boolean);
|
||||||
|
#undef CASE
|
||||||
|
case integer_tag : return (this->f64 == value.f64);
|
||||||
|
// question: are all undefined values equal to one another?
|
||||||
|
case undefined_tag: return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Formatter& operator<<(Formatter& f, JSObject& obj)
|
||||||
|
{
|
||||||
|
obj.printProperties(f);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSObject::printProperties(Formatter& f)
|
||||||
|
{
|
||||||
|
for (JSProperties::const_iterator i = mProperties.begin(); i != mProperties.end(); i++) {
|
||||||
|
f << (*i).first << " : " << (*i).second;
|
||||||
|
f << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Formatter& operator<<(Formatter& f, const JSValue& value)
|
||||||
|
{
|
||||||
|
switch (value.tag) {
|
||||||
|
case JSValue::i32_tag:
|
||||||
|
f << float64(value.i32);
|
||||||
|
break;
|
||||||
|
case JSValue::u32_tag:
|
||||||
|
f << float64(value.u32);
|
||||||
|
break;
|
||||||
|
case JSValue::integer_tag:
|
||||||
|
case JSValue::f64_tag:
|
||||||
|
f << value.f64;
|
||||||
|
break;
|
||||||
|
case JSValue::object_tag:
|
||||||
|
printFormat(f, "Object @ 0x%08X\n", value.object);
|
||||||
|
f << *value.object;
|
||||||
|
break;
|
||||||
|
case JSValue::array_tag:
|
||||||
|
printFormat(f, "Array @ 0x%08X", value.object);
|
||||||
|
break;
|
||||||
|
case JSValue::function_tag:
|
||||||
|
printFormat(f, "Function @ 0x%08X", value.object);
|
||||||
|
break;
|
||||||
|
case JSValue::string_tag:
|
||||||
|
f << *value.string;
|
||||||
|
break;
|
||||||
|
case JSValue::boolean_tag:
|
||||||
|
f << ((value.boolean) ? "true" : "false");
|
||||||
|
break;
|
||||||
|
case JSValue::undefined_tag:
|
||||||
|
f << "undefined";
|
||||||
|
break;
|
||||||
|
case JSValue::type_tag:
|
||||||
|
printFormat(f, "Type @ 0x%08X\n", value.type);
|
||||||
|
f << *value.type;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NOT_REACHED("Bad tag");
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue JSValue::toPrimitive(ECMA_type /*hint*/) const
|
||||||
|
{
|
||||||
|
JSObject *obj;
|
||||||
|
switch (tag) {
|
||||||
|
case i32_tag:
|
||||||
|
case u32_tag:
|
||||||
|
case integer_tag:
|
||||||
|
case f64_tag:
|
||||||
|
case string_tag:
|
||||||
|
case boolean_tag:
|
||||||
|
case undefined_tag:
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
case object_tag:
|
||||||
|
obj = object;
|
||||||
|
break;
|
||||||
|
case array_tag:
|
||||||
|
obj = array;
|
||||||
|
break;
|
||||||
|
case function_tag:
|
||||||
|
obj = function;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
NOT_REACHED("Bad tag");
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSValue &toString = obj->getProperty(widenCString("toString"));
|
||||||
|
if (toString.isObject()) {
|
||||||
|
if (toString.isFunction()) {
|
||||||
|
}
|
||||||
|
else // right? The spec doesn't say
|
||||||
|
throw new JSException("Runtime error from toPrimitive"); // XXX
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSValue &valueOf = obj->getProperty(widenCString("valueOf"));
|
||||||
|
if (!valueOf.isObject())
|
||||||
|
throw new JSException("Runtime error from toPrimitive"); // XXX
|
||||||
|
|
||||||
|
return kUndefinedValue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JSValue JSValue::valueToString(const JSValue& value) // can assume value is not a string
|
||||||
|
{
|
||||||
|
const char* chrp;
|
||||||
|
char buf[dtosStandardBufferSize];
|
||||||
|
switch (value.tag) {
|
||||||
|
case i32_tag:
|
||||||
|
chrp = doubleToStr(buf, dtosStandardBufferSize, value.i32, dtosStandard, 0);
|
||||||
|
break;
|
||||||
|
case u32_tag:
|
||||||
|
chrp = doubleToStr(buf, dtosStandardBufferSize, value.u32, dtosStandard, 0);
|
||||||
|
break;
|
||||||
|
case integer_tag:
|
||||||
|
case f64_tag:
|
||||||
|
chrp = doubleToStr(buf, dtosStandardBufferSize, value.f64, dtosStandard, 0);
|
||||||
|
break;
|
||||||
|
case object_tag:
|
||||||
|
chrp = "object";
|
||||||
|
break;
|
||||||
|
case array_tag:
|
||||||
|
chrp = "array";
|
||||||
|
break;
|
||||||
|
case function_tag:
|
||||||
|
chrp = "function";
|
||||||
|
break;
|
||||||
|
case string_tag:
|
||||||
|
return value;
|
||||||
|
case boolean_tag:
|
||||||
|
chrp = (value.boolean) ? "true" : "false";
|
||||||
|
break;
|
||||||
|
case undefined_tag:
|
||||||
|
chrp = "undefined";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NOT_REACHED("Bad tag");
|
||||||
|
}
|
||||||
|
return JSValue(new JSString(chrp));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue JSValue::valueToNumber(const JSValue& value) // can assume value is not a number
|
||||||
|
{
|
||||||
|
switch (value.tag) {
|
||||||
|
case i32_tag:
|
||||||
|
return JSValue((float64)value.i32);
|
||||||
|
case u32_tag:
|
||||||
|
return JSValue((float64)value.u32);
|
||||||
|
case integer_tag:
|
||||||
|
case f64_tag:
|
||||||
|
return value;
|
||||||
|
case string_tag:
|
||||||
|
{
|
||||||
|
JSString* str = value.string;
|
||||||
|
const char16 *numEnd;
|
||||||
|
double d = stringToDouble(str->begin(), str->end(), numEnd);
|
||||||
|
return JSValue(d);
|
||||||
|
}
|
||||||
|
case object_tag:
|
||||||
|
case array_tag:
|
||||||
|
case function_tag:
|
||||||
|
// XXX more needed :
|
||||||
|
// toNumber(toPrimitive(hint Number))
|
||||||
|
return kUndefinedValue;
|
||||||
|
case boolean_tag:
|
||||||
|
return JSValue((value.boolean) ? 1.0 : 0.0);
|
||||||
|
case undefined_tag:
|
||||||
|
return kNaNValue;
|
||||||
|
default:
|
||||||
|
NOT_REACHED("Bad tag");
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue JSValue::valueToInteger(const JSValue& value)
|
||||||
|
{
|
||||||
|
JSValue result = valueToNumber(value);
|
||||||
|
ASSERT(result.tag == f64_tag);
|
||||||
|
result.tag = i64_tag;
|
||||||
|
bool neg = (result.f64 < 0);
|
||||||
|
result.f64 = floor((neg) ? -result.f64 : result.f64);
|
||||||
|
result.f64 = (neg) ? -result.f64 : result.f64;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JSValue JSValue::valueToBoolean(const JSValue& value)
|
||||||
|
{
|
||||||
|
switch (value.tag) {
|
||||||
|
case i32_tag:
|
||||||
|
return JSValue(value.i32 != 0);
|
||||||
|
case u32_tag:
|
||||||
|
return JSValue(value.u32 != 0);
|
||||||
|
case integer_tag:
|
||||||
|
case f64_tag:
|
||||||
|
return JSValue(!(value.f64 == 0.0) || JSDOUBLE_IS_NaN(value.f64));
|
||||||
|
case string_tag:
|
||||||
|
return JSValue(value.string->length() != 0);
|
||||||
|
case boolean_tag:
|
||||||
|
return value;
|
||||||
|
case object_tag:
|
||||||
|
case array_tag:
|
||||||
|
case function_tag:
|
||||||
|
return kTrueValue;
|
||||||
|
case undefined_tag:
|
||||||
|
return kFalseValue;
|
||||||
|
default:
|
||||||
|
NOT_REACHED("Bad tag");
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const double two32 = 4294967296.0;
|
||||||
|
static const double two31 = 2147483648.0;
|
||||||
|
|
||||||
|
JSValue JSValue::valueToInt32(const JSValue& value)
|
||||||
|
{
|
||||||
|
double d;
|
||||||
|
switch (value.tag) {
|
||||||
|
case i32_tag:
|
||||||
|
return value;
|
||||||
|
case u32_tag:
|
||||||
|
d = value.u32;
|
||||||
|
break;
|
||||||
|
case integer_tag:
|
||||||
|
case f64_tag:
|
||||||
|
d = value.f64;
|
||||||
|
break;
|
||||||
|
case string_tag:
|
||||||
|
{
|
||||||
|
JSString* str = value.string;
|
||||||
|
const char16 *numEnd;
|
||||||
|
d = stringToDouble(str->begin(), str->end(), numEnd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case boolean_tag:
|
||||||
|
return JSValue((int32)((value.boolean) ? 1 : 0));
|
||||||
|
case object_tag:
|
||||||
|
case array_tag:
|
||||||
|
case undefined_tag:
|
||||||
|
// toNumber(toPrimitive(hint Number))
|
||||||
|
return kUndefinedValue;
|
||||||
|
default:
|
||||||
|
NOT_REACHED("Bad tag");
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
if ((d == 0.0) || !JSDOUBLE_IS_FINITE(d) )
|
||||||
|
return JSValue((int32)0);
|
||||||
|
d = fmod(d, two32);
|
||||||
|
d = (d >= 0) ? d : d + two32;
|
||||||
|
if (d >= two31)
|
||||||
|
return JSValue((int32)(d - two32));
|
||||||
|
else
|
||||||
|
return JSValue((int32)d);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue JSValue::valueToUInt32(const JSValue& value)
|
||||||
|
{
|
||||||
|
double d;
|
||||||
|
switch (value.tag) {
|
||||||
|
case i32_tag:
|
||||||
|
return JSValue((uint32)value.i32);
|
||||||
|
case u32_tag:
|
||||||
|
return value;
|
||||||
|
case f64_tag:
|
||||||
|
d = value.f64;
|
||||||
|
break;
|
||||||
|
case string_tag:
|
||||||
|
{
|
||||||
|
JSString* str = value.string;
|
||||||
|
const char16 *numEnd;
|
||||||
|
d = stringToDouble(str->begin(), str->end(), numEnd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case boolean_tag:
|
||||||
|
return JSValue((uint32)((value.boolean) ? 1 : 0));
|
||||||
|
case object_tag:
|
||||||
|
case array_tag:
|
||||||
|
case undefined_tag:
|
||||||
|
// toNumber(toPrimitive(hint Number))
|
||||||
|
return kUndefinedValue;
|
||||||
|
default:
|
||||||
|
NOT_REACHED("Bad tag");
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
if ((d == 0.0) || !JSDOUBLE_IS_FINITE(d))
|
||||||
|
return JSValue((uint32)0);
|
||||||
|
bool neg = (d < 0);
|
||||||
|
d = floor(neg ? -d : d);
|
||||||
|
d = neg ? -d : d;
|
||||||
|
d = fmod(d, two32);
|
||||||
|
d = (d >= 0) ? d : d + two32;
|
||||||
|
return JSValue((uint32)d);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JSValue JSValue::convert(JSType *toType)
|
||||||
|
{
|
||||||
|
if (toType == &Any_Type) // yuck, something wrong with this
|
||||||
|
// maybe the base types should be
|
||||||
|
// a family of classes, not just instances
|
||||||
|
// of JSType ???
|
||||||
|
return *this;
|
||||||
|
else if (toType == &Integer_Type)
|
||||||
|
return valueToInteger(*this);
|
||||||
|
else {
|
||||||
|
JSClass *toClass = dynamic_cast<JSClass *>(toType);
|
||||||
|
if (toClass) {
|
||||||
|
if (tag == object_tag) {
|
||||||
|
JSClass *fromClass = dynamic_cast<JSClass *>(object->getType());
|
||||||
|
if (fromClass) {
|
||||||
|
while (fromClass != toClass) {
|
||||||
|
fromClass = fromClass->getSuperClass();
|
||||||
|
if (fromClass == NULL)
|
||||||
|
throw new JSException("Can't cast to unrelated class");
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new JSException("Can't cast a generic object to a class");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new JSException("Can't cast a non-object to a class");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JSFunction::~JSFunction()
|
||||||
|
{
|
||||||
|
delete mICode;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSString::JSString(const String& str)
|
||||||
|
{
|
||||||
|
size_t n = str.size();
|
||||||
|
resize(n);
|
||||||
|
traits_type::copy(begin(), str.begin(), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSString::JSString(const String* str)
|
||||||
|
{
|
||||||
|
size_t n = str->size();
|
||||||
|
resize(n);
|
||||||
|
traits_type::copy(begin(), str->begin(), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSString::JSString(const char* str)
|
||||||
|
{
|
||||||
|
size_t n = ::strlen(str);
|
||||||
|
resize(n);
|
||||||
|
std::transform(str, str + n, begin(), JavaScript::widen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSString::append(const char* str)
|
||||||
|
{
|
||||||
|
size_t n = ::strlen(str);
|
||||||
|
size_t oldSize = size();
|
||||||
|
resize(oldSize + n);
|
||||||
|
std::transform(str, str + n, begin() + oldSize, JavaScript::widen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSString::append(const JSStringBase* str)
|
||||||
|
{
|
||||||
|
size_t n = str->size();
|
||||||
|
size_t oldSize = size();
|
||||||
|
resize(oldSize + n);
|
||||||
|
traits_type::copy(begin() + oldSize, str->begin(), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSString::operator String()
|
||||||
|
{
|
||||||
|
return String(begin(), size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// # of sub-type relationship between this type and the other type
|
||||||
|
// (== MAX_INT if other is not a base type)
|
||||||
|
|
||||||
|
int32 JSType::distance(const JSType *other) const
|
||||||
|
{
|
||||||
|
if (other == this)
|
||||||
|
return 0;
|
||||||
|
if (mBaseType == NULL)
|
||||||
|
return NoRelation;
|
||||||
|
int32 baseDistance = mBaseType->distance(other);
|
||||||
|
if (baseDistance != NoRelation)
|
||||||
|
++baseDistance;
|
||||||
|
return baseDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace JSTypes */
|
||||||
|
} /* namespace JavaScript */
|
||||||
579
mozilla/js/js2/jstypes.h
Normal file
579
mozilla/js/js2/jstypes.h
Normal file
@@ -0,0 +1,579 @@
|
|||||||
|
/* -*- 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 jstypes_h
|
||||||
|
#define jstypes_h
|
||||||
|
|
||||||
|
#include "utilities.h"
|
||||||
|
#include "gc_allocator.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
|
|
||||||
|
/* forward declare classes from JavaScript::ICG */
|
||||||
|
namespace JavaScript {
|
||||||
|
namespace ICG {
|
||||||
|
class ICodeModule;
|
||||||
|
} /* namespace ICG */
|
||||||
|
namespace Interpreter {
|
||||||
|
class Context;
|
||||||
|
} /* namespace Interpreter */
|
||||||
|
} /* namespace JavaScript */
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
namespace JSTypes {
|
||||||
|
|
||||||
|
using ICG::ICodeModule;
|
||||||
|
using Interpreter::Context;
|
||||||
|
|
||||||
|
class JSObject;
|
||||||
|
class JSArray;
|
||||||
|
class JSFunction;
|
||||||
|
class JSScope;
|
||||||
|
class JSString;
|
||||||
|
class JSType;
|
||||||
|
class Context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All JavaScript data types.
|
||||||
|
*/
|
||||||
|
struct JSValue {
|
||||||
|
union {
|
||||||
|
int8 i8;
|
||||||
|
uint8 u8;
|
||||||
|
int16 i16;
|
||||||
|
uint16 u16;
|
||||||
|
int32 i32;
|
||||||
|
uint32 u32;
|
||||||
|
int64 i64;
|
||||||
|
uint64 u64;
|
||||||
|
float32 f32;
|
||||||
|
float64 f64;
|
||||||
|
JSObject* object;
|
||||||
|
JSArray* array;
|
||||||
|
JSFunction *function;
|
||||||
|
JSString *string;
|
||||||
|
JSType *type;
|
||||||
|
bool boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* These are the ECMA types, for use in 'toPrimitive' calls */
|
||||||
|
enum ECMA_type {
|
||||||
|
Undefined, Null, Boolean, Number, Object, String,
|
||||||
|
NoHint
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
i8_tag, u8_tag,
|
||||||
|
i16_tag, u16_tag,
|
||||||
|
i32_tag, u32_tag,
|
||||||
|
i64_tag, u64_tag,
|
||||||
|
f32_tag, f64_tag,
|
||||||
|
integer_tag,
|
||||||
|
object_tag, array_tag, function_tag, string_tag, boolean_tag, type_tag,
|
||||||
|
undefined_tag
|
||||||
|
} tag;
|
||||||
|
|
||||||
|
JSValue() : f64(0.0), tag(undefined_tag) {}
|
||||||
|
explicit JSValue(int32 i32) : i32(i32), tag(i32_tag) {}
|
||||||
|
explicit JSValue(uint32 u32) : u32(u32), tag(u32_tag) {}
|
||||||
|
explicit JSValue(float64 f64) : f64(f64), tag(f64_tag) {}
|
||||||
|
explicit JSValue(JSObject* object) : object(object), tag(object_tag) {}
|
||||||
|
explicit JSValue(JSArray* array) : array(array), tag(array_tag) {}
|
||||||
|
explicit JSValue(JSFunction* function) : function(function), tag(function_tag) {}
|
||||||
|
explicit JSValue(JSString* string) : string(string), tag(string_tag) {}
|
||||||
|
explicit JSValue(bool boolean) : boolean(boolean), tag(boolean_tag) {}
|
||||||
|
explicit JSValue(JSType* type) : type(type), tag(type_tag) {}
|
||||||
|
|
||||||
|
int32& operator=(int32 i32) { return (tag = i32_tag, this->i32 = i32); }
|
||||||
|
uint32& operator=(uint32 u32) { return (tag = u32_tag, this->u32 = u32); }
|
||||||
|
float64& operator=(float64 f64) { return (tag = f64_tag, this->f64 = f64); }
|
||||||
|
JSObject*& operator=(JSObject* object) { return (tag = object_tag, this->object = object); }
|
||||||
|
JSArray*& operator=(JSArray* array) { return (tag = array_tag, this->array = array); }
|
||||||
|
JSFunction*& operator=(JSFunction* function) { return (tag = function_tag, this->function = function); }
|
||||||
|
JSString*& operator=(JSString* string) { return (tag = string_tag, this->string = string); }
|
||||||
|
bool& operator=(bool boolean) { return (tag = boolean_tag, this->boolean = boolean); }
|
||||||
|
JSType*& operator=(JSType* type) { return (tag = type_tag, this->type = type); }
|
||||||
|
|
||||||
|
bool isFunction() const { return (tag == function_tag); }
|
||||||
|
bool isObject() const { return ((tag == object_tag) || (tag == function_tag) || (tag == array_tag) || (tag == type_tag)); }
|
||||||
|
bool isString() const { return (tag == string_tag); }
|
||||||
|
bool isBoolean() const { return (tag == boolean_tag); }
|
||||||
|
bool isNumber() const { return (tag == f64_tag) || (tag == integer_tag); }
|
||||||
|
|
||||||
|
/* this is correct wrt ECMA, The i32 & u32 kinds
|
||||||
|
will have to be converted (to doubles?) anyway because
|
||||||
|
we can't have overflow happening in generic arithmetic */
|
||||||
|
|
||||||
|
bool isUndefined() const { return (tag == undefined_tag); }
|
||||||
|
bool isNull() const { return ((tag == object_tag) && (this->object == NULL)); }
|
||||||
|
bool isNaN() const;
|
||||||
|
bool isNegativeInfinity() const;
|
||||||
|
bool isPositiveInfinity() const;
|
||||||
|
bool isNegativeZero() const;
|
||||||
|
bool isPositiveZero() const;
|
||||||
|
bool isType() const { return (tag == type_tag); }
|
||||||
|
|
||||||
|
JSValue toString() const { return (isString() ? *this : valueToString(*this)); }
|
||||||
|
JSValue toNumber() const { return (isNumber() ? *this : valueToNumber(*this)); }
|
||||||
|
JSValue toInt32() const { return ((tag == i32_tag) ? *this : valueToInt32(*this)); }
|
||||||
|
JSValue toUInt32() const { return ((tag == u32_tag) ? *this : valueToUInt32(*this)); }
|
||||||
|
JSValue toBoolean() const { return ((tag == boolean_tag) ? *this : valueToBoolean(*this)); }
|
||||||
|
|
||||||
|
JSValue toPrimitive(ECMA_type hint = NoHint) const;
|
||||||
|
|
||||||
|
JSValue convert(JSType *toType);
|
||||||
|
|
||||||
|
|
||||||
|
static JSValue valueToString(const JSValue& value);
|
||||||
|
static JSValue valueToNumber(const JSValue& value);
|
||||||
|
static JSValue valueToInteger(const JSValue& value);
|
||||||
|
static JSValue valueToInt32(const JSValue& value);
|
||||||
|
static JSValue valueToUInt32(const JSValue& value);
|
||||||
|
static JSValue valueToBoolean(const JSValue& value);
|
||||||
|
|
||||||
|
|
||||||
|
const JSType *getType() const; // map from tag type to JS2 type
|
||||||
|
|
||||||
|
int operator==(const JSValue& value) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
Formatter& operator<<(Formatter& f, const JSValue& value);
|
||||||
|
|
||||||
|
#if defined(XP_MAC)
|
||||||
|
// copied from default template parameters in map.
|
||||||
|
typedef gc_allocator<std::pair<const String, JSValue> > gc_map_allocator;
|
||||||
|
#elif defined(XP_UNIX)
|
||||||
|
// FIXME: in libg++, they assume the map's allocator is a byte allocator,
|
||||||
|
// which is wrapped in a simple_allocator. this is crap.
|
||||||
|
typedef char _Char[1];
|
||||||
|
typedef gc_allocator<_Char> gc_map_allocator;
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
// FIXME: MSVC++'s notion. this is why we had to add _Charalloc().
|
||||||
|
typedef gc_allocator<JSValue> gc_map_allocator;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GC-scannable array of values.
|
||||||
|
*/
|
||||||
|
typedef std::vector<JSValue, gc_allocator<JSValue> > JSValues;
|
||||||
|
|
||||||
|
extern const JSValue kUndefinedValue;
|
||||||
|
extern const JSValue kNaNValue;
|
||||||
|
extern const JSValue kTrueValue;
|
||||||
|
extern const JSValue kFalseValue;
|
||||||
|
extern const JSValue kNullValue;
|
||||||
|
extern const JSValue kNegativeZero;
|
||||||
|
extern const JSValue kPositiveZero;
|
||||||
|
extern const JSValue kNegativeInfinity;
|
||||||
|
extern const JSValue kPositiveInfinity;
|
||||||
|
|
||||||
|
extern JSType Any_Type;
|
||||||
|
extern JSType Integer_Type;
|
||||||
|
extern JSType Number_Type;
|
||||||
|
extern JSType Character_Type;
|
||||||
|
extern JSType String_Type;
|
||||||
|
extern JSType Function_Type;
|
||||||
|
extern JSType Array_Type;
|
||||||
|
extern JSType Type_Type;
|
||||||
|
extern JSType Boolean_Type;
|
||||||
|
extern JSType Null_Type;
|
||||||
|
extern JSType Void_Type;
|
||||||
|
extern JSType None_Type;
|
||||||
|
|
||||||
|
typedef std::map<String, JSValue, std::less<String>, gc_map_allocator> JSProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic behavior of all JS objects, mapping a name to a value,
|
||||||
|
* with prototype-based inheritance.
|
||||||
|
*/
|
||||||
|
class JSObject : public gc_base {
|
||||||
|
protected:
|
||||||
|
JSProperties mProperties;
|
||||||
|
JSObject* mPrototype;
|
||||||
|
JSType* mType;
|
||||||
|
JSString* mClass; // this is the internal [[Class]] property
|
||||||
|
|
||||||
|
static JSObject *initJSObject();
|
||||||
|
static String ObjectString;
|
||||||
|
static JSObject *objectPrototypeObject;
|
||||||
|
|
||||||
|
void init(JSObject* prototype);
|
||||||
|
|
||||||
|
public:
|
||||||
|
JSObject() { init(objectPrototypeObject); }
|
||||||
|
JSObject(JSValue &constructor) { init(constructor.object->getProperty(widenCString("prototype")).object); }
|
||||||
|
JSObject(JSObject *prototype) { init(prototype); }
|
||||||
|
|
||||||
|
static void initObjectObject(JSScope *g);
|
||||||
|
|
||||||
|
bool hasProperty(const String& name)
|
||||||
|
{
|
||||||
|
return (mProperties.count(name) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSValue& getProperty(const String& name)
|
||||||
|
{
|
||||||
|
JSProperties::const_iterator i = mProperties.find(name);
|
||||||
|
if (i != mProperties.end())
|
||||||
|
return i->second;
|
||||||
|
if (mPrototype)
|
||||||
|
return mPrototype->getProperty(name);
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the property AND the object it's found in
|
||||||
|
// (would rather return references, but couldn't get that to work)
|
||||||
|
const JSValue getReference(JSValue &prop, const String& name)
|
||||||
|
{
|
||||||
|
JSProperties::const_iterator i = mProperties.find(name);
|
||||||
|
if (i != mProperties.end()) {
|
||||||
|
prop = i->second;
|
||||||
|
return JSValue(this);
|
||||||
|
}
|
||||||
|
if (mPrototype)
|
||||||
|
return mPrototype->getReference(prop, name);
|
||||||
|
return kUndefinedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue& setProperty(const String& name, const JSValue& value)
|
||||||
|
{
|
||||||
|
return (mProperties[name] = value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSValue& deleteProperty(const String& name)
|
||||||
|
{
|
||||||
|
JSProperties::iterator i = mProperties.find(name);
|
||||||
|
if (i != mProperties.end()) {
|
||||||
|
mProperties.erase(i);
|
||||||
|
return kTrueValue;
|
||||||
|
}
|
||||||
|
if (mPrototype)
|
||||||
|
return mPrototype->deleteProperty(name);
|
||||||
|
return kFalseValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPrototype(JSObject* prototype)
|
||||||
|
{
|
||||||
|
mPrototype = prototype;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSObject* getPrototype()
|
||||||
|
{
|
||||||
|
return mPrototype;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSType* getType()
|
||||||
|
{
|
||||||
|
return mType;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSString* getClass()
|
||||||
|
{
|
||||||
|
return mClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setClass(JSString* s)
|
||||||
|
{
|
||||||
|
mClass = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void printProperties(Formatter& f);
|
||||||
|
};
|
||||||
|
|
||||||
|
Formatter& operator<<(Formatter& f, JSObject& obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private representation of a JavaScript array.
|
||||||
|
*/
|
||||||
|
class JSArray : public JSObject {
|
||||||
|
JSValues elements;
|
||||||
|
public:
|
||||||
|
JSArray() : elements(1) {}
|
||||||
|
JSArray(uint32 size) : elements(size) {}
|
||||||
|
JSArray(const JSValues &v) : elements(v) {}
|
||||||
|
|
||||||
|
uint32 length()
|
||||||
|
{
|
||||||
|
return elements.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue& operator[](const JSValue& index)
|
||||||
|
{
|
||||||
|
// for now, we can only handle f64 index values.
|
||||||
|
uint32 n = (uint32)index.f64;
|
||||||
|
// obviously, a sparse representation might be better.
|
||||||
|
uint32 size = elements.size();
|
||||||
|
if (n >= size) expand(n, size);
|
||||||
|
return elements[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue& operator[](uint32 n)
|
||||||
|
{
|
||||||
|
// obviously, a sparse representation might be better.
|
||||||
|
uint32 size = elements.size();
|
||||||
|
if (n >= size) expand(n, size);
|
||||||
|
return elements[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize(uint32 size)
|
||||||
|
{
|
||||||
|
elements.resize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void expand(uint32 n, uint32 size)
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
size *= 2;
|
||||||
|
} while (n >= size);
|
||||||
|
elements.resize(size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private representation of a JS function. This simply
|
||||||
|
* holds a reference to the iCode module that is the
|
||||||
|
* compiled code of the function.
|
||||||
|
*/
|
||||||
|
class JSFunction : public JSObject {
|
||||||
|
static String FunctionString;
|
||||||
|
static JSObject *functionPrototypeObject;
|
||||||
|
ICodeModule* mICode;
|
||||||
|
protected:
|
||||||
|
JSFunction() : mICode(0) {}
|
||||||
|
|
||||||
|
typedef JavaScript::gc_traits_finalizable<JSFunction> traits;
|
||||||
|
typedef gc_allocator<JSFunction, traits> allocator;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void JSFunction::initFunctionObject(JSScope *g);
|
||||||
|
|
||||||
|
JSFunction(ICodeModule* iCode);
|
||||||
|
~JSFunction();
|
||||||
|
|
||||||
|
void* operator new(size_t) { return allocator::allocate(1); }
|
||||||
|
|
||||||
|
ICodeModule* getICode() { return mICode; }
|
||||||
|
virtual bool isNative() { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class JSNativeFunction : public JSFunction {
|
||||||
|
public:
|
||||||
|
typedef JSValue (*JSCode)(Context *cx, const JSValues& argv);
|
||||||
|
JSCode mCode;
|
||||||
|
JSNativeFunction(JSCode code) : mCode(code) {}
|
||||||
|
virtual bool isNative() { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class JSBinaryOperator : public JSFunction {
|
||||||
|
public:
|
||||||
|
typedef JSValue (*JSBinaryCode)(const JSValue& arg1, const JSValue& arg2);
|
||||||
|
JSBinaryCode mCode;
|
||||||
|
JSBinaryOperator(JSBinaryCode code) : mCode(code) {}
|
||||||
|
virtual bool isNative() { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef STLPORT
|
||||||
|
# if defined(XP_UNIX)
|
||||||
|
// bastring.cc defines a funky operator new that assumes a byte-allocator.
|
||||||
|
typedef string_char_traits<char16> JSCharTraits;
|
||||||
|
typedef gc_allocator<_Char> JSStringAllocator;
|
||||||
|
# else
|
||||||
|
typedef std::char_traits<char16> JSCharTraits;
|
||||||
|
typedef gc_allocator<char16> JSStringAllocator;
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
typedef std::char_traits<char16> JSCharTraits;
|
||||||
|
typedef gc_allocator<char16> JSStringAllocator;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef std::basic_string<char16, JSCharTraits, JSStringAllocator> JSStringBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Garbage collectable UNICODE string.
|
||||||
|
*/
|
||||||
|
class JSString : public JSStringBase, public gc_base {
|
||||||
|
public:
|
||||||
|
JSString() {}
|
||||||
|
explicit JSString(const JSStringBase& str) : JSStringBase(str) {}
|
||||||
|
explicit JSString(const JSStringBase* str) : JSStringBase(*str) {}
|
||||||
|
explicit JSString(const String& str);
|
||||||
|
explicit JSString(const String* str);
|
||||||
|
explicit JSString(const char* str);
|
||||||
|
|
||||||
|
operator String();
|
||||||
|
|
||||||
|
void append(const char* str);
|
||||||
|
void append(const JSStringBase* str);
|
||||||
|
};
|
||||||
|
|
||||||
|
class JSException : public gc_base {
|
||||||
|
public:
|
||||||
|
JSException(char *mess) : value(JSValue(new JSString(mess))) { }
|
||||||
|
JSException(JSValue v) : value(v) { }
|
||||||
|
JSValue value;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline Formatter& operator<<(Formatter& f, const JSString& str)
|
||||||
|
{
|
||||||
|
printString(f, str.begin(), str.end());
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a set of nested scopes.
|
||||||
|
*/
|
||||||
|
class JSScope : public JSObject {
|
||||||
|
protected:
|
||||||
|
JSScope* mParent;
|
||||||
|
JSProperties mTypes;
|
||||||
|
public:
|
||||||
|
JSScope(JSScope* parent = 0, JSObject* prototype = 0)
|
||||||
|
: mParent(parent)
|
||||||
|
{
|
||||||
|
if (prototype)
|
||||||
|
setPrototype(prototype);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSScope* getParent()
|
||||||
|
{
|
||||||
|
return mParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isDefined(const String& name)
|
||||||
|
{
|
||||||
|
if (hasProperty(name))
|
||||||
|
return true;
|
||||||
|
if (mParent)
|
||||||
|
return mParent->isDefined(name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSValue& getVariable(const String& name)
|
||||||
|
{
|
||||||
|
const JSValue& ret = getProperty(name);
|
||||||
|
if (ret.isUndefined() && mParent)
|
||||||
|
return mParent->getVariable(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue& setVariable(const String& name, const JSValue& value)
|
||||||
|
{
|
||||||
|
return (mProperties[name] = value);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue& defineVariable(const String& name, JSType* type, const JSValue& value)
|
||||||
|
{
|
||||||
|
if (type != &Any_Type)
|
||||||
|
mTypes[name] = type;
|
||||||
|
return (mProperties[name] = value);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue& defineVariable(const String& name, JSType* type)
|
||||||
|
{
|
||||||
|
if (type != &Any_Type)
|
||||||
|
mTypes[name] = type;
|
||||||
|
return (mProperties[name] = kUndefinedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setType(const String& name, JSType* type)
|
||||||
|
{
|
||||||
|
// only type variables that are defined in this scope.
|
||||||
|
JSProperties::iterator i = mProperties.find(name);
|
||||||
|
if (i != mProperties.end())
|
||||||
|
mTypes[name] = type;
|
||||||
|
else
|
||||||
|
if (mParent)
|
||||||
|
mParent->setType(name, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSType* getType(const String& name)
|
||||||
|
{
|
||||||
|
JSType* result = &Any_Type;
|
||||||
|
// only consider types for variables defined in this scope.
|
||||||
|
JSProperties::const_iterator i = mProperties.find(name);
|
||||||
|
if (i != mProperties.end()) {
|
||||||
|
i = mTypes.find(name);
|
||||||
|
if (i != mTypes.end())
|
||||||
|
result = i->second.type;
|
||||||
|
} else {
|
||||||
|
// see if variable is defined in parent scope.
|
||||||
|
if (mParent)
|
||||||
|
result = mParent->getType(name);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue& defineFunction(const String& name, ICodeModule* iCode)
|
||||||
|
{
|
||||||
|
JSValue value(new JSFunction(iCode));
|
||||||
|
return defineVariable(name, &Function_Type, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue& defineNativeFunction(const String& name, JSNativeFunction::JSCode code)
|
||||||
|
{
|
||||||
|
JSValue value(new JSNativeFunction(code));
|
||||||
|
return defineVariable(name, &Function_Type, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class JSType : public JSObject {
|
||||||
|
protected:
|
||||||
|
String mName;
|
||||||
|
JSType *mBaseType;
|
||||||
|
public:
|
||||||
|
JSType(const String &name, JSType *baseType) : mName(name), mBaseType(baseType)
|
||||||
|
{
|
||||||
|
mType = &Type_Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum { NoRelation = 0x7FFFFFFF };
|
||||||
|
|
||||||
|
const String& getName() const { return mName; }
|
||||||
|
|
||||||
|
int32 distance(const JSType *other) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline void JSObject::init(JSObject* prototype) { mPrototype = prototype; mType = &Any_Type; mClass = new JSString(ObjectString); }
|
||||||
|
|
||||||
|
inline JSFunction::JSFunction(ICodeModule* iCode) : mICode(iCode), JSObject(functionPrototypeObject) { setClass(new JSString(FunctionString)); }
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace JSTypes */
|
||||||
|
} /* namespace JavaScript */
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* jstypes_h */
|
||||||
BIN
mozilla/js/js2/macbuild/GCTest.mcp
Normal file
BIN
mozilla/js/js2/macbuild/GCTest.mcp
Normal file
Binary file not shown.
BIN
mozilla/js/js2/macbuild/JS2.mcp
Normal file
BIN
mozilla/js/js2/macbuild/JS2.mcp
Normal file
Binary file not shown.
1
mozilla/js/js2/macbuild/JS2.prefix
Normal file
1
mozilla/js/js2/macbuild/JS2.prefix
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#define XP_MAC 1
|
||||||
4319
mozilla/js/js2/macbuild/JS2.xml
Normal file
4319
mozilla/js/js2/macbuild/JS2.xml
Normal file
File diff suppressed because it is too large
Load Diff
2
mozilla/js/js2/macbuild/JS2Debug.prefix
Normal file
2
mozilla/js/js2/macbuild/JS2Debug.prefix
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define XP_MAC 1
|
||||||
|
#define DEBUG 1
|
||||||
2
mozilla/js/js2/macbuild/JS2MPW.prefix
Normal file
2
mozilla/js/js2/macbuild/JS2MPW.prefix
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define XP_MAC 1
|
||||||
|
#define XP_MAC_MPW 1
|
||||||
3
mozilla/js/js2/macbuild/JS2MPWDebug.prefix
Normal file
3
mozilla/js/js2/macbuild/JS2MPWDebug.prefix
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#define XP_MAC 1
|
||||||
|
#define XP_MAC_MPW 1
|
||||||
|
#define DEBUG 1
|
||||||
BIN
mozilla/js/js2/macbuild/gc.mcp
Normal file
BIN
mozilla/js/js2/macbuild/gc.mcp
Normal file
Binary file not shown.
BIN
mozilla/js/js2/macbuild/gc.o
Normal file
BIN
mozilla/js/js2/macbuild/gc.o
Normal file
Binary file not shown.
91
mozilla/js/js2/macbuild/gc_config.h
Normal file
91
mozilla/js/js2/macbuild/gc_config.h
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
MacOS_config.h
|
||||||
|
|
||||||
|
Configuration flags for Macintosh development systems.
|
||||||
|
|
||||||
|
<Revision History>
|
||||||
|
|
||||||
|
11/16/95 pcb Updated compilation flags to reflect latest 4.6 Makefile.
|
||||||
|
|
||||||
|
by Patrick C. Beard.
|
||||||
|
*/
|
||||||
|
/* Boehm, November 17, 1995 12:10 pm PST */
|
||||||
|
|
||||||
|
#ifdef __MWERKS__
|
||||||
|
|
||||||
|
// for CodeWarrior Pro with Metrowerks Standard Library (MSL).
|
||||||
|
// #define MSL_USE_PRECOMPILED_HEADERS 0
|
||||||
|
#include <ansi_prefix.mac.h>
|
||||||
|
#ifndef __STDC__
|
||||||
|
#define __STDC__ 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __MWERKS__ */
|
||||||
|
|
||||||
|
// these are defined again in gc_priv.h.
|
||||||
|
#undef TRUE
|
||||||
|
#undef FALSE
|
||||||
|
|
||||||
|
#define ALL_INTERIOR_POINTERS // follows interior pointers.
|
||||||
|
#define SILENT // no collection messages.
|
||||||
|
//#define DONT_ADD_BYTE_AT_END // no padding.
|
||||||
|
//#define SMALL_CONFIG // whether to use a smaller heap.
|
||||||
|
#define NO_SIGNALS // signals aren't real on the Macintosh.
|
||||||
|
#define USE_TEMPORARY_MEMORY // use Macintosh temporary memory.
|
||||||
|
//#define FIND_LEAK // use as a leak detector.
|
||||||
|
//#define LARGE_CONFIG // try a big heap, for fun.
|
||||||
|
|
||||||
|
// CFLAGS= -O -DNO_SIGNALS -DSILENT -DALL_INTERIOR_POINTERS
|
||||||
|
//
|
||||||
|
//LIBGC_CFLAGS= -O -DNO_SIGNALS -DSILENT \
|
||||||
|
// -DREDIRECT_MALLOC=GC_malloc_uncollectable \
|
||||||
|
// -DDONT_ADD_BYTE_AT_END -DALL_INTERIOR_POINTERS
|
||||||
|
// Flags for building libgc.a -- the last two are required.
|
||||||
|
//
|
||||||
|
// Setjmp_test may yield overly optimistic results when compiled
|
||||||
|
// without optimization.
|
||||||
|
// -DSILENT disables statistics printing, and improves performance.
|
||||||
|
// -DCHECKSUMS reports on erroneously clear dirty bits, and unexpectedly
|
||||||
|
// altered stubborn objects, at substantial performance cost.
|
||||||
|
// Use only for incremental collector debugging.
|
||||||
|
// -DFIND_LEAK causes the collector to assume that all inaccessible
|
||||||
|
// objects should have been explicitly deallocated, and reports exceptions.
|
||||||
|
// Finalization and the test program are not usable in this mode.
|
||||||
|
// -DSOLARIS_THREADS enables support for Solaris (thr_) threads.
|
||||||
|
// (Clients should also define SOLARIS_THREADS and then include
|
||||||
|
// gc.h before performing thr_ or GC_ operations.)
|
||||||
|
// This is broken on nonSPARC machines.
|
||||||
|
// -DALL_INTERIOR_POINTERS allows all pointers to the interior
|
||||||
|
// of objects to be recognized. (See gc_priv.h for consequences.)
|
||||||
|
// -DSMALL_CONFIG tries to tune the collector for small heap sizes,
|
||||||
|
// usually causing it to use less space in such situations.
|
||||||
|
// Incremental collection no longer works in this case.
|
||||||
|
// -DLARGE_CONFIG tunes the collector for unusually large heaps.
|
||||||
|
// Necessary for heaps larger than about 500 MB on most machines.
|
||||||
|
// Recommended for heaps larger than about 64 MB.
|
||||||
|
// -DDONT_ADD_BYTE_AT_END is meaningful only with
|
||||||
|
// -DALL_INTERIOR_POINTERS. Normally -DALL_INTERIOR_POINTERS
|
||||||
|
// causes all objects to be padded so that pointers just past the end of
|
||||||
|
// an object can be recognized. This can be expensive. (The padding
|
||||||
|
// is normally more than one byte due to alignment constraints.)
|
||||||
|
// -DDONT_ADD_BYTE_AT_END disables the padding.
|
||||||
|
// -DNO_SIGNALS does not disable signals during critical parts of
|
||||||
|
// the GC process. This is no less correct than many malloc
|
||||||
|
// implementations, and it sometimes has a significant performance
|
||||||
|
// impact. However, it is dangerous for many not-quite-ANSI C
|
||||||
|
// programs that call things like printf in asynchronous signal handlers.
|
||||||
|
// -DOPERATOR_NEW_ARRAY declares that the C++ compiler supports the
|
||||||
|
// new syntax "operator new[]" for allocating and deleting arrays.
|
||||||
|
// See gc_cpp.h for details. No effect on the C part of the collector.
|
||||||
|
// This is defined implicitly in a few environments.
|
||||||
|
// -DREDIRECT_MALLOC=X causes malloc, realloc, and free to be defined
|
||||||
|
// as aliases for X, GC_realloc, and GC_free, respectively.
|
||||||
|
// Calloc is redefined in terms of the new malloc. X should
|
||||||
|
// be either GC_malloc or GC_malloc_uncollectable.
|
||||||
|
// The former is occasionally useful for working around leaks in code
|
||||||
|
// you don't want to (or can't) look at. It may not work for
|
||||||
|
// existing code, but it often does. Neither works on all platforms,
|
||||||
|
// since some ports use malloc or calloc to obtain system memory.
|
||||||
|
// (Probably works for UNIX, and win32.)
|
||||||
|
// -DNO_DEBUG removes GC_dump and the debugging routines it calls.
|
||||||
|
// Reduces code size slightly at the expense of debuggability.
|
||||||
2755
mozilla/js/js2/numerics.cpp
Normal file
2755
mozilla/js/js2/numerics.cpp
Normal file
File diff suppressed because it is too large
Load Diff
153
mozilla/js/js2/numerics.h
Normal file
153
mozilla/js/js2/numerics.h
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
// -*- 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.
|
||||||
|
|
||||||
|
#ifndef numerics_h
|
||||||
|
#define numerics_h
|
||||||
|
|
||||||
|
#include "utilities.h"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
/* Use platform-defined floating-point routines.
|
||||||
|
* On platforms with faulty floating-point code
|
||||||
|
* ifdef these out and replace by custom implementations. */
|
||||||
|
|
||||||
|
#ifndef STLPORT
|
||||||
|
# ifndef _WIN32
|
||||||
|
using std::abs;
|
||||||
|
using std::floor;
|
||||||
|
using std::ceil;
|
||||||
|
using std::fmod;
|
||||||
|
using std::sqrt;
|
||||||
|
using std::sin;
|
||||||
|
using std::cos;
|
||||||
|
using std::tan;
|
||||||
|
using std::asin;
|
||||||
|
using std::acos;
|
||||||
|
using std::atan;
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Double-precision constants
|
||||||
|
//
|
||||||
|
|
||||||
|
extern double positiveInfinity;
|
||||||
|
extern double negativeInfinity;
|
||||||
|
extern double nan;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Portable double-precision floating point to string and back conversions
|
||||||
|
//
|
||||||
|
|
||||||
|
double ulp(double x);
|
||||||
|
int hi0bits(uint32 x);
|
||||||
|
|
||||||
|
class BigInt {
|
||||||
|
enum {maxLgGrossSize = 15}; // Maximum value of lg2(grossSize)
|
||||||
|
static uint32 *freeLists[maxLgGrossSize+1];
|
||||||
|
|
||||||
|
uint lgGrossSize; // lg2(grossSize)
|
||||||
|
public:
|
||||||
|
bool negative; // True if negative. Ignored by most BigInt routines!
|
||||||
|
private:
|
||||||
|
uint32 grossSize; // Number of words allocated for <words>
|
||||||
|
uint32 size; // Actual number of words. If the number is nonzero, the most significant word must be nonzero.
|
||||||
|
// If the number is zero, then size is also 0.
|
||||||
|
uint32 *words; // <size> words of the number, in little endian order
|
||||||
|
|
||||||
|
void allocate(uint lgGrossSize);
|
||||||
|
void recycle();
|
||||||
|
void initCopy(const BigInt &b);
|
||||||
|
void move(BigInt &b);
|
||||||
|
public:
|
||||||
|
BigInt(): words(0) {}
|
||||||
|
explicit BigInt(uint lgGrossSize) {allocate(lgGrossSize);}
|
||||||
|
BigInt(const BigInt &b) {initCopy(b);}
|
||||||
|
void operator=(const BigInt &b) {ASSERT(!words); initCopy(b);}
|
||||||
|
~BigInt() {if (words) recycle();}
|
||||||
|
|
||||||
|
void setLgGrossSize(uint lgGrossSize);
|
||||||
|
void init(uint32 i);
|
||||||
|
void init(double d, int32 &e, int32 &bits);
|
||||||
|
void mulAdd(uint m, uint a);
|
||||||
|
void operator*=(const BigInt &m);
|
||||||
|
void pow2Mul(int32 k);
|
||||||
|
void pow5Mul(int32 k);
|
||||||
|
bool isZero() const {ASSERT(words); return !size;}
|
||||||
|
int cmp(const BigInt &b) const;
|
||||||
|
void initDiff(const BigInt &m, const BigInt &n);
|
||||||
|
uint32 quoRem2(int32 k);
|
||||||
|
int32 quoRem(const BigInt &S);
|
||||||
|
uint32 divRem(uint32 divisor);
|
||||||
|
double b2d(int32 &e) const;
|
||||||
|
double ratio(const BigInt &denominator) const;
|
||||||
|
void s2b(const char *s, int32 nd0, int32 nd, uint32 y9);
|
||||||
|
|
||||||
|
uint32 nWords() const {return size;}
|
||||||
|
uint32 word(uint32 i) const {ASSERT(i < size); return words[i];}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Modes for converting floating-point numbers to strings.
|
||||||
|
//
|
||||||
|
// Some of the modes can round-trip; this means that if the number is converted to
|
||||||
|
// a string using one of these mode and then converted back to a number, the result
|
||||||
|
// will be identical to the original number (except that, due to ECMA, -0 will get converted
|
||||||
|
// to +0). These round-trip modes return the minimum number of significand digits that
|
||||||
|
// permit the round trip.
|
||||||
|
//
|
||||||
|
// Some of the modes take an integer parameter <precision>.
|
||||||
|
//
|
||||||
|
// Keep this in sync with doubleToAsciiModes[].
|
||||||
|
enum DToStrMode {
|
||||||
|
dtosStandard, // Either fixed or exponential format; round-trip
|
||||||
|
dtosStandardExponential, // Always exponential format; round-trip
|
||||||
|
dtosFixed, // Round to <precision> digits after the decimal point; exponential if number is large
|
||||||
|
dtosExponential, // Always exponential format; <precision> significant digits
|
||||||
|
dtosPrecision // Either fixed or exponential format; <precision> significant digits
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Maximum number of characters (including trailing null) that a dtosStandard or dtosStandardExponential
|
||||||
|
// conversion can produce. This maximum is reached for a number like -1.2345678901234567e+123.
|
||||||
|
const int dtosStandardBufferSize = 25;
|
||||||
|
|
||||||
|
// Maximum number of characters (including trailing null) that one of the other conversions
|
||||||
|
// can produce. This maximum is reached for TO_FIXED, which can generate up to 21 digits before the decimal point.
|
||||||
|
#define dtosVariableBufferSize(precision) ((precision)+24 > dtosStandardBufferSize ? (precision)+24 : dtosStandardBufferSize)
|
||||||
|
|
||||||
|
// "-0.0000...(1073 zeros after decimal point)...0001\0" is the longest string that we could produce,
|
||||||
|
// which occurs when printing -5e-324 in binary. We could compute a better estimate of the size of
|
||||||
|
// the output string and malloc fewer bytes depending on d and base, but why bother?
|
||||||
|
const int dtobasesBufferSize = 1078;
|
||||||
|
|
||||||
|
double strToDouble(const char *str, const char *&numEnd);
|
||||||
|
double stringToDouble(const char16 *str, const char16 *strEnd, const char16 *&numEnd);
|
||||||
|
double stringToInteger(const char16 *str, const char16 *strEnd, const char16 *&numEnd, uint base);
|
||||||
|
|
||||||
|
char *doubleToStr(char *buffer, size_t bufferSize, double value, DToStrMode mode, int precision);
|
||||||
|
size_t doubleToBaseStr(char *buffer, double value, uint base);
|
||||||
|
void appendDouble(String &dst, double value, DToStrMode mode = dtosStandard, int precision = 0);
|
||||||
|
inline String &operator+=(String &s, double value) {appendDouble(s, value); return s;}
|
||||||
|
void printDouble(Formatter &f, double value, DToStrMode mode = dtosStandard, int precision = 0);
|
||||||
|
inline Formatter &operator<<(Formatter &f, double value) {printDouble(f, value); return f;}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
3330
mozilla/js/js2/parser.cpp
Normal file
3330
mozilla/js/js2/parser.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1063
mozilla/js/js2/parser.h
Normal file
1063
mozilla/js/js2/parser.h
Normal file
File diff suppressed because it is too large
Load Diff
93
mozilla/js/js2/systemtypes.h
Normal file
93
mozilla/js/js2/systemtypes.h
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
// -*- 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.
|
||||||
|
|
||||||
|
#ifndef systemtypes_h
|
||||||
|
#define systemtypes_h
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Turn off warnings about identifiers too long in browser information
|
||||||
|
#pragma warning(disable: 4786)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Define int8, int16, int32, int64, uint8, uint16, uint32, uint64, and uint.
|
||||||
|
typedef unsigned int uint;
|
||||||
|
typedef unsigned char uchar;
|
||||||
|
|
||||||
|
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
|
||||||
|
typedef long int32;
|
||||||
|
typedef unsigned long uint32;
|
||||||
|
#endif
|
||||||
|
#ifdef _WIN32
|
||||||
|
typedef __int64 int64;
|
||||||
|
typedef unsigned __int64 uint64;
|
||||||
|
#else
|
||||||
|
typedef long long int64;
|
||||||
|
typedef unsigned long long uint64;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Define this if the machine natively supports 64-bit integers
|
||||||
|
#define NATIVE_INT64
|
||||||
|
|
||||||
|
// Define float32 and float64.
|
||||||
|
typedef double float64;
|
||||||
|
typedef float float32;
|
||||||
|
|
||||||
|
// A UTF-16 character
|
||||||
|
// Use wchar_t on platforms on which wchar_t has 16 bits; otherwise use int16.
|
||||||
|
// Note that in C++ wchar_t is a distinct type rather than a typedef for some integral type.
|
||||||
|
// Like char, a char16 can be either signed or unsigned at the implementation's discretion.
|
||||||
|
#ifdef __GNUC__
|
||||||
|
// GCC's wchar_t is 32 bits, so we can't use it.
|
||||||
|
typedef uint16 char16;
|
||||||
|
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 unsigned wchar_t uchar16;
|
||||||
|
#else
|
||||||
|
typedef wchar_t uchar16;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define IS_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
#ifdef __i386__
|
||||||
|
#define IS_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// basicAlignment is the maximum alignment required by any native type. An object aligned to
|
||||||
|
// a multiple of basicAlignment can hold any native type. malloc should return a pointer whose
|
||||||
|
// lgBasicAlignment least significant bits are clear.
|
||||||
|
// Currently basicAlignment is set to 8 to allow doubles and int64s to have their natural alignment;
|
||||||
|
// may be customized for individual platforms.
|
||||||
|
const uint lgBasicAlignment = 3;
|
||||||
|
const uint basicAlignment = 1u<<lgBasicAlignment;
|
||||||
|
|
||||||
|
#endif /* systemtypes_h */
|
||||||
28
mozilla/js/js2/tests/classes.js
Normal file
28
mozilla/js/js2/tests/classes.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
class A {
|
||||||
|
static var x = 0;
|
||||||
|
|
||||||
|
static function f()
|
||||||
|
{
|
||||||
|
return A.x++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Point3D {
|
||||||
|
var x = 0, y = 0, z = 0;
|
||||||
|
|
||||||
|
function set(x, y, z) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setX(x) { this.x = x; }
|
||||||
|
function getX() { return this.x; }
|
||||||
|
|
||||||
|
function setY(y) { this.y = y; }
|
||||||
|
function getY() { return this.y; }
|
||||||
|
|
||||||
|
function setZ(z) { this.z = z; }
|
||||||
|
function getZ() { return this.z; }
|
||||||
|
}
|
||||||
596
mozilla/js/js2/tools/gencode.pl
Normal file
596
mozilla/js/js2/tools/gencode.pl
Normal file
@@ -0,0 +1,596 @@
|
|||||||
|
#!perl
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
my $tab = " ";
|
||||||
|
my $init_tab = $tab;
|
||||||
|
my $enum_decs = "";
|
||||||
|
my $class_decs = "";
|
||||||
|
my @name_array;
|
||||||
|
my $opcode_maxlen = 0;
|
||||||
|
|
||||||
|
#
|
||||||
|
# fields are:
|
||||||
|
#
|
||||||
|
# * super: Class to inherit from, if super is Instruction_(1|2|3), the script
|
||||||
|
# will automatically append the correct template info based on |params|
|
||||||
|
# * super_has_print: Set to 1 if you want to inherit the print() and print_args()
|
||||||
|
# methods from the superclass, set to 0 (or just don't set)
|
||||||
|
# to generate print methods.
|
||||||
|
# * rem: Remark you want to show up after the enum def, and inside the class.
|
||||||
|
# * params: The parameter list expected by the constructor, you can specify a
|
||||||
|
# default value, using the syntax, [ ("Type = default") ].
|
||||||
|
#
|
||||||
|
# class names will be generated based on the opcode mnemonic. See the
|
||||||
|
# subroutine get_classname for the implementation. Basically underscores will
|
||||||
|
# be removes and the class name will be WordCapped, using the positions where the
|
||||||
|
# underscores were as word boundries. The only exception occurs when a word is
|
||||||
|
# two characters, in which case both characters will be capped,
|
||||||
|
# as in BRANCH_GT -> BranchGT.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# template definitions for compare, arithmetic, and conditional branch ops
|
||||||
|
#
|
||||||
|
my $binary_op =
|
||||||
|
{
|
||||||
|
super => "Instruction_3",
|
||||||
|
super_has_print => 1,
|
||||||
|
rem => "dest, source1, source2",
|
||||||
|
params => [ ("TypedRegister", "TypedRegister", "TypedRegister") ]
|
||||||
|
};
|
||||||
|
|
||||||
|
my $math_op =
|
||||||
|
{
|
||||||
|
super => "Arithmetic",
|
||||||
|
super_has_print => 1,
|
||||||
|
rem => "dest, source1, source2",
|
||||||
|
params => [ ("TypedRegister", "TypedRegister", "TypedRegister") ]
|
||||||
|
};
|
||||||
|
|
||||||
|
my $cbranch_op =
|
||||||
|
{
|
||||||
|
super => "GenericBranch",
|
||||||
|
super_has_print => 1,
|
||||||
|
rem => "target label, condition",
|
||||||
|
params => [ ("Label*", "TypedRegister") ]
|
||||||
|
};
|
||||||
|
|
||||||
|
my $unary_op =
|
||||||
|
{
|
||||||
|
super => "Instruction_2",
|
||||||
|
rem => "dest, source",
|
||||||
|
params => [ ("TypedRegister", "TypedRegister") ]
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# op defititions
|
||||||
|
#
|
||||||
|
my %ops;
|
||||||
|
$ops{"NOP"} =
|
||||||
|
{
|
||||||
|
super => "Instruction",
|
||||||
|
rem => "do nothing and like it",
|
||||||
|
};
|
||||||
|
$ops{"DEBUGGER"} =
|
||||||
|
{
|
||||||
|
super => "Instruction",
|
||||||
|
rem => "drop to the debugger",
|
||||||
|
};
|
||||||
|
$ops{"GENERIC_BINARY_OP"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_4",
|
||||||
|
rem => "dest, op, source1, source2",
|
||||||
|
params => [ ("TypedRegister", "BinaryOperator::BinaryOp", "TypedRegister", "TypedRegister") ]
|
||||||
|
};
|
||||||
|
$ops{"MOVE"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_2",
|
||||||
|
rem => "dest, source",
|
||||||
|
params => [ ("TypedRegister", "TypedRegister") ]
|
||||||
|
};
|
||||||
|
$ops{"LOAD_IMMEDIATE"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_2",
|
||||||
|
rem => "dest, immediate value (double)",
|
||||||
|
params => [ ("TypedRegister", "double" ) ]
|
||||||
|
};
|
||||||
|
$ops{"LOAD_BOOLEAN"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_2",
|
||||||
|
rem => "dest, immediate value (boolean)",
|
||||||
|
params => [ ("TypedRegister", "bool" ) ]
|
||||||
|
};
|
||||||
|
$ops{"LOAD_STRING"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_2",
|
||||||
|
rem => "dest, immediate value (string)",
|
||||||
|
params => [ ("TypedRegister", "JSString*" ) ]
|
||||||
|
};
|
||||||
|
$ops{"LOAD_NAME"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_2",
|
||||||
|
rem => "dest, name",
|
||||||
|
params => [ ("TypedRegister", "const StringAtom*" ) ]
|
||||||
|
};
|
||||||
|
$ops{"SUPER"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_1",
|
||||||
|
rem => "dest",
|
||||||
|
params => [ ("TypedRegister" ) ]
|
||||||
|
};
|
||||||
|
$ops{"SAVE_NAME"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_2",
|
||||||
|
rem => "name, source",
|
||||||
|
params => [ ("const StringAtom*", "TypedRegister") ]
|
||||||
|
};
|
||||||
|
$ops{"NEW_OBJECT"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_2",
|
||||||
|
rem => "dest, constructor",
|
||||||
|
params => [ ("TypedRegister", "TypedRegister") ]
|
||||||
|
};
|
||||||
|
$ops{"NEW_CLASS"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_2",
|
||||||
|
rem => "dest, class",
|
||||||
|
params => [ ("TypedRegister", "JSClass*") ]
|
||||||
|
};
|
||||||
|
$ops{"NEW_FUNCTION"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_2",
|
||||||
|
rem => "dest, ICodeModule",
|
||||||
|
params => [ ("TypedRegister", "ICodeModule*") ]
|
||||||
|
};
|
||||||
|
$ops{"NEW_ARRAY"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_1",
|
||||||
|
rem => "dest",
|
||||||
|
params => [ ("TypedRegister") ]
|
||||||
|
};
|
||||||
|
$ops{"DELETE_PROP"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_3",
|
||||||
|
rem => "dest, object, prop name",
|
||||||
|
params => [ ("TypedRegister", "TypedRegister", "const StringAtom*") ]
|
||||||
|
};
|
||||||
|
$ops{"GET_PROP"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_3",
|
||||||
|
rem => "dest, object, prop name",
|
||||||
|
params => [ ("TypedRegister", "TypedRegister", "const StringAtom*") ]
|
||||||
|
};
|
||||||
|
$ops{"SET_PROP"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_3",
|
||||||
|
rem => "object, name, source",
|
||||||
|
params => [ ("TypedRegister", "const StringAtom*", "TypedRegister") ]
|
||||||
|
};
|
||||||
|
$ops{"GET_SLOT"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_3",
|
||||||
|
rem => "dest, object, slot number",
|
||||||
|
params => [ ("TypedRegister", "TypedRegister", "uint32") ]
|
||||||
|
};
|
||||||
|
$ops{"SET_SLOT"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_3",
|
||||||
|
rem => "object, slot number, source",
|
||||||
|
params => [ ("TypedRegister", "uint32", "TypedRegister") ]
|
||||||
|
};
|
||||||
|
$ops{"GET_STATIC"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_3",
|
||||||
|
rem => "dest, class, index",
|
||||||
|
params => [ ("TypedRegister", "JSClass*", "uint32") ]
|
||||||
|
};
|
||||||
|
$ops{"SET_STATIC"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_3",
|
||||||
|
rem => "class, index, source",
|
||||||
|
params => [ ("JSClass*", "uint32", "TypedRegister") ]
|
||||||
|
};
|
||||||
|
$ops{"STATIC_XCR"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_4",
|
||||||
|
rem => "dest, class, index, value",
|
||||||
|
params => [ ("TypedRegister", "JSClass*", "uint32", "double") ]
|
||||||
|
};
|
||||||
|
$ops{"SLOT_XCR"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_4",
|
||||||
|
rem => "dest, source, slot number, value",
|
||||||
|
params => [ ("TypedRegister", "TypedRegister", "uint32", "double") ]
|
||||||
|
};
|
||||||
|
$ops{"PROP_XCR"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_4",
|
||||||
|
rem => "dest, source, name, value",
|
||||||
|
params => [ ("TypedRegister", "TypedRegister", "const StringAtom*", "double") ]
|
||||||
|
};
|
||||||
|
$ops{"ELEM_XCR"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_4",
|
||||||
|
rem => "dest, base, index, value",
|
||||||
|
params => [ ("TypedRegister", "TypedRegister", "TypedRegister", "double") ]
|
||||||
|
};
|
||||||
|
$ops{"NAME_XCR"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_3",
|
||||||
|
rem => "dest, name, value",
|
||||||
|
params => [ ("TypedRegister", "const StringAtom*", "double") ]
|
||||||
|
};
|
||||||
|
$ops{"VAR_XCR"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_3",
|
||||||
|
rem => "dest, source, value",
|
||||||
|
params => [ ("TypedRegister", "TypedRegister", "double") ]
|
||||||
|
};
|
||||||
|
$ops{"GET_ELEMENT"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_3",
|
||||||
|
rem => "dest, base, index",
|
||||||
|
params => [ ("TypedRegister", "TypedRegister", "TypedRegister") ]
|
||||||
|
};
|
||||||
|
$ops{"SET_ELEMENT"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_3",
|
||||||
|
rem => "base, index, value",
|
||||||
|
params => [ ("TypedRegister", "TypedRegister", "TypedRegister") ]
|
||||||
|
};
|
||||||
|
$ops{"ADD"} = $math_op;
|
||||||
|
$ops{"SUBTRACT"} = $math_op;
|
||||||
|
$ops{"MULTIPLY"} = $math_op;
|
||||||
|
$ops{"DIVIDE"} = $math_op;
|
||||||
|
$ops{"REMAINDER"} = $math_op;
|
||||||
|
$ops{"SHIFTLEFT"} = $math_op;
|
||||||
|
$ops{"SHIFTRIGHT"} = $math_op;
|
||||||
|
$ops{"USHIFTRIGHT"}= $math_op;
|
||||||
|
$ops{"AND"} = $math_op;
|
||||||
|
$ops{"OR"} = $math_op;
|
||||||
|
$ops{"XOR"} = $math_op;
|
||||||
|
$ops{"COMPARE_LT"} = $binary_op;
|
||||||
|
$ops{"COMPARE_LE"} = $binary_op;
|
||||||
|
$ops{"COMPARE_EQ"} = $binary_op;
|
||||||
|
$ops{"COMPARE_NE"} = $binary_op;
|
||||||
|
$ops{"COMPARE_GE"} = $binary_op;
|
||||||
|
$ops{"COMPARE_GT"} = $binary_op;
|
||||||
|
$ops{"COMPARE_IN"} = $binary_op;
|
||||||
|
$ops{"STRICT_EQ"} = $binary_op;
|
||||||
|
$ops{"STRICT_NE"} = $binary_op;
|
||||||
|
$ops{"INSTANCEOF"} = $binary_op;
|
||||||
|
$ops{"BITNOT"} = $unary_op;
|
||||||
|
$ops{"NOT"} = $unary_op;
|
||||||
|
$ops{"TEST"} = $unary_op;
|
||||||
|
$ops{"NEGATE"} = $unary_op;
|
||||||
|
$ops{"POSATE"} = $unary_op;
|
||||||
|
$ops{"BRANCH"} =
|
||||||
|
{
|
||||||
|
super => "GenericBranch",
|
||||||
|
rem => "target label",
|
||||||
|
params => [ ("Label*") ]
|
||||||
|
};
|
||||||
|
$ops{"BRANCH_TRUE"} = $cbranch_op;
|
||||||
|
$ops{"BRANCH_FALSE"} = $cbranch_op;
|
||||||
|
$ops{"RETURN"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_1",
|
||||||
|
rem => "return value",
|
||||||
|
params => [ ("TypedRegister") ]
|
||||||
|
};
|
||||||
|
$ops{"RETURN_VOID"} =
|
||||||
|
{
|
||||||
|
super => "Instruction",
|
||||||
|
rem => "Return without a value"
|
||||||
|
};
|
||||||
|
$ops{"CALL"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_4",
|
||||||
|
rem => "result, base, target, args",
|
||||||
|
params => [ ("TypedRegister", "TypedRegister", "TypedRegister", "RegisterList") ]
|
||||||
|
};
|
||||||
|
$ops{"GET_METHOD"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_3",
|
||||||
|
rem => "result, target base, index",
|
||||||
|
params => [ ("TypedRegister", "TypedRegister", "uint32") ]
|
||||||
|
};
|
||||||
|
$ops{"THROW"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_1",
|
||||||
|
rem => "exception value",
|
||||||
|
params => [ ("TypedRegister") ]
|
||||||
|
};
|
||||||
|
$ops{"TRYIN"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_2",
|
||||||
|
rem => "catch target, finally target",
|
||||||
|
params => [ ("Label*", "Label*") ]
|
||||||
|
};
|
||||||
|
$ops{"TRYOUT"} =
|
||||||
|
{
|
||||||
|
super => "Instruction",
|
||||||
|
rem => "mmm, there is no try, only do",
|
||||||
|
};
|
||||||
|
$ops{"JSR"} =
|
||||||
|
{
|
||||||
|
super => "GenericBranch",
|
||||||
|
rem => "target",
|
||||||
|
params => [ ("Label*") ]
|
||||||
|
};
|
||||||
|
$ops{"RTS"} =
|
||||||
|
{
|
||||||
|
super => "Instruction",
|
||||||
|
rem => "Return to sender",
|
||||||
|
};
|
||||||
|
$ops{"WITHIN"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_1",
|
||||||
|
rem => "within this object",
|
||||||
|
params => [ ("TypedRegister") ]
|
||||||
|
};
|
||||||
|
$ops{"WITHOUT"} =
|
||||||
|
{
|
||||||
|
super => "Instruction",
|
||||||
|
rem => "without this object",
|
||||||
|
};
|
||||||
|
$ops{"CAST"} =
|
||||||
|
{
|
||||||
|
super => "Instruction_3",
|
||||||
|
rem => "dest, rvalue, toType",
|
||||||
|
params => [ ("TypedRegister", "TypedRegister", "JSType*") ]
|
||||||
|
};
|
||||||
|
|
||||||
|
#
|
||||||
|
# nasty perl code, you probably don't need to muck around below this line
|
||||||
|
#
|
||||||
|
|
||||||
|
my $k;
|
||||||
|
|
||||||
|
if (!$ARGV[0]) {
|
||||||
|
# no args, collect all opcodes
|
||||||
|
for $k (sort(keys(%ops))) {
|
||||||
|
&collect($k);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# collect defs for only the opcodes specified on the command line
|
||||||
|
while ($k = pop(@ARGV)) {
|
||||||
|
&collect (uc($k));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&spew;
|
||||||
|
|
||||||
|
sub collect {
|
||||||
|
# grab the info from the $k record in $ops, and append it to
|
||||||
|
# $enum_decs, @name_array, and $class_decs.
|
||||||
|
my ($k) = @_;
|
||||||
|
|
||||||
|
if (length($k) > $opcode_maxlen) {
|
||||||
|
$opcode_maxlen = length($k);
|
||||||
|
}
|
||||||
|
|
||||||
|
my $c = $ops{$k};
|
||||||
|
if (!$c) {
|
||||||
|
die ("Unknown opcode, $k\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
my $opname = $k;
|
||||||
|
my $cname = get_classname ($k);
|
||||||
|
my $super = $c->{"super"};
|
||||||
|
my $constructor = $super;
|
||||||
|
my @params;
|
||||||
|
|
||||||
|
if ($c->{"params"}) {
|
||||||
|
@params = @{$c->{"params"}};
|
||||||
|
} else {
|
||||||
|
@params = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
my $rem = $c->{"rem"};
|
||||||
|
my ($dec_list, $call_list, $template_list) =
|
||||||
|
&get_paramlists(@params);
|
||||||
|
my @types = split (", ", $template_list);
|
||||||
|
|
||||||
|
my $constr_params = $call_list ? $opname . ", " . $call_list : $opname;
|
||||||
|
|
||||||
|
if ($super =~ /Instruction_\d/) {
|
||||||
|
$super .= "<" . $template_list . ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
push (@name_array, $opname);
|
||||||
|
$enum_decs .= "$init_tab$tab$opname, /* $rem */\n";
|
||||||
|
if ($super) {
|
||||||
|
$class_decs .= ($init_tab . "class $cname : public $super {\n" .
|
||||||
|
$init_tab . "public:\n" .
|
||||||
|
$init_tab . $tab . "/* $rem */\n" .
|
||||||
|
$init_tab . $tab . "$cname ($dec_list) :\n" .
|
||||||
|
$init_tab . $tab . $tab . "$super\n" .
|
||||||
|
"$init_tab$tab$tab($constr_params) " .
|
||||||
|
"{};\n");
|
||||||
|
|
||||||
|
if (!$c->{"super_has_print"}) {
|
||||||
|
$class_decs .= ($init_tab . $tab .
|
||||||
|
"virtual Formatter& print(Formatter& f) {\n" .
|
||||||
|
$init_tab . $tab . $tab . "f << opcodeNames[$opname]" .
|
||||||
|
&get_print_body(@types) . ";\n" .
|
||||||
|
$init_tab . $tab . $tab . "return f;\n" .
|
||||||
|
$init_tab . $tab . "}\n");
|
||||||
|
|
||||||
|
my $printops_body = &get_printops_body(@types);
|
||||||
|
my $printops_decl = "virtual Formatter& printOperands(Formatter& f, ";
|
||||||
|
|
||||||
|
$printops_decl .= ($dec_list =~ /RegisterList/) ?
|
||||||
|
"const JSValues& registers" :
|
||||||
|
"const JSValues& /*registers*/";
|
||||||
|
$printops_decl .= ") {\n";
|
||||||
|
|
||||||
|
$class_decs .= ($init_tab . $tab .
|
||||||
|
$printops_decl .
|
||||||
|
$printops_body .
|
||||||
|
$init_tab . $tab . $tab . "return f;\n" .
|
||||||
|
$init_tab . $tab . "}\n");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$class_decs .= $init_tab . $tab .
|
||||||
|
"/* print() and printOperands() inherited from $super */\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$class_decs .= $init_tab . "};\n\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub spew {
|
||||||
|
# print the info in $enum_decs, @name_aray, and $class_decs to stdout.
|
||||||
|
my $opname;
|
||||||
|
|
||||||
|
print "// THIS FILE IS MACHINE GENERATED! DO NOT EDIT BY HAND!\n\n";
|
||||||
|
|
||||||
|
print "#if !defined(OPCODE_NAMES)\n\n";
|
||||||
|
|
||||||
|
print $tab . "enum {\n$enum_decs$tab};\n\n";
|
||||||
|
|
||||||
|
print $class_decs;
|
||||||
|
|
||||||
|
print "#else\n\n";
|
||||||
|
|
||||||
|
print $tab . "char *opcodeNames[] = {\n";
|
||||||
|
|
||||||
|
for $opname (@name_array) {
|
||||||
|
print "$tab$tab\"$opname";
|
||||||
|
for (0 .. $opcode_maxlen - length($opname) - 1) {
|
||||||
|
print " ";
|
||||||
|
}
|
||||||
|
print "\",\n"
|
||||||
|
}
|
||||||
|
print "$tab};\n\n";
|
||||||
|
|
||||||
|
print "#endif\n\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_classname {
|
||||||
|
# munge an OPCODE_MNEMONIC into a ClassName
|
||||||
|
my ($enum_name) = @_;
|
||||||
|
my @words = split ("_", $enum_name);
|
||||||
|
my $cname = "";
|
||||||
|
my $i = 0;
|
||||||
|
my $word;
|
||||||
|
|
||||||
|
for $word (@words) {
|
||||||
|
if ((length($word) == 2) && ($i != 0)) {
|
||||||
|
$cname .= uc($word);
|
||||||
|
} else {
|
||||||
|
$cname .= uc(substr($word, 0, 1)) . lc(substr($word, 1));
|
||||||
|
}
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cname;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_paramlists {
|
||||||
|
# parse the params entry (passed into @types) into various parameter lists
|
||||||
|
# used in the class declaration
|
||||||
|
my @types = @_;
|
||||||
|
my @dec;
|
||||||
|
my @call;
|
||||||
|
my @tostr;
|
||||||
|
my @template;
|
||||||
|
my $op = 1;
|
||||||
|
my $type;
|
||||||
|
|
||||||
|
for $type (@types) {
|
||||||
|
my $pfx;
|
||||||
|
my $deref;
|
||||||
|
my $member;
|
||||||
|
my $default;
|
||||||
|
|
||||||
|
($type, $default) = split (" = ", $type);
|
||||||
|
if ($default ne "") {
|
||||||
|
$default = " = " . $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pfx = $deref = "";
|
||||||
|
$member = "mOp$op";
|
||||||
|
|
||||||
|
push (@dec, "$type aOp$op" . "$default");
|
||||||
|
push (@call, "aOp$op");
|
||||||
|
push (@template, $type);
|
||||||
|
$op++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (join (", ", @dec), join (", ", @call), join (", ", @template));
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_print_body {
|
||||||
|
# generate the body of the print() function
|
||||||
|
my (@types) = @_;
|
||||||
|
my $type;
|
||||||
|
my @oplist;
|
||||||
|
my $op = 1;
|
||||||
|
my $in = $init_tab . $tab . $tab;
|
||||||
|
|
||||||
|
for $type (@types) {
|
||||||
|
|
||||||
|
if ($type eq "TypedRegister") {
|
||||||
|
|
||||||
|
push (@oplist, "mOp$op" );
|
||||||
|
|
||||||
|
# push (@oplist, "\"R\" << ((mOp$op.first == NotARegister) ? -1 : mOp$op.first)");
|
||||||
|
|
||||||
|
} elsif ($type eq "Label*") {
|
||||||
|
push (@oplist, "\"Offset \" << ((mOp$op) ? mOp$op->mOffset : NotAnOffset)")
|
||||||
|
} elsif ($type =~ /String/) {
|
||||||
|
push (@oplist, "\"'\" << *mOp$op << \"'\"");
|
||||||
|
} elsif ($type =~ /JSType\*/) {
|
||||||
|
push (@oplist, "\"'\" << mOp$op->getName() << \"'\"");
|
||||||
|
} elsif ($type =~ /bool/) {
|
||||||
|
push (@oplist, "\"'\" << ((mOp$op) ? \"true\" : \"false\") << \"'\"");
|
||||||
|
} elsif ($type =~ /ICodeModule/) {
|
||||||
|
push (@oplist, "\"ICodeModule\"");
|
||||||
|
} elsif ($type =~ /JSClass\*/) {
|
||||||
|
push (@oplist, "mOp$op->getName()");
|
||||||
|
} else {
|
||||||
|
push (@oplist, "mOp$op");
|
||||||
|
}
|
||||||
|
|
||||||
|
$op++;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $rv = join (" << \", \" << ", @oplist);
|
||||||
|
if ($rv ne "") {
|
||||||
|
$rv = " << \"\\t\" << " . $rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_printops_body {
|
||||||
|
# generate the body of the printOperands() function
|
||||||
|
my (@types) = @_;
|
||||||
|
my $type;
|
||||||
|
my @oplist;
|
||||||
|
my $op = 1;
|
||||||
|
my $in = $init_tab . $tab . $tab;
|
||||||
|
|
||||||
|
for $type (@types) {
|
||||||
|
|
||||||
|
if ($type eq "TypedRegister") {
|
||||||
|
push (@oplist, "mOp$op.first");
|
||||||
|
# push (@oplist, "\"R\" << mOp$op.first << '=' << registers[mOp$op.first]");
|
||||||
|
} elsif ($type eq "RegisterList") {
|
||||||
|
push (@oplist, "ArgList(mOp$op, registers)");
|
||||||
|
}
|
||||||
|
|
||||||
|
$op++;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $rv = join (" << \", \" << ", @oplist);
|
||||||
|
if ($rv ne "") {
|
||||||
|
$rv = $init_tab . $tab . $tab . "f << " . $rv . ";\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $rv;
|
||||||
|
}
|
||||||
2563
mozilla/js/js2/utilities.cpp
Normal file
2563
mozilla/js/js2/utilities.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1527
mozilla/js/js2/utilities.h
Normal file
1527
mozilla/js/js2/utilities.h
Normal file
File diff suppressed because it is too large
Load Diff
178
mozilla/js/js2/vmtypes.cpp
Normal file
178
mozilla/js/js2/vmtypes.cpp
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
/* -*- 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 "utilities.h"
|
||||||
|
#include "vmtypes.h"
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
namespace VM {
|
||||||
|
|
||||||
|
using namespace JSTypes;
|
||||||
|
|
||||||
|
#define OPCODE_NAMES
|
||||||
|
#include "icode.h"
|
||||||
|
|
||||||
|
Formatter& operator<< (Formatter& f, Instruction& i)
|
||||||
|
{
|
||||||
|
return i.print(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
Formatter& operator<< (Formatter& f, RegisterList& rl)
|
||||||
|
{
|
||||||
|
TypedRegister* e = rl.end();
|
||||||
|
|
||||||
|
f << "(";
|
||||||
|
for (RegisterList::iterator r = rl.begin(); r != e; r++) {
|
||||||
|
f << "R" << r->first;
|
||||||
|
if ((r + 1) != e)
|
||||||
|
f << ", ";
|
||||||
|
}
|
||||||
|
f << ")";
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Formatter& operator<< (Formatter& f, const ArgList& al)
|
||||||
|
{
|
||||||
|
const RegisterList& rl = al.mList;
|
||||||
|
const JSValues& registers = al.mRegisters;
|
||||||
|
f << "(";
|
||||||
|
RegisterList::const_iterator i = rl.begin(), e = rl.end();
|
||||||
|
if (i != e) {
|
||||||
|
TypedRegister r = *i++;
|
||||||
|
f << "R" << r.first << '=' << registers[r.first];
|
||||||
|
while (i != e) {
|
||||||
|
r = *i++;
|
||||||
|
f << ", R" << r.first << '=' << registers[r.first];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f << ")";
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Formatter& operator<< (Formatter& f, TypedRegister& r)
|
||||||
|
{
|
||||||
|
if (r.first == NotARegister)
|
||||||
|
f << "<NaR>";
|
||||||
|
else
|
||||||
|
f << "R" << r.first;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Formatter& operator<< (Formatter &f, InstructionStream &is)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (InstructionIterator i = is.begin();
|
||||||
|
i != is.end(); i++) {
|
||||||
|
/*
|
||||||
|
bool isLabel = false;
|
||||||
|
|
||||||
|
for (LabelList::iterator k = labels.begin();
|
||||||
|
k != labels.end(); k++)
|
||||||
|
if ((ptrdiff_t)(*k)->mOffset == (i - is.begin())) {
|
||||||
|
f << "#" << (uint32)(i - is.begin()) << "\t";
|
||||||
|
isLabel = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLabel)
|
||||||
|
f << "\t";
|
||||||
|
|
||||||
|
f << **i << "\n";
|
||||||
|
*/
|
||||||
|
|
||||||
|
printFormat(stdOut, "%04u", (uint32)(i - is.begin()));
|
||||||
|
f << ": " << **i << "\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryOperator::BinaryOp BinaryOperator::mapICodeOp(ICodeOp op) {
|
||||||
|
// a table later... or maybe we need a grand opcode re-unification
|
||||||
|
switch (op) {
|
||||||
|
case ADD : return Add;
|
||||||
|
case SUBTRACT : return Subtract;
|
||||||
|
case MULTIPLY : return Multiply;
|
||||||
|
case DIVIDE : return Divide;
|
||||||
|
case REMAINDER : return Remainder;
|
||||||
|
case SHIFTLEFT : return LeftShift;
|
||||||
|
case SHIFTRIGHT : return RightShift;
|
||||||
|
case USHIFTRIGHT: return LogicalRightShift;
|
||||||
|
|
||||||
|
case AND : return BitwiseAnd;
|
||||||
|
case OR : return BitwiseOr;
|
||||||
|
case XOR : return BitwiseXor;
|
||||||
|
|
||||||
|
case COMPARE_LT : return Less;
|
||||||
|
case COMPARE_LE : return LessOrEqual;
|
||||||
|
case COMPARE_EQ : return Equal;
|
||||||
|
case STRICT_EQ : return Identical;
|
||||||
|
default :
|
||||||
|
NOT_REACHED("Unsupported binary op");
|
||||||
|
return (BinaryOp)-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Formatter& operator<< (Formatter &f, BinaryOperator::BinaryOp &b)
|
||||||
|
{
|
||||||
|
switch (b) {
|
||||||
|
case BinaryOperator::Add: return f << "Add";
|
||||||
|
case BinaryOperator::Subtract: return f << "Subtract";
|
||||||
|
case BinaryOperator::Multiply: return f << "Multiply";
|
||||||
|
case BinaryOperator::Divide: return f << "Divide";
|
||||||
|
case BinaryOperator::Remainder: return f << "Remainder";
|
||||||
|
case BinaryOperator::LeftShift: return f << "LeftShift";
|
||||||
|
case BinaryOperator::RightShift: return f << "RightShift";
|
||||||
|
case BinaryOperator::LogicalRightShift: return f << "LogicalRightShift";
|
||||||
|
|
||||||
|
case BinaryOperator::BitwiseAnd: return f << "BitwiseAnd";
|
||||||
|
case BinaryOperator::BitwiseOr: return f << "BitwiseOr";
|
||||||
|
case BinaryOperator::BitwiseXor: return f << "BitwiseXor";
|
||||||
|
|
||||||
|
case BinaryOperator::Less: return f << "Less";
|
||||||
|
case BinaryOperator::LessOrEqual: return f << "LessOrEqual";
|
||||||
|
case BinaryOperator::Equal: return f << "Equal";
|
||||||
|
case BinaryOperator::Identical: return f << "Identical";
|
||||||
|
default :
|
||||||
|
NOT_REACHED("inner peace, either");
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace VM */
|
||||||
|
} /* namespace JavaScript */
|
||||||
|
|
||||||
|
|
||||||
304
mozilla/js/js2/vmtypes.h
Normal file
304
mozilla/js/js2/vmtypes.h
Normal file
@@ -0,0 +1,304 @@
|
|||||||
|
/* -*- 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 vmtypes_h
|
||||||
|
#define vmtypes_h
|
||||||
|
|
||||||
|
#include "numerics.h" /* needed for formatter << double */
|
||||||
|
#include "jstypes.h"
|
||||||
|
#include "jsclasses.h"
|
||||||
|
#include "world.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
/* forward declare classes from JavaScript::ICG */
|
||||||
|
namespace JavaScript {
|
||||||
|
namespace ICG {
|
||||||
|
class ICodeModule;
|
||||||
|
} /* namespace ICG */
|
||||||
|
} /* namespace JavaScript */
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
namespace VM {
|
||||||
|
|
||||||
|
using namespace JSTypes;
|
||||||
|
using namespace JSClasses;
|
||||||
|
|
||||||
|
/********************************************************************/
|
||||||
|
|
||||||
|
typedef uint32 ICodeOp;
|
||||||
|
extern char *opcodeNames[];
|
||||||
|
|
||||||
|
/* super-class for all instructions */
|
||||||
|
class Instruction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Instruction(ICodeOp aOpcode) : mOpcode(aOpcode) {}
|
||||||
|
|
||||||
|
virtual Formatter& print(Formatter& f) = 0;
|
||||||
|
virtual Formatter& printOperands(Formatter& f, const JSValues& /*registers*/) = 0;
|
||||||
|
|
||||||
|
ICodeOp op() { return mOpcode; }
|
||||||
|
|
||||||
|
virtual int32 count() { return 0; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ICodeOp mOpcode;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/********************************************************************/
|
||||||
|
|
||||||
|
enum { NotARegister = 0xFFFFFFFF };
|
||||||
|
enum { NotALabel = 0xFFFFFFFF };
|
||||||
|
enum { NotAnOffset = 0xFFFFFFFF };
|
||||||
|
enum { NotABanana = 0xFFFFFFFF };
|
||||||
|
|
||||||
|
/********************************************************************/
|
||||||
|
|
||||||
|
typedef uint32 Register;
|
||||||
|
typedef std::pair<Register, JSType*> TypedRegister;
|
||||||
|
typedef std::vector<TypedRegister> RegisterList;
|
||||||
|
typedef std::vector<Instruction *> InstructionStream;
|
||||||
|
typedef InstructionStream::iterator InstructionIterator;
|
||||||
|
typedef std::map<String, TypedRegister, std::less<String> > VariableMap;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to print Call operands.
|
||||||
|
*/
|
||||||
|
struct ArgList {
|
||||||
|
const RegisterList& mList;
|
||||||
|
const JSValues& mRegisters;
|
||||||
|
ArgList(const RegisterList& rl, const JSValues& registers)
|
||||||
|
: mList(rl), mRegisters(registers) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/********************************************************************/
|
||||||
|
|
||||||
|
Formatter& operator<< (Formatter& f, Instruction& i);
|
||||||
|
Formatter& operator<< (Formatter& f, RegisterList& rl);
|
||||||
|
Formatter& operator<< (Formatter& f, const ArgList& al);
|
||||||
|
Formatter& operator<< (Formatter& f, InstructionStream& is);
|
||||||
|
Formatter& operator<< (Formatter& f, TypedRegister& r);
|
||||||
|
|
||||||
|
/********************************************************************/
|
||||||
|
|
||||||
|
class Label {
|
||||||
|
public:
|
||||||
|
Label(InstructionStream* aBase) :
|
||||||
|
mBase(aBase), mOffset(NotALabel) {}
|
||||||
|
|
||||||
|
InstructionStream *mBase;
|
||||||
|
uint32 mOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<Label *> LabelList;
|
||||||
|
typedef LabelList::iterator LabelIterator;
|
||||||
|
|
||||||
|
/********************************************************************/
|
||||||
|
|
||||||
|
/* 1, 2 and 3 operand opcode templates */
|
||||||
|
|
||||||
|
template <typename Operand1>
|
||||||
|
class Instruction_1 : public Instruction {
|
||||||
|
public:
|
||||||
|
Instruction_1(ICodeOp aOpcode, Operand1 aOp1) :
|
||||||
|
Instruction(aOpcode), mOp1(aOp1) { }
|
||||||
|
Operand1& o1() { return mOp1; }
|
||||||
|
|
||||||
|
virtual int32 count() { return 1; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Operand1 mOp1;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Operand1, typename Operand2>
|
||||||
|
class Instruction_2 : public Instruction {
|
||||||
|
public:
|
||||||
|
Instruction_2(ICodeOp aOpcode, Operand1 aOp1, Operand2 aOp2) :
|
||||||
|
Instruction(aOpcode), mOp1(aOp1), mOp2(aOp2) {}
|
||||||
|
Operand1& o1() { return mOp1; }
|
||||||
|
Operand2& o2() { return mOp2; }
|
||||||
|
|
||||||
|
virtual int32 count() { return 2; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Operand1 mOp1;
|
||||||
|
Operand2 mOp2;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Operand1, typename Operand2, typename Operand3>
|
||||||
|
class Instruction_3 : public Instruction {
|
||||||
|
public:
|
||||||
|
Instruction_3(ICodeOp aOpcode, Operand1 aOp1, Operand2 aOp2,
|
||||||
|
Operand3 aOp3) :
|
||||||
|
Instruction(aOpcode), mOp1(aOp1), mOp2(aOp2), mOp3(aOp3) { }
|
||||||
|
Operand1& o1() { return mOp1; }
|
||||||
|
Operand2& o2() { return mOp2; }
|
||||||
|
Operand3& o3() { return mOp3; }
|
||||||
|
|
||||||
|
virtual int32 count() { return 3; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Operand1 mOp1;
|
||||||
|
Operand2 mOp2;
|
||||||
|
Operand3 mOp3;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Operand1, typename Operand2, typename Operand3, typename Operand4>
|
||||||
|
class Instruction_4 : public Instruction {
|
||||||
|
public:
|
||||||
|
Instruction_4(ICodeOp aOpcode, Operand1 aOp1, Operand2 aOp2,
|
||||||
|
Operand3 aOp3, Operand4 aOp4) :
|
||||||
|
Instruction(aOpcode), mOp1(aOp1), mOp2(aOp2), mOp3(aOp3), mOp4(aOp4) { }
|
||||||
|
Operand1& o1() { return mOp1; }
|
||||||
|
Operand2& o2() { return mOp2; }
|
||||||
|
Operand3& o3() { return mOp3; }
|
||||||
|
Operand4& o4() { return mOp4; }
|
||||||
|
|
||||||
|
virtual int32 count() { return 4; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Operand1 mOp1;
|
||||||
|
Operand2 mOp2;
|
||||||
|
Operand3 mOp3;
|
||||||
|
Operand4 mOp4;
|
||||||
|
};
|
||||||
|
|
||||||
|
/********************************************************************/
|
||||||
|
|
||||||
|
/* Instruction groups */
|
||||||
|
|
||||||
|
class Arithmetic : public Instruction_3<TypedRegister, TypedRegister, TypedRegister> {
|
||||||
|
public:
|
||||||
|
Arithmetic (ICodeOp aOpcode, TypedRegister aDest, TypedRegister aSrc1,
|
||||||
|
TypedRegister aSrc2) :
|
||||||
|
Instruction_3<TypedRegister, TypedRegister, TypedRegister>(aOpcode, aDest, aSrc1, aSrc2) {}
|
||||||
|
|
||||||
|
virtual Formatter& print(Formatter& f)
|
||||||
|
{
|
||||||
|
f << opcodeNames[mOpcode] << "\tR" << mOp1.first << ", R" << mOp2.first << ", R" << mOp3.first;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Formatter& printOperands(Formatter& f, const JSValues& registers)
|
||||||
|
{
|
||||||
|
f << "R" << mOp1.first << '=' << registers[mOp1.first] << ", " << "R" << mOp2.first << '=' << registers[mOp2.first] << ", " << "R" << mOp3.first << '=' << registers[mOp3.first];
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Unary : public Instruction_2<TypedRegister, TypedRegister> {
|
||||||
|
public:
|
||||||
|
Unary(ICodeOp aOpcode, TypedRegister aDest, TypedRegister aSrc) :
|
||||||
|
Instruction_2<TypedRegister, TypedRegister>(aOpcode, aDest, aSrc) {}
|
||||||
|
virtual Formatter& print (Formatter& f) {
|
||||||
|
f << opcodeNames[mOpcode] << "\tR" << mOp1.first << ", R" << mOp2.first;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Formatter& printOperands(Formatter& f, const JSValues& registers)
|
||||||
|
{
|
||||||
|
f << "R" << mOp1.first << '=' << registers[mOp1.first] << ", " << "R" << mOp2.first << '=' << registers[mOp2.first];
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class GenericBranch : public Instruction_2<Label*, TypedRegister> {
|
||||||
|
public:
|
||||||
|
GenericBranch (ICodeOp aOpcode, Label* aLabel,
|
||||||
|
TypedRegister aR = TypedRegister(NotARegister, &Any_Type) ) :
|
||||||
|
Instruction_2<Label*, TypedRegister>(aOpcode, aLabel, aR) {}
|
||||||
|
virtual Formatter& print (Formatter& f) {
|
||||||
|
f << opcodeNames[mOpcode] << "\tOffset " << mOp1->mOffset;
|
||||||
|
if (mOp2.first == NotARegister) {
|
||||||
|
f << ", R~";
|
||||||
|
} else {
|
||||||
|
f << ", R" << mOp2.first;
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Formatter& printOperands(Formatter& f, const JSValues& registers)
|
||||||
|
{
|
||||||
|
if (mOp2.first != NotARegister)
|
||||||
|
f << "R" << mOp2.first << '=' << registers[mOp2.first];
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resolveTo (uint32 aOffset) { mOp1->mOffset = aOffset; }
|
||||||
|
uint32 getOffset() { return mOp1->mOffset; }
|
||||||
|
void setTarget(Label *label) { mOp1 = label; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/********************************************************************/
|
||||||
|
|
||||||
|
class BinaryOperator {
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Wah, here's a third enumeration of opcodes - ExprNode, ICodeOp and now here, this can't be right??
|
||||||
|
typedef enum {
|
||||||
|
BinaryOperatorFirst,
|
||||||
|
Add = BinaryOperatorFirst, Subtract, Multiply, Divide,
|
||||||
|
Remainder, LeftShift, RightShift, LogicalRightShift,
|
||||||
|
BitwiseOr, BitwiseXor, BitwiseAnd, Less, LessOrEqual,
|
||||||
|
Equal, Identical, BinaryOperatorCount
|
||||||
|
} BinaryOp;
|
||||||
|
|
||||||
|
BinaryOperator(const JSType *t1, const JSType *t2, JSBinaryOperator *function) :
|
||||||
|
t1(t1), t2(t2), function(function) { }
|
||||||
|
|
||||||
|
BinaryOperator(const JSType *t1, const JSType *t2, JSFunction *function) :
|
||||||
|
t1(t1), t2(t2), function(function) { }
|
||||||
|
|
||||||
|
static BinaryOp mapICodeOp(ICodeOp op);
|
||||||
|
|
||||||
|
const JSType *t1;
|
||||||
|
const JSType *t2;
|
||||||
|
JSFunction *function;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<BinaryOperator *> BinaryOperatorList;
|
||||||
|
|
||||||
|
Formatter& operator<<(Formatter &f, BinaryOperator::BinaryOp &b);
|
||||||
|
|
||||||
|
/********************************************************************/
|
||||||
|
|
||||||
|
#include "icode.h"
|
||||||
|
|
||||||
|
} /* namespace VM */
|
||||||
|
|
||||||
|
} /* namespace JavaScript */
|
||||||
|
|
||||||
|
#endif /* vmtypes_h */
|
||||||
5
mozilla/js/js2/winbuild/buildgc.bat
Executable file
5
mozilla/js/js2/winbuild/buildgc.bat
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
cd ..\..\..\..
|
||||||
|
cvs co mozilla/gc/boehm
|
||||||
|
cd mozilla\gc\boehm
|
||||||
|
nmake -f NT_MAKEFILE gc.lib
|
||||||
|
cd ..\..\js\js2\winbuild
|
||||||
234
mozilla/js/js2/winbuild/js2.dsp
Normal file
234
mozilla/js/js2/winbuild/js2.dsp
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
# Microsoft Developer Studio Project File - Name="js2" - Package Owner=<4>
|
||||||
|
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||||
|
# ** DO NOT EDIT **
|
||||||
|
|
||||||
|
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||||
|
|
||||||
|
CFG=js2 - Win32 Partial Debug
|
||||||
|
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||||
|
!MESSAGE use the Export Makefile command and run
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "js2.mak".
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE You can specify a configuration when running NMAKE
|
||||||
|
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "js2.mak" CFG="js2 - Win32 Partial Debug"
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE Possible choices for configuration are:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE "js2 - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||||
|
!MESSAGE "js2 - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||||
|
!MESSAGE "js2 - Win32 Partial Debug" (based on "Win32 (x86) Console Application")
|
||||||
|
!MESSAGE
|
||||||
|
|
||||||
|
# Begin Project
|
||||||
|
# PROP AllowPerConfigDependencies 0
|
||||||
|
# PROP Scc_ProjName ""
|
||||||
|
# PROP Scc_LocalPath ""
|
||||||
|
CPP=cl.exe
|
||||||
|
RSC=rc.exe
|
||||||
|
|
||||||
|
!IF "$(CFG)" == "js2 - Win32 Release"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 0
|
||||||
|
# PROP BASE Output_Dir "Release"
|
||||||
|
# PROP BASE Intermediate_Dir "Release"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 0
|
||||||
|
# PROP Output_Dir "Release"
|
||||||
|
# PROP Intermediate_Dir "Release"
|
||||||
|
# PROP Ignore_Export_Lib 0
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||||
|
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||||
|
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=link.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib gc.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\gc\boehm"
|
||||||
|
# SUBTRACT LINK32 /pdb:none
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "js2 - Win32 Debug"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 1
|
||||||
|
# PROP BASE Output_Dir "Debug"
|
||||||
|
# PROP BASE Intermediate_Dir "Debug"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 1
|
||||||
|
# PROP Output_Dir "Debug"
|
||||||
|
# PROP Intermediate_Dir "Debug"
|
||||||
|
# PROP Ignore_Export_Lib 0
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||||
|
# ADD CPP /nologo /W3 /Gm /GR /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "DEBUG" /FR /YX /FD /GZ /c
|
||||||
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "_DEBUG" /d "DEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# SUBTRACT BSC32 /nologo
|
||||||
|
LINK32=link.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib gc.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\gc\boehm"
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "js2 - Win32 Partial Debug"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 1
|
||||||
|
# PROP BASE Output_Dir "js2___Win32_Partial_Debug"
|
||||||
|
# PROP BASE Intermediate_Dir "js2___Win32_Partial_Debug"
|
||||||
|
# PROP BASE Ignore_Export_Lib 0
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 1
|
||||||
|
# PROP Output_Dir "js2___Win32_Partial_Debug"
|
||||||
|
# PROP Intermediate_Dir "js2___Win32_Partial_Debug"
|
||||||
|
# PROP Ignore_Export_Lib 0
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "DEBUG" /FR /YX /FD /GZ /c
|
||||||
|
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c
|
||||||
|
# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "DEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "_DEBUG" /d "DEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# SUBTRACT BASE BSC32 /nologo
|
||||||
|
# SUBTRACT BSC32 /nologo
|
||||||
|
LINK32=link.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib gc.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\gc\boehm"
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib gc.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\gc\boehm"
|
||||||
|
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
|
# Begin Target
|
||||||
|
|
||||||
|
# Name "js2 - Win32 Release"
|
||||||
|
# Name "js2 - Win32 Debug"
|
||||||
|
# Name "js2 - Win32 Partial Debug"
|
||||||
|
# Begin Group "Source Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\debugger.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\hash.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\icodegenerator.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\interpreter.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\js2.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\jsmath.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\jstypes.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\numerics.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\parser.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\utilities.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\vmtypes.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\world.cpp
|
||||||
|
# End Source File
|
||||||
|
# End Group
|
||||||
|
# Begin Group "Header Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\cpucfg.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\gc_allocator.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\hash.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\icode.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\icodegenerator.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\interpreter.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\jsclasses.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\jsmath.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\jstypes.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\numerics.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\parser.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\systemtypes.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\utilities.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\vmtypes.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\world.h
|
||||||
|
# End Source File
|
||||||
|
# End Group
|
||||||
|
# Begin Group "Resource Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||||
|
# End Group
|
||||||
|
# End Target
|
||||||
|
# End Project
|
||||||
29
mozilla/js/js2/winbuild/js2.dsw
Normal file
29
mozilla/js/js2/winbuild/js2.dsw
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||||
|
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
Project: "js2"=.\js2.dsp - Package Owner=<4>
|
||||||
|
|
||||||
|
Package=<5>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
Package=<4>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
Global:
|
||||||
|
|
||||||
|
Package=<5>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
Package=<3>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
39
mozilla/js/js2/world.cpp
Normal file
39
mozilla/js/js2/world.cpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// -*- 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.
|
||||||
|
|
||||||
|
#include "world.h"
|
||||||
|
namespace JS = 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.
|
||||||
|
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);
|
||||||
|
}
|
||||||
73
mozilla/js/js2/world.h
Normal file
73
mozilla/js/js2/world.h
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
// -*- 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.
|
||||||
|
|
||||||
|
#ifndef world_h
|
||||||
|
#define world_h
|
||||||
|
|
||||||
|
#include "utilities.h"
|
||||||
|
#include "hash.h"
|
||||||
|
#include "parser.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.
|
||||||
|
|
||||||
|
class StringAtom: public String {
|
||||||
|
public:
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
HT ht;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StringAtom &operator[](const String &s);
|
||||||
|
|
||||||
|
StringAtom &operator[](const char *s)
|
||||||
|
{
|
||||||
|
return operator[](widenCString(s));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class World {
|
||||||
|
public:
|
||||||
|
StringAtomTable identifiers;
|
||||||
|
|
||||||
|
World();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
44
mozilla/js2/src/Makefile
Normal file
44
mozilla/js2/src/Makefile
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
STLPORT = /usr/local/include/stlport
|
||||||
|
|
||||||
|
CC = gcc
|
||||||
|
CFLAGS = -g -ggdb -DDEBUG -DXP_UNIX -Wall -W -Wpointer-arith \
|
||||||
|
-Wbad-function-cast -Wstrict-prototypes -Wmissing-prototypes \
|
||||||
|
-Wno-non-virtual-dtor -I$(STLPORT)
|
||||||
|
|
||||||
|
objs = hash.o \
|
||||||
|
icodegenerator.o \
|
||||||
|
interpreter.o \
|
||||||
|
js2.o \
|
||||||
|
jsmath.o \
|
||||||
|
jstypes.o \
|
||||||
|
numerics.o \
|
||||||
|
parser.o \
|
||||||
|
utilities.o \
|
||||||
|
world.o \
|
||||||
|
vmtypes.o \
|
||||||
|
debugger.o
|
||||||
|
|
||||||
|
gc_path = ../../gc/boehm/
|
||||||
|
|
||||||
|
libs = gc.a -lstdc++ -lm
|
||||||
|
|
||||||
|
%.o : %.cpp
|
||||||
|
$(CC) -c $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
js2: $(objs) gc.a
|
||||||
|
$(CC) -o $@ -ggdb $(objs) $(libs)
|
||||||
|
|
||||||
|
gc.a:
|
||||||
|
(cd $(gc_path) ; ln -f -s Makefile.unix Makefile ; make gc.a)
|
||||||
|
ln -f -s $(gc_path)gc.a ./gc.a
|
||||||
|
|
||||||
|
gctest: gc_allocator.o
|
||||||
|
$(CC) -o $@ -ggdb $^ $(libs)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(objs)
|
||||||
|
|
||||||
|
depend:
|
||||||
|
gcc -MM *.cpp > dependencies
|
||||||
|
|
||||||
|
include dependencies
|
||||||
191
mozilla/js2/src/cpucfg.h
Normal file
191
mozilla/js2/src/cpucfg.h
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
/* -*- 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 Mozilla Communicator client code, released
|
||||||
|
* March 31, 1998.
|
||||||
|
*
|
||||||
|
* 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 cpucfg_h
|
||||||
|
#define cpucfg_h
|
||||||
|
|
||||||
|
#define JS_HAVE_LONG_LONG
|
||||||
|
|
||||||
|
#ifdef XP_MAC
|
||||||
|
#undef IS_LITTLE_ENDIAN
|
||||||
|
#define IS_BIG_ENDIAN 1
|
||||||
|
|
||||||
|
#define JS_BYTES_PER_BYTE 1L
|
||||||
|
#define JS_BYTES_PER_SHORT 2L
|
||||||
|
#define JS_BYTES_PER_INT 4L
|
||||||
|
#define JS_BYTES_PER_INT64 8L
|
||||||
|
#define JS_BYTES_PER_LONG 4L
|
||||||
|
#define JS_BYTES_PER_FLOAT 4L
|
||||||
|
#define JS_BYTES_PER_DOUBLE 8L
|
||||||
|
#define JS_BYTES_PER_WORD 4L
|
||||||
|
#define JS_BYTES_PER_DWORD 8L
|
||||||
|
|
||||||
|
#define JS_BITS_PER_BYTE 8L
|
||||||
|
#define JS_BITS_PER_SHORT 16L
|
||||||
|
#define JS_BITS_PER_INT 32L
|
||||||
|
#define JS_BITS_PER_INT64 64L
|
||||||
|
#define JS_BITS_PER_LONG 32L
|
||||||
|
#define JS_BITS_PER_FLOAT 32L
|
||||||
|
#define JS_BITS_PER_DOUBLE 64L
|
||||||
|
#define JS_BITS_PER_WORD 32L
|
||||||
|
|
||||||
|
#define JS_BITS_PER_BYTE_LOG2 3L
|
||||||
|
#define JS_BITS_PER_SHORT_LOG2 4L
|
||||||
|
#define JS_BITS_PER_INT_LOG2 5L
|
||||||
|
#define JS_BITS_PER_INT64_LOG2 6L
|
||||||
|
#define JS_BITS_PER_LONG_LOG2 5L
|
||||||
|
#define JS_BITS_PER_FLOAT_LOG2 5L
|
||||||
|
#define JS_BITS_PER_DOUBLE_LOG2 6L
|
||||||
|
#define JS_BITS_PER_WORD_LOG2 5L
|
||||||
|
|
||||||
|
#define JS_ALIGN_OF_SHORT 2L
|
||||||
|
#define JS_ALIGN_OF_INT 4L
|
||||||
|
#define JS_ALIGN_OF_LONG 4L
|
||||||
|
#define JS_ALIGN_OF_INT64 2L
|
||||||
|
#define JS_ALIGN_OF_FLOAT 4L
|
||||||
|
#define JS_ALIGN_OF_DOUBLE 4L
|
||||||
|
#define JS_ALIGN_OF_POINTER 4L
|
||||||
|
#define JS_ALIGN_OF_WORD 4L
|
||||||
|
|
||||||
|
#define JS_BYTES_PER_WORD_LOG2 2L
|
||||||
|
#define JS_BYTES_PER_DWORD_LOG2 3L
|
||||||
|
#define PR_WORDS_PER_DWORD_LOG2 1L
|
||||||
|
|
||||||
|
#elif defined(XP_PC)
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define IS_LITTLE_ENDIAN 1
|
||||||
|
#undef IS_BIG_ENDIAN
|
||||||
|
|
||||||
|
#define JS_BYTES_PER_BYTE 1L
|
||||||
|
#define JS_BYTES_PER_SHORT 2L
|
||||||
|
#define JS_BYTES_PER_INT 4L
|
||||||
|
#define JS_BYTES_PER_INT64 8L
|
||||||
|
#define JS_BYTES_PER_LONG 4L
|
||||||
|
#define JS_BYTES_PER_FLOAT 4L
|
||||||
|
#define JS_BYTES_PER_DOUBLE 8L
|
||||||
|
#define JS_BYTES_PER_WORD 4L
|
||||||
|
#define JS_BYTES_PER_DWORD 8L
|
||||||
|
|
||||||
|
#define JS_BITS_PER_BYTE 8L
|
||||||
|
#define JS_BITS_PER_SHORT 16L
|
||||||
|
#define JS_BITS_PER_INT 32L
|
||||||
|
#define JS_BITS_PER_INT64 64L
|
||||||
|
#define JS_BITS_PER_LONG 32L
|
||||||
|
#define JS_BITS_PER_FLOAT 32L
|
||||||
|
#define JS_BITS_PER_DOUBLE 64L
|
||||||
|
#define JS_BITS_PER_WORD 32L
|
||||||
|
|
||||||
|
#define JS_BITS_PER_BYTE_LOG2 3L
|
||||||
|
#define JS_BITS_PER_SHORT_LOG2 4L
|
||||||
|
#define JS_BITS_PER_INT_LOG2 5L
|
||||||
|
#define JS_BITS_PER_INT64_LOG2 6L
|
||||||
|
#define JS_BITS_PER_LONG_LOG2 5L
|
||||||
|
#define JS_BITS_PER_FLOAT_LOG2 5L
|
||||||
|
#define JS_BITS_PER_DOUBLE_LOG2 6L
|
||||||
|
#define JS_BITS_PER_WORD_LOG2 5L
|
||||||
|
|
||||||
|
#define JS_ALIGN_OF_SHORT 2L
|
||||||
|
#define JS_ALIGN_OF_INT 4L
|
||||||
|
#define JS_ALIGN_OF_LONG 4L
|
||||||
|
#define JS_ALIGN_OF_INT64 8L
|
||||||
|
#define JS_ALIGN_OF_FLOAT 4L
|
||||||
|
#define JS_ALIGN_OF_DOUBLE 4L
|
||||||
|
#define JS_ALIGN_OF_POINTER 4L
|
||||||
|
#define JS_ALIGN_OF_WORD 4L
|
||||||
|
|
||||||
|
#define JS_BYTES_PER_WORD_LOG2 2L
|
||||||
|
#define JS_BYTES_PER_DWORD_LOG2 3L
|
||||||
|
#define PR_WORDS_PER_DWORD_LOG2 1L
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
#if defined(_WINDOWS) && !defined(_WIN32) /* WIN16 */
|
||||||
|
#define IS_LITTLE_ENDIAN 1
|
||||||
|
#undef IS_BIG_ENDIAN
|
||||||
|
|
||||||
|
#define JS_BYTES_PER_BYTE 1L
|
||||||
|
#define JS_BYTES_PER_SHORT 2L
|
||||||
|
#define JS_BYTES_PER_INT 2L
|
||||||
|
#define JS_BYTES_PER_INT64 8L
|
||||||
|
#define JS_BYTES_PER_LONG 4L
|
||||||
|
#define JS_BYTES_PER_FLOAT 4L
|
||||||
|
#define JS_BYTES_PER_DOUBLE 8L
|
||||||
|
#define JS_BYTES_PER_WORD 4L
|
||||||
|
#define JS_BYTES_PER_DWORD 8L
|
||||||
|
|
||||||
|
#define JS_BITS_PER_BYTE 8L
|
||||||
|
#define JS_BITS_PER_SHORT 16L
|
||||||
|
#define JS_BITS_PER_INT 16L
|
||||||
|
#define JS_BITS_PER_INT64 64L
|
||||||
|
#define JS_BITS_PER_LONG 32L
|
||||||
|
#define JS_BITS_PER_FLOAT 32L
|
||||||
|
#define JS_BITS_PER_DOUBLE 64L
|
||||||
|
#define JS_BITS_PER_WORD 32L
|
||||||
|
|
||||||
|
#define JS_BITS_PER_BYTE_LOG2 3L
|
||||||
|
#define JS_BITS_PER_SHORT_LOG2 4L
|
||||||
|
#define JS_BITS_PER_INT_LOG2 4L
|
||||||
|
#define JS_BITS_PER_INT64_LOG2 6L
|
||||||
|
#define JS_BITS_PER_LONG_LOG2 5L
|
||||||
|
#define JS_BITS_PER_FLOAT_LOG2 5L
|
||||||
|
#define JS_BITS_PER_DOUBLE_LOG2 6L
|
||||||
|
#define JS_BITS_PER_WORD_LOG2 5L
|
||||||
|
|
||||||
|
#define JS_ALIGN_OF_SHORT 2L
|
||||||
|
#define JS_ALIGN_OF_INT 2L
|
||||||
|
#define JS_ALIGN_OF_LONG 2L
|
||||||
|
#define JS_ALIGN_OF_INT64 2L
|
||||||
|
#define JS_ALIGN_OF_FLOAT 2L
|
||||||
|
#define JS_ALIGN_OF_DOUBLE 2L
|
||||||
|
#define JS_ALIGN_OF_POINTER 2L
|
||||||
|
#define JS_ALIGN_OF_WORD 2L
|
||||||
|
|
||||||
|
#define JS_BYTES_PER_WORD_LOG2 2L
|
||||||
|
#define JS_BYTES_PER_DWORD_LOG2 3L
|
||||||
|
#define PR_WORDS_PER_DWORD_LOG2 1L
|
||||||
|
#endif /* defined(_WINDOWS) && !defined(_WIN32) */
|
||||||
|
|
||||||
|
#elif defined(XP_UNIX) || defined(XP_BEOS)
|
||||||
|
|
||||||
|
#error "This file is supposed to be auto-generated on UNIX platforms, but the"
|
||||||
|
#error "static version for Mac and Windows platforms is being used."
|
||||||
|
#error "Something's probably wrong with paths/headers/dependencies/Makefiles."
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#error "Must define one of XP_MAC, XP_PC, or XP_UNIX"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
466
mozilla/js2/src/debugger.cpp
Normal file
466
mozilla/js2/src/debugger.cpp
Normal file
@@ -0,0 +1,466 @@
|
|||||||
|
/* -*- 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 "world.h"
|
||||||
|
#include "debugger.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
namespace Debugger {
|
||||||
|
|
||||||
|
using namespace Interpreter;
|
||||||
|
|
||||||
|
/* keep in sync with list in debugger.h */
|
||||||
|
static const char *shell_cmds[][3] = {
|
||||||
|
{"assemble", "", 0},
|
||||||
|
{"ambiguous", "", "Test command for ambiguous command detection"},
|
||||||
|
{"ambiguous2", "", "Test command for ambiguous command detection"},
|
||||||
|
{"continue", "", "Continue execution until complete."},
|
||||||
|
{"dissassemble", "[start_pc] [end_pc]", "Dissassemble entire module, or subset of module."},
|
||||||
|
{"exit", "", 0},
|
||||||
|
{"help", "", "Display this message."},
|
||||||
|
{"istep", "", "Execute the current opcode and stop."},
|
||||||
|
{"let", "", "Set a debugger environment variable."},
|
||||||
|
{"print", "", 0},
|
||||||
|
{"register", "", "(nyi) Show the value of a single register or all registers, or set the value of a single register."},
|
||||||
|
{"step", "", "Execute the current JS statement and stop."},
|
||||||
|
{0, 0} /* sentry */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ShellVariable {
|
||||||
|
TRACE_SOURCE,
|
||||||
|
TRACE_ICODE,
|
||||||
|
VARIABLE_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *shell_vars[][3] = {
|
||||||
|
{"tracesource", "", "(bool) Show JS source while executing."},
|
||||||
|
{"traceicode", " ", "(bool) Show opcodes while executing."},
|
||||||
|
{0, 0} /* sentry */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* return true if str2 starts with/is str1
|
||||||
|
* XXX ignore case */
|
||||||
|
static bool
|
||||||
|
startsWith (const String &str1, const String &str2)
|
||||||
|
{
|
||||||
|
uint n;
|
||||||
|
size_t m = str1.size();
|
||||||
|
|
||||||
|
if (m > str2.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (n = 0; n < m; ++n)
|
||||||
|
if (str1[n] != str2[n])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* locate the best match for |partial| in the command list |list|.
|
||||||
|
* if no matches are found, return |length|, if multiple matches are found,
|
||||||
|
* return |length| plus the number of ambiguous matches
|
||||||
|
*/
|
||||||
|
static uint32
|
||||||
|
matchElement (const String &partial, const char *list[][3], size_t length)
|
||||||
|
{
|
||||||
|
uint32 ambig_matches = 0;
|
||||||
|
uint32 match = length;
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < length ; ++i)
|
||||||
|
{
|
||||||
|
String possibleMatch (widenCString(list[i][0]));
|
||||||
|
if (startsWith(partial, possibleMatch))
|
||||||
|
{
|
||||||
|
if (partial.size() == possibleMatch.size())
|
||||||
|
{
|
||||||
|
/* exact match */
|
||||||
|
ambig_matches = 0;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
else if (match == COMMAND_COUNT) /* no match yet */
|
||||||
|
match = i;
|
||||||
|
else
|
||||||
|
++ambig_matches; /* something already matched,
|
||||||
|
* ambiguous command */
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ambig_matches == 0)
|
||||||
|
return match;
|
||||||
|
else
|
||||||
|
return length + ambig_matches;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
showHelp(Formatter &out)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
out << "JavaScript 2.0 Debugger Help...\n\n";
|
||||||
|
|
||||||
|
for (i = 0; shell_cmds[i][0] != 0; i++)
|
||||||
|
{
|
||||||
|
out << "Command : " << shell_cmds[i][0] << " " <<
|
||||||
|
shell_cmds[i][1] << "\n";
|
||||||
|
|
||||||
|
if (shell_cmds[i][2])
|
||||||
|
out << "Help : " << shell_cmds[i][2] << "\n";
|
||||||
|
else
|
||||||
|
out << "Help : (probably) Not Implemented.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32
|
||||||
|
getClosestSourcePosForPC (Context *cx, InstructionIterator pc)
|
||||||
|
{
|
||||||
|
ICodeModule *iCode = cx->getICode();
|
||||||
|
|
||||||
|
if (iCode->mInstructionMap->begin() == iCode->mInstructionMap->end())
|
||||||
|
return NotABanana;
|
||||||
|
/*NOT_REACHED ("Instruction map is empty, waah.");*/
|
||||||
|
|
||||||
|
InstructionMap::iterator pos_iter =
|
||||||
|
iCode->mInstructionMap->upper_bound (pc - iCode->its_iCode->begin());
|
||||||
|
if (pos_iter != iCode->mInstructionMap->begin())
|
||||||
|
--pos_iter;
|
||||||
|
|
||||||
|
return pos_iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Shell::showSourceAtPC (Context *cx, InstructionIterator pc)
|
||||||
|
{
|
||||||
|
if (!mResolveFileCallback)
|
||||||
|
{
|
||||||
|
mErr << "Source not available (Debugger was improperly initialized.)\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ICodeModule *iCode = cx->getICode();
|
||||||
|
|
||||||
|
String fn = iCode->getFileName();
|
||||||
|
const Reader *reader = mResolveFileCallback(fn);
|
||||||
|
if (!reader)
|
||||||
|
{
|
||||||
|
mErr << "Source not available.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 pos = getClosestSourcePosForPC(cx, pc);
|
||||||
|
if (pos == NotABanana)
|
||||||
|
{
|
||||||
|
mErr << "Map is empty, cannot display source.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 lineNum = reader->posToLineNum (pos);
|
||||||
|
const char16 *lineBegin, *lineEnd;
|
||||||
|
|
||||||
|
uint32 lineStartPos = reader->getLine (lineNum, lineBegin, lineEnd);
|
||||||
|
String sourceLine (lineBegin, lineEnd);
|
||||||
|
|
||||||
|
mOut << fn << ":" << lineNum << " " << sourceLine << "\n";
|
||||||
|
|
||||||
|
uint padding = fn.length() + (uint32)(lineNum / 10) + 3;
|
||||||
|
uint i;
|
||||||
|
|
||||||
|
for (i = 0; i < padding; i++)
|
||||||
|
mOut << " ";
|
||||||
|
|
||||||
|
padding = (pos - lineStartPos);
|
||||||
|
for (i = 0; i < padding; i++)
|
||||||
|
mOut << ".";
|
||||||
|
|
||||||
|
mOut << "^\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Shell::showOpAtPC(Context* cx, InstructionIterator pc)
|
||||||
|
{
|
||||||
|
ICodeModule *iCode = cx->getICode();
|
||||||
|
|
||||||
|
if ((pc < iCode->its_iCode->begin()) ||
|
||||||
|
(pc >= iCode->its_iCode->end()))
|
||||||
|
{
|
||||||
|
mErr << "PC Out Of Range.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValues ®isters = cx->getRegisters();
|
||||||
|
|
||||||
|
printFormat(mOut, "trace [%02u:%04u]: ",
|
||||||
|
iCode->mID, (pc - iCode->its_iCode->begin()));
|
||||||
|
Instruction* i = *pc;
|
||||||
|
stdOut << *i;
|
||||||
|
if (i->op() != BRANCH && i->count() > 0) {
|
||||||
|
mOut << " [";
|
||||||
|
i->printOperands(stdOut, registers);
|
||||||
|
mOut << "]\n";
|
||||||
|
} else {
|
||||||
|
mOut << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Shell::listen(Context* cx, Context::Event event)
|
||||||
|
{
|
||||||
|
InstructionIterator pc = cx->getPC();
|
||||||
|
|
||||||
|
if (mTraceSource)
|
||||||
|
showSourceAtPC (cx, pc);
|
||||||
|
if (mTraceICode)
|
||||||
|
showOpAtPC (cx, pc);
|
||||||
|
|
||||||
|
if (!(mStopMask & event))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((mLastCommand == STEP) && (mLastICodeID == cx->getICode()->mID) &&
|
||||||
|
(mLastSourcePos == getClosestSourcePosForPC (cx, cx->getPC())))
|
||||||
|
/* we're in source-step mode, and the source position hasn't
|
||||||
|
* changed yet */
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!mTraceSource && !mTraceICode)
|
||||||
|
showSourceAtPC (cx, pc);
|
||||||
|
|
||||||
|
static String lastLine(widenCString("help\n"));
|
||||||
|
String line;
|
||||||
|
LineReader reader(mIn);
|
||||||
|
|
||||||
|
do {
|
||||||
|
stdOut << "jsd";
|
||||||
|
if (mLastCommand != COMMAND_COUNT)
|
||||||
|
stdOut << " (" << shell_cmds[mLastCommand][0] << ") ";
|
||||||
|
stdOut << "> ";
|
||||||
|
|
||||||
|
reader.readLine(line);
|
||||||
|
|
||||||
|
if (line[0] == uni::lf)
|
||||||
|
line = lastLine;
|
||||||
|
else
|
||||||
|
lastLine = line;
|
||||||
|
|
||||||
|
} while (doCommand(cx, line));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lex and execute the debugger command in |source|, return true if the
|
||||||
|
* command does not require the script being debugged to continue (eg, ask
|
||||||
|
* for more debugger input.)
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
Shell::doCommand (Interpreter::Context *cx, const String &source)
|
||||||
|
{
|
||||||
|
Lexer lex (mWorld, source, widenCString("debugger console"), 0);
|
||||||
|
const String *cmd;
|
||||||
|
uint32 match;
|
||||||
|
bool rv = true;
|
||||||
|
|
||||||
|
const Token &t = lex.get(true);
|
||||||
|
|
||||||
|
if (t.hasKind(Token::identifier))
|
||||||
|
cmd = &(t.getIdentifier());
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mErr << "you idiot.\n";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
match = matchElement (*cmd, shell_cmds, (size_t)COMMAND_COUNT);
|
||||||
|
|
||||||
|
if (match <= (uint32)COMMAND_COUNT)
|
||||||
|
{
|
||||||
|
switch ((ShellCommand)match)
|
||||||
|
{
|
||||||
|
case COMMAND_COUNT:
|
||||||
|
mErr << "Unknown command '" << *cmd << "'.\n";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AMBIGUOUS:
|
||||||
|
case AMBIGUOUS2:
|
||||||
|
mErr << "I pity the foogoo.\n";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONTINUE:
|
||||||
|
mStopMask &= (Context::EV_ALL ^ Context::EV_STEP);
|
||||||
|
rv = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DISSASSEMBLE:
|
||||||
|
mOut << *cx->getICode();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HELP:
|
||||||
|
showHelp (mOut);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PRINT:
|
||||||
|
doPrint (cx, lex);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STEP:
|
||||||
|
mStopMask |= Context::EV_STEP;
|
||||||
|
rv = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LET:
|
||||||
|
doSetVariable (lex);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
mErr << "Input '" << *cmd << "' matched unimplemented " <<
|
||||||
|
"command '" << shell_cmds[match][0] << "'.\n";
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mLastSourcePos = getClosestSourcePosForPC (cx, cx->getPC());
|
||||||
|
mLastICodeID = cx->getICode()->mID;
|
||||||
|
mLastCommand = (ShellCommand)match;
|
||||||
|
|
||||||
|
} else
|
||||||
|
mErr << "Ambiguous command '" << *cmd << "', " <<
|
||||||
|
(match - (uint32)COMMAND_COUNT + 1) << " similar commands.\n";
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Shell::doSetVariable (Lexer &lex)
|
||||||
|
{
|
||||||
|
uint32 match;
|
||||||
|
const String *varname;
|
||||||
|
const Token *t = &(lex.get(true));
|
||||||
|
|
||||||
|
if (t->hasKind(Token::identifier))
|
||||||
|
varname = &(t->getIdentifier());
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mErr << "invalid variable name.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match = matchElement (*varname, shell_vars, (size_t)VARIABLE_COUNT);
|
||||||
|
|
||||||
|
if (match <= (uint32)VARIABLE_COUNT)
|
||||||
|
switch ((ShellVariable)match)
|
||||||
|
{
|
||||||
|
case VARIABLE_COUNT:
|
||||||
|
mErr << "Unknown variable '" << *varname << "'.\n";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TRACE_SOURCE:
|
||||||
|
t = &(lex.get(true));
|
||||||
|
if (t->hasKind(Token::assignment))
|
||||||
|
t = &(lex.get(true)); /* optional = */
|
||||||
|
|
||||||
|
if (t->hasKind(Token::True))
|
||||||
|
mTraceSource = true;
|
||||||
|
else if (t->hasKind(Token::False))
|
||||||
|
mTraceSource = false;
|
||||||
|
else
|
||||||
|
goto badval;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TRACE_ICODE:
|
||||||
|
t = &(lex.get(true));
|
||||||
|
if (t->hasKind(Token::assignment))
|
||||||
|
t = &(lex.get(true)); /* optional = */
|
||||||
|
|
||||||
|
if (t->hasKind(Token::True))
|
||||||
|
mTraceICode = true;
|
||||||
|
else if (t->hasKind(Token::False))
|
||||||
|
mTraceICode = false;
|
||||||
|
else
|
||||||
|
goto badval;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
mErr << "Variable '" << *varname <<
|
||||||
|
"' matched unimplemented variable '" <<
|
||||||
|
shell_vars[match][0] << "'.\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mErr << "Ambiguous variable '" << *varname << "', " <<
|
||||||
|
(match - (uint32)COMMAND_COUNT + 1) << " similar variables.\n";
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
badval:
|
||||||
|
mErr << "Invalid value for variable '" <<
|
||||||
|
shell_vars[(ShellVariable)match][0] << "'\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Shell::doPrint (Context *, Lexer &lex)
|
||||||
|
{
|
||||||
|
const Token *t = &(lex.get(true));
|
||||||
|
|
||||||
|
if (!(t->hasKind(Token::identifier)))
|
||||||
|
{
|
||||||
|
mErr << "Invalid register name.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
const StringAtom *name = &(t->getIdentifier());
|
||||||
|
|
||||||
|
VariableMap::iterator i = ((cx->getICode())->itsVariables)->find(*name);
|
||||||
|
// if (i)
|
||||||
|
mOut << (*i).first << " = " << (*i).second << "\n";
|
||||||
|
// else
|
||||||
|
// mOut << "No " << *name << " defined.\n";
|
||||||
|
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace Debugger */
|
||||||
|
} /* namespace JavaScript */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
163
mozilla/js2/src/debugger.h
Normal file
163
mozilla/js2/src/debugger.h
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
/* -*- 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* this is all vapor, don't take it to serious yet */
|
||||||
|
|
||||||
|
#ifndef debugger_h
|
||||||
|
#define debugger_h
|
||||||
|
|
||||||
|
#include "utilities.h"
|
||||||
|
#include "interpreter.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
namespace Debugger {
|
||||||
|
|
||||||
|
using namespace Interpreter;
|
||||||
|
|
||||||
|
class Shell;
|
||||||
|
|
||||||
|
typedef const Reader *ResolveFileCallback (const String &fileName);
|
||||||
|
typedef bool DebuggerCommandCallback (Shell &debugger, const Lexer &lex);
|
||||||
|
|
||||||
|
class Breakpoint {
|
||||||
|
public:
|
||||||
|
/* representation of a breakpoint */
|
||||||
|
void set();
|
||||||
|
void clear();
|
||||||
|
bool getState();
|
||||||
|
InstructionIterator getPC();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DebuggerCommand
|
||||||
|
{
|
||||||
|
DebuggerCommand(String aName, String aParamDesc, String aShortHelp,
|
||||||
|
String aLongHelp = widenCString("No more help available."),
|
||||||
|
DebuggerCommandCallback *aCommandFunction = 0)
|
||||||
|
: mName(aName), mParamDesc(aParamDesc), mShortHelp(aShortHelp),
|
||||||
|
mLongHelp(aLongHelp), mCommandFunction(aCommandFunction) {}
|
||||||
|
|
||||||
|
String mName;
|
||||||
|
String mParamDesc;
|
||||||
|
String mShortHelp;
|
||||||
|
String mLongHelp;
|
||||||
|
DebuggerCommandCallback *mCommandFunction;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* keep in sync with list in debugger.cpp */
|
||||||
|
enum ShellCommand {
|
||||||
|
ASSEMBLE,
|
||||||
|
AMBIGUOUS,
|
||||||
|
AMBIGUOUS2,
|
||||||
|
CONTINUE,
|
||||||
|
DISSASSEMBLE,
|
||||||
|
EXIT,
|
||||||
|
HELP,
|
||||||
|
ISTEP,
|
||||||
|
LET,
|
||||||
|
PRINT,
|
||||||
|
REGISTER,
|
||||||
|
STEP,
|
||||||
|
COMMAND_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
class Shell : public Context::Listener {
|
||||||
|
public:
|
||||||
|
Shell (World &aWorld, FILE *aIn, Formatter &aOut, Formatter &aErr,
|
||||||
|
ResolveFileCallback *aCallback = 0) :
|
||||||
|
mWorld(aWorld), mIn(aIn), mOut(aOut), mErr(aErr),
|
||||||
|
mResolveFileCallback(aCallback), mStopMask(Context::EV_DEBUG),
|
||||||
|
mTraceSource(false), mTraceICode(false), mLastSourcePos(0),
|
||||||
|
mLastICodeID(NotABanana), mLastCommand(COMMAND_COUNT)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Shell ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ResolveFileCallback
|
||||||
|
*setResolveFileCallback (ResolveFileCallback *aCallback)
|
||||||
|
{
|
||||||
|
ResolveFileCallback *rv = mResolveFileCallback;
|
||||||
|
mResolveFileCallback = aCallback;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void listen(Context *context, Context::Event event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* install on a context
|
||||||
|
*/
|
||||||
|
bool attachToContext (Context *aContext)
|
||||||
|
{
|
||||||
|
aContext->addListener (this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* detach an icdebugger from a context
|
||||||
|
*/
|
||||||
|
bool detachFromContext (Context *aContext)
|
||||||
|
{
|
||||||
|
aContext->removeListener (this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *getIStream() { return mIn; }
|
||||||
|
Formatter &getOStream() { return mOut; }
|
||||||
|
Formatter &getEStream() { return mErr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool doCommand (Context *cx, const String &aSource);
|
||||||
|
void doSetVariable (Lexer &lex);
|
||||||
|
void doPrint (Context *cx, Lexer &lex);
|
||||||
|
|
||||||
|
void showOpAtPC(Context* cx, InstructionIterator pc);
|
||||||
|
void showSourceAtPC(Context* cx, InstructionIterator pc);
|
||||||
|
|
||||||
|
World &mWorld;
|
||||||
|
FILE *mIn;
|
||||||
|
Formatter &mOut, &mErr;
|
||||||
|
ResolveFileCallback *mResolveFileCallback;
|
||||||
|
uint32 mStopMask;
|
||||||
|
bool mTraceSource, mTraceICode;
|
||||||
|
uint32 mLastSourcePos, mLastICodeID;
|
||||||
|
ShellCommand mLastCommand;
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace Debugger */
|
||||||
|
} /* namespace JavaScript */
|
||||||
|
|
||||||
|
#endif /* debugger_h */
|
||||||
26
mozilla/js2/src/dependencies
Normal file
26
mozilla/js2/src/dependencies
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
debugger.o: debugger.cpp world.h utilities.h systemtypes.h hash.h \
|
||||||
|
parser.h debugger.h interpreter.h jstypes.h gc_allocator.h vmtypes.h \
|
||||||
|
numerics.h jsclasses.h icode.h icodegenerator.h
|
||||||
|
gc_allocator.o: gc_allocator.cpp gc_allocator.h gc_container.h
|
||||||
|
hash.o: hash.cpp hash.h utilities.h systemtypes.h
|
||||||
|
icodegenerator.o: icodegenerator.cpp numerics.h utilities.h \
|
||||||
|
systemtypes.h world.h hash.h parser.h vmtypes.h jstypes.h \
|
||||||
|
gc_allocator.h jsclasses.h icode.h icodegenerator.h interpreter.h
|
||||||
|
interpreter.o: interpreter.cpp interpreter.h utilities.h systemtypes.h \
|
||||||
|
jstypes.h gc_allocator.h vmtypes.h numerics.h jsclasses.h world.h \
|
||||||
|
hash.h parser.h icode.h icodegenerator.h jsmath.h
|
||||||
|
js2.o: js2.cpp world.h utilities.h systemtypes.h hash.h parser.h \
|
||||||
|
interpreter.h jstypes.h gc_allocator.h vmtypes.h numerics.h \
|
||||||
|
jsclasses.h icode.h icodegenerator.h debugger.h
|
||||||
|
jsmath.o: jsmath.cpp jsmath.h jstypes.h utilities.h systemtypes.h \
|
||||||
|
gc_allocator.h
|
||||||
|
jstypes.o: jstypes.cpp jstypes.h utilities.h systemtypes.h \
|
||||||
|
gc_allocator.h jsclasses.h numerics.h icodegenerator.h parser.h \
|
||||||
|
vmtypes.h world.h hash.h icode.h
|
||||||
|
numerics.o: numerics.cpp numerics.h utilities.h systemtypes.h
|
||||||
|
parser.o: parser.cpp numerics.h utilities.h systemtypes.h parser.h \
|
||||||
|
world.h hash.h
|
||||||
|
utilities.o: utilities.cpp utilities.h systemtypes.h
|
||||||
|
vmtypes.o: vmtypes.cpp utilities.h systemtypes.h vmtypes.h numerics.h \
|
||||||
|
jstypes.h gc_allocator.h jsclasses.h world.h hash.h parser.h icode.h
|
||||||
|
world.o: world.cpp world.h utilities.h systemtypes.h hash.h parser.h
|
||||||
150
mozilla/js2/src/gc_allocator.cpp
Normal file
150
mozilla/js2/src/gc_allocator.cpp
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
// -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; 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) 2000 Netscape Communications Corporation. All
|
||||||
|
// Rights Reserved.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "gc_allocator.h"
|
||||||
|
#include "gc_container.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
namespace JavaScript {
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
typename gc_allocator<T>::pointer
|
||||||
|
gc_allocator<T>::allocate(gc_allocator<T>::size_type n, const void*)
|
||||||
|
{
|
||||||
|
return static_cast<pointer>(GC_malloc(n*sizeof(T)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void gc_allocator<T>::deallocate(gc_allocator<T>::pointer ptr, gc_allocator<T>::size_type)
|
||||||
|
{
|
||||||
|
// this can really be a NO-OP with the GC.
|
||||||
|
// ::GC_free(static_cast<void*>(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// test driver for standalone GC development.
|
||||||
|
|
||||||
|
namespace JS = JavaScript;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void* operator new(std::size_t, const JS::gc_allocator<T>& alloc)
|
||||||
|
{
|
||||||
|
return alloc.allocate(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a C++ class that is garbage collectable, and wants to have its destructor
|
||||||
|
* called when it is finalized.
|
||||||
|
*/
|
||||||
|
class A {
|
||||||
|
public:
|
||||||
|
typedef JS::gc_traits_finalizable<A> traits;
|
||||||
|
typedef JS::gc_allocator<A, traits> allocator;
|
||||||
|
friend struct traits;
|
||||||
|
|
||||||
|
static int instances;
|
||||||
|
|
||||||
|
void* operator new(std::size_t)
|
||||||
|
{
|
||||||
|
return allocator::allocate(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
A()
|
||||||
|
{
|
||||||
|
++instances;
|
||||||
|
std::cout << "A::A() here." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~A()
|
||||||
|
{
|
||||||
|
--instances;
|
||||||
|
std::cout << "A::~A() here." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// void operator delete(void*) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
int A::instances = 0;
|
||||||
|
|
||||||
|
int main(int /* argc */, char* /* argv[] */)
|
||||||
|
{
|
||||||
|
using namespace std;
|
||||||
|
using namespace JS;
|
||||||
|
|
||||||
|
cout << "testing the GC allocator." << endl;
|
||||||
|
|
||||||
|
#ifdef XP_MAC
|
||||||
|
// allocate a string, using the GC, and owned by an auto_ptr, that knows how to correctly destroy the string.
|
||||||
|
typedef gc_container<char>::string char_string;
|
||||||
|
typedef gc_allocator<char_string> char_string_alloc;
|
||||||
|
auto_ptr<char_string, char_string_alloc> ptr(new(char_string_alloc()) char_string("This is a garbage collectable string."));
|
||||||
|
const char_string& str = *ptr;
|
||||||
|
cout << str << endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// question, how can we partially evaluate a template?
|
||||||
|
// can we say, typedef template <class T> vector<typename T>.
|
||||||
|
// typedef vector<int, gc_allocator<int> > int_vector;
|
||||||
|
typedef gc_container<int>::vector int_vector;
|
||||||
|
|
||||||
|
// generate 1000 random values.
|
||||||
|
int_vector values;
|
||||||
|
for (int i = 0; i < 1000; ++i) {
|
||||||
|
int value = rand() % 32767;
|
||||||
|
values.push_back(value);
|
||||||
|
// allocate a random amount of garbage.
|
||||||
|
if (!GC_malloc(static_cast<size_t>(value)))
|
||||||
|
cerr << "GC_malloc failed." << endl;
|
||||||
|
// allocate an object that has a finalizer to call its destructor.
|
||||||
|
A* a = new A();
|
||||||
|
}
|
||||||
|
|
||||||
|
// run a collection.
|
||||||
|
// gc_allocator<void>::collect();
|
||||||
|
GC_gcollect();
|
||||||
|
|
||||||
|
// print out instance count.
|
||||||
|
cout << "A::instances = " << A::instances << endl;
|
||||||
|
|
||||||
|
// sort the values.
|
||||||
|
sort(values.begin(), values.end());
|
||||||
|
|
||||||
|
// print the values.
|
||||||
|
int_vector::iterator iter = values.begin(), last = values.end();
|
||||||
|
cout << *iter++;
|
||||||
|
while (iter < last)
|
||||||
|
cout << ' ' << *iter++;
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
#ifdef XP_MAC
|
||||||
|
// finally, print the string again.
|
||||||
|
cout << str << endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
178
mozilla/js2/src/gc_allocator.h
Normal file
178
mozilla/js2/src/gc_allocator.h
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
// -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; 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) 2000 Netscape Communications Corporation. All
|
||||||
|
// Rights Reserved.
|
||||||
|
|
||||||
|
#ifndef gc_allocator_h
|
||||||
|
#define gc_allocator_h
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#ifndef _WIN32 // Microsoft VC6 bug: standard identifiers should be in std namespace
|
||||||
|
using std::size_t;
|
||||||
|
using std::ptrdiff_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
extern "C" {
|
||||||
|
void* GC_malloc(size_t bytes);
|
||||||
|
void* GC_malloc_atomic(size_t bytes);
|
||||||
|
void GC_free(void* ptr);
|
||||||
|
void GC_gcollect(void);
|
||||||
|
|
||||||
|
typedef void (*GC_finalization_proc) (void* obj, void* client_data);
|
||||||
|
void GC_register_finalizer(void* obj, GC_finalization_proc proc, void* client_data,
|
||||||
|
GC_finalization_proc *old_proc, void* *old_client_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0 && !defined(XP_MAC)
|
||||||
|
// for platforms where GC doesn't exist yet.
|
||||||
|
inline void* GC_malloc(size_t bytes) { return ::operator new(bytes); }
|
||||||
|
inline void* GC_malloc_atomic(size_t bytes) { return ::operator new(bytes); }
|
||||||
|
inline void GC_free(void* ptr) { operator delete(ptr); }
|
||||||
|
inline void GC_gcollect() {}
|
||||||
|
inline void GC_register_finalizer(void* obj, GC_finalization_proc proc, void* client_data,
|
||||||
|
GC_finalization_proc *old_proc, void* *old_client_data) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* General case: memory for type must be allocated as a conservatively
|
||||||
|
* scanned block of memory.
|
||||||
|
*/
|
||||||
|
template <class T> struct gc_traits {
|
||||||
|
static T* allocate(size_t n) { return static_cast<T*>(GC_malloc(n * sizeof(T))); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specializations for blocks of atomic types: the macro define_atomic_type(_type)
|
||||||
|
* specializes gc_traits<T> for types that need not be scanned by the
|
||||||
|
* GC. Implementors are free to define other types as atomic, if they are
|
||||||
|
* guaranteed not to contain pointers.
|
||||||
|
*/
|
||||||
|
#define define_atomic_type(_type) \
|
||||||
|
template <> struct gc_traits<_type> { \
|
||||||
|
static _type* allocate(size_t n) \
|
||||||
|
{ \
|
||||||
|
return static_cast<_type*>(GC_malloc_atomic(n * sizeof(_type))); \
|
||||||
|
} \
|
||||||
|
};
|
||||||
|
|
||||||
|
define_atomic_type(char)
|
||||||
|
define_atomic_type(unsigned char)
|
||||||
|
define_atomic_type(short)
|
||||||
|
define_atomic_type(unsigned short)
|
||||||
|
define_atomic_type(int)
|
||||||
|
define_atomic_type(unsigned int)
|
||||||
|
define_atomic_type(long)
|
||||||
|
define_atomic_type(unsigned long)
|
||||||
|
define_atomic_type(float)
|
||||||
|
define_atomic_type(double)
|
||||||
|
|
||||||
|
#undef define_atomic_type
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traits for classes that need to have their destructor called
|
||||||
|
* when reclaimed by the garbage collector.
|
||||||
|
*/
|
||||||
|
template <class T> struct gc_traits_finalizable {
|
||||||
|
static void finalizer(void* obj, void* client_data)
|
||||||
|
{
|
||||||
|
T* t = static_cast<T*>(obj);
|
||||||
|
size_t n = reinterpret_cast<size_t>(client_data);
|
||||||
|
for (size_t i = 0; i < n; ++i)
|
||||||
|
t[i].~T();
|
||||||
|
}
|
||||||
|
|
||||||
|
static T* allocate(size_t n)
|
||||||
|
{
|
||||||
|
T* t = gc_traits<T>::allocate(n);
|
||||||
|
GC_finalization_proc old_proc; void* old_client_data;
|
||||||
|
GC_register_finalizer(t, &finalizer, reinterpret_cast<void*>(n), &old_proc, &old_client_data);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An allocator that can be used to allocate objects in the garbage collected heap.
|
||||||
|
*/
|
||||||
|
template <class T, class traits = gc_traits<T> > class gc_allocator {
|
||||||
|
public:
|
||||||
|
typedef T value_type;
|
||||||
|
typedef size_t size_type;
|
||||||
|
typedef ptrdiff_t difference_type;
|
||||||
|
typedef T *pointer;
|
||||||
|
typedef const T *const_pointer;
|
||||||
|
typedef T &reference;
|
||||||
|
typedef const T &const_reference;
|
||||||
|
|
||||||
|
gc_allocator() {}
|
||||||
|
template<typename U, typename UTraits> gc_allocator(const gc_allocator<U, UTraits>&) {}
|
||||||
|
// ~gc_allocator() {}
|
||||||
|
|
||||||
|
static pointer address(reference r) { return &r; }
|
||||||
|
static const_pointer address(const_reference r) { return &r; }
|
||||||
|
|
||||||
|
static pointer allocate(size_type n, const void* /* hint */ = 0) { return traits::allocate(n); }
|
||||||
|
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(); }
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(_WIN32)
|
||||||
|
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); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<class U> struct rebind { typedef gc_allocator<U> other; };
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// raw byte allocator used on some platforms (grrr).
|
||||||
|
typedef char _Char[1];
|
||||||
|
static char* _Charalloc(size_type n) { return (char*) rebind<_Char>::other::allocate(n); }
|
||||||
|
|
||||||
|
// funky operator required for calling basic_string<T> constructor (grrr).
|
||||||
|
template<typename U, typename UTraits> int operator==(const gc_allocator<U, UTraits>&) { return 0; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// void* deallocate used on some platforms (grrr).
|
||||||
|
static void deallocate(void*, size_type) {}
|
||||||
|
|
||||||
|
static void collect() { GC_gcollect(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic base class for objects allocated using a gc_allocator. How they are allocated
|
||||||
|
* can be controlled by specializing gc_traits for the specific class.
|
||||||
|
*/
|
||||||
|
template <typename T> class gc_object {
|
||||||
|
public:
|
||||||
|
void* operator new(size_t) { return gc_allocator<T>::allocate(1, 0); }
|
||||||
|
void operator delete(void* /* ptr */) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simpler base class for classes that have no need to specialize allocation behavior.
|
||||||
|
*/
|
||||||
|
class gc_base {
|
||||||
|
public:
|
||||||
|
void* operator new(size_t n) { return GC_malloc(n); }
|
||||||
|
void operator delete(void*) {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* gc_allocator_h */
|
||||||
71
mozilla/js2/src/gc_container.h
Normal file
71
mozilla/js2/src/gc_container.h
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
// -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; 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) 2000 Netscape Communications Corporation. All
|
||||||
|
// Rights Reserved.
|
||||||
|
|
||||||
|
#ifndef gc_container_h
|
||||||
|
#define gc_container_h
|
||||||
|
|
||||||
|
#include "gc_allocator.h"
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define LIST std::list
|
||||||
|
#define VECTOR std::vector
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
// grr, what kind of standard is this?
|
||||||
|
#define STRING basic_string
|
||||||
|
#define CHAR_TRAITS string_char_traits
|
||||||
|
#else
|
||||||
|
#define STRING std::basic_string
|
||||||
|
#define CHAR_TRAITS std::char_traits
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
/**
|
||||||
|
* Rebind some of the basic container types to use a GC_allocator.
|
||||||
|
* What I really want is something more general, something like:
|
||||||
|
* template <typename Container, typename T> class gc_rebind {
|
||||||
|
* typedef typename Container<T, gc_allocator<T> > other;
|
||||||
|
* };
|
||||||
|
* But I can't figure out how to do that with C++ templates.
|
||||||
|
*/
|
||||||
|
template <class T> struct gc_container {
|
||||||
|
typedef typename LIST<T, gc_allocator<T> > list;
|
||||||
|
typedef typename VECTOR<T, gc_allocator<T> > vector;
|
||||||
|
typedef typename STRING<T, CHAR_TRAITS<T>, gc_allocator<T> > string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* But, it's pretty easy to do with macros:
|
||||||
|
*/
|
||||||
|
#define GC_CONTAINER(container, type) container<T, gc_allocator<T> >
|
||||||
|
|
||||||
|
/*
|
||||||
|
// this gives an "unimplemented C++ feature" error using CWPro5.
|
||||||
|
// maybe someday.
|
||||||
|
template <template<class, class> typename Container, typename T>
|
||||||
|
struct gc_rebind {
|
||||||
|
typedef typename Container<T, gc_allocator<T> > container;
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* gc_container_h */
|
||||||
173
mozilla/js2/src/hash.cpp
Normal file
173
mozilla/js2/src/hash.cpp
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
// -*- 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.
|
||||||
|
|
||||||
|
#include "hash.h"
|
||||||
|
#include <new>
|
||||||
|
namespace JS = JavaScript;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Hash Codes
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
// General-purpose null-terminated C string hash function
|
||||||
|
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
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
while (bucket != bucketsEnd) {
|
||||||
|
e = *bucket++;
|
||||||
|
if (e) {
|
||||||
|
backpointer = bucket-1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nextBucket = bucket;
|
||||||
|
}
|
||||||
|
entry = e;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JS::GenericHashTable::GenericHashTable(uint32 nEntriesDefault):
|
||||||
|
nEntries(0)
|
||||||
|
{
|
||||||
|
DEBUG_ONLY(nReferences = 0);
|
||||||
|
|
||||||
|
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 JS::GenericHashTable::recomputeMinMaxNEntries(uint lgNBuckets)
|
||||||
|
{
|
||||||
|
uint32 nBuckets = JS_BIT(lgNBuckets);
|
||||||
|
shift = 32 - lgNBuckets;
|
||||||
|
maxNEntries = nBuckets; // Maximum ratio is 100%
|
||||||
|
minNEntries = lgNBuckets <= defaultLgNBuckets ? 0 : 3*(nBuckets>>3); // Minimum ratio is 37.5%
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Rehash the table. This method cannot throw out-of-memory exceptions, so it is
|
||||||
|
// safe to call from a destructor.
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
373
mozilla/js2/src/hash.h
Normal file
373
mozilla/js2/src/hash.h
Normal file
@@ -0,0 +1,373 @@
|
|||||||
|
// -*- 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.
|
||||||
|
|
||||||
|
#ifndef hash_h
|
||||||
|
#define hash_h
|
||||||
|
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Hash Codes
|
||||||
|
//
|
||||||
|
|
||||||
|
typedef uint32 HashNumber;
|
||||||
|
|
||||||
|
HashNumber hashString(const char *s);
|
||||||
|
HashNumber hashString(const String &s);
|
||||||
|
|
||||||
|
|
||||||
|
template<class Key>
|
||||||
|
struct Hash {
|
||||||
|
HashNumber operator()(Key key) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Key>
|
||||||
|
inline HashNumber Hash<Key>::operator()(Key key) const
|
||||||
|
{
|
||||||
|
return hashString(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const HashNumber goldenRatio = 0x9E3779B9U;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Private
|
||||||
|
//
|
||||||
|
|
||||||
|
// Base class for user-defined hash entries.
|
||||||
|
// private
|
||||||
|
class GenericHashEntry {
|
||||||
|
public:
|
||||||
|
GenericHashEntry *next; // Link to next entry in the same bucket
|
||||||
|
const HashNumber keyHash; // This entry's hash value
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit GenericHashEntry(HashNumber keyHash): next(0), keyHash(keyHash) {}
|
||||||
|
|
||||||
|
friend class GenericHashTable;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// private
|
||||||
|
class GenericHashTableIterator;
|
||||||
|
class GenericHashTable {
|
||||||
|
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
|
||||||
|
uint32 nEntries; // Number of entries in table
|
||||||
|
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:
|
||||||
|
uint32 nReferences; // Number of iterators and references currently pointing to this hash table
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit GenericHashTable(uint32 nEntriesDefault);
|
||||||
|
~GenericHashTable() {
|
||||||
|
#ifndef _WIN32
|
||||||
|
ASSERT(nReferences == 0);
|
||||||
|
#endif
|
||||||
|
delete[] buckets;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recomputeMinMaxNEntries(uint lgNBuckets);
|
||||||
|
void rehash();
|
||||||
|
void maybeGrow() {if (nEntries > maxNEntries) rehash();}
|
||||||
|
void maybeShrink() {if (nEntries < minNEntries) rehash();}
|
||||||
|
|
||||||
|
friend class GenericHashTableIterator;
|
||||||
|
|
||||||
|
typedef GenericHashTableIterator Iterator;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This ought to be GenericHashTable::Iterator, but this doesn't work due to a
|
||||||
|
// Microsoft VC6 bug.
|
||||||
|
class GenericHashTableIterator {
|
||||||
|
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
|
||||||
|
public:
|
||||||
|
explicit GenericHashTableIterator(GenericHashTable &ht);
|
||||||
|
~GenericHashTableIterator() {ht.maybeShrink(); DEBUG_ONLY(--ht.nReferences);}
|
||||||
|
|
||||||
|
operator bool() const {return entry != 0;} // Return true if there are entries left.
|
||||||
|
GenericHashTableIterator &operator++();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Hash Tables
|
||||||
|
//
|
||||||
|
|
||||||
|
template<class Data, class Key, class H = Hash<Key> >
|
||||||
|
class HashTable: private GenericHashTable {
|
||||||
|
H hasher; // Hash function
|
||||||
|
|
||||||
|
struct Entry: public GenericHashEntry {
|
||||||
|
Data data;
|
||||||
|
|
||||||
|
Entry(HashNumber keyHash, Key key): GenericHashEntry(keyHash), data(key) {}
|
||||||
|
template<class Value>
|
||||||
|
Entry(HashNumber keyHash, Key key, Value value): GenericHashEntry(keyHash), data(key, value) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
class Reference {
|
||||||
|
#ifdef _WIN32 // Microsoft VC6 bug: friend declarations to inner classes don't work
|
||||||
|
public:
|
||||||
|
#endif
|
||||||
|
Entry *entry; // Current entry; nil if done
|
||||||
|
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
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
#ifndef _WIN32
|
||||||
|
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
|
||||||
|
Reference(HashTable &ht, Key key): keyHash(ht.hasher(key)) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
Reference::ht = &ht;
|
||||||
|
++ht.nReferences;
|
||||||
|
#endif
|
||||||
|
HashNumber kh = keyHash;
|
||||||
|
HashNumber h = kh*goldenRatio >> ht.shift;
|
||||||
|
GenericHashEntry **bp = ht.buckets + h;
|
||||||
|
Entry *e;
|
||||||
|
|
||||||
|
while ((e = static_cast<Entry *>(*bp)) != 0 && !(e->keyHash == kh && e->data == key))
|
||||||
|
bp = &e->next;
|
||||||
|
entry = e;
|
||||||
|
backpointer = bp;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
private:
|
||||||
|
Reference(const Reference&); // No copy constructor
|
||||||
|
void operator=(const Reference&); // No assignment operator
|
||||||
|
public:
|
||||||
|
#if defined(DEBUG) && !defined(_WIN32)
|
||||||
|
~Reference() {if (ht) --ht->nReferences;}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
operator bool() const {return entry != 0;} // Return true if an entry was found.
|
||||||
|
Data &operator*() const {ASSERT(entry); return entry->data;} // Return the data of the entry that was found.
|
||||||
|
|
||||||
|
friend class HashTable;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Iterator: public GenericHashTableIterator {
|
||||||
|
public:
|
||||||
|
explicit Iterator(HashTable &ht): GenericHashTableIterator(ht) {}
|
||||||
|
private:
|
||||||
|
Iterator(const Iterator&); // No copy constructor
|
||||||
|
void operator=(const Iterator&); // No assignment operator
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Go to next entry.
|
||||||
|
Iterator &operator++() {return *static_cast<Iterator*>(&GenericHashTableIterator::operator++());}
|
||||||
|
Data &operator*() const {ASSERT(entry); return static_cast<Entry *>(entry)->data;} // Return current entry's data.
|
||||||
|
void erase();
|
||||||
|
};
|
||||||
|
|
||||||
|
HashTable(uint32 nEntriesDefault = 0, const H &hasher = H()): GenericHashTable(nEntriesDefault), hasher(hasher) {}
|
||||||
|
~HashTable();
|
||||||
|
|
||||||
|
template<class Value> Data &insert(Reference &r, Key key, Value value);
|
||||||
|
Data &insert(Reference &r, Key key);
|
||||||
|
Data &insert(Key key);
|
||||||
|
void erase(Reference &r);
|
||||||
|
void erase(Key key);
|
||||||
|
Data *operator[](Key key);
|
||||||
|
|
||||||
|
friend class Reference;
|
||||||
|
friend class Iterator;
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
template<class Value> Data &insert(Key key, Value value);
|
||||||
|
#else // Microsoft VC6 bug: VC6 doesn't allow this to be defined outside the class
|
||||||
|
template<class Value> Data &insert(Key key, Value value) {
|
||||||
|
Reference r(*this, key);
|
||||||
|
if (r)
|
||||||
|
return *r = value;
|
||||||
|
else
|
||||||
|
return insert(r, key, value);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Implementation
|
||||||
|
//
|
||||||
|
|
||||||
|
template<class Data, class Key, class H>
|
||||||
|
HashTable<Data, Key, H>::~HashTable()
|
||||||
|
{
|
||||||
|
GenericHashEntry **be = bucketsEnd;
|
||||||
|
for (GenericHashEntry **b = buckets; b != be; b++) {
|
||||||
|
Entry *e = static_cast<Entry *>(*b);
|
||||||
|
while (e) {
|
||||||
|
Entry *next = static_cast<Entry *>(e->next);
|
||||||
|
delete e;
|
||||||
|
e = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
template<class Data, class Key, class H>
|
||||||
|
HashTable<Data, Key, H>::Reference::Reference(HashTable &ht, Key key):
|
||||||
|
keyHash(ht.hasher(key))
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
Reference::ht = &ht;
|
||||||
|
++ht.nReferences;
|
||||||
|
#endif
|
||||||
|
HashNumber kh = keyHash;
|
||||||
|
HashNumber h = kh*goldenRatio >> ht.shift;
|
||||||
|
GenericHashEntry **bp = ht.buckets + h;
|
||||||
|
Entry *e;
|
||||||
|
|
||||||
|
while ((e = static_cast<Entry *>(*bp)) != 0 && !(e->keyHash == kh && e->data == key))
|
||||||
|
bp = &e->next;
|
||||||
|
entry = e;
|
||||||
|
backpointer = bp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Insert the given key/value pair into the hash table. Reference must
|
||||||
|
// be the result of an unsuccessful search for that key in the table.
|
||||||
|
// The reference is not valid after this method is called.
|
||||||
|
// Return a reference to the new entry's value.
|
||||||
|
template<class Data, class Key, class H> template<class Value>
|
||||||
|
inline Data &HashTable<Data, Key, H>::insert(Reference &r, Key key, Value value)
|
||||||
|
{
|
||||||
|
ASSERT(r.ht == this && !r.entry);
|
||||||
|
Entry *e = new Entry(r.keyHash, key, value);
|
||||||
|
*r.backpointer = e;
|
||||||
|
++nEntries;
|
||||||
|
maybeGrow();
|
||||||
|
#ifdef DEBUG
|
||||||
|
--r.ht->nReferences;
|
||||||
|
r.ht = 0;
|
||||||
|
#endif
|
||||||
|
return e->data;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Same as above but without a Value argument.
|
||||||
|
template<class Data, class Key, class H>
|
||||||
|
inline Data &HashTable<Data, Key, H>::insert(Reference &r, Key key)
|
||||||
|
{
|
||||||
|
ASSERT(r.ht == this && !r.entry);
|
||||||
|
Entry *e = new Entry(r.keyHash, key);
|
||||||
|
*r.backpointer = e;
|
||||||
|
++nEntries;
|
||||||
|
maybeGrow();
|
||||||
|
#ifdef DEBUG
|
||||||
|
--r.ht->nReferences;
|
||||||
|
r.ht = 0;
|
||||||
|
#endif
|
||||||
|
return e->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Insert the given key/value pair into the hash table. If an entry with a
|
||||||
|
// matching key already exists, replace that entry's value.
|
||||||
|
// Return a reference to the new entry's value.
|
||||||
|
#ifndef _WIN32 // Microsoft VC6 bug: VC6 doesn't allow this to be defined outside the class
|
||||||
|
template<class Data, class Key, class H> template<class Value>
|
||||||
|
Data &HashTable<Data, Key, H>::insert(Key key, Value value)
|
||||||
|
{
|
||||||
|
Reference r(*this, key);
|
||||||
|
if (r)
|
||||||
|
return *r = value;
|
||||||
|
else
|
||||||
|
return insert(r, key, value);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Same as above but without a Value argument.
|
||||||
|
template<class Data, class Key, class H>
|
||||||
|
Data &HashTable<Data, Key, H>::insert(Key key)
|
||||||
|
{
|
||||||
|
Reference r(*this, key);
|
||||||
|
if (r)
|
||||||
|
return *r;
|
||||||
|
else
|
||||||
|
return insert(r, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Reference r must point to an existing entry. Delete that entry.
|
||||||
|
// The reference is not valid after this method is called.
|
||||||
|
template<class Data, class Key, class H>
|
||||||
|
inline void HashTable<Data, Key, H>::erase(Reference &r)
|
||||||
|
{
|
||||||
|
Entry *e = r.entry;
|
||||||
|
ASSERT(r.ht == this && e);
|
||||||
|
*r.backpointer = e->next;
|
||||||
|
--nEntries;
|
||||||
|
delete e;
|
||||||
|
#ifdef DEBUG
|
||||||
|
--r.ht->nReferences;
|
||||||
|
r.ht = 0;
|
||||||
|
#endif
|
||||||
|
maybeShrink();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Remove the hash table entry, if any, matching the given key.
|
||||||
|
template<class Data, class Key, class H>
|
||||||
|
void HashTable<Data, Key, H>::erase(Key key)
|
||||||
|
{
|
||||||
|
Reference r(*this, key);
|
||||||
|
if (r)
|
||||||
|
erase(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Return a pointer to the value of the hash table entry matching the given key.
|
||||||
|
// Return nil if no entry matches.
|
||||||
|
template<class Data, class Key, class H>
|
||||||
|
Data *HashTable<Data, Key, H>::operator[](Key key)
|
||||||
|
{
|
||||||
|
Reference r(*this, key);
|
||||||
|
if (r)
|
||||||
|
return &*r;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
1104
mozilla/js2/src/icode.h
Normal file
1104
mozilla/js2/src/icode.h
Normal file
File diff suppressed because it is too large
Load Diff
2138
mozilla/js2/src/icodegenerator.cpp
Normal file
2138
mozilla/js2/src/icodegenerator.cpp
Normal file
File diff suppressed because it is too large
Load Diff
306
mozilla/js2/src/icodegenerator.h
Normal file
306
mozilla/js2/src/icodegenerator.h
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
/* -*- 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 icodegenerator_h
|
||||||
|
#define icodegenerator_h
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
|
#include "utilities.h"
|
||||||
|
#include "parser.h"
|
||||||
|
#include "vmtypes.h"
|
||||||
|
#include "jsclasses.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
namespace ICG {
|
||||||
|
|
||||||
|
using namespace VM;
|
||||||
|
using namespace JSTypes;
|
||||||
|
using namespace JSClasses;
|
||||||
|
|
||||||
|
typedef std::map<String, TypedRegister, std::less<String> > VariableList;
|
||||||
|
typedef std::map<uint32, uint32, std::less<uint32> > InstructionMap;
|
||||||
|
|
||||||
|
|
||||||
|
class ICodeModule {
|
||||||
|
public:
|
||||||
|
ICodeModule(InstructionStream *iCode, VariableList *variables,
|
||||||
|
uint32 maxRegister, uint32 maxParameter,
|
||||||
|
InstructionMap *instructionMap) :
|
||||||
|
its_iCode(iCode), itsVariables(variables),
|
||||||
|
itsParameterCount(maxParameter), itsMaxRegister(maxRegister),
|
||||||
|
mID(++sMaxID), mInstructionMap(instructionMap) { }
|
||||||
|
~ICodeModule()
|
||||||
|
{
|
||||||
|
delete its_iCode;
|
||||||
|
delete itsVariables;
|
||||||
|
delete mInstructionMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
Formatter& print(Formatter& f);
|
||||||
|
void setFileName (String aFileName) { mFileName = aFileName; }
|
||||||
|
String getFileName () { return mFileName; }
|
||||||
|
|
||||||
|
InstructionStream *its_iCode;
|
||||||
|
VariableList *itsVariables;
|
||||||
|
uint32 itsParameterCount;
|
||||||
|
uint32 itsMaxRegister;
|
||||||
|
uint32 mID;
|
||||||
|
InstructionMap *mInstructionMap;
|
||||||
|
String mFileName;
|
||||||
|
|
||||||
|
static uint32 sMaxID;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<const StringAtom *> LabelSet;
|
||||||
|
class LabelEntry {
|
||||||
|
public:
|
||||||
|
LabelEntry(LabelSet *labelSet, Label *breakLabel)
|
||||||
|
: labelSet(labelSet), breakLabel(breakLabel), continueLabel(NULL) { }
|
||||||
|
LabelEntry(LabelSet *labelSet, Label *breakLabel, Label *continueLabel)
|
||||||
|
: labelSet(labelSet), breakLabel(breakLabel), continueLabel(continueLabel) { }
|
||||||
|
|
||||||
|
bool containsLabel(const StringAtom *label);
|
||||||
|
|
||||||
|
LabelSet *labelSet;
|
||||||
|
Label *breakLabel;
|
||||||
|
Label *continueLabel;
|
||||||
|
};
|
||||||
|
typedef std::vector<LabelEntry *> LabelStack;
|
||||||
|
|
||||||
|
Formatter& operator<<(Formatter &f, ICodeModule &i);
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
|
||||||
|
// An ICodeGenerator provides the interface between the parser and the
|
||||||
|
// interpreter. The parser constructs one of these for each
|
||||||
|
// function/script, adds statements and expressions to it and then
|
||||||
|
// converts it into an ICodeModule, ready for execution.
|
||||||
|
|
||||||
|
class ICodeGenerator {
|
||||||
|
public:
|
||||||
|
typedef enum { kNoFlags = 0, kIsTopLevel = 0x01, kIsStaticMethod = 0x02, kIsWithinWith = 0x04 } ICodeGeneratorFlags;
|
||||||
|
private:
|
||||||
|
InstructionStream *iCode;
|
||||||
|
bool iCodeOwner;
|
||||||
|
LabelList labels;
|
||||||
|
|
||||||
|
Register mTopRegister; // highest (currently) alloacated register
|
||||||
|
uint32 mParameterCount; // number of parameters declared for the function
|
||||||
|
// these must come before any variables declared.
|
||||||
|
TypedRegister mExceptionRegister; // reserved to carry the exception object.
|
||||||
|
VariableList *variableList; // name|register pair for each variable
|
||||||
|
|
||||||
|
World *mWorld; // used to register strings
|
||||||
|
JSScope *mGlobal; // the scope for compiling within
|
||||||
|
LabelStack mLabelStack; // stack of LabelEntry objects, one per nested looping construct
|
||||||
|
// maps source position to instruction index
|
||||||
|
InstructionMap *mInstructionMap;
|
||||||
|
|
||||||
|
JSClass *mClass; // enclosing class when generating code for methods
|
||||||
|
ICodeGeneratorFlags mFlags; // assorted flags
|
||||||
|
|
||||||
|
std::vector<bool> mPermanentRegister;
|
||||||
|
|
||||||
|
Register getTempRegister()
|
||||||
|
{
|
||||||
|
while (mTopRegister < mPermanentRegister.size())
|
||||||
|
if (!mPermanentRegister[mTopRegister])
|
||||||
|
return mTopRegister++;
|
||||||
|
else
|
||||||
|
++mTopRegister;
|
||||||
|
mPermanentRegister.resize(mTopRegister + 1);
|
||||||
|
mPermanentRegister[mTopRegister] = false;
|
||||||
|
return mTopRegister++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetTopRegister() { mTopRegister = mParameterCount; }
|
||||||
|
void resetStatement() { resetTopRegister(); }
|
||||||
|
|
||||||
|
TypedRegister allocateRegister(const StringAtom& name, JSType *type);
|
||||||
|
|
||||||
|
void setRegisterForVariable(const StringAtom& name, TypedRegister r) { (*variableList)[name] = r; }
|
||||||
|
|
||||||
|
JSType *findType(const StringAtom& typeName);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void setLabel(Label *label);
|
||||||
|
|
||||||
|
void jsr(Label *label) { iCode->push_back(new Jsr(label)); }
|
||||||
|
void rts() { iCode->push_back(new Rts()); }
|
||||||
|
void branch(Label *label);
|
||||||
|
GenericBranch *branchTrue(Label *label, TypedRegister condition);
|
||||||
|
GenericBranch *branchFalse(Label *label, TypedRegister condition);
|
||||||
|
|
||||||
|
void beginTry(Label *catchLabel, Label *finallyLabel)
|
||||||
|
{ iCode->push_back(new Tryin(catchLabel, finallyLabel)); }
|
||||||
|
void endTry() { iCode->push_back(new Tryout()); }
|
||||||
|
|
||||||
|
void beginWith(TypedRegister obj) { iCode->push_back(new Within(obj)); }
|
||||||
|
void endWith() { iCode->push_back(new Without()); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void startStatement(uint32 pos) { (*mInstructionMap)[iCode->size()] = pos; }
|
||||||
|
|
||||||
|
ICodeOp mapExprNodeToICodeOp(ExprNode::Kind kind);
|
||||||
|
|
||||||
|
|
||||||
|
bool isTopLevel() { return (mFlags & kIsTopLevel) != 0; }
|
||||||
|
bool isWithinWith() { return (mFlags & kIsWithinWith) != 0; }
|
||||||
|
bool isStaticMethod() { return (mFlags & kIsStaticMethod) != 0; }
|
||||||
|
|
||||||
|
void setFlag(uint32 flag, bool v) { mFlags = (ICodeGeneratorFlags)((v) ? mFlags | flag : mFlags & ~flag); }
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {Var, Property, Slot, Static, Constructor, Name, Method} LValueKind;
|
||||||
|
|
||||||
|
LValueKind resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex);
|
||||||
|
TypedRegister handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args);
|
||||||
|
TypedRegister handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args);
|
||||||
|
ICodeModule *genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superClass);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
ICodeGenerator(World *world, JSScope *global, JSClass *aClass = NULL, ICodeGeneratorFlags flags = kIsTopLevel);
|
||||||
|
|
||||||
|
~ICodeGenerator()
|
||||||
|
{
|
||||||
|
if (iCodeOwner) {
|
||||||
|
delete iCode;
|
||||||
|
delete mInstructionMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ICodeModule *complete();
|
||||||
|
|
||||||
|
TypedRegister genExpr(ExprNode *p,
|
||||||
|
bool needBoolValueInBranch = false,
|
||||||
|
Label *trueBranch = NULL,
|
||||||
|
Label *falseBranch = NULL);
|
||||||
|
TypedRegister genStmt(StmtNode *p, LabelSet *currentLabelSet = NULL);
|
||||||
|
|
||||||
|
void returnStmt(TypedRegister r);
|
||||||
|
void returnStmt();
|
||||||
|
void throwStmt(TypedRegister r) { iCode->push_back(new Throw(r)); }
|
||||||
|
void debuggerStmt() { iCode->push_back(new Debugger()); }
|
||||||
|
|
||||||
|
TypedRegister allocateVariable(const StringAtom& name);
|
||||||
|
TypedRegister allocateVariable(const StringAtom& name, const StringAtom& typeName);
|
||||||
|
|
||||||
|
TypedRegister findVariable(const StringAtom& name)
|
||||||
|
{
|
||||||
|
VariableList::iterator i = variableList->find(name);
|
||||||
|
return (i == variableList->end()) ? TypedRegister(NotARegister, &None_Type) : (*i).second;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypedRegister allocateParameter(const StringAtom& name) { mParameterCount++; return allocateRegister(name, &Any_Type); }
|
||||||
|
TypedRegister allocateParameter(const StringAtom& name, const StringAtom& typeName)
|
||||||
|
{ mParameterCount++; return allocateRegister(name, findType(typeName)); }
|
||||||
|
TypedRegister allocateParameter(const StringAtom& name, JSType *type)
|
||||||
|
{ mParameterCount++; return allocateRegister(name, type); }
|
||||||
|
|
||||||
|
Formatter& print(Formatter& f);
|
||||||
|
|
||||||
|
TypedRegister op(ICodeOp op, TypedRegister source);
|
||||||
|
TypedRegister op(ICodeOp op, TypedRegister source1, TypedRegister source2);
|
||||||
|
TypedRegister binaryOp(ICodeOp op, TypedRegister source1, TypedRegister source2);
|
||||||
|
TypedRegister call(TypedRegister base, TypedRegister target, RegisterList *args);
|
||||||
|
TypedRegister getMethod(TypedRegister thisArg, uint32 slotIndex);
|
||||||
|
|
||||||
|
void move(TypedRegister destination, TypedRegister source);
|
||||||
|
TypedRegister logicalNot(TypedRegister source);
|
||||||
|
TypedRegister test(TypedRegister source);
|
||||||
|
|
||||||
|
TypedRegister loadBoolean(bool value);
|
||||||
|
TypedRegister loadImmediate(double value);
|
||||||
|
TypedRegister loadString(const String &value);
|
||||||
|
TypedRegister loadString(const StringAtom &name);
|
||||||
|
|
||||||
|
TypedRegister newObject(TypedRegister constructor);
|
||||||
|
TypedRegister newArray();
|
||||||
|
TypedRegister newFunction(ICodeModule *icm);
|
||||||
|
TypedRegister newClass(JSClass *clazz);
|
||||||
|
|
||||||
|
TypedRegister cast(TypedRegister arg, JSType *toType);
|
||||||
|
|
||||||
|
TypedRegister super();
|
||||||
|
TypedRegister loadName(const StringAtom &name, JSType *t = &Any_Type);
|
||||||
|
void saveName(const StringAtom &name, TypedRegister value);
|
||||||
|
TypedRegister nameXcr(const StringAtom &name, ICodeOp op);
|
||||||
|
|
||||||
|
TypedRegister deleteProperty(TypedRegister base, const StringAtom &name);
|
||||||
|
TypedRegister getProperty(TypedRegister base, const StringAtom &name);
|
||||||
|
void setProperty(TypedRegister base, const StringAtom &name, TypedRegister value);
|
||||||
|
TypedRegister propertyXcr(TypedRegister base, const StringAtom &name, ICodeOp op);
|
||||||
|
|
||||||
|
TypedRegister getStatic(JSClass *base, const String &name);
|
||||||
|
void setStatic(JSClass *base, const StringAtom &name, TypedRegister value);
|
||||||
|
TypedRegister staticXcr(JSClass *base, const StringAtom &name, ICodeOp op);
|
||||||
|
|
||||||
|
TypedRegister getElement(TypedRegister base, TypedRegister index);
|
||||||
|
void setElement(TypedRegister base, TypedRegister index, TypedRegister value);
|
||||||
|
TypedRegister elementXcr(TypedRegister base, TypedRegister index, ICodeOp op);
|
||||||
|
|
||||||
|
TypedRegister getSlot(TypedRegister base, uint32 slot);
|
||||||
|
void setSlot(TypedRegister base, uint32 slot, TypedRegister value);
|
||||||
|
TypedRegister slotXcr(TypedRegister base, uint32 slot, ICodeOp op);
|
||||||
|
|
||||||
|
TypedRegister varXcr(TypedRegister var, ICodeOp op);
|
||||||
|
|
||||||
|
InstructionStream *getICode() { return iCode; }
|
||||||
|
|
||||||
|
Label *getLabel();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Formatter& operator<<(Formatter &f, ICodeGenerator &i);
|
||||||
|
Formatter& operator<<(Formatter &f, ICodeModule &i);
|
||||||
|
/*
|
||||||
|
std::ostream &operator<<(std::ostream &s, ICodeGenerator &i);
|
||||||
|
std::ostream &operator<<(std::ostream &s, StringAtom &str);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace IGC */
|
||||||
|
} /* namespace JavaScript */
|
||||||
|
|
||||||
|
#endif /* icodegenerator_h */
|
||||||
1361
mozilla/js2/src/interpreter.cpp
Normal file
1361
mozilla/js2/src/interpreter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
113
mozilla/js2/src/interpreter.h
Normal file
113
mozilla/js2/src/interpreter.h
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
// -*- 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) 2000 Netscape Communications Corporation. All
|
||||||
|
// Rights Reserved.
|
||||||
|
|
||||||
|
#ifndef interpreter_h
|
||||||
|
#define interpreter_h
|
||||||
|
|
||||||
|
#include "utilities.h"
|
||||||
|
#include "jstypes.h"
|
||||||
|
#include "vmtypes.h"
|
||||||
|
#include "icodegenerator.h"
|
||||||
|
#include "gc_allocator.h"
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
namespace Interpreter {
|
||||||
|
|
||||||
|
using namespace ICG;
|
||||||
|
using namespace JSTypes;
|
||||||
|
|
||||||
|
struct Activation;
|
||||||
|
|
||||||
|
struct Linkage;
|
||||||
|
|
||||||
|
class Context : public gc_base {
|
||||||
|
void initContext();
|
||||||
|
public:
|
||||||
|
explicit Context(World& world, JSScope* aGlobal)
|
||||||
|
: mWorld(world), mGlobal(aGlobal), mLinkage(0), mActivation(0), mHasOperatorsPackageLoaded(false) { initContext(); }
|
||||||
|
|
||||||
|
World& getWorld() { return mWorld; }
|
||||||
|
JSScope* getGlobalObject() { return mGlobal; }
|
||||||
|
InstructionIterator getPC() { return mPC; }
|
||||||
|
|
||||||
|
JSValues& getRegisters();
|
||||||
|
ICodeModule* getICode();
|
||||||
|
|
||||||
|
enum Event {
|
||||||
|
EV_NONE = 0x0000,
|
||||||
|
EV_STEP = 0x0001,
|
||||||
|
EV_THROW = 0x0002,
|
||||||
|
EV_DEBUG = 0x0004,
|
||||||
|
EV_ALL = 0xffff
|
||||||
|
};
|
||||||
|
|
||||||
|
class Listener {
|
||||||
|
public:
|
||||||
|
virtual void listen(Context *context, Event event) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void addListener(Listener* listener);
|
||||||
|
void removeListener(Listener* listener);
|
||||||
|
|
||||||
|
class Frame {
|
||||||
|
public:
|
||||||
|
virtual Frame* getNext() = 0;
|
||||||
|
virtual void getState(InstructionIterator& pc, JSValues*& registers,
|
||||||
|
ICodeModule*& iCode) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
Frame* getFrames();
|
||||||
|
|
||||||
|
JSValue interpret(ICodeModule* iCode, const JSValues& args);
|
||||||
|
void doCall(JSFunction *target, Instruction *pc);
|
||||||
|
|
||||||
|
ICodeModule* compile(const String &source);
|
||||||
|
ICodeModule* genCode(StmtNode *p, const String &fileName);
|
||||||
|
JSValue readEvalFile(FILE* in, const String& fileName);
|
||||||
|
|
||||||
|
void addBinaryOperator(BinaryOperator::BinaryOp op, BinaryOperator *fn) { mBinaryOperators[op].push_back(fn); }
|
||||||
|
const JSValue findBinaryOverride(JSValue &operand1, JSValue &operand2, BinaryOperator::BinaryOp op);
|
||||||
|
|
||||||
|
|
||||||
|
bool hasOperatorsPackageLoaded() { return mHasOperatorsPackageLoaded; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void broadcast(Event event);
|
||||||
|
void initOperatorsPackage();
|
||||||
|
|
||||||
|
private:
|
||||||
|
World& mWorld;
|
||||||
|
JSScope* mGlobal;
|
||||||
|
Linkage* mLinkage;
|
||||||
|
typedef std::vector<Listener*, gc_allocator<Listener*> > ListenerList;
|
||||||
|
typedef ListenerList::iterator ListenerIterator;
|
||||||
|
ListenerList mListeners;
|
||||||
|
Activation* mActivation;
|
||||||
|
bool mHasOperatorsPackageLoaded;
|
||||||
|
|
||||||
|
InstructionIterator mPC;
|
||||||
|
|
||||||
|
BinaryOperatorList mBinaryOperators[BinaryOperator::BinaryOperatorCount];
|
||||||
|
|
||||||
|
}; /* class Context */
|
||||||
|
|
||||||
|
} /* namespace Interpreter */
|
||||||
|
} /* namespace JavaScript */
|
||||||
|
|
||||||
|
#endif /* interpreter_h */
|
||||||
316
mozilla/js2/src/jsclasses.h
Normal file
316
mozilla/js2/src/jsclasses.h
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
/* -*- 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 jsclasses_h
|
||||||
|
#define jsclasses_h
|
||||||
|
|
||||||
|
#include "jstypes.h"
|
||||||
|
|
||||||
|
namespace JavaScript {
|
||||||
|
namespace JSClasses {
|
||||||
|
|
||||||
|
using JSTypes::JSValue;
|
||||||
|
using JSTypes::JSObject;
|
||||||
|
using JSTypes::JSType;
|
||||||
|
using JSTypes::JSScope;
|
||||||
|
using JSTypes::JSFunction;
|
||||||
|
using ICG::ICodeModule;
|
||||||
|
|
||||||
|
|
||||||
|
struct JSSlot {
|
||||||
|
typedef enum { kNoFlag = 0, kIsConstructor = 0x01 } SlotFlags; // <-- readonly, enumerable etc
|
||||||
|
|
||||||
|
JSType* mType;
|
||||||
|
uint32 mIndex;
|
||||||
|
SlotFlags mFlags;
|
||||||
|
|
||||||
|
JSSlot() : mType(0), mFlags(kNoFlag)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isConstructor() const { return (mFlags & kIsConstructor) != 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(XP_MAC)
|
||||||
|
// copied from default template parameters in map.
|
||||||
|
typedef gc_allocator<std::pair<const String, JSSlot> > gc_slot_allocator;
|
||||||
|
#elif defined(XP_UNIX)
|
||||||
|
typedef JSTypes::gc_map_allocator gc_slot_allocator;
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
typedef gc_allocator<JSSlot> gc_slot_allocator;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef std::map<String, JSSlot, std::less<const String>, gc_slot_allocator> JSSlots;
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::pair<String, JSFunction*> MethodEntry;
|
||||||
|
typedef std::vector<MethodEntry> JSMethods;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a class in the JavaScript 2 (ECMA 4) language.
|
||||||
|
* Since a class defines a scope, and is defined in a scope,
|
||||||
|
* a new scope is created whose parent scope is the scope of
|
||||||
|
* class definition.
|
||||||
|
*/
|
||||||
|
class JSClass : public JSType {
|
||||||
|
protected:
|
||||||
|
JSScope* mScope;
|
||||||
|
uint32 mSlotCount;
|
||||||
|
JSSlots mSlots;
|
||||||
|
uint32 mStaticCount;
|
||||||
|
JSSlots mStaticSlots;
|
||||||
|
JSValue* mStaticData;
|
||||||
|
JSMethods mMethods;
|
||||||
|
public:
|
||||||
|
JSClass(JSScope* scope, const String& name, JSClass* superClass = 0)
|
||||||
|
: JSType(name, superClass),
|
||||||
|
mScope(new JSScope(scope)),
|
||||||
|
mSlotCount(superClass ? superClass->mSlotCount : 0),
|
||||||
|
mStaticCount(0),
|
||||||
|
mStaticData(0)
|
||||||
|
{
|
||||||
|
if (superClass) {
|
||||||
|
// inherit superclass methods
|
||||||
|
JSMethods::iterator end = superClass->mMethods.end();
|
||||||
|
for (JSMethods::iterator i = superClass->mMethods.begin(); i != end; i++)
|
||||||
|
mMethods.push_back(*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSClass* getSuperClass()
|
||||||
|
{
|
||||||
|
return static_cast<JSClass*>(mBaseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSScope* getScope()
|
||||||
|
{
|
||||||
|
return mScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSSlot& defineSlot(const String& name, JSType* type)
|
||||||
|
{
|
||||||
|
JSSlot& slot = mSlots[name];
|
||||||
|
ASSERT(slot.mType == 0);
|
||||||
|
slot.mType = type;
|
||||||
|
slot.mIndex = mSlotCount++; // starts at 0.
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSSlot& getSlot(const String& name)
|
||||||
|
{
|
||||||
|
return mSlots[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasSlot(const String& name)
|
||||||
|
{
|
||||||
|
return (mSlots.find(name) != mSlots.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
JSSlots& getSlots()
|
||||||
|
{
|
||||||
|
return mSlots;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 getSlotCount()
|
||||||
|
{
|
||||||
|
return mSlotCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a static/class variable.
|
||||||
|
*/
|
||||||
|
const JSSlot& defineStatic(const String& name, JSType* type)
|
||||||
|
{
|
||||||
|
JSSlot& slot = mStaticSlots[name];
|
||||||
|
ASSERT(slot.mType == 0);
|
||||||
|
slot.mType = type;
|
||||||
|
slot.mIndex = mStaticCount++;
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSSlot& defineConstructor(const String& name)
|
||||||
|
{
|
||||||
|
JSSlot& slot = mStaticSlots[name];
|
||||||
|
ASSERT(slot.mType == 0);
|
||||||
|
slot.mType = &JSTypes::Function_Type;
|
||||||
|
slot.mIndex = mStaticCount++;
|
||||||
|
slot.mFlags = JSSlot::kIsConstructor;
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSSlot& getStatic(const String& name)
|
||||||
|
{
|
||||||
|
return mStaticSlots[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasStatic(const String& name, JSType*& type, bool &isConstructor)
|
||||||
|
{
|
||||||
|
JSSlots::const_iterator i = mStaticSlots.find(name);
|
||||||
|
if (i != mStaticSlots.end()) {
|
||||||
|
type = i->second.mType;
|
||||||
|
isConstructor = i->second.isConstructor();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasStatic(const String& name)
|
||||||
|
{
|
||||||
|
return (mStaticSlots.find(name) != mStaticSlots.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool complete()
|
||||||
|
{
|
||||||
|
mStaticData = new JSValue[mStaticCount];
|
||||||
|
return (mStaticData != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue& operator[] (uint32 index)
|
||||||
|
{
|
||||||
|
return mStaticData[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void printProperties(Formatter& f)
|
||||||
|
{
|
||||||
|
f << "Properties:\n";
|
||||||
|
JSObject::printProperties(f);
|
||||||
|
f << "Statics:\n";
|
||||||
|
printStatics(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printStatics(Formatter& f)
|
||||||
|
{
|
||||||
|
JSClass* superClass = getSuperClass();
|
||||||
|
if (superClass) superClass->printStatics(f);
|
||||||
|
for (JSSlots::iterator i = mStaticSlots.begin(), end = mStaticSlots.end(); i != end; ++i) {
|
||||||
|
f << i->first << " : " << mStaticData[i->second.mIndex] << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void defineMethod(const String& name, JSFunction *f)
|
||||||
|
{
|
||||||
|
uint32 slot;
|
||||||
|
if (hasMethod(name, slot))
|
||||||
|
mMethods[slot] = MethodEntry(name, f);
|
||||||
|
else
|
||||||
|
mMethods.push_back(MethodEntry(name, f));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasMethod(const String& name, uint32& index)
|
||||||
|
{
|
||||||
|
JSMethods::iterator end = mMethods.end();
|
||||||
|
for (JSMethods::iterator i = mMethods.begin(); i != end; i++) {
|
||||||
|
if (i->first == name) {
|
||||||
|
index = i - mMethods.begin();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSFunction* getMethod(uint32 index)
|
||||||
|
{
|
||||||
|
return mMethods[index].second;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an instance of a JSClass.
|
||||||
|
*/
|
||||||
|
class JSInstance : public JSObject {
|
||||||
|
protected:
|
||||||
|
JSValue mSlots[1];
|
||||||
|
public:
|
||||||
|
void* operator new(size_t n, JSClass* thisClass)
|
||||||
|
{
|
||||||
|
uint32 slotCount = thisClass->getSlotCount();
|
||||||
|
if (slotCount > 0) n += sizeof(JSValue) * (slotCount - 1);
|
||||||
|
return gc_base::operator new(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(XP_MAC)
|
||||||
|
void operator delete(void* /*ptr*/, JSClass* /*thisClass*/) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JSInstance(JSClass* thisClass)
|
||||||
|
{
|
||||||
|
mType = thisClass;
|
||||||
|
// initialize extra slots with undefined.
|
||||||
|
uint32 slotCount = thisClass->getSlotCount();
|
||||||
|
if (slotCount > 0) {
|
||||||
|
std::uninitialized_fill(&mSlots[1], &mSlots[1] + (slotCount - 1),
|
||||||
|
JSTypes::kUndefinedValue);
|
||||||
|
}
|
||||||
|
// for grins, use the prototype link to access methods.
|
||||||
|
setPrototype(thisClass->getScope());
|
||||||
|
}
|
||||||
|
|
||||||
|
JSFunction* getMethod(uint32 index)
|
||||||
|
{
|
||||||
|
return getClass()->getMethod(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSClass* getClass()
|
||||||
|
{
|
||||||
|
return static_cast<JSClass*>(mType);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue& operator[] (uint32 index)
|
||||||
|
{
|
||||||
|
return mSlots[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void printProperties(Formatter& f)
|
||||||
|
{
|
||||||
|
f << "Properties:\n";
|
||||||
|
JSObject::printProperties(f);
|
||||||
|
f << "Slots:\n";
|
||||||
|
printSlots(f, getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void printSlots(Formatter& f, JSClass* thisClass)
|
||||||
|
{
|
||||||
|
JSClass* superClass = thisClass->getSuperClass();
|
||||||
|
if (superClass) printSlots(f, superClass);
|
||||||
|
JSSlots& slots = thisClass->getSlots();
|
||||||
|
for (JSSlots::iterator i = slots.begin(), end = slots.end(); i != end; ++i) {
|
||||||
|
f << i->first << " : " << mSlots[i->second.mIndex] << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace JSClasses */
|
||||||
|
} /* namespace JavaScript */
|
||||||
|
|
||||||
|
#endif /* jsclasses_h */
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user