removed kjs and kjsembed

This commit is contained in:
Ivailo Monev 2014-11-18 13:35:43 +00:00
parent 38427d5c45
commit 6141d2ef50
371 changed files with 2 additions and 74184 deletions

View file

@ -53,7 +53,7 @@ if(UNIX AND Q_WS_X11)
endif(UNIX AND Q_WS_X11) endif(UNIX AND Q_WS_X11)
#required features: #required features:
# Perl is used e.g. in khtml, kjs, kjsembed and others # FIXME: is perl really needed?
find_package(Perl) find_package(Perl)
set_package_properties(Perl PROPERTIES URL "http://www.perl.org" TYPE REQUIRED PURPOSE "Needed for building kdelibs") set_package_properties(Perl PROPERTIES URL "http://www.perl.org" TYPE REQUIRED PURPOSE "Needed for building kdelibs")
@ -150,12 +150,7 @@ endif(QCA2_FOUND)
# Use the one variable for the lib you depend upon. # Use the one variable for the lib you depend upon.
# E.g. kdeui uses ${KDE4_KDECORE_INCLUDES}. Something that depends on kparts uses ${KDE4_KPARTS_INCLUDES}. # E.g. kdeui uses ${KDE4_KDECORE_INCLUDES}. Something that depends on kparts uses ${KDE4_KPARTS_INCLUDES}.
set(KDE4_KJS_INCLUDES ${CMAKE_SOURCE_DIR}/kjs # kdecore depends on Qt
${CMAKE_BINARY_DIR}/kjs)
set(KDE4_KDECORE_INCLUDES ${KDE4_KJS_INCLUDES} )
# kdecore depends on Qt (need only headers from kjs)
set(KDE4_KDECORE_INCLUDES ${KDE4_KDECORE_INCLUDES} set(KDE4_KDECORE_INCLUDES ${KDE4_KDECORE_INCLUDES}
${CMAKE_SOURCE_DIR}/kdecore ${CMAKE_SOURCE_DIR}/kdecore
${CMAKE_BINARY_DIR}/kdecore ${CMAKE_BINARY_DIR}/kdecore
@ -247,8 +242,6 @@ add_subdirectory( kdecore )
add_subdirectory( kdeui ) add_subdirectory( kdeui )
add_subdirectory( kpty ) add_subdirectory( kpty )
add_subdirectory( kdesu ) add_subdirectory( kdesu )
add_subdirectory( kjs )
add_subdirectory( kjsembed )
add_subdirectory( kio ) add_subdirectory( kio )
add_subdirectory( solid ) add_subdirectory( solid )
add_subdirectory( kded ) add_subdirectory( kded )

View file

@ -1,284 +0,0 @@
project(kjs)
add_subdirectory(tests)
# Conflict between KJS::HashTable and WTF::HashTable, due to "using namespace" of both namespaces.
kde4_no_enable_final(kjs)
# Configuration checks
include(FindThreads)
check_library_exists(pthread pthread_attr_get_np "" HAVE_PTHREAD_ATTR_GET_NP)
check_library_exists(pthread pthread_getattr_np "" HAVE_PTHREAD_GETATTR_NP)
check_include_files(float.h HAVE_FLOAT_H)
check_include_files(sys/timeb.h HAVE_SYS_TIMEB_H)
check_include_files(ieeefp.h HAVE_IEEEFP_H)
check_include_files("pthread.h;pthread_np.h" HAVE_PTHREAD_NP_H)
check_include_files(valgrind/memcheck.h HAVE_MEMCHECK_H)
check_struct_member(tm tm_gmtoff time.h HAVE_TM_GMTOFF)
macro_push_required_vars()
if(NOT WIN32)
set(CMAKE_REQUIRED_LIBRARIES "-lm")
endif(NOT WIN32)
check_function_exists(_finite HAVE_FUNC__FINITE)
check_function_exists(finite HAVE_FUNC_FINITE)
check_function_exists(posix_memalign HAVE_FUNC_POSIX_MEMALIGN)
check_symbol_exists(isnan "math.h" HAVE_FUNC_ISNAN)
check_symbol_exists(isinf "math.h" HAVE_FUNC_ISINF)
macro_pop_required_vars()
#Do not make PCRE optional here. PCRE is a hard requirement for modern systems
#but we give old systems some slack... that's why we don't specify "REQUIRED".
find_package(PCRE)
set_package_properties(PCRE PROPERTIES DESCRIPTION "Perl-compatible regular expressions in KJS"
URL "http://www.pcre.org"
TYPE OPTIONAL
PURPOSE "Without PCRE, KJS will have extremely poor regular expression support, breaking many webpages."
)
macro_bool_to_01(PCRE_FOUND HAVE_PCREPOSIX)
option(KJS_FORCE_DISABLE_PCRE "Force building of KJS without PCRE. Doing this will result in many webpage working incorrectly, due to extremely poor regular expression support")
# Generate global.h
configure_file(global.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/global.h )
configure_file(config-kjs.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kjs.h )
include_directories(${KDE4_KDECORE_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR}/wtf ${KDEWIN_INCLUDES} )
# the check for pcre is in kdelibs/CMakeLists.txt
if(PCRE_FOUND AND NOT KJS_FORCE_DISABLE_PCRE)
include_directories(${PCRE_INCLUDE_DIR})
# tell check_symbol_exists to -I pcre dirs.
macro_push_required_vars()
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${PCRE_INCLUDE_DIR})
check_symbol_exists(PCRE_CONFIG_UTF8 "pcre.h" HAVE_PCRE_UTF8)
check_symbol_exists(PCRE_CONFIG_STACKRECURSE "pcre.h" HAVE_PCRE_STACK)
macro_pop_required_vars()
# Even though we "support" non-PCRE builds, if we build PCRE, we want a version
# recent enough, and we don't want to fallback to a completely crippled
# POSIX code just like that.
if (NOT HAVE_PCRE_UTF8 OR NOT HAVE_PCRE_STACK)
message(FATAL_ERROR "Your libPCRE is too old. KJS requires at least PCRE4.5")
endif (NOT HAVE_PCRE_UTF8 OR NOT HAVE_PCRE_STACK)
else (PCRE_FOUND AND NOT KJS_FORCE_DISABLE_PCRE)
# if we're here, either PCRE support is disabled, or it's not found...
# it better be disabled.
if (NOT KJS_FORCE_DISABLE_PCRE)
message(FATAL_ERROR "The PCRE regular expression library has not been found. KJS requires PCRE >= 4.5 to function properly. If you for some reason can not install it, you can force a build with POSIX regex.h by passing -DKJS_FORCE_DISABLE_PCRE=true to cmake. However, be advised that it'll result in many websites breaking")
endif (NOT KJS_FORCE_DISABLE_PCRE)
# if pcre is not installed or disabled, at least the posix regex.h has to be available
if(APPLE)
check_include_files("sys/types.h;regex.h" HAVE_REGEX_H)
else(APPLE)
check_include_files(regex.h HAVE_REGEX_H)
endif(APPLE)
if (NOT HAVE_REGEX_H)
message(FATAL_ERROR "Neither the PCRE regular expression library nor the POSIX regex.h header have been found. Consider installing PCRE.")
endif (NOT HAVE_REGEX_H)
endif(PCRE_FOUND AND NOT KJS_FORCE_DISABLE_PCRE)
# The crosscompiling parts are commented out on purpose. Alex
# if (CMAKE_CROSSCOMPILING)
# set(IMPORT_ICEMAKER_EXECUTABLE "${KDE_HOST_TOOLS_PATH}/ImportIcemakerExecutable.cmake" CACHE FILEPATH "Point it to the export file of icemaker from a native build")
# include(${IMPORT_ICEMAKER_EXECUTABLE})
# set(ICEMAKER_EXECUTABLE icemaker)
# else (CMAKE_CROSSCOMPILING)
########### icemaker, generates some tables for kjs/frostbyte ###############
set(icemaker_SRCS
bytecode/generator/tablebuilder.cpp
bytecode/generator/types.cpp
bytecode/generator/codeprinter.cpp
bytecode/generator/driver.cpp
bytecode/generator/lexer.cpp
bytecode/generator/parser.cpp
)
kde4_add_executable(icemaker NOGUI ${icemaker_SRCS})
# get the name of the generated wrapper script (which sets up LD_LIBRARY_PATH)
get_target_property(ICEMAKER_EXECUTABLE icemaker WRAPPER_SCRIPT)
# export(TARGETS icemaker FILE ${CMAKE_BINARY_DIR}/ImportIcemakerExecutable.cmake)
# endif (CMAKE_CROSSCOMPILING)
# and the custom command
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/opcodes.h ${CMAKE_CURRENT_BINARY_DIR}/opcodes.cpp
${CMAKE_CURRENT_BINARY_DIR}/machine.cpp
COMMAND ${ICEMAKER_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/bytecode
DEPENDS icemaker ${CMAKE_CURRENT_SOURCE_DIR}/bytecode/codes.def
${CMAKE_CURRENT_SOURCE_DIR}/bytecode/opcodes.cpp.in
${CMAKE_CURRENT_SOURCE_DIR}/bytecode/opcodes.h.in
${CMAKE_CURRENT_SOURCE_DIR}/bytecode/machine.cpp.in
)
########### next target ###############
# We don't want -pedantic/--pedantic for KJS since we want to use GCC extension when available
string(REPLACE "--pedantic" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
string(REPLACE "-pedantic" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
add_definitions(-DBUILDING_KDE__)
add_subdirectory( wtf )
set(CREATE_HASH_TABLE ${CMAKE_CURRENT_SOURCE_DIR}/create_hash_table )
macro(CREATE_LUT _srcs_LIST _in_FILE _out_FILE _dep_FILE)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_out_FILE}
COMMAND ${PERL_EXECUTABLE} ${CREATE_HASH_TABLE} ${CMAKE_CURRENT_SOURCE_DIR}/${_in_FILE} -i > ${CMAKE_CURRENT_BINARY_DIR}/${_out_FILE}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_in_FILE} )
set( ${_srcs_LIST} ${${_srcs_LIST}} ${CMAKE_CURRENT_BINARY_DIR}/${_out_FILE})
endmacro(CREATE_LUT)
create_lut(kjs_LIB_SRCS date_object.cpp date_object.lut.h date_object.cpp)
create_lut(kjs_LIB_SRCS number_object.cpp number_object.lut.h number_object.cpp)
create_lut(kjs_LIB_SRCS string_object.cpp string_object.lut.h string_object.cpp)
create_lut(kjs_LIB_SRCS array_object.cpp array_object.lut.h array_object.cpp)
create_lut(kjs_LIB_SRCS math_object.cpp math_object.lut.h math_object.cpp)
create_lut(kjs_LIB_SRCS json_object.cpp json_object.lut.h json_object.cpp)
create_lut(kjs_LIB_SRCS regexp_object.cpp regexp_object.lut.h regexp_object.cpp)
create_lut(kjs_LIB_SRCS keywords.table lexer.lut.h lexer.cpp)
set(kjs_LIB_SRCS
${kjs_LIB_SRCS}
ustring.cpp
date_object.cpp
collector.cpp
nodes.cpp
grammar.cpp
lexer.cpp
lookup.cpp
operations.cpp
regexp.cpp
function_object.cpp
string_object.cpp
bool_object.cpp
number_object.cpp
internal.cpp
ExecState.cpp
Parser.cpp
array_object.cpp
array_instance.cpp
math_object.cpp
object_object.cpp
regexp_object.cpp
error_object.cpp
function.cpp
debugger.cpp
value.cpp
list.cpp
object.cpp
interpreter.cpp
package.cpp
property_map.cpp
property_slot.cpp
nodes2string.cpp
identifier.cpp
scope_chain.cpp
dtoa.cpp
fpconst.cpp
JSLock.cpp
JSImmediate.cpp
PropertyNameArray.cpp
JSWrapperObject.cpp
CommonIdentifiers.cpp
JSVariableObject.cpp
${CMAKE_CURRENT_BINARY_DIR}/opcodes.cpp
${CMAKE_CURRENT_BINARY_DIR}/machine.cpp
nodes2bytecode.cpp
CompileState.cpp
jsonlexer.cpp
json_object.cpp
jsonstringify.cpp
propertydescriptor.cpp
)
if (NOT DEFINED QT_ONLY)
set(KJSLIBNAME kjs)
else (NOT DEFINED QT_ONLY)
set(KJSLIBNAME qkjs)
endif (NOT DEFINED QT_ONLY)
kde4_add_library(${KJSLIBNAME} ${LIBRARY_TYPE} ${kjs_LIB_SRCS})
if(WIN32)
target_link_libraries(${KJSLIBNAME} ${KDEWIN_LIBRARIES})
endif(WIN32)
if(CMAKE_THREAD_LIBS_INIT)
target_link_libraries(${KJSLIBNAME} ${CMAKE_THREAD_LIBS_INIT})
endif(CMAKE_THREAD_LIBS_INIT)
if(UNIX)
target_link_libraries(${KJSLIBNAME} m)
endif(UNIX)
if(PCRE_FOUND)
target_link_libraries(${KJSLIBNAME} ${PCRE_LIBRARIES})
endif(PCRE_FOUND)
set_target_properties(${KJSLIBNAME} PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} )
install(TARGETS ${KJSLIBNAME} EXPORT kdelibsLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS})
########### kjs - basic shell ###############
set(kjs_SRCS kjs.cpp)
#required by win32 see kdelibs/cmake/modules/kde4Macros.cmake kde4_add_manifest
set (kjs_bin_OUTPUT_NAME kjs)
# 'kjs_bin' because cmake doesn't like having a lib and app with the same name
kde4_add_executable(kjs_bin NOGUI ${kjs_SRCS})
set_target_properties(kjs_bin PROPERTIES RUNTIME_OUTPUT_NAME ${kjs_bin_OUTPUT_NAME})
target_link_libraries(kjs_bin ${KJSLIBNAME})
install(TARGETS kjs_bin ${INSTALL_TARGETS_DEFAULT_ARGS})
########### KDE-specific API ##############
add_subdirectory(api)
########### install files ###############
# install( FILES
# ExecState.h
# JSImmediate.h
# JSLock.h
# JSType.h
# PropertyNameArray.h
# collector.h
# completion.h
# function.h
# identifier.h
# interpreter.h
# list.h
# lookup.h
# object.h
# operations.h
# package.h
# property_map.h
# property_slot.h
# protect.h
# scope_chain.h
# types.h
# ustring.h
# value.h
# CommonIdentifiers.h
#
# ${CMAKE_CURRENT_BINARY_DIR}/global.h
#
# DESTINATION ${INCLUDE_INSTALL_DIR}/kjs COMPONENT Devel )

View file

@ -1,49 +0,0 @@
/*
* Copyright (C) 2003, 2007 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "CommonIdentifiers.h"
#include <config-kjs.h>
#include "JSLock.h"
namespace KJS {
const char* const nullCString = 0;
#define INITIALIZE_PROPERTY_NAME(name) , name ( #name )
CommonIdentifiers::CommonIdentifiers()
: nullIdentifier(nullCString)
, underscoreProto("__proto__")
KJS_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PROPERTY_NAME)
{
}
CommonIdentifiers* CommonIdentifiers::shared()
{
static CommonIdentifiers* sharedInstance;
if (!sharedInstance) {
JSLock lock;
sharedInstance = new CommonIdentifiers;
}
return sharedInstance;
}
} // namespace KJS

View file

@ -1,103 +0,0 @@
/*
* Copyright (C) 2003,2007 Apple Computer, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef KJS_COMMON_IDENTIFIERS_H
#define KJS_COMMON_IDENTIFIERS_H
#include "identifier.h"
#include <wtf/Noncopyable.h>
// List of property names, passed to a macro so we can do set them up various
// ways without repeating the list.
#define KJS_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(macro) \
macro(arguments) \
macro(callee) \
macro(caller) \
macro(constructor) \
macro(fromCharCode) \
macro(global) \
macro(ignoreCase) \
macro(index) \
macro(input) \
macro(lastIndex) \
macro(length) \
macro(message) \
macro(multiline) \
macro(name) \
macro(prototype) \
macro(source) \
macro(toExponential) \
macro(toFixed) \
macro(toLocaleString) \
macro(toPrecision) \
macro(toString) \
macro(valueOf) \
macro(toJSON) \
macro(configurable) \
macro(value) \
macro(writable) \
macro(enumerable) \
macro(get) \
macro(set) \
macro(toISOString)
namespace KJS {
class KJS_EXPORT CommonIdentifiers : Noncopyable {
private:
CommonIdentifiers();
public:
static CommonIdentifiers* shared();
const Identifier nullIdentifier;
const Identifier underscoreProto;
#define KJS_IDENTIFIER_DECLARE_PROPERTY_NAME_GLOBAL(name) const Identifier name;
KJS_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(KJS_IDENTIFIER_DECLARE_PROPERTY_NAME_GLOBAL)
#undef KJS_IDENTIFIER_DECLARE_PROPERTY_NAME_GLOBAL
};
} // namespace KJS
// ### better place in identifier.h. only here because of the shared null
namespace WTF {
// Provide hashing of Identifiers --- using the rep ptr
struct IdentHash {
static unsigned hash(const KJS::Identifier& key) {
return PtrHash<KJS::UString::Rep*>::hash(key.ustring().rep());
}
static bool equal(const KJS::Identifier& a, const KJS::Identifier& b) { return a == b; }
static const bool safeToCompareToEmptyOrDeleted = false;
};
template<> struct DefaultHash<KJS::Identifier> { typedef IdentHash Hash; };
template<> struct HashTraits<KJS::Identifier> : GenericHashTraits<KJS::Identifier> {
static const bool emptyValueIsZero = false;
static const bool needsDestruction = true;
static void constructDeletedValue(KJS::Identifier* slot) { new (slot) KJS::Identifier(); }
static bool isDeletedValue(const KJS::Identifier& value) { return value.isNull(); }
};
} // namespace WTF
#endif // KJS_COMMON_IDENTIFIERS_H

View file

@ -1,292 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
* Copyright (C) 2007, 2008 Maksim Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "CompileState.h"
#include "nodes.h"
#include <wtf/Assertions.h>
#include <wtf/Vector.h>
namespace KJS {
CompileState::~CompileState()
{
deleteAllValues(locals);
deleteAllValues(freeMarkTemps);
deleteAllValues(freeNonMarkTemps);
}
CodeBlock& CompileState::codeBlock()
{
return fbody->code();
}
void CompileState::requestTemporary(OpType type, OpValue* value, OpValue* reference)
{
ASSERT(type == OpType_value || type == OpType_bool || type == OpType_int32 || type == OpType_number);
value->type = type;
value->immediate = false;
reference->type = OpType_reg;
reference->immediate = true;
RegDescriptor* temp = 0;
bool markable = (type == OpType_value);
if (markable && !freeMarkTemps.isEmpty()) {
temp = freeMarkTemps.last();
freeMarkTemps.removeLast();
} else if (!markable && !freeNonMarkTemps.isEmpty()) {
temp = freeNonMarkTemps.last();
freeNonMarkTemps.removeLast();
}
if (!temp) {
Register id = maxTemp;
fbody->reserveSlot(id, markable);
temp = new RegDescriptor(this, id, markable);
++maxTemp;
}
value->ownedReg = temp;
reference->ownedReg = temp;
reference->value.narrow.regVal = temp->reg();
}
OpValue CompileState::localReadVal(Register regNum)
{
OpValue val;
val.immediate = false;
val.type = OpType_value;
RegDescriptor* desc = locals[regNum];
if (!desc) {
desc = new RegDescriptor(this, regNum, true, false /*not a temp!*/);
locals[regNum] = desc;
}
val.ownedReg = desc;
return val;
}
void CompileState::localFlushAll(CodeBlock& block)
{
for (Register r = 0; r < initialMaxTemp; ++r) {
if (locals[r] && locals[r]->live())
flushLocal(block, r);
}
}
void CompileState::flushLocal(CodeBlock& /*block*/, Register regNum)
{
if (locals[regNum] && locals[regNum]->live()) {
OpValue localVal;
localVal.immediate = false;
localVal.type = OpType_value;
localVal.ownedReg = locals[regNum];
OpValue out, outReg;
requestTemporary(OpType_value, &out, &outReg);
CodeGen::emitOp(this, Op_RegPutValue, 0, &outReg, &localVal);
// Now, patch up the descriptor to point to the same place as the temporary, and to
// take ownership of it, and remove it from local descriptors list.
locals[regNum]->adopt(out.ownedReg.get());
locals[regNum] = 0;
}
}
OpValue CompileState::localWriteRef(CodeBlock& block, Register regNum)
{
// Detach any live value copies.
flushLocal(block, regNum);
OpValue rval;
rval.immediate = true;
rval.type = OpType_reg;
rval.value.narrow.regVal = regNum;
return rval;
}
bool CompileState::pushLabel(const Identifier& label)
{
if (!seenLabels.add(label).second)
return false; // Dupe!
seenLabelsStack.append(label);
pendingLabels.append(label);
return true;
}
void CompileState::popLabel()
{
Identifier name = seenLabelsStack.last();
seenLabelsStack.removeLast();
seenLabels.remove (name);
labelTargets.remove(name);
ASSERT(pendingLabels.isEmpty());
}
void CompileState::bindLabels(Node* node)
{
for (size_t l = 0; l < pendingLabels.size(); ++l)
labelTargets.set(pendingLabels[l], node);
pendingLabels.clear();
}
Node* CompileState::resolveBreakLabel(Identifier label)
{
if (label.isEmpty()) {
if (defaultBreakTargets.isEmpty())
return 0;
else
return defaultBreakTargets.last();
} else {
return labelTargets.get(label);
}
}
Node* CompileState::resolveContinueLabel(Identifier label)
{
if (label.isEmpty()) {
if (defaultContinueTargets.isEmpty())
return 0;
else
return defaultContinueTargets.last();
} else {
return labelTargets.get(label);
}
}
void CompileState::pushNest(NestType type, Node* node)
{
if (type == Scope)
++scopeDepth;
else if (type == TryFinally)
++finallyDepth;
NestInfo inf;
inf.type = type;
inf.node = node;
nests.append(inf);
assert(!(type == ContBreakTarget && !node));
}
void CompileState::popNest()
{
if (nests.last().type == Scope)
--scopeDepth;
else if (nests.last().type == TryFinally)
--finallyDepth;
nests.removeLast();
}
void CompileState::pushDefaultBreak(Node* node)
{
defaultBreakTargets.append(node);
}
void CompileState::pushDefaultContinue(Node* node)
{
defaultContinueTargets.append(node);
}
void CompileState::popDefaultBreak()
{
defaultBreakTargets.removeLast();
}
void CompileState::popDefaultContinue()
{
defaultContinueTargets.removeLast();
}
void CompileState::addPendingBreak(Node* node, Addr addr)
{
if (!pendingBreaks.contains(node))
pendingBreaks.set(node, new WTF::Vector<Addr>());
pendingBreaks.get(node)->append(addr);
}
void CompileState::addPendingContinue(Node* node, Addr addr)
{
if (!pendingContinues.contains(node))
pendingContinues.set(node, new WTF::Vector<Addr>());
pendingContinues.get(node)->append(addr);
}
void CompileState::resolvePendingBreaks(Node* node, Addr dest)
{
const WTF::Vector<Addr>* stats = pendingBreaks.get(node);
if (!stats)
return;
CodeBlock& block = codeBlock();
OpValue newDest = OpValue::immAddr(dest);
for (size_t c = 0; c < stats->size(); ++c)
CodeGen::patchOpArgument(block, (*stats)[c], 0, newDest);
pendingBreaks.remove(node);
delete stats;
}
void CompileState::resolvePendingContinues(Node* node, Addr dest)
{
const WTF::Vector<Addr>* stats = pendingContinues.get(node);
if (!stats)
return;
CodeBlock& block = codeBlock();
OpValue newDest = OpValue::immAddr(dest);
for (size_t c = 0; c < stats->size(); ++c)
CodeGen::patchOpArgument(block, (*stats)[c], 0, newDest);
pendingContinues.remove(node);
delete stats;
}
static OpValue* addrDummy;
OpValue* OpValue::dummyAddr()
{
if (!addrDummy) {
addrDummy = new OpValue;
*addrDummy = OpValue::immAddr(0);
}
return addrDummy;
}
} //namespace KJS
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,394 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
* Copyright (C) 2007, 2008 Maksim Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef COMPILE_STATE_H
#define COMPILE_STATE_H
#include "ExecState.h" // For codetype... Kinda odd.
#include "opcodes.h"
#include "bytecode/opargs.h"
#include <wtf/Assertions.h>
#include <wtf/HashSet.h>
#include <wtf/HashMap.h>
using WTF::HashSet;
using WTF::HashMap;
using WTF::Vector;
namespace KJS {
class RegDescriptor;
class FunctionBodyNode;
enum CompileType
{
NotCompiled,
Release,
Debug
};
class CompileState
{
public:
CompileState(CodeType ctype, CompileType compType, FunctionBodyNode* fbody, Register initialMaxTemp):
localScopeVal(0), thisVal(0), globalScopeVal(0), evalResRegister(0),
ctype(ctype), compType(compType), locals(initialMaxTemp, 0), initialMaxTemp(initialMaxTemp),
maxTemp(initialMaxTemp), fbody(fbody), scopeDepth(0), finallyDepth(0), neededClosures(false)
{ }
FunctionBodyNode* functionBody() {
return fbody;
}
CodeType codeType() const {
return ctype;
}
CodeBlock& codeBlock();
CompileType compileType() const {
return compType;
}
~CompileState();
// Returns true if the register is a formal temporary.
bool isTemporaryReg(Register regNum) {
return regNum >= initialMaxTemp;
}
// We distinguish two kinds of temporaries --- markable and not. They'll get
// corresponding bits set in localStore when that's initialized.
void requestTemporary(OpType type, OpValue* value, OpValue* reference);
// This method is used to acquire a read value of a local...
OpValue localReadVal(Register regNum);
// And this one returns a reference, acquiring it for (immediate) write.
// If there are any active read copies, we will backup the old value to
// a temporary, and petchup their register descriptor to point to the backup.
OpValue localWriteRef(CodeBlock& block, Register regNum);
// This forces all live locals to temporaries.
void localFlushAll(CodeBlock& block);
// This sets the registers containing the local scope and
// 'this' values... It should be the rvalue, not the regnums
void setPreloadRegs(OpValue* localReg, OpValue* globalReg, OpValue* thisReg) {
localScopeVal = localReg;
globalScopeVal = globalReg;
thisVal = thisReg;
}
OpValue* localScope() {
return localScopeVal;
}
OpValue* thisValue() {
return thisVal;
}
OpValue* globalScope() {
return globalScopeVal;
}
void setEvalResultRegister(OpValue* val) {
evalResRegister = val;
}
OpValue* evalResultReg() {
return evalResRegister;
}
// To properly implement operations like continue and break, we need to keep track whether we
// are nested inside with, try-catch and try-finally operations.
// This serves two purposes:
// 1) if we're not jumping out of a try-finally, we have to unwind the cleanup stacks
// 2) if we're inside a try-finally, we have to jump to the finally and not
// do the normal operation (this applies to return as well)
// Also, if we're inside a 'with' or a catch we cannot optimize local variable access.
enum NestType {
Scope,
OtherCleanup,
TryFinally,
ContBreakTarget
};
void pushNest(NestType type, Node* node = 0);
void popNest ();
struct NestInfo {
NestType type;
Node* node;
};
bool inNestedScope() {
return scopeDepth > 0;
}
bool inTryFinally() {
return finallyDepth > 0;
}
const WTF::Vector<NestInfo>& nestStack() {
return nests;
}
// Some constructs can be detected at compile time to involve
// taking of closures. We keep track of that and avoid stack-allocation
// if those are present.
bool needsClosures() {
return neededClosures;
}
void setNeedsClosures() {
neededClosures = true;
}
// Label stuff....
// Registers a pending label. Returns true if the label is OK, false if it's a duplicate.
// If it fails, the label stack isn't touched!
bool pushLabel(const Identifier& label);
void popLabel();
// Binds all the labels to the given node
void bindLabels(Node* node);
// Returns destination for the label (node will be 0 if not found)
Node* resolveContinueLabel(Identifier label);
Node* resolveBreakLabel (Identifier label);
// Sets the targets for break/continues w/o label name
void pushDefaultBreak (Node* node);
void pushDefaultContinue(Node* node);
void popDefaultBreak ();
void popDefaultContinue();
// Helpers for these and resolvePendingBreak
void enterLoop(Node* node) {
pushNest(ContBreakTarget, node);
pushDefaultBreak(node);
pushDefaultContinue(node);
}
void exitLoop(Node* node) {
popNest();
popDefaultBreak();
popDefaultContinue();
resolvePendingBreaks(node, CodeGen::nextPC(this));
}
// Adds break/continue as needing relevant target for given node
void addPendingBreak (Node* node, Addr addr);
void addPendingContinue(Node* node, Addr addr);
// Patches up all pending break/continue statements to given destination.
// LabelNode takes care of the breaks itself, the loops need to deal
// with continue, though.
void resolvePendingBreaks (Node* node, Addr dest);
void resolvePendingContinues(Node* node, Addr dest);
private:
OpValue* localScopeVal;
OpValue* thisVal;
OpValue* globalScopeVal;
OpValue* evalResRegister;
CodeType ctype;
CompileType compType;
// Makes sure that any values of a local are
void flushLocal(CodeBlock& block, Register reg);
friend class RegDescriptor;
WTF::Vector<RegDescriptor*> locals;
WTF::Vector<RegDescriptor*> freeMarkTemps;
WTF::Vector<RegDescriptor*> freeNonMarkTemps;
Register initialMaxTemp;
Register maxTemp;
FunctionBodyNode* fbody;
void reuse(RegDescriptor* desc, bool markable) {
if (markable)
freeMarkTemps.append(desc);
else
freeNonMarkTemps.append(desc);
}
// Cached version of #of Scopes's from below.
int scopeDepth;
// Cached version of #of Finally's from below...
int finallyDepth;
WTF::Vector<NestInfo> nests;
// This is true if we see code constructs that require taking a closure
// inside here, which means we should not stack-allocate activations.
bool neededClosures;
// Label resolution..
WTF::HashSet<Identifier> seenLabels; // all labels we're inside
WTF::Vector <Identifier> seenLabelsStack;
WTF::Vector <Identifier> pendingLabels; // labels tha that haven't been bound to
// a statement yet.
// Targets for continue/break w/o destination.
WTF::Vector<Node*> defaultBreakTargets;
WTF::Vector<Node*> defaultContinueTargets;
// Named label targets
WTF::HashMap<Identifier, Node*> labelTargets;
WTF::HashMap<Node*, WTF::Vector<Addr>* > pendingBreaks;
WTF::HashMap<Node*, WTF::Vector<Addr>* > pendingContinues;
};
// We used register descriptors for two reasons:
// 1) For temporaries, we ref-counted them by OpValue in order to manage their lifetime
// 2) For locals, we use them to do COW of values...
class RegDescriptor
{
public:
RegDescriptor(CompileState* owner, Register reg, bool markable, bool temp = true):
owner(owner), regNo(reg), temp(temp), markable(markable), killed(false), refCount(0)
{}
Register reg() const {
return regNo;
}
void ref() {
++refCount;
}
void deref() {
--refCount;
if (refCount == 0) {
if (killed)
delete this;
else if (temp)
owner->reuse(this, markable);
}
}
bool live() {
return refCount > 0;
}
void adopt(RegDescriptor* other) {
// Make this point to the same as an another descriptor, which is about to die..
temp = other->temp;
markable = other->markable;
regNo = other->regNo;
// Mark the other descriptor as killed, as we took ownership of this.
other->killed = true;
}
private:
CompileState* owner;
Register regNo;
bool temp;
bool markable;
bool killed;
int refCount;
};
inline OpValue OpValue::immInt32(int32_t in) {
OpValue res;
initImm(&res, OpType_int32);
res.value.narrow.int32Val = in;
return res;
}
inline OpValue OpValue::immNumber(double in) {
OpValue res;
initImm(&res, OpType_number);
res.value.wide.numberVal = in;
return res;
}
inline OpValue OpValue::immValue(JSValue* in) {
assert(in);
OpValue res;
initImm(&res, OpType_value);
res.value.wide.valueVal = in;
return res;
}
inline OpValue OpValue::immBool(bool in) {
OpValue res;
initImm(&res, OpType_bool);
res.value.narrow.boolVal = in;
return res;
}
inline OpValue OpValue::immString(UString* in) {
OpValue res;
initImm(&res, OpType_string);
res.value.wide.stringVal = in;
return res;
}
inline OpValue OpValue::immIdent(Identifier* in) {
OpValue res;
initImm(&res, OpType_ident);
res.value.wide.identVal = in;
return res;
}
inline OpValue OpValue::immNode(KJS::Node* in) {
OpValue res;
initImm(&res, OpType_node);
res.value.wide.nodeVal = in;
return res;
}
inline OpValue OpValue::immCStr(const char* in) {
OpValue res;
initImm(&res, OpType_cstr);
res.value.wide.cstrVal = in;
return res;
}
inline OpValue OpValue::immAddr(Addr in) {
OpValue res;
initImm(&res, OpType_addr);
res.value.narrow.addrVal = in;
return res;
}
inline OpValue::OpValue(): type(OpType_void) {} // since should never occur as an argument..
}
#endif
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,110 +0,0 @@
Get rid of SourceElementsNode by integrating its functionality into
StatementNode.
==========================================================================
The hash value of a string could be calculated at creation time and be
stored in the UString instance for later use by the lookup functions.
==========================================================================
Proposal for a new object model. Far from being complete.
Object Type
+---------+ +-------------+
| type | ----------------> | toString() |
| | | toNumber() |
| data | | .... |
+---------+ | construct() |
| +-------------+
| | /|\
\|/ | |
+---------+ | |
| type | | |
| | Shared (optional) \|/ |
| data | +-------------+
+---------+ +---------+ | types |
/|\ | |<------| gc | Interpreter/Environment
+-------| | | .... |
| | | excp state |
+---------+ +-------------+
Garbage Collector
Features:
- offers class static data (nice replacement for pointers to member
function objects in the prototype object)
- no more need to pass around ExecState pointers for the C++ user
(substituted with the need for Object* in the type implementation)
- simple types are stored simple (no new'ed Imp objects)
Alternative A: pass around Object by pointer rather than value
rather than new'ing they should come out of a pool
Alternative B: instead of virtual functions like toBoolean(), Type could
have an array of function pointers which can be modified
on the fly and checked for != 0.
Limitations: Konqueror's requirement to allow access to other frame's
interpreter data but flagging errors on the caller's side
is not satisfied.
class Interpreter;
class Type {
public:
Type(Interpreter* i, Type *b) : ip(i), bs(b) { }
virtual UString name() const = 0;
Type* base() const { return bs; }
Interpreter* interpreter() const { return ip; }
virtual bool toBoolean(Object *o);
// ....
virtual Object construct(const List &args);
// factory
Boolean newBoolean(bool b) { return Boolean(interpreter(), b); }
private:
Interpreter* ip;
Type* bs;
};
union Data {
bool b;
double d;
// UString ???
Shared* sh;
};
class Object {
public:
// creation
Boolean newBoolean(bool b) { return Boolean(typ->interpreter(), b); }
// conversion
bool to Boolean() const { return typ->toBoolean(this); }
// this object's "parent"
Interpreter* interpreter() const { return typ->ip; }
private:
Type* typ;
Data dat;
};
class Boolean : public Object {
public:
// used by convenience function newBoolean()
Boolean(Interpreter *i, bool b) {
typ = i->booleanType();
dat.b = b;
}
Boolean(const Boolean &b) {
typ = b.typ;
dat.b = b.b;
}
Boolean& operator=(const Boolean &b) {
type = b.typ;
dat.b = b.b;
return *this;
}
};

View file

@ -1,301 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2008 Maksim Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "ExecState.h"
#include "function.h"
#include "scriptfunction.h"
#include "internal.h"
#include "nodes.h"
#include "debugger.h"
namespace KJS {
Interpreter* ExecState::lexicalInterpreter() const
{
JSObject* outerScope = scopeChain().bottom();
assert(outerScope->isGlobalObject());
Interpreter* result = static_cast<JSGlobalObject*>(outerScope)->interpreter();
if (!result)
return dynamicInterpreter();
return result;
}
void ExecState::markSelf()
{
if (m_codeType != FunctionCode && m_localStore) {
//### some code dupe here with JSVariableObject::mark. Not sure how to best
// restructure.
// Note: the m_localStore check is needed here, since for non-function code,
// we may create function object in declaration elaboration stage, before
// compilation and set up of this
size_t size = m_localStoreSize;
LocalStorageEntry* entries = m_localStore;
for (size_t i = 0; i < size; ++i) {
JSValue* value = entries[i].val.valueVal;
if (!(entries[i].attributes & DontMark) && !value->marked())
value->mark();
}
}
for (size_t i = 0; i < m_deferredCompletions.size(); ++i) {
JSValue* e = m_deferredCompletions[i].value();
if (e && !e->marked())
e->mark();
}
JSValue* e = m_completion.value();
if (e && !e->marked())
e->mark();
scope.mark();
// Propagate up to other eval chains..
if (m_savedExec && m_savedExec != m_callingExec) {
ASSERT(m_savedExec != this);
m_savedExec->mark();
}
}
void ExecState::mark()
{
for (ExecState* exec = this; exec; exec = exec->m_callingExec)
exec->markSelf();
}
ExecState::ExecState(Interpreter* intp, ExecState* save) :
m_interpreter(intp),
m_propertyNames(CommonIdentifiers::shared()),
m_callingExec(0),
m_savedExec(save),
m_currentBody(0),
m_function(0),
m_localStore(0),
m_pcBase(0),
m_pc(0),
m_machineLocalStore(0)
{
/**
The reason we need m_savedExec and can't just be content with m_callingExec is two-fold.
First of all, in many cases KHTML (and ktranscript) invoke functions such as event handlers
on globalExec. When that happens, we still need to be able to mark the previous call-chain.
Also, it is possible for the client to call Interpreter::evaluate again; and we still
need to mark things from the outside when that happens
*/
if (m_callingExec && m_savedExec && m_callingExec != m_savedExec)
assert(m_callingExec == intp->globalExec());
m_interpreter->setExecState(this);
}
ExecState::~ExecState()
{
m_interpreter->setExecState(m_savedExec);
}
void ExecState::pushExceptionHandler(HandlerType type, Addr addr)
{
m_exceptionHandlers.append(ExceptionHandler(type, addr));
}
void ExecState::popExceptionHandler()
{
m_exceptionHandlers.removeLast();
}
JSValue* ExecState::reactivateCompletion(bool insideTryFinally)
{
// First, unwind and get the old completion..
ASSERT(m_exceptionHandlers.last().type == RemoveDeferred);
popExceptionHandler();
Completion comp = m_deferredCompletions.last();
m_deferredCompletions.removeLast();
// Now, our behavior behaves on whether we're inside an another
// try..finally or not. If we're, we must route even
// continue/break/return completions via the EH machinery;
// if not, we execute them directly
if (comp.complType() == Normal) {
// We just straight fell into 'finally'. Nothing fancy to do.
return 0;
}
if (comp.complType() == Throw || insideTryFinally) {
setAbruptCompletion(comp);
} else {
if (comp.complType() == ReturnValue) {
return comp.value();
} else {
assert(comp.complType() == Break || comp.complType() == Continue);
*m_pc = m_pcBase + comp.target();
}
}
return 0;
}
void ExecState::setException(JSValue* e)
{
if (e)
setAbruptCompletion(Completion(Throw, e));
else
clearException();
}
void ExecState::setAbruptCompletion(Completion comp)
{
// If we already had an exception, merely update the object, to permit
// users to refine the exception, being careful not to double-unwind.
// However, warn about it in debug builds.
if (hadException()) {
#ifndef NDEBUG
printInfo(this, "warning: overriding already set exception ", m_completion.value());
printInfo(this, "with ", comp.value());
#endif
m_completion = comp;
return;
}
// Trace to debugger if needed.
Debugger* dbg = dynamicInterpreter()->debugger();
if (dbg && comp.complType() == Throw)
dbg->reportException(this, comp.value());
m_completion = comp;
while (!m_exceptionHandlers.isEmpty()) {
switch (m_exceptionHandlers.last().type) {
case JumpToCatch:
*m_pc = m_pcBase + m_exceptionHandlers.last().dest;
m_exceptionHandlers.removeLast();
return; // done handling it
case PopScope:
popScope();
m_exceptionHandlers.removeLast();
continue; // get the next handler
case RemoveDeferred:
m_deferredCompletions.removeLast();
m_exceptionHandlers.removeLast();
continue; // get the next handler
case Silent:
// Exception blocked by tracing code. nothing to do.
return;
}
}
}
void ExecState::quietUnwind(int depth)
{
ASSERT(m_exceptionHandlers.size() >= size_t(depth));
for (int e = 0; e < depth; ++e) {
HandlerType type = m_exceptionHandlers.last().type;
m_exceptionHandlers.removeLast();
switch (type) {
case JumpToCatch:
break; //Nothing to do here!
case PopScope:
popScope();
break;
case RemoveDeferred:
m_deferredCompletions.removeLast();
break;
case Silent:
ASSERT(0); // Should not happen in the middle of the code.
break;
}
}
}
GlobalExecState::GlobalExecState(Interpreter* intp, JSGlobalObject* glob): ExecState(intp, 0 /* nothing else constructed yet*/)
{
scope.push(glob);
m_codeType = GlobalCode;
m_variable = glob;
m_thisVal = glob;
}
InterpreterExecState::InterpreterExecState(Interpreter* intp, JSGlobalObject* glob,
JSObject* thisObject, ProgramNode* body):
ExecState(intp, intp->execState())
{
m_currentBody = body;
scope.push(glob);
m_codeType = GlobalCode;
m_variable = glob;
// Per 10.2.1, we should use the global object here, but
// Interpreter::evaluate permits it to be overridden, e.g. for LiveConnect.
m_thisVal = thisObject;
}
EvalExecState::EvalExecState(Interpreter* intp, JSGlobalObject* glob,
ProgramNode* body, ExecState* callingExecState):
ExecState(intp, intp->execState())
{
m_currentBody = body;
m_codeType = EvalCode;
m_callingExec = callingExecState;
if (m_callingExec) {
scope = m_callingExec->scopeChain();
m_variable = m_callingExec->variableObject();
m_thisVal = m_callingExec->thisValue();
return;
}
// 10.2.2 talks about the behavior w/o a calling context here,
// saying it should be like global code. This can not happen
// in actual JS code, but it may be synthesized by e.g.
// the JS debugger calling 'eval' itself, from globalExec
m_thisVal = glob;
m_variable = glob;
scope.push(glob);
}
FunctionExecState::FunctionExecState(Interpreter* intp, JSObject* thisObject,
FunctionBodyNode* body, ExecState* callingExecState,
FunctionImp* function): ExecState(intp, intp->execState())
{
m_function = function;
m_currentBody = body;
m_codeType = FunctionCode;
m_callingExec = callingExecState;
scope = function->scope(); // Activation will push itself when setting up
m_variable = m_interpreter->getRecycledActivation();// TODO: DontDelete ? (ECMA 10.2.3)
if (!m_variable)
m_variable = new ActivationImp();
m_thisVal = thisObject;
}
} // namespace KJS
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,306 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2008 Maksim Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef ExecState_H
#define ExecState_H
#include "completion.h"
#include "value.h"
#include "types.h"
#include "CommonIdentifiers.h"
#include "scope_chain.h"
#include "LocalStorage.h"
#include "wtf/Vector.h"
#include "PropertyNameArray.h"
namespace KJS {
class ActivationImp;
class Interpreter;
class FunctionImp;
class FunctionBodyNode;
class ProgramNode;
class JSGlobalObject;
enum CodeType { GlobalCode, EvalCode, FunctionCode };
/**
* Represents the current state of script execution. This object allows you
* obtain a handle the interpreter that is currently executing the script,
* and also the current execution context.
*/
class KJS_EXPORT ExecState : Noncopyable {
friend class Interpreter;
friend class FunctionImp;
friend class GlobalFuncImp;
public:
/**
* Returns the interpreter associated with this execution state
*
* @return The interpreter executing the script
*/
Interpreter* dynamicInterpreter() const { return m_interpreter; }
/**
* Returns the interpreter associated with the current scope's
* global object
*
* @return The interpreter currently in scope
*/
Interpreter* lexicalInterpreter() const;
/**
* This describes how an exception should be handled
*/
enum HandlerType {
JumpToCatch, ///< jump to the specified address
PopScope, ///< remove a scope chain entry, and run the next handler
RemoveDeferred, ///< remove any deferred exception object, and run the next entry
Silent ///< just update the exception object. For debugger-type use only
};
void pushExceptionHandler(HandlerType type, Addr addr = 0);
void popExceptionHandler();
// Cleanup depth entries from the stack, w/o running jumps
void quietUnwind(int depth);
void setMachineRegisters(const unsigned char* pcBase, const unsigned char** pcLoc, LocalStorageEntry** machineLocalStoreLoc) {
m_pcBase = pcBase;
m_pc = pcLoc;
m_machineLocalStore = machineLocalStoreLoc;
}
/**
The below methods deal with deferring of completions inside finally clauses.
Essentially, we clear any set exceptions and memorize any non-normal completion
(including the target addresses for the continue/break statements) on
the m_deferredCompletions stack. If the 'finally' finishes normally,
we will resume the previous completion. If not, finally's abnormal
termination is handled as usually; a RemoveDeferred cleanup stack
entry is added to unwind m_deferredCompletions if that happens.
*/
void deferCompletion() {
pushExceptionHandler(RemoveDeferred);
m_deferredCompletions.append(abruptCompletion());
clearException();
}
/**
This resumes dispatch of a completion that was deferred due to a try ... finally,
handling it as appropriate for whether it's inside an another try-finally.
This will handle all the cases itself except for one: return,
for which it will return the value to return (otherwise returning 0)
*/
JSValue* reactivateCompletion(bool insideTryFinally);
/**
* Set the exception associated with this execution state,
* updating the program counter appropriately, and executing any relevant EH cleanups.
* @param e The JSValue of the exception being set
*/
void setException(JSValue* e);
/**
* Records an abrupt completion of code, and jumps to the closest catch or finally.
* This always happens for exceptions, but can also happen for continue/break/return when
* they're inside try ... finally, since that case gets routed through the EH machinery.
*/
void setAbruptCompletion(Completion comp);
/**
* Clears the exception or other abnormal completion set on this execution state.
*/
void clearException() { m_completion = Completion(); }
/**
* Returns the exception associated with this execution state.
* @return The current execution state exception
*/
JSValue* exception() const { return m_completion.complType() == Throw ? m_completion.value() : 0; }
/**
* Use this to check if an exception was thrown in the current
* execution state.
*
* @return Whether an exception was thrown
*/
bool hadException() const { return m_completion.complType() == Throw; }
Completion abruptCompletion() const { return m_completion; }
/**
* Returns the scope chain for this execution context. This is used for
* variable lookup, with the list being searched from start to end until a
* variable is found.
*
* @return The execution context's scope chain
*/
const ScopeChain& scopeChain() const { return scope; }
/**
* Returns the variable object for the execution context. This contains a
* property for each variable declared in the execution context.
*
* @return The execution context's variable object
*/
JSObject* variableObject() const { return m_variable; }
void setVariableObject(JSObject* v) { m_variable = v; }
/**
* Returns the "this" value for the execution context. This is the value
* returned when a script references the special variable "this". It should
* always be an Object, unless application-specific code has passed in a
* different type.
*
* The object that is used as the "this" value depends on the type of
* execution context - for global contexts, the global object is used. For
* function objewcts, the value is given by the caller (e.g. in the case of
* obj.func(), obj would be the "this" value). For code executed by the
* built-in "eval" function, the this value is the same as the calling
* context.
*
* @return The execution context's "this" value
*/
JSObject* thisValue() const { return m_thisVal; }
/**
* Returns the context from which the current context was invoked. For
* global code this will be a null context (i.e. one for which
* isNull() returns true). You should check isNull() on the returned
* value before calling any of its methods.
*
* @return The calling execution context
*/
ExecState* callingExecState() { return m_callingExec; }
/**
* Returns the execState of a previous nested evaluation session, if any.
*/
ExecState* savedExecState() { return m_savedExec; }
JSObject* activationObject() {
assert(m_codeType == FunctionCode);
return m_variable;
}
CodeType codeType() { return m_codeType; }
FunctionBodyNode* currentBody() { return m_currentBody; }
FunctionImp* function() const { return m_function; }
void pushVariableObjectScope(JSVariableObject* s) { scope.pushVariableObject(s); }
void pushScope(JSObject* s) { scope.push(s); }
void popScope() { scope.pop(); }
void mark();
void initLocalStorage(LocalStorageEntry* store, size_t size) {
m_localStore = store;
m_localStoreSize = size;
}
void updateLocalStorage(LocalStorageEntry* newStore) {
m_localStore = newStore;
*m_machineLocalStore = newStore;
}
LocalStorageEntry* localStorage() { return m_localStore; }
// This is a workaround to avoid accessing the global variables for these identifiers in
// important property lookup functions, to avoid taking PIC branches in Mach-O binaries
const CommonIdentifiers& propertyNames() const { return *m_propertyNames; }
// Compatibility stuff:
ExecState* context() { return this; }
ExecState* callingContext() { return callingExecState(); }
protected:
ExecState(Interpreter* intp, ExecState* save);
~ExecState();
void markSelf();
Interpreter* m_interpreter;
Completion m_completion;
CommonIdentifiers* m_propertyNames;
ExecState* m_callingExec;
ExecState* m_savedExec; // in case of recursion of evaluation. Needed to mark things properly;
// note that this is disjoint from the above, since that's only used for
// eval/function, while this is for global.
FunctionBodyNode* m_currentBody;
FunctionImp* m_function;
ScopeChain scope;
JSObject* m_variable;
JSObject* m_thisVal;
LocalStorageEntry* m_localStore;
size_t m_localStoreSize;
struct ExceptionHandler {
ExceptionHandler() {}
ExceptionHandler(HandlerType type, Addr dest):
type(type), dest(dest) {}
HandlerType type;
Addr dest;
};
const unsigned char* m_pcBase; // The address of pc = 0
const unsigned char** m_pc; // Where the current fetch address is stored
LocalStorageEntry** m_machineLocalStore; // Machine's copy of m_localStore
WTF::Vector<ExceptionHandler, 4> m_exceptionHandlers;
WTF::Vector<Completion, 4> m_deferredCompletions;
CodeType m_codeType;
};
typedef ExecState Context; // Compatibility only
class GlobalExecState : public ExecState {
public:
GlobalExecState(Interpreter* intp, JSGlobalObject* global);
};
class InterpreterExecState : public ExecState {
public:
InterpreterExecState(Interpreter* intp, JSGlobalObject* global, JSObject* thisObject, ProgramNode*);
};
class EvalExecState : public ExecState {
public:
EvalExecState(Interpreter* intp, JSGlobalObject* global, ProgramNode* body, ExecState* callingExecState);
};
// Note: this does not push the activation on the scope chain,
// as the activation is not initialized at this point.
class FunctionExecState : public ExecState {
public:
FunctionExecState(Interpreter* intp, JSObject* thisObject,
FunctionBodyNode*, ExecState* callingExecState, FunctionImp*);
};
} // namespace KJS
#endif // ExecState_H

View file

@ -1,77 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2003-2006 Apple Computer, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "JSImmediate.h"
#include "object.h"
namespace KJS {
JSObject *JSImmediate::toObject(const JSValue *v, ExecState *exec)
{
assert(isImmediate(v));
if (v == jsNull())
return throwError(exec, TypeError, "Null value");
else if (v == jsUndefined())
return throwError(exec, TypeError, "Undefined value");
else if (isBoolean(v)) {
List args;
args.append(const_cast<JSValue *>(v));
return exec->lexicalInterpreter()->builtinBoolean()->construct(exec, args);
} else {
ASSERT(isNumber(v));
List args;
args.append(const_cast<JSValue *>(v));
return exec->lexicalInterpreter()->builtinNumber()->construct(exec, args);
}
}
UString JSImmediate::toString(const JSValue *v)
{
ASSERT(isImmediate(v));
if (v == jsNull())
return "null";
else if (v == jsUndefined())
return "undefined";
else if (v == jsBoolean(true))
return "true";
else if (v == jsBoolean(false))
return "false";
else {
assert(isNumber(v));
double d = toDouble(v);
if (d == 0.0) // +0.0 or -0.0
return "0";
return UString::from(d);
}
}
JSType JSImmediate::type(const JSValue *v)
{
ASSERT(isImmediate(v));
uintptr_t tag = getTag(v);
if (tag == UndefinedType)
return v == jsUndefined() ? UndefinedType : NullType;
return static_cast<JSType>(tag);
}
} // namespace KJS

View file

@ -1,311 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
* Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef KJS_JS_IMMEDIATE_H
#define KJS_JS_IMMEDIATE_H
#include <kjs/global.h>
#include "JSType.h"
#include <wtf/Assertions.h>
#include <wtf/AlwaysInline.h>
#include <wtf/MathExtras.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdlib.h>
#if PLATFORM(SOLARIS_OS)
static inline int signbit(double x)
{
return (x<0.0) ? 1 : 0;
}
#endif
namespace KJS {
class ExecState;
class JSObject;
class JSValue;
class UString;
KJS_EXPORT extern const double NaN;
KJS_EXPORT extern const double Inf;
/*
* A JSValue* is either a pointer to a cell (a heap-allocated object) or an immediate (a type-tagged
* signed int masquerading as a pointer). The low two bits in a JSValue* are available
* for type tagging because allocator alignment guarantees they will be 00 in cell pointers.
*
* For example, on a 32 bit system:
*
* JSCell*: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 00
* [ high 30 bits: pointer address ] [ low 2 bits -- always 0 ]
*
* JSImmediate: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX TT
* [ high 30 bits: signed int ] [ low 2 bits -- type tag ]
*
* The bit "payload" (the high 30 bits) is a 30 bit signed int for immediate numbers, a flag to distinguish true/false
* and undefined/null.
*
* Notice that the JSType value of NullType is 4, which requires 3 bits to encode. Since we only have 2 bits
* available for type tagging, we tag the null immediate with UndefinedType, and JSImmediate::type() has
* to sort them out.
*/
class KJS_EXPORT JSImmediate {
public:
static ALWAYS_INLINE bool isImmediate(const JSValue* v)
{
return getTag(v) != 0;
}
static ALWAYS_INLINE bool isNumber(const JSValue* v)
{
return (getTag(v) == NumberType);
}
static ALWAYS_INLINE bool isBoolean(const JSValue* v)
{
return (getTag(v) == BooleanType);
}
// Since we have room for only 3 unique tags, null and undefined have to share.
static ALWAYS_INLINE bool isUndefinedOrNull(const JSValue* v)
{
return (getTag(v) == UndefinedType);
}
static JSValue* from(char);
static JSValue* from(signed char);
static JSValue* from(unsigned char);
static JSValue* from(short);
static JSValue* from(unsigned short);
static JSValue* from(int);
static JSValue* from(unsigned);
static JSValue* from(long);
static JSValue* from(unsigned long);
static JSValue* from(long long);
static JSValue* from(unsigned long long);
static JSValue* from(double);
static ALWAYS_INLINE bool areBothImmediateNumbers(const JSValue* v1, const JSValue* v2)
{
return (reinterpret_cast<uintptr_t>(v1) & reinterpret_cast<uintptr_t>(v2) & TagMask) == NumberType;
}
static ALWAYS_INLINE JSValue* andImmediateNumbers(const JSValue* v1, const JSValue* v2)
{
ASSERT(areBothImmediateNumbers(v1, v2));
return reinterpret_cast<JSValue*>(reinterpret_cast<uintptr_t>(v1) & reinterpret_cast<uintptr_t>(v2));
}
static double toDouble(const JSValue*);
// Non-converting getters for Number's
static double getNumber(const JSValue*); // This returns NaN if the value is not a Number.
static bool getNumber(const JSValue*, double& valOut);
static bool toBoolean(const JSValue*);
static JSObject* toObject(const JSValue*, ExecState*);
static UString toString(const JSValue*);
static JSType type(const JSValue*);
static bool getUInt32(const JSValue*, uint32_t&);
static bool getTruncatedInt32(const JSValue*, int32_t&);
static bool getTruncatedUInt32(const JSValue*, uint32_t&);
static int32_t getTruncatedInt32(const JSValue*);
static JSValue* trueImmediate();
static JSValue* falseImmediate();
static JSValue* undefinedImmediate();
static JSValue* nullImmediate();
private:
static const uintptr_t TagMask = 3; // type tags are 2 bits long
// Immediate values are restricted to a 30 bit signed value.
static const int minImmediateInt = -(1 << 29);
static const int maxImmediateInt = (1 << 29) - 1;
static const unsigned maxImmediateUInt = maxImmediateInt;
static ALWAYS_INLINE JSValue* tag(uintptr_t bits, uintptr_t tag)
{
return reinterpret_cast<JSValue*>(bits | tag);
}
static ALWAYS_INLINE uintptr_t unTag(const JSValue* v)
{
return reinterpret_cast<uintptr_t>(v) & ~TagMask;
}
static ALWAYS_INLINE uintptr_t getTag(const JSValue* v)
{
return reinterpret_cast<uintptr_t>(v) & TagMask;
}
};
ALWAYS_INLINE JSValue* JSImmediate::trueImmediate() { return tag(1 << 2, BooleanType); }
ALWAYS_INLINE JSValue* JSImmediate::falseImmediate() { return tag(0, BooleanType); }
ALWAYS_INLINE JSValue* JSImmediate::undefinedImmediate() { return tag(1 << 2, UndefinedType); }
ALWAYS_INLINE JSValue* JSImmediate::nullImmediate() { return tag(0, UndefinedType); }
ALWAYS_INLINE bool JSImmediate::toBoolean(const JSValue* v)
{
ASSERT(isImmediate(v));
uintptr_t bits = unTag(v);
return (bits != 0) & (JSImmediate::getTag(v) != UndefinedType);
}
ALWAYS_INLINE JSValue* JSImmediate::from(char i)
{
return tag(i << 2, NumberType);
}
ALWAYS_INLINE JSValue* JSImmediate::from(signed char i)
{
return tag(i << 2, NumberType);
}
ALWAYS_INLINE JSValue* JSImmediate::from(unsigned char i)
{
return tag(i << 2, NumberType);
}
ALWAYS_INLINE JSValue* JSImmediate::from(short i)
{
return tag(i << 2, NumberType);
}
ALWAYS_INLINE JSValue* JSImmediate::from(unsigned short i)
{
return tag(i << 2, NumberType);
}
ALWAYS_INLINE JSValue* JSImmediate::from(int i)
{
if ((i < minImmediateInt) || (i > maxImmediateInt))
return 0;
return tag(i << 2, NumberType);
}
ALWAYS_INLINE JSValue* JSImmediate::from(unsigned i)
{
if (i > maxImmediateUInt)
return 0;
return tag(i << 2, NumberType);
}
ALWAYS_INLINE JSValue* JSImmediate::from(long i)
{
if ((i < minImmediateInt) || (i > maxImmediateInt))
return 0;
return tag(i << 2, NumberType);
}
ALWAYS_INLINE JSValue* JSImmediate::from(unsigned long i)
{
if (i > maxImmediateUInt)
return 0;
return tag(i << 2, NumberType);
}
ALWAYS_INLINE JSValue* JSImmediate::from(long long i)
{
if ((i < minImmediateInt) || (i > maxImmediateInt))
return 0;
return tag(static_cast<uintptr_t>(i) << 2, NumberType);
}
ALWAYS_INLINE JSValue* JSImmediate::from(unsigned long long i)
{
if (i > maxImmediateUInt)
return 0;
return tag(static_cast<uintptr_t>(i) << 2, NumberType);
}
ALWAYS_INLINE JSValue* JSImmediate::from(double d)
{
const int intVal = static_cast<int>(d);
if ((intVal < minImmediateInt) || (intVal > maxImmediateInt))
return 0;
// Check for data loss from conversion to int.
if ((intVal != d) || (!intVal && signbit(d)))
return 0;
return tag(intVal << 2, NumberType);
}
ALWAYS_INLINE int32_t JSImmediate::getTruncatedInt32(const JSValue* v)
{
ASSERT(isNumber(v));
return static_cast<int32_t>(unTag(v)) >> 2;
}
ALWAYS_INLINE double JSImmediate::toDouble(const JSValue* v)
{
ASSERT(isImmediate(v));
const int32_t i = static_cast<int32_t>(unTag(v)) >> 2;
if (JSImmediate::getTag(v) == UndefinedType && i)
return NaN;
return i;
}
ALWAYS_INLINE double JSImmediate::getNumber(const JSValue* v)
{
ASSERT(isImmediate(v));
const int32_t i = static_cast<int32_t>(unTag(v)) >> 2;
if (JSImmediate::getTag(v) != NumberType)
return NaN;
return i;
}
ALWAYS_INLINE bool JSImmediate::getNumber(const JSValue* v, double& numberOut)
{
ASSERT(isImmediate(v));
numberOut = static_cast<int32_t>(unTag(v)) >> 2;
return (JSImmediate::getTag(v) == NumberType);
}
ALWAYS_INLINE bool JSImmediate::getUInt32(const JSValue* v, uint32_t& i)
{
const int32_t si = static_cast<int32_t>(unTag(v)) >> 2;
i = si;
return isNumber(v) & (si >= 0);
}
ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(const JSValue* v, int32_t& i)
{
i = static_cast<int32_t>(unTag(v)) >> 2;
return isNumber(v);
}
ALWAYS_INLINE bool JSImmediate::getTruncatedUInt32(const JSValue* v, uint32_t& i)
{
return getUInt32(v, i);
}
} // namespace KJS
#endif

View file

@ -1,84 +0,0 @@
// -*- mode: c++; c-basic-offset: 4 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 2005 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA
*
*/
#include "JSLock.h"
#include <config-kjs.h>
#include "collector.h"
namespace KJS {
#if USE(MULTIPLE_THREADS)
static pthread_once_t interpreterLockOnce = PTHREAD_ONCE_INIT;
static pthread_mutex_t interpreterLock;
static int interpreterLockCount = 0;
static void initializeJSLock()
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&interpreterLock, &attr);
}
void JSLock::lock()
{
pthread_once(&interpreterLockOnce, initializeJSLock);
pthread_mutex_lock(&interpreterLock);
interpreterLockCount++;
Collector::registerThread();
}
void JSLock::unlock()
{
interpreterLockCount--;
pthread_mutex_unlock(&interpreterLock);
}
int JSLock::lockCount()
{
return interpreterLockCount;
}
#endif
JSLock::DropAllLocks::DropAllLocks()
{
int lockCount = JSLock::lockCount();
for (int i = 0; i < lockCount; i++) {
JSLock::unlock();
}
m_lockCount = lockCount;
}
JSLock::DropAllLocks::~DropAllLocks()
{
int lockCount = m_lockCount;
for (int i = 0; i < lockCount; i++) {
JSLock::lock();
}
}
}

View file

@ -1,85 +0,0 @@
// -*- mode: c++; c-basic-offset: 4 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 2005 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef JSLOCK_H
#define JSLOCK_H
#include "global.h"
namespace KJS {
// to make it safe to use JavaScript on multiple threads, it is
// important to lock before doing anything that allocates a
// garbage-collected object or which may affect other shared state
// such as the protect count hash table. The simplest way to do
// this is by having a local JSLock object for the scope
// where the lock must be held. The lock is recursive so nesting
// is ok.
// Sometimes it is necessary to temporarily release the lock -
// since it is recursive you have to actually release all locks
// held by your thread. This is safe to do if you are executing
// code that doesn't require the lock, and reacquire the right
// number of locks at the end. You can do this by constructing a
// locally scoped JSLock::DropAllLocks object.
class KJS_EXPORT JSLock
{
public:
JSLock()
{
lock();
}
~JSLock() {
unlock();
}
static void lock();
static void unlock();
static int lockCount();
class DropAllLocks {
public:
DropAllLocks();
~DropAllLocks();
private:
int m_lockCount;
DropAllLocks(const DropAllLocks&);
DropAllLocks& operator=(const DropAllLocks&);
};
private:
JSLock(const JSLock&);
JSLock& operator=(const JSLock&);
};
#if !USE(MULTIPLE_THREADS)
inline void JSLock::lock() {}
inline void JSLock::unlock() {}
// Fix the lock count at 1 so assertions that the lock is held don't fail
inline int JSLock::lockCount() { return 1; }
#endif
} // namespace
#endif // JSLOCK_H

View file

@ -1,43 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2006 Apple Computer, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef KJS_JSTYPE_H
#define KJS_JSTYPE_H
namespace KJS {
/**
* Primitive types
*/
enum JSType {
UnspecifiedType = 0,
NumberType = 1,
BooleanType = 2,
UndefinedType = 3,
NullType = 4,
StringType = 5,
ObjectType = 6,
GetterSetterType = 7
};
} // namespace KJS
#endif

View file

@ -1,89 +0,0 @@
/*
* Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
* (C) 2008 Maksim Orlovich <maksim@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* Portions of this code that are (C) 2007, 2008 Apple Inc. were
* originally distributed under the following terms
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <config-kjs.h>
#include "JSVariableObject.h"
#include "PropertyNameArray.h"
#include "property_map.h"
namespace KJS {
bool JSVariableObject::deleteProperty(ExecState* exec, const Identifier& propertyName)
{
if (symbolTable->contains(propertyName.ustring().rep()))
return false;
return JSObject::deleteProperty(exec, propertyName);
}
void JSVariableObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, PropertyMap::PropertyMode mode)
{
SymbolTable::const_iterator::Keys end = symbolTable->end().keys();
for (SymbolTable::const_iterator::Keys it = symbolTable->begin().keys(); it != end; ++it)
propertyNames.add(Identifier(it->get()));
JSObject::getOwnPropertyNames(exec, propertyNames, mode);
}
void JSVariableObject::mark()
{
JSObject::mark();
if (!localStorage)
return;
size_t size = lengthSlot();
LocalStorageEntry* entries = localStorage;
for (size_t i = 0; i < size; ++i) {
JSValue* value = entries[i].val.valueVal;
if (!(entries[i].attributes & DontMark) && !value->marked())
value->mark();
}
}
} // namespace KJS

View file

@ -1,181 +0,0 @@
/*
* Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
* (C) 2008 Maksim Orlovich <maksim@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* Portions of this code that are (C) 2007, 2008 Apple Inc. were
* originally distributed under the following terms
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef JSVariableObject_h
#define JSVariableObject_h
#include "LocalStorage.h"
#include "SymbolTable.h"
#include "object.h"
#include <wtf/Vector.h>
namespace KJS {
class Interpreter;
class JSVariableObject : public JSObject {
public:
using KJS::JSObject::deleteProperty;
virtual bool deleteProperty(ExecState*, const Identifier&);
virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, PropertyMap::PropertyMode mode);
virtual void mark();
enum {
LengthSlot,
TearOffNeeded, // Set when a tearoff is requested;
// the actual tearoff will only happen once the function
// stops running, though
ScopeLink,
NumVarObjectSlots = 3
};
int32_t& lengthSlot() { return localStorage[LengthSlot].val.int32Val; }
const int32_t& lengthSlot() const { return localStorage[LengthSlot].val.int32Val; }
bool& tearOffNeededSlot() { return localStorage[TearOffNeeded].val.boolVal; }
ScopeChainLink& scopeLink() { return localStorage[ScopeLink].val.scopeVal; }
protected:
JSVariableObject(): localStorage(0), symbolTable(0) { }
~JSVariableObject();
bool symbolTableGet(const Identifier&, PropertySlot&);
bool symbolTablePut(const Identifier&, JSValue*, bool checkReadOnly);
public:
LocalStorageEntry* localStorage; // Storage for variables in the symbol table.
SymbolTable* symbolTable; // Maps name -> index in localStorage.
};
inline bool JSVariableObject::symbolTableGet(const Identifier& propertyName, PropertySlot& slot)
{
size_t index = symbolTable->get(propertyName.ustring().rep());
if (index != missingSymbolMarker()) {
slot.setValueSlot(this, &localStorage[index].val.valueVal);
return true;
}
return false;
}
inline bool JSVariableObject::symbolTablePut(const Identifier& propertyName, JSValue* value, bool checkReadOnly)
{
size_t index = symbolTable->get(propertyName.ustring().rep());
if (index == missingSymbolMarker())
return false;
LocalStorageEntry& entry = localStorage[index];
if (checkReadOnly && (entry.attributes & ReadOnly))
return true;
entry.val.valueVal = value;
return true;
}
inline JSVariableObject::~JSVariableObject()
{
if (localStorage) {
scopeLink().deref();
if (tearOffNeededSlot())
delete[] localStorage;
}
}
inline JSObject* ScopeChainLink::object() const
{
if (isToScopeChainNode())
return asScopeChainNode()->object;
else
return asVariableObject();
}
inline ScopeChainLink ScopeChainLink::next() const
{
if (isToScopeChainNode())
return asScopeChainNode()->next;
else
return asVariableObject()->scopeLink();
}
inline void ScopeChain::mark()
{
for (ScopeChainLink n = m_top; n.ptr; n = n.next()) {
JSObject *o = n.object();
if (!o->marked())
o->mark();
}
}
inline void ScopeChain::pushVariableObject(JSVariableObject* act)
{
// note: this assumes the new variable object is not in any
// scope chain in the moment.
// Set the item's next pointer to the current top.
// there is no refcount ops since it's transferring a reference
act->scopeLink() = m_top;
// new top!
m_top.set(act);
}
class KJS_EXPORT JSGlobalObject : public JSObject // ### TODO: should inherit off JSVariableObject
{
public:
JSGlobalObject(): m_interpreter(0) {}
JSGlobalObject(JSValue* proto): JSObject(proto), m_interpreter(0) {}
virtual bool isGlobalObject() const { return true; }
void setInterpreter(Interpreter* intp) { m_interpreter = intp; }
Interpreter* interpreter() const { return m_interpreter; }
private:
Interpreter* m_interpreter;
};
} // namespace KJS
#endif // JSVariableObject_h
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,36 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* Copyright (C) 2006 Maks Orlovich <maksim@kde.org>
* Copyright (C) 2006 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "JSWrapperObject.h"
namespace KJS {
void JSWrapperObject::mark()
{
JSObject::mark();
if (m_internalValue && !m_internalValue->marked())
m_internalValue->mark();
if (!m_originalProto->marked())
m_originalProto->mark();
}
} // namespace KJS

View file

@ -1,96 +0,0 @@
// -*- mode: c++; c-basic-offset: 4 -*-
/*
* Copyright (C) 2006 Maks Orlovich <maksim@kde.org>
* Copyright (C) 2006 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef KJS_JSWrapperObject_h
#define KJS_JSWrapperObject_h
#include "object.h"
namespace KJS {
/**
This class is used as a base for classes such as String,
Number, Boolean and Date which which are wrappers for primitive
types. These classes stores the internal value, which is the
actual value represented by the wrapper objects.
*/
class JSWrapperObject : public JSObject {
public:
JSWrapperObject(JSValue* proto);
/**
* Returns the internal value of the object. This is used for objects such
* as String and Boolean which are wrappers for native types. The interal
* value is the actual value represented by the wrapper objects.
*
* @see ECMA 8.6.2
* @return The internal value of the object
*/
JSValue* internalValue() const;
/**
* Sets the internal value of the object
*
* @see internalValue()
*
* @param v The new internal value
*/
void setInternalValue(JSValue* v);
virtual void mark();
/**
* Returns the prototype this object had during construction
*/
JSValue* originalProto() const;
private:
JSValue* m_internalValue;
JSValue* m_originalProto;
};
inline JSWrapperObject::JSWrapperObject(JSValue* proto)
: JSObject(proto)
, m_internalValue(0)
, m_originalProto(proto)
{
}
inline JSValue* JSWrapperObject::internalValue() const
{
return m_internalValue;
}
inline JSValue* JSWrapperObject::originalProto() const
{
return m_originalProto;
}
inline void JSWrapperObject::setInternalValue(JSValue* v)
{
ASSERT(v);
m_internalValue = v;
}
} // namespace KJS
#endif // KJS_JSWrapperObject_h
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on; hl c++;

View file

@ -1,68 +0,0 @@
// -*- mode: c++; c-basic-offset: 4 -*-
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2003, 2006, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
* Copyright (C) 2007 Maks Orlovich
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef KJS_LOCAL_STORAGE_H
#define KJS_LOCAL_STORAGE_H
#include "kjs/global.h"
#ifdef HAVE_STDINT_H
#include <stdint.h> // int32_t
#endif
#include <wtf/Vector.h>
#include <wtf/VectorTraits.h>
#include "scope_chain.h" // for ScopeChainLink
namespace KJS {
class JSValue;
struct LocalStorageEntry {
LocalStorageEntry()
{
}
LocalStorageEntry(JSValue* v, unsigned a) :
attributes(a)
{
val.valueVal = v;
}
union {
double numberVal; //### TODO: use 2 entries for this on 32-bit..
JSValue* valueVal;
bool boolVal;
int32_t int32Val;
ScopeChainLink scopeVal;
} val;
unsigned attributes;
};
typedef Vector<LocalStorageEntry, 32> LocalStorage;
}
namespace WTF {
template<> struct VectorTraits<KJS::LocalStorageEntry> : VectorTraitsBase<true, KJS::LocalStorageEntry> { };
}
#endif // KJS_LOCAL_STORAGE_H

View file

@ -1,30 +0,0 @@
/** @mainpage KDE JavaScript/EcmaScript Engine
This library provides an ECMAScript compatible interpreter. The ECMA standard
is based on well known scripting languages such as Netscape's JavaScript and
Microsoft's JScript.
@authors
Harri Porten \<porten@kde.org\><br>
Maks Orlovich \<maksim@kde.org\><br>
Apple Computer, Inc.<br>
Richard Moore \<rich@kde.org\><br>
Daegeun Lee \<realking@mizi.com\><br>
Marco Pinelli \<pinmc@libero.it\><br>
Christian Kirsch \<ck@held.mind.de\>
@maintainers
Maks Orlovich \<maksim@kde.org\><br>
Harri Porten \<porten@kde.org\>
@licenses
@lgpl
*/
// DOXYGEN_REFERENCES = kdecore
// DOXYGEN_SET_PROJECT_NAME = KJS
// DOXYGEN_SET_EXCLUDE_PATTERNS += */wtf/*
// DOXYGEN_SET_EXCLUDE_PATTERNS += */kjs/*.cpp */kjs/*.h
// vim:ts=4:sw=4:expandtab:filetype=doxygen

View file

@ -1,147 +0,0 @@
// -*- c-basic-offset: 4 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2003, 2006, 2007 Apple Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "Parser.h"
#include <config-kjs.h>
#include "lexer.h"
#include "nodes.h"
#include <wtf/HashSet.h>
#include <wtf/Vector.h>
#ifdef KJS_VERBOSE
#include <stdio.h>
#endif
extern int kjsyyparse();
namespace KJS {
Parser::Parser()
: m_sourceId(0)
{
}
PassRefPtr<ProgramNode> Parser::parseProgram(const UString& sourceURL, int startingLineNumber,
const UChar* code, unsigned length,
int* sourceId, int* errLine, UString* errMsg)
{
parse(sourceURL, startingLineNumber, code, length, sourceId, errLine, errMsg);
return m_progNode.release();
}
static HashSet<Node*>* nodeCycles;
void Parser::noteNodeCycle(Node *node)
{
if (!nodeCycles)
nodeCycles = new HashSet<Node*>;
nodeCycles->add(node);
}
void Parser::removeNodeCycle(Node *node)
{
ASSERT(nodeCycles);
nodeCycles->remove(node);
}
static void clearNewNodes()
{
if (nodeCycles) {
for (HashSet<Node*>::iterator it = nodeCycles->begin(); it != nodeCycles->end(); ++it)
(*it)->breakCycle();
delete nodeCycles;
nodeCycles = 0;
}
Node::clearNewNodes();
}
PassRefPtr<FunctionBodyNode> Parser::parseFunctionBody(const UString& sourceURL, int startingLineNumber,
const UChar* code, unsigned length,
int* sourceId, int* errLine, UString* errMsg)
{
parse(sourceURL, startingLineNumber, code, length, sourceId, errLine, errMsg);
return m_progNode.release();
}
void Parser::parse(const UString& sourceURL, int startingLineNumber,
const UChar* code, unsigned length,
int* sourceId, int* errLine, UString* errMsg)
{
pushFunctionContext(0);
ASSERT(!m_progNode);
if (errLine)
*errLine = -1;
if (errMsg)
*errMsg = 0;
Lexer& lexer = KJS::lexer();
lexer.setCode(sourceURL, startingLineNumber, code, length);
m_sourceId++;
if (sourceId)
*sourceId = m_sourceId;
// Enable this and the #define YYDEBUG in grammar.y to debug a parse error
//extern int kjsyydebug;
//kjsyydebug=1;
int parseError = kjsyyparse();
bool lexError = lexer.sawError();
lexer.clear();
clearNewNodes();
if (parseError || lexError) {
if (errLine)
*errLine = lexer.lineNo();
if (errMsg)
*errMsg = "Parse error";
m_progNode = 0;
return;
}
#ifdef KJS_VERBOSE
fprintf( stderr, "%s\n", m_progNode->toString().ascii() );
#endif
}
void Parser::didFinishParsing(PassRefPtr<ProgramNode> progNode)
{
m_progNode = progNode;
}
Parser& parser()
{
// ASSERT(JSLock::currentThreadIsHoldingLock());
static Parser staticParser;
return staticParser;
}
} // namespace KJS

View file

@ -1,106 +0,0 @@
// -*- c-basic-offset: 4 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2003, 2006, 2007 Apple Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef Parser_h
#define Parser_h
#include <wtf/Forward.h>
#include <wtf/Noncopyable.h>
#include <wtf/RefPtr.h>
#include <wtf/Vector.h>
namespace KJS {
class Node;
class FunctionBodyNode;
class ProgramNode;
class UString;
struct UChar;
/**
* @internal
*
* Parses ECMAScript source code and converts into ProgramNode objects, which
* represent the root of a parse tree. The tree is then semantically
* checked with a semantic analyzer. This class provides a convenient
* workaround for the problem of the bison parser working in a static context.
*/
class Parser : Noncopyable {
public:
PassRefPtr<ProgramNode> parseProgram(const UString& sourceURL, int startingLineNumber,
const UChar* code, unsigned length,
int* sourceId = 0, int* errLine = 0, UString* errMsg = 0);
PassRefPtr<FunctionBodyNode> parseFunctionBody(const UString& sourceURL, int startingLineNumber,
const UChar* code, unsigned length,
int* sourceId = 0, int* errLine = 0, UString* errMsg = 0);
int sourceId() { return m_sourceId; }
void didFinishParsing(PassRefPtr<ProgramNode>);
static void noteNodeCycle(Node*);
static void removeNodeCycle(Node*);
// We keep track of various flags about the function body we're
// tracking on a stack; the FunctionBody ctor pops them off
// when we're done parsing and are making the body node.
void pushFunctionContext(unsigned initialFlags);
void setFunctionFlags(unsigned newFlags);
unsigned popFunctionContext();
private:
friend Parser& parser();
Parser(); // Use parser() instead.
void parse(const UString& sourceURL, int startingLineNumber,
const UChar* code, unsigned length,
int* sourceId = 0, int* errLine = 0, UString* errMsg = 0);
int m_sourceId;
RefPtr<ProgramNode> m_progNode;
WTF::Vector<unsigned, 8> m_functionFlags;
};
Parser& parser(); // Returns the singleton JavaScript parser.
inline void Parser::pushFunctionContext(unsigned initialFlags) {
m_functionFlags.append(initialFlags);
}
inline void Parser::setFunctionFlags(unsigned newFlags) {
m_functionFlags.last() |= newFlags;
}
inline unsigned Parser::popFunctionContext() {
unsigned flags = m_functionFlags.last();
m_functionFlags.removeLast();
return flags;
}
} // namespace KJS
#endif // Parser_h
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,35 +0,0 @@
// -*- mode: c++; c-basic-offset: 4 -*-
/*
* Copyright (C) 2006 Apple Computer, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "PropertyNameArray.h"
namespace KJS {
void PropertyNameArray::add(const Identifier& ident)
{
if (!m_set.add(ident.ustring().rep()).second)
return;
m_vector.append(ident);
}
} // namespace KJS

View file

@ -1,58 +0,0 @@
// -*- mode: c++; c-basic-offset: 4 -*-
/*
* Copyright (C) 2006 Apple Computer, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef KJS_PROPERTY_NAME_ARRAY_H
#define KJS_PROPERTY_NAME_ARRAY_H
#include "identifier.h"
#include <wtf/HashSet.h>
#include <wtf/Vector.h>
namespace KJS {
class PropertyNameArray;
typedef Vector<Identifier>::const_iterator PropertyNameArrayIterator;
class KJS_EXPORT PropertyNameArray {
public:
typedef PropertyNameArrayIterator iterator;
void add(const Identifier&);
iterator begin() const { return m_vector.begin(); }
iterator end() const { return m_vector.end(); }
int size() const { return m_vector.size(); }
Identifier& operator[](unsigned i) { return m_vector[i]; }
const Identifier& operator[](unsigned i) const { return m_vector[i]; }
private:
typedef HashSet<UString::Rep*, PtrHash<UString::Rep*> > IdentifierSet;
IdentifierSet m_set;
Vector<Identifier> m_vector;
};
} // namespace KJS
#endif // KJS_PROPERTY_NAME_ARRAY_H

View file

@ -1,27 +0,0 @@
This library provides an ECMAScript compatible interpreter. The ECMA standard
is based on well known scripting languages such as Netscape's JavaScript and
Microsoft's JScript.
I'm currently pursuing to be compliant with Edition 3 of ECMA-262. Postscript
and pdf versions of the standard are available at:
http://www.ecma-international.org/publications/files/ecma-st/Ecma-262.pdf
for PDF and
http://www.ecma-international.org/publications/standards/Ecma-262.htm
for the standard page.
About 95% of the required features should be covered by now. Note that this
number covers the core language elements only. Features like the famous
roll-over buttons on the www are NOT part of the standard. Those extensions
are added via a module loaded dynamically by the KHTML Widget.
I'll provide some examples of how to extend this library for various needs at
a later point in time. Feel free to contact me via mail if you have any
questions on how to provide scripting capabilities for your application.
A debugger is being worked on.
Bug reports, patches or feedback of any kind is very welcome.
Harri Porten <porten@kde.org>

View file

@ -1,81 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef SavedBuiltins_H
#define SavedBuiltins_H
namespace KJS {
class SavedBuiltinsInternal;
class SavedBuiltins {
friend class Interpreter;
public:
SavedBuiltins();
~SavedBuiltins();
private:
SavedBuiltinsInternal *_internal;
};
class SavedBuiltinsInternal {
friend class Interpreter;
private:
ProtectedPtr<JSObject> m_Object;
ProtectedPtr<JSObject> m_Function;
ProtectedPtr<JSObject> m_Array;
ProtectedPtr<JSObject> m_Boolean;
ProtectedPtr<JSObject> m_String;
ProtectedPtr<JSObject> m_Number;
ProtectedPtr<JSObject> m_Date;
ProtectedPtr<JSObject> m_RegExp;
ProtectedPtr<JSObject> m_Error;
ProtectedPtr<JSObject> m_ObjectPrototype;
ProtectedPtr<JSObject> m_FunctionPrototype;
ProtectedPtr<JSObject> m_ArrayPrototype;
ProtectedPtr<JSObject> m_BooleanPrototype;
ProtectedPtr<JSObject> m_StringPrototype;
ProtectedPtr<JSObject> m_NumberPrototype;
ProtectedPtr<JSObject> m_DatePrototype;
ProtectedPtr<JSObject> m_RegExpPrototype;
ProtectedPtr<JSObject> m_ErrorPrototype;
ProtectedPtr<JSObject> m_EvalError;
ProtectedPtr<JSObject> m_RangeError;
ProtectedPtr<JSObject> m_ReferenceError;
ProtectedPtr<JSObject> m_SyntaxError;
ProtectedPtr<JSObject> m_TypeError;
ProtectedPtr<JSObject> m_UriError;
ProtectedPtr<JSObject> m_EvalErrorPrototype;
ProtectedPtr<JSObject> m_RangeErrorPrototype;
ProtectedPtr<JSObject> m_ReferenceErrorPrototype;
ProtectedPtr<JSObject> m_SyntaxErrorPrototype;
ProtectedPtr<JSObject> m_TypeErrorPrototype;
ProtectedPtr<JSObject> m_UriErrorPrototype;
};
} // namespace
#endif // SavedBuiltins_H

View file

@ -1,52 +0,0 @@
/*
* Copyright (C) 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SymbolTable_h
#define SymbolTable_h
#include "ustring.h"
#include <wtf/AlwaysInline.h>
namespace KJS {
struct IdentifierRepHash : PtrHash<RefPtr<UString::Rep> > {
static unsigned hash(const RefPtr<UString::Rep>& key) { return key->computedHash(); }
static unsigned hash(UString::Rep* key) { return key->computedHash(); }
};
static ALWAYS_INLINE size_t missingSymbolMarker() { return std::numeric_limits<size_t>::max(); }
struct SymbolTableIndexHashTraits : HashTraits<size_t> {
static const bool emptyValueIsZero = false;
static size_t emptyValue() { return missingSymbolMarker(); }
};
typedef HashMap<RefPtr<UString::Rep>, size_t, IdentifierRepHash, HashTraits<RefPtr<UString::Rep> >, SymbolTableIndexHashTraits> SymbolTable;
} // namespace KJS
#endif // SymbolTable_h

View file

@ -1,7 +0,0 @@
I would like to thank the following people for their help:
Richard Moore <rich@kde.org> - for filling the Math object with some life
Daegeun Lee <realking@mizi.com> - for pointing out some bugs and providing
much code for the String and Date object.
Marco Pinelli <pinmc@libero.it> - for his patches
Christian Kirsch <ck@held.mind.de> - for his contribution to the Date object

View file

@ -1,31 +0,0 @@
include_directories(${KDE4_KDECORE_INCLUDES})
set(kjsapi_LIB_SRCS
kjsinterpreter.cpp
kjscontext.cpp
kjsobject.cpp
kjsprototype.cpp
kjsarguments.cpp
)
kde4_add_library(kjsapi ${LIBRARY_TYPE} ${kjsapi_LIB_SRCS})
target_link_libraries(kjsapi ${KJSLIBNAME} ${KDE4_KDECORE_LIBS})
set_target_properties(kjsapi PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} )
install(TARGETS kjsapi EXPORT kdelibsLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS})
install(FILES
kjsapi_export.h
kjsinterpreter.h
kjscontext.h
kjsobject.h
kjsprototype.h
kjsarguments.h
DESTINATION ${INCLUDE_INSTALL_DIR}/kjs)
############# tests ########################
kde4_add_unit_test(kjsapitest NOGUI kjsapitest.cpp)
target_link_libraries(kjsapitest kjsapi ${KDE4_KDECORE_LIBS} ${QT_QTTEST_LIBRARY})

View file

@ -1,37 +0,0 @@
/** @mainpage KDE ECMAScript Engine
This library provides an extensible interpreter for ECMAScript - a
dynamic scripting language also known as JavaScript or JScript. Within
the set of KDE libraries is used in the HTML component of Konqueror
and the application scripting solutions KJSEmbed and Kross.
KJS is made up of an internal core library and a public kjsapi library
that provides a stable and easy-to-use interface for developers
wanting to embed the engine as well as implement custom object types.
See the <a href="annotated.html">class list</a> for an overview of
classes representing the interpreter, standard types as well as
extension interfaces.
@authors
Harri Porten \<porten@kde.org\><br>
Maks Orlovich \<maksim@kde.org\><br>
Apple Computer, Inc.<br>
Peter Kelly \<pmk@post.com\><br>
Christopher E. Hyde \<C.Hyde@parableuk.force9.co.uk\><br>
David Faure \<faure@kde.org\><br>
Plus various contributors like Richard Moore, Daegeun Lee, Marco
Pinelli and Christian Kirsch.
@maintainers
Maks Orlovich \<maksim@kde.org\><br>
Harri Porten \<porten@kde.org\>
@licenses
@lgpl
*/
// DOXYGEN_SET_PROJECT_NAME = KJS-API
// vim:ts=4:sw=4:expandtab:filetype=doxygen

View file

@ -1,40 +0,0 @@
/* This file is part of the KDE project
Copyright (C) 2007 David Faure <faure@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KJSAPI_EXPORT_H
#define KJSAPI_EXPORT_H
/* needed for KDE_EXPORT and KDE_IMPORT macros */
#include <kdemacros.h>
#ifndef KJSAPI_EXPORT
# if defined(MAKE_KJSAPI_LIB)
/* We are building this library */
# define KJSAPI_EXPORT KDE_EXPORT
# else
/* We are using this library */
# define KJSAPI_EXPORT KDE_IMPORT
# endif
#endif
# ifndef KJSAPI_EXPORT_DEPRECATED
# define KJSAPI_EXPORT_DEPRECATED KDE_DEPRECATED KJSAPI_EXPORT
# endif
#endif

View file

@ -1,279 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2008 Harri Porten (porten@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "kjsobject.h"
#include "kjsprototype.h"
#include "kjsarguments.h"
#include "kjsinterpreter.h"
#include "qtest_kde.h"
class KJSApiTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void objectConstruction();
void interpreterEvaluate();
void interpreterNormalizeCode();
void objectProperties();
void prototypeConstants();
void prototypeProperties();
void prototypeFunctions();
void globalObject();
};
void KJSApiTest::objectConstruction()
{
KJSInterpreter ip;
KJSContext* ctx = ip.globalContext();
// Object
QVERIFY2(KJSObject().isObject(), "Broken default object");
// undefined
QVERIFY2(KJSUndefined().isUndefined(),
"Undefined object is not undefined");
// null
QVERIFY2(KJSNull().isNull(),
"Null object is not null");
// Boolean
KJSBoolean boolObject(true);
QVERIFY2(boolObject.isBoolean(), "Boolean object is not of boolean type");
QVERIFY2(boolObject.toBoolean(ctx), "Boolean object has wrong value");
QVERIFY2(!ctx->hasException(), "Boolean conversion threw exception");
// Number
KJSNumber numObject(42.0);
QVERIFY2(numObject.isNumber(), "Number object is not of number type");
QCOMPARE(numObject.toNumber(ctx), 42.0);
QCOMPARE(numObject.toInt32(ctx), 42);
QVERIFY2(!ctx->hasException(), "Number conversion threw exception");
// String
KJSString stringObject("Trunk");
QVERIFY2(stringObject.isString(), "String object is not of string type");
QCOMPARE(stringObject.toString(ctx), QLatin1String("Trunk"));
QVERIFY2(!ctx->hasException(), "String conversion threw exception");
// Array
KJSArray arrayObject(ctx, 3);
QVERIFY2(arrayObject.isObject(), "Array object is not of object type");
QCOMPARE(arrayObject.property(ctx, "length").toNumber(ctx), 3.0);
QCOMPARE(arrayObject.toString(ctx), QLatin1String(",,"));
QVERIFY2(!ctx->hasException(), "Array conversion threw exception");
// copying
KJSObject copy(stringObject);
QCOMPARE(copy.toString(ctx), QLatin1String("Trunk"));
copy = numObject;
QCOMPARE(copy.toNumber(ctx), 42.0);
}
void KJSApiTest::interpreterEvaluate()
{
KJSInterpreter ip;
KJSContext* ctx = ip.globalContext();
KJSResult res;
// syntax error
res = ip.evaluate(")(");
QVERIFY2(res.isException(), "Syntax error not caught");
res = ip.evaluate("11+22");
QVERIFY2(!res.isException(), "Evaluation returned non-number object");
QCOMPARE(res.value().toNumber(ctx), 33.0);
}
void KJSApiTest::interpreterNormalizeCode()
{
int errLine = -1;
QString errMsg;
QString norm;
bool ok;
// syntax error case
ok = KJSInterpreter::normalizeCode(")(", &norm, &errLine, &errMsg);
QVERIFY(!ok);
QVERIFY(!errMsg.isEmpty());
QVERIFY(errLine >= 0 && errLine <= 2); // ### imprecise
// success case
ok = KJSInterpreter::normalizeCode("foo(); bar();", &norm);
QVERIFY(ok);
QVERIFY(!norm.isEmpty());
QStringList lines = norm.split('\n');
QVERIFY(lines.size() >= 2); // ### imprecise
int fooLine = lines.indexOf(QRegExp(" *foo\\(\\);"));
int barLine = lines.indexOf(QRegExp(" *bar\\(\\);"));
QVERIFY(fooLine >= 0);
QVERIFY(barLine > fooLine);
}
void KJSApiTest::objectProperties()
{
KJSInterpreter ip;
KJSContext* ctx = ip.globalContext();
KJSObject global = ip.globalObject();
KJSObject v;
// bool
global.setProperty(ctx, "myprop", true);
v = global.property(ctx, "myprop");
QVERIFY(v.isBoolean());
QCOMPARE(v.toBoolean(ctx), true);
// double
global.setProperty(ctx, "myprop", 21.0);
v = global.property(ctx, "myprop");
QVERIFY(v.isNumber());
QCOMPARE(v.toNumber(ctx), 21.0);
// int
global.setProperty(ctx, "myprop", 22);
v = global.property(ctx, "myprop");
QVERIFY(v.isNumber());
QCOMPARE(v.toNumber(ctx), 22.0);
// string (8-bit)
global.setProperty(ctx, "myprop", "myvalue8");
v = global.property(ctx, "myprop");
QVERIFY(v.isString());
QCOMPARE(v.toString(ctx), QLatin1String("myvalue8"));
// string (Unicode)
global.setProperty(ctx, "myprop", QLatin1String("myvalue16"));
v = global.property(ctx, "myprop");
QVERIFY(v.isString());
QCOMPARE(v.toString(ctx), QLatin1String("myvalue16"));
}
void KJSApiTest::prototypeConstants()
{
KJSInterpreter ip;
KJSContext* ctx = ip.globalContext();
KJSPrototype proto;
proto.defineConstant("d0", 44.4);
proto.defineConstant("s0", QLatin1String("XYZ"));
KJSObject obj = proto.constructObject(ctx, 0);
QCOMPARE(obj.property(ctx, "d0").toNumber(ctx), 44.4);
QCOMPARE(obj.property(ctx, "s0").toString(ctx), QLatin1String("XYZ"));
}
static struct O { int x; } o0 = { 42 };
static KJSObject getX(KJSContext* /*context*/, void* object)
{
O* o = reinterpret_cast<O*>(object);
int x = o->x;
return KJSNumber(x);
}
static void setX(KJSContext* context, void* object, KJSObject value)
{
O* o = reinterpret_cast<O*>(object);
double n = value.toNumber(context);
o->x = n;
}
void KJSApiTest::prototypeProperties()
{
KJSInterpreter ip;
KJSContext* ctx = ip.globalContext();
KJSPrototype proto;
proto.defineProperty(ctx, "x", getX, setX);
proto.defineProperty(ctx, "readOnlyX", getX);
KJSObject obj = proto.constructObject(ctx, &o0);
// read/write property
QCOMPARE(obj.property(ctx, "x").toNumber(ctx), 42.0);
obj.setProperty(ctx, "x", KJSNumber(43));
QCOMPARE(obj.property(ctx, "x").toNumber(ctx), 43.0);
QCOMPARE(obj.property(ctx, "readOnlyX").toNumber(ctx), 43.0);
obj.setProperty(ctx, "readOnlyX", KJSNumber(44));
QVERIFY2(ctx->hasException(), "Write access caused no exception");
QCOMPARE(obj.property(ctx, "readOnlyX").toNumber(ctx), 43.0);
}
static KJSObject multiply(KJSContext* context, void* object,
const KJSArguments& arguments)
{
double factor = *reinterpret_cast<double*>(object);
// test number of arguments
if (arguments.count() != 1)
return context->throwException("Missing argument");
KJSObject a0 = arguments.at(0);
if (!a0.isNumber())
return KJSNumber(-2);
double v0 = a0.toNumber(context);
return KJSNumber(factor * v0);
}
void KJSApiTest::prototypeFunctions()
{
KJSInterpreter ip;
KJSContext* ctx = ip.globalContext();
KJSPrototype proto;
proto.defineFunction(ctx, "multiply", multiply);
double factor = 3.0;
KJSObject obj = proto.constructObject(ctx, &factor);
ip.globalObject().setProperty(ctx, "obj", obj);
KJSResult res = ip.evaluate("obj.multiply(4)");
QCOMPARE(res.value().toNumber(ctx), 12.0);
// expect exception
res = ip.evaluate("obj.multiply()");
QVERIFY2(res.isException(), "Exception did not work");
}
void KJSApiTest::globalObject()
{
KJSPrototype proto;
proto.defineConstant("g0", 55.5);
KJSGlobalObject glob = proto.constructGlobalObject(0);
KJSInterpreter ip(glob);
KJSResult res = ip.evaluate("2 * g0");
QCOMPARE(res.value().toNumber(ip.globalContext()), 111.0);
}
QTEST_KDEMAIN_CORE(KJSApiTest)
#include "kjsapitest.moc"

View file

@ -1,39 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2008 Harri Porten (porten@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "kjsarguments.h"
#include "kjsprivate.h"
int KJSArguments::count() const
{
const KJS::List* l = LIST(this);
return l->size();
}
KJSObject KJSArguments::at(int idx) const
{
const KJS::List* l = LIST(this);
if (idx < 0 || idx >= l->size())
return KJSUndefined();
KJS::JSValue* a = l->at(idx);
return KJSObject(JSVALUE_HANDLE(a));
}

View file

@ -1,58 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2008 Harri Porten (porten@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef KJSARGUMENTS_H
#define KJSARGUMENTS_H
#include "kjsapi_export.h"
#include "kjsobject.h"
class KJSArgumentsHandle;
class KJSCustomFunction;
/**
* A class representing a list of JavaScript arguments.
*
* @short Argument list
*/
class KJSAPI_EXPORT KJSArguments
{
friend class KJSCustomFunction;
public:
/**
* Returns the number of arguments.
*/
int count() const;
/**
* Returns the argument at the specified index. Accessing an
* argument outside of the valid range will return an object of
* type "undefined".
*/
KJSObject at(int idx) const;
private:
KJSArguments(const KJSArguments&); // undefined
KJSArguments& operator=(const KJSArguments&); // undefined
KJSArguments(const KJSArgumentsHandle* h) : hnd(h) { }
const KJSArgumentsHandle* hnd;
};
#endif

View file

@ -1,58 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2008 Harri Porten (porten@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "kjscontext.h"
#include "kjsinterpreter.h"
#include "kjsprivate.h"
#include "kjs/object.h"
#include "kjs/ExecState.h"
#include "kjs/interpreter.h"
using namespace KJS;
KJSContext::KJSContext(KJSContextHandle* h)
: hnd(h)
{
}
bool KJSContext::hasException() const
{
return EXECSTATE(this)->hadException();
}
KJSObject KJSContext::throwException(const QString& message) const
{
ExecState* exec = EXECSTATE(this);
JSValue* ex = Error::create(exec, GeneralError, toUString(message),
-1, -1, UString());
exec->setException(ex);
return KJSObject(JSVALUE_HANDLE(ex));
}
KJSInterpreter KJSContext::interpreter()
{
ExecState* exec = EXECSTATE(this);
Interpreter* ip = exec->dynamicInterpreter();
return KJSInterpreter(INTERPRETER_HANDLE(ip));
}

View file

@ -1,68 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2008 Harri Porten (porten@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef KJSCONTEXT_H
#define KJSCONTEXT_H
#include "kjsapi_export.h"
class KJSObject;
class KJSArray;
class KJSInterpreter;
class KJSContextHandle;
class KJSCustomProperty;
class KJSCustomFunction;
/**
* A class representing a JavaScript execution context.
*
* @short Execution context
*/
class KJSAPI_EXPORT KJSContext
{
friend class KJSObject;
friend class KJSArray;
friend class KJSPrototype;
friend class KJSInterpreter;
friend class KJSCustomProperty;
friend class KJSCustomFunction;
public:
/**
* Returns true if this context has an unhandled exception.
*/
bool hasException() const;
/**
* Throws a general exception with the specified error message.
*/
KJSObject throwException(const QString& message) const;
/**
* Returns the currently executing interpreter.
*/
KJSInterpreter interpreter();
private:
KJSContext(KJSContextHandle* h);
KJSContext(const KJSContext&); // undefined
KJSContext& operator=(const KJSContext&); // undefined
KJSContextHandle* hnd;
};
#endif

View file

@ -1,218 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2008 Harri Porten (porten@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "kjsinterpreter.h"
#include "kjsprivate.h"
#include "kjs/interpreter.h"
#include "kjs/completion.h"
#include "kjs/object.h"
#include "kjs/JSVariableObject.h"
#include <QString>
#include <stdio.h>
using namespace KJS;
class KJSResultHandle
{
public:
KJSResultHandle() : rc(1), val(KJSUndefined()) { }
int rc;
KJSObject val;
UString errMsg;
void ref() { ++rc; }
void deref() { if (--rc == 0) delete this; }
};
KJSResult::KJSResult()
: hnd(new KJSResultHandle())
{
}
KJSResult::KJSResult(const KJSResult& r)
{
hnd = r.hnd;
hnd->ref();
}
KJSResult& KJSResult::operator=(const KJSResult& r)
{
if (hnd != r.hnd) {
r.hnd->ref();
hnd->deref();
hnd = r.hnd;
}
return *this;
}
KJSResult::~KJSResult()
{
hnd->deref();
}
bool KJSResult::isException() const
{
return !hnd->errMsg.isNull();
}
QString KJSResult::errorMessage() const
{
return toQString(hnd->errMsg);
}
KJSObject KJSResult::value() const
{
return hnd->val;
}
KJSInterpreter::KJSInterpreter()
: globCtx(0)
{
Interpreter* ip = new Interpreter();
ip->ref();
hnd = INTERPRETER_HANDLE(ip);
}
KJSInterpreter::KJSInterpreter(const KJSGlobalObject& global)
: globCtx(0)
{
JSValue* gv = JSVALUE(&global);
assert(gv->isObject());
JSObject* go = static_cast<JSObject*>(gv);
assert(go->isGlobalObject());
Interpreter* ip = new Interpreter(static_cast<JSGlobalObject*>(go));
ip->ref();
assert(go->prototype()->isObject());
JSObject* p = static_cast<JSObject*>(go->prototype());
JSObject* objectProto = ip->builtinObjectPrototype();
p->setPrototype(objectProto);
hnd = INTERPRETER_HANDLE(ip);
}
KJSInterpreter::KJSInterpreter(const KJSInterpreter& other)
: globCtx(0)
{
Interpreter* ip = INTERPRETER(&other);
ip->ref();
hnd = INTERPRETER_HANDLE(ip);
globCtx.hnd = EXECSTATE_HANDLE(ip->globalExec());
}
KJSInterpreter& KJSInterpreter::operator=(const KJSInterpreter& other)
{
Interpreter* thisIp = INTERPRETER(this);
Interpreter* otherIp = INTERPRETER(&other);
if (otherIp != thisIp) {
otherIp->ref();
thisIp->deref();
hnd = INTERPRETER_HANDLE(otherIp);
globCtx.hnd = EXECSTATE_HANDLE(otherIp->globalExec());
}
return *this;
}
KJSInterpreter::KJSInterpreter(KJSInterpreterHandle* h)
: hnd(h), globCtx(0)
{
Interpreter* ip = INTERPRETER(this);
globCtx.hnd = EXECSTATE_HANDLE(ip->globalExec());
}
KJSInterpreter::~KJSInterpreter()
{
Interpreter* ip = INTERPRETER(this);
ip->deref();
ip = 0;
}
KJSContext* KJSInterpreter::globalContext()
{
Interpreter* ip = INTERPRETER(this);
globCtx.hnd = EXECSTATE_HANDLE(ip->globalExec());
return &globCtx;
}
KJSObject KJSInterpreter::globalObject()
{
Interpreter* ip = INTERPRETER(this);
return KJSObject(JSVALUE_HANDLE(ip->globalObject()));
}
KJSResult KJSInterpreter::evaluate(const QString& sourceURL,
int startingLineNumber,
const QString& code,
KJSObject* thisValue)
{
Interpreter* ip = INTERPRETER(this);
JSValue* tv = thisValue ? JSVALUE(thisValue) : 0;
KJS::Completion c = ip->evaluate(toUString(sourceURL), startingLineNumber,
toUString(code), tv);
KJSResult res;
if (c.complType() == Throw) {
ExecState* exec = ip->globalExec();
UString msg = c.value()->toString(exec);
#if 0
JSObject* resObj = c.value()->toObject(exec);
CString message = resObj->toString(exec).UTF8String();
int line = resObj->toObject(exec)->get(exec, "line")->toUInt32(exec);
if (!sourceURL.isEmpty())
fprintf(stderr, "%s (line %d): ", qPrintable(sourceURL), line);
fprintf(stderr, "%s\n", msg.c_str());
#endif
fprintf(stderr, "evaluate() threw an exception\n");
res.hnd->errMsg = msg;
} else {
if (c.isValueCompletion())
res.hnd->val = KJSObject(JSVALUE_HANDLE(c.value()));
}
return res;
}
KJSResult KJSInterpreter::evaluate(const QString& code,
KJSObject* thisValue)
{
return evaluate("<string>", 0, code, thisValue);
}
bool KJSInterpreter::normalizeCode(const QString& code, QString* normalized,
int* errLine, QString* errMsg)
{
assert(normalized);
UString codeOut, msg;
bool success = Interpreter::normalizeCode(toUString(code), &codeOut,
errLine, &msg);
*normalized = toQString(codeOut);
if (errMsg)
*errMsg = toQString(msg);
return success;
}

View file

@ -1,162 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2008 Harri Porten (porten@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef KJSINTERPRETER_H
#define KJSINTERPRETER_H
#include "kjsapi_export.h"
#include "kjsobject.h"
#include "kjscontext.h"
class KJSPrototype;
class KJSInterpreter;
class KJSInterpreterHandle;
class KJSResultHandle;
/**
* A class representing the result of a script evaluation.
*/
class KJSAPI_EXPORT KJSResult
{
friend class KJSInterpreter;
public:
/**
* Constructs a default result object.
*/
KJSResult();
/**
* Constructs a copy of another result object.
*/
KJSResult(const KJSResult&);
/**
* Assigns the properties of another result object to this one.
*/
KJSResult& operator=(const KJSResult&);
/**
* Frees resources held by this result object.
*/
~KJSResult();
/**
* Returns true if the script evaluation has caused an exception.
*/
bool isException() const;
/**
* Returns the error message if this is an exception result.
*/
QString errorMessage() const;
/*
* If the evaluation was successful, i.e. isException() is false
* this function returns the value returned by the script. Can be
* an "undefined" (isUndefined()) value.
*/
KJSObject value() const;
private:
KJSResultHandle* hnd;
};
/**
* A class representing a JavaScript interpreter
*
* @short JavaScript interpreter
*/
class KJSAPI_EXPORT KJSInterpreter
{
friend class KJSResult;
friend class KJSPrototype;
friend class KJSContext;
public:
/**
* Constructs an interpreter with a default global object.
*/
KJSInterpreter();
/**
* Constructs an interpreter with a custom global object.
*/
KJSInterpreter(const KJSGlobalObject& global);
/**
* Creates a copy of another interpreter.
*/
KJSInterpreter(const KJSInterpreter& other);
/**
* Assign another interpreter instance to this object.
*/
KJSInterpreter& operator=(const KJSInterpreter& other);
/**
* Destructs this interpreter and frees resources it has
* allocated. This renders any still existing objects referencing
* those invalid.
*/
~KJSInterpreter();
/**
* Returns a handle to the global execution context.
*/
KJSContext* globalContext();
/**
* @overload
*/
const KJSContext* globalContext() const;
/**
* Returns the object that is used as the global object during all
* script execution performed by this interpreter,
*/
KJSObject globalObject();
/**
* Evaluates a piece of code with a "this" set to (optionally set)
* value. The sourceURL and startingLineNumber parameters are used
* to provide information about the origin of a parse error or
* runtime exception.
*/
KJSResult evaluate(const QString& sourceURL, int startingLineNumber,
const QString& code,
KJSObject* thisValue = 0);
/**
* @overload
*/
KJSResult evaluate(const QString& code,
KJSObject* thisValue = 0);
/**
* Reformat the given script code to an easy to read format with
* only one statement per line. This can be useful when debugging
* a script that was e.g. condensed into a single line to a single
* line. While comments will be removed the script will remain
* unchanged semantically.
*
* @param codeIn The code to be reformatted
* @param codeOut Points to string holding the result.
* @param errLine Will hold the line of a parse error
* @param errMsg Will hold the message of a parse error
*
* @return Returns true if the reformatting was successful, false
* on a parse error.
*/
static bool normalizeCode(const QString& codeIn, QString* codeOut,
int* errLine = 0, QString* errMsg = 0);
private:
KJSInterpreter(KJSInterpreterHandle* h);
KJSInterpreterHandle* hnd;
KJSContext globCtx;
};
#endif

View file

@ -1,248 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2008 Harri Porten (porten@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "kjsobject.h"
#include "kjsprivate.h"
#include "kjscontext.h"
#include "kjs/value.h"
#include "kjs/object.h"
#include "kjs/protect.h"
#include "kjs/ExecState.h"
#include "kjs/JSVariableObject.h"
#include <kdebug.h>
#include <QDateTime>
using namespace KJS;
KJSObject::KJSObject()
: hnd(JSVALUE_HANDLE(new JSObject()))
{
gcProtect(JSVALUE(this));
}
KJSObject::KJSObject(const KJSObject& o)
: hnd(o.hnd)
{
gcProtectNullTolerant(JSVALUE(this));
}
KJSObject& KJSObject::operator=(const KJSObject& o)
{
gcUnprotectNullTolerant(JSVALUE(this));
hnd = o.hnd;
gcProtectNullTolerant(JSVALUE(this));
return *this;
}
KJSObject::~KJSObject()
{
gcUnprotectNullTolerant(JSVALUE(this));
}
KJSNull::KJSNull()
: KJSObject(JSVALUE_HANDLE(jsNull()))
{
}
KJSUndefined::KJSUndefined()
: KJSObject(JSVALUE_HANDLE(jsUndefined()))
{
}
KJSBoolean::KJSBoolean(bool b)
: KJSObject(JSVALUE_HANDLE(jsBoolean(b)))
{
}
KJSNumber::KJSNumber(double d)
: KJSObject(JSVALUE_HANDLE(jsNumber(d)))
{
gcProtect(JSVALUE(this));
}
KJSString::KJSString(const QString& s)
: KJSObject(JSVALUE_HANDLE(jsString(toUString(s))))
{
gcProtect(JSVALUE(this));
}
KJSString::KJSString(const char* s)
: KJSObject(JSVALUE_HANDLE(jsString(s)))
{
gcProtect(JSVALUE(this));
}
static JSValue* constructArrayHelper(ExecState* exec, int len)
{
JSObject* builtinArray = exec->lexicalInterpreter()->builtinArray();
JSObject* newArray = builtinArray->construct(exec, List());
newArray->put(exec, exec->propertyNames().length, jsNumber(len),
DontDelete|ReadOnly|DontEnum);
return newArray;
}
KJSArray::KJSArray(KJSContext* ctx, int len)
: KJSObject(JSVALUE_HANDLE(constructArrayHelper(EXECSTATE(ctx), len)))
{
gcProtect(JSVALUE(this));
}
static JSValue* constructDateHelper(KJSContext* ctx, const QDateTime& dt)
{
Q_UNUSED(ctx);
Q_UNUSED(dt);
kWarning() << "converDateTimeHelper() not implemented, yet";
// ### make call into data_object.cpp
return jsNumber(42.0);
}
KJSDate::KJSDate(KJSContext* ctx, const QDateTime& dt)
: KJSObject(JSVALUE_HANDLE(constructDateHelper(ctx, dt)))
{
gcProtect(JSVALUE(this));
}
bool KJSObject::isUndefined() const
{
return JSVALUE(this)->isUndefined();
}
bool KJSObject::isNull() const
{
return JSVALUE(this)->isNull();
}
bool KJSObject::isBoolean() const
{
return JSVALUE(this)->isBoolean();
}
bool KJSObject::isNumber() const
{
return JSVALUE(this)->isNumber();
}
bool KJSObject::isString() const
{
return JSVALUE(this)->isString();
}
bool KJSObject::isObject() const
{
return JSVALUE(this)->isObject();
}
bool KJSObject::toBoolean(KJSContext* ctx)
{
ExecState* exec = EXECSTATE(ctx);
assert(exec);
return JSVALUE(this)->toBoolean(exec);
}
double KJSObject::toNumber(KJSContext* ctx)
{
ExecState* exec = EXECSTATE(ctx);
assert(exec);
return JSVALUE(this)->toNumber(exec);
}
int KJSObject::toInt32(KJSContext* ctx)
{
ExecState* exec = EXECSTATE(ctx);
assert(exec);
return JSVALUE(this)->toInt32(exec);
}
QString KJSObject::toString(KJSContext* ctx)
{
ExecState* exec = EXECSTATE(ctx);
assert(exec);
return toQString(JSVALUE(this)->toString(exec));
}
KJSObject KJSObject::property(KJSContext* ctx, const QString& name)
{
JSValue* v = JSVALUE(this);
assert(v);
#if 0
// would normally throw an exception
if (v == jsUndefined || v == jsNull())
return KJSUndefined();
#endif
ExecState* exec = EXECSTATE(ctx);
JSObject* o = v->toObject(exec);
JSValue* res = o->get(exec, toIdentifier(name));
return KJSObject(JSVALUE_HANDLE(res));
}
void KJSObject::setProperty(KJSContext* ctx, const QString& name,
const KJSObject& value)
{
JSValue* v = JSVALUE(this);
assert(v);
ExecState* exec = EXECSTATE(ctx);
JSObject* o = v->toObject(exec);
o->put(exec, toIdentifier(name), JSVALUE(&value));
}
void KJSObject::setProperty(KJSContext* ctx, const QString& name, bool value)
{
setProperty(ctx, name, KJSBoolean(value));
}
void KJSObject::setProperty(KJSContext* ctx, const QString& name,
double value)
{
setProperty(ctx, name, KJSNumber(value));
}
void KJSObject::setProperty(KJSContext* ctx, const QString& name,
int value)
{
setProperty(ctx, name, KJSNumber(double(value)));
}
void KJSObject::setProperty(KJSContext* ctx, const QString& name,
const QString &value)
{
setProperty(ctx, name, KJSString(value));
}
void KJSObject::setProperty(KJSContext* ctx, const QString& name,
const char* value)
{
setProperty(ctx, name, KJSString(value));
}
KJSGlobalObject::KJSGlobalObject(): KJSObject(JSVALUE_HANDLE(new JSGlobalObject()))
{
}

View file

@ -1,294 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2008 Harri Porten (porten@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef KJSOBJECT_H
#define KJSOBJECT_H
#include "kjsapi_export.h"
#include <QtCore/QString>
class QDateTime;
class KJSContext;
class KJSNull;
class KJSUndefined;
class KJSBoolean;
class KJSNumber;
class KJSString;
class KJSArray;
class KJSDate;
class KJSArguments;
class KJSInterpreter;
class KJSObjectHandle;
class KJSCustomProperty;
class KJSCustomFunction;
/**
* A class representing a JavaScript value.
*
* @short Script object
*/
class KJSAPI_EXPORT KJSObject
{
friend class KJSNull;
friend class KJSUndefined;
friend class KJSBoolean;
friend class KJSNumber;
friend class KJSString;
friend class KJSArray;
friend class KJSDate;
friend class KJSGlobalObject;
friend class KJSPrototype;
friend class KJSContext;
friend class KJSArguments;
friend class KJSInterpreter;
friend class KJSCustomProperty;
friend class KJSCustomFunction;
public:
/**
* Constructs a JavaScript object of the generic Object type.
*/
KJSObject();
/**
* Constructs on object from another one
*/
KJSObject(const KJSObject& o);
/**
* Assigns another JS object references to this one.
*/
KJSObject& operator=(const KJSObject& o);
/**
* Destructs this object freeing any references it might have held.
*/
~KJSObject();
/**
* Returns whether this object is undefined.
*/
bool isUndefined() const;
/**
* Returns whether this object is null.
*/
bool isNull() const;
/**
* Returns whether this object is a boolean.
*/
bool isBoolean() const;
/**
* Returns whether this object is a number.
*/
bool isNumber() const;
/**
* Returns whether this object is a string.
*/
bool isString() const;
/**
* Returns whether this object is a full blown object.
*/
bool isObject() const;
/**
* Returns this value converted to a boolean. If the conversion
* fails the context will have an exception set.
*/
bool toBoolean(KJSContext* ctx);
/**
* Returns this value converted to a number. If the conversion
* fails the context will have an exception set.
*/
double toNumber(KJSContext* ctx);
/**
* Returns this value converted to a 32-bit integer number. NaN,
* positive and negative Infinity will be converted to 0. If the
* conversion fails the context will have an exception set.
*/
int toInt32(KJSContext* ctx);
/**
* Returns this value converted to a string. If the conversion
* fails the context will have an exception set.
*/
QString toString(KJSContext* ctx);
/**
* Reads the specified property from this object. This operation
* might throw an exception.
*/
KJSObject property(KJSContext* ctx, const QString& name);
/**
* Sets the specified property on this object. This operation
* might throw an exception.
*/
void setProperty(KJSContext* ctx, const QString& name,
const KJSObject& value);
/**
* @overload
*/
void setProperty(KJSContext* ctx, const QString& name, bool value);
/**
* @overload
*/
void setProperty(KJSContext* ctx, const QString& name, double value);
/**
* @overload
*/
void setProperty(KJSContext* ctx, const QString& name, int value);
/**
* @overload
*/
void setProperty(KJSContext* ctx, const QString& name,
const QString &value);
/**
* @overload
*
* Accepts a Latin1 encoded, null-terminated string.
*/
void setProperty(KJSContext* ctx, const QString& name,
const char* value);
private:
KJSObject(KJSObjectHandle* h) : hnd(h) { }
KJSObjectHandle* hnd;
};
/**
* A class representing a JavaScript null value.
*
* @short Null value
*/
class KJSAPI_EXPORT KJSNull : public KJSObject
{
public:
/**
* Constructs a null object.
*/
KJSNull();
};
/**
* A class representing an undefined JavaScript value.
*
* @short Undefined value
*/
class KJSAPI_EXPORT KJSUndefined : public KJSObject
{
public:
/**
* Constructs an undefined object.
*/
KJSUndefined();
};
/**
* A class representing a boolean JavaScript value.
*
* @short Boolean value
*/
class KJSAPI_EXPORT KJSBoolean : public KJSObject
{
public:
/**
* Constructs a boolean object.
*/
KJSBoolean(bool b);
};
/**
* A class representing a JavaScript number value.
*
* @short Number value
*/
class KJSAPI_EXPORT KJSNumber : public KJSObject
{
public:
/**
* Constructs a number object.
*/
KJSNumber(double d);
};
/**
* A class representing a JavaScript string value.
*
* @short String value
*/
class KJSAPI_EXPORT KJSString : public KJSObject
{
public:
/**
* Constructs a string object.
*/
KJSString(const QString& s);
/**
* Constructs a string object from an Latin1 encoded,
* null-terminated string. Note the limited input character range
* which rules out a big part of Unicode.
*
* @overload
*/
KJSString(const char* s);
};
/**
* A class representing a JavaScript array object.
*
* @short Array object
*/
class KJSAPI_EXPORT KJSArray : public KJSObject
{
public:
/**
* Constructs an array object with the specified length.
*/
KJSArray(KJSContext* ctx, int len = 0);
};
/**
* A class representing a JavaScript date object.
*
* @short Date object
*/
class KJSAPI_EXPORT KJSDate : public KJSObject
{
public:
/**
* Constructs a date object from the specified date and time.
*/
KJSDate(KJSContext* ctx, const QDateTime& dt);
};
/**
* A class representing a global object of an execution environment.
*
* @short Global object
*/
class KJSAPI_EXPORT KJSGlobalObject : public KJSObject
{
friend class KJSPrototype;
public:
/**
* Constructs an empty global object. Usually done through
* KJSPrototype::constructGlobalObject().
*/
KJSGlobalObject();
private:
KJSGlobalObject(KJSObjectHandle* h) : KJSObject(h) { }
};
#endif

View file

@ -1,67 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2008 Harri Porten (porten@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef KJSPRIVATE_H
#define KJSPRIVATE_H
#include "kjs/ustring.h"
#include "kjs/identifier.h"
#include "kjs/list.h"
#include <QtCore/QString>
#define JSVALUE_HANDLE(v) reinterpret_cast<KJSObjectHandle*>(v)
#define JSVALUE(h) reinterpret_cast<KJS::JSValue*>((h)->hnd)
#define EXECSTATE_HANDLE(c) reinterpret_cast<KJSContextHandle*>(c)
#define EXECSTATE(ctx) reinterpret_cast<ExecState*>((ctx)->hnd)
#define INTERPRETER_HANDLE(i) reinterpret_cast<KJSInterpreterHandle*>(i)
#define INTERPRETER(h) reinterpret_cast<KJS::Interpreter*>((h)->hnd)
#define PROTOTYPE_HANDLE(p) reinterpret_cast<KJSPrototypeHandle*>(p)
#define PROTOTYPE(h) reinterpret_cast<CustomPrototype*>((h)->hnd)
#define LIST_HANDLE(l) reinterpret_cast<const KJSArgumentsHandle*>(l)
#define LIST(h) reinterpret_cast<const KJS::List*>((h)->hnd)
static inline KJS::UString toUString(const QString& s)
{
// ### can be done faster. see khtml/ecma/kjs_binding.cpp
int l = s.length();
const KJS::UChar* u = reinterpret_cast<const KJS::UChar*>(s.unicode());
return KJS::UString(u, l);
}
static inline KJS::Identifier toIdentifier(const QString& s)
{
int l = s.length();
const KJS::UChar* u = reinterpret_cast<const KJS::UChar*>(s.unicode());
return KJS::Identifier(u, l);
}
static inline QString toQString(const KJS::UString& s)
{
int l = s.size();
const QChar* u = reinterpret_cast<const QChar*>(s.data());
return QString(u, l);
}
#endif

View file

@ -1,311 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2008 Harri Porten (porten@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "kjsprototype.h"
#include "kjsinterpreter.h"
#include "kjsarguments.h"
#include "kjsprivate.h"
#include "kjs/object.h"
#include "kjs/JSVariableObject.h"
#include "kjs/context.h"
#include "kjs/interpreter.h"
#include <QMap>
using namespace KJS;
class KJSCustomProperty
{
public:
KJSCustomProperty(KJSPrototype::PropertyGetter g,
KJSPrototype::PropertySetter s)
: getter(g), setter(s)
{
}
JSValue* read(ExecState* exec, void* object);
void write(ExecState* exec, void* object, JSValue* value);
private:
KJSPrototype::PropertyGetter getter;
KJSPrototype::PropertySetter setter;
};
class CustomObjectInfo {
public:
CustomObjectInfo(void* v): iv(v) {}
virtual ~CustomObjectInfo() {}
void* internalValue() { return iv; }
protected:
void* iv;
};
template<class Base>
class CustomObject : public Base, public CustomObjectInfo {
public:
CustomObject(JSValue* proto, void* v)
: Base(proto),
CustomObjectInfo(v)
{}
using Base::put;
void put(ExecState* exec, const Identifier& id,
JSValue *value, int attr = None);
// rtti
static const ClassInfo info;
const ClassInfo* classInfo() const { return &info; }
};
template<>
const ClassInfo CustomObject<JSObject>::info = { "CustomObject", 0, 0, 0 };
template<>
const ClassInfo CustomObject<JSGlobalObject>::info = { "CustomGlobalObject", 0, 0, 0 };
class KJSCustomFunction : public JSObject {
public:
KJSCustomFunction(ExecState* exec, KJSPrototype::FunctionCall f)
: callback(f)
{
setPrototype(exec->lexicalInterpreter()->builtinObjectPrototype());
}
JSValue* callAsFunction(ExecState* exec, JSObject* thisObj,
const List &args);
bool implementsCall() const { return true; }
private:
KJSPrototype::FunctionCall callback;
};
JSValue* KJSCustomFunction::callAsFunction(ExecState* exec, JSObject* thisObj,
const List &args)
{
// FIXME: does not protect against mixing custom objects
CustomObjectInfo* inf = dynamic_cast<CustomObjectInfo*>(thisObj);
if (!inf) {
const char* errMsg = "Attempt at calling a function with an invalid receiver";
KJS::JSObject *err = KJS::Error::create(exec, KJS::TypeError, errMsg);
exec->setException(err);
return err;
}
void* thisValue = inf->internalValue();
KJSContext ctx(EXECSTATE_HANDLE(exec));
KJSArguments a(LIST_HANDLE(&args));
KJSObject res = (*callback)(&ctx, thisValue, a);
return JSVALUE(&res);
}
JSValue* KJSCustomProperty::read(ExecState* exec, void* object)
{
assert(getter);
KJSContext ctx(EXECSTATE_HANDLE(exec));
KJSObject res = (*getter)(&ctx, object);
return JSVALUE(&res);
}
void KJSCustomProperty::write(ExecState* exec, void* object, JSValue* value)
{
KJSContext ctx(EXECSTATE_HANDLE(exec));
if (setter) {
KJSObject vo(JSVALUE_HANDLE(value));
(*setter)(&ctx, object, vo);
} else {
JSObject *e = Error::create(exec, GeneralError,
"Property is read-only");
exec->setException(e);
}
}
static JSValue* getPropertyValue(ExecState* exec, JSObject *originalObject,
const Identifier&, const PropertySlot& sl)
{
CustomObjectInfo* inf = dynamic_cast<CustomObjectInfo*>(originalObject);
if (!inf)
return jsUndefined();
KJSCustomProperty* p =
reinterpret_cast<KJSCustomProperty*>(sl.customValue());
return p->read(exec, inf->internalValue());
}
// FIXME: or use Identifier?
// FIXME: use values
typedef QMap<UString, KJSCustomProperty*> CustomPropertyMap;
class CustomPrototype : public JSObject {
public:
CustomPrototype()
{
}
~CustomPrototype()
{
qDeleteAll(properties);
}
using KJS::JSObject::getOwnPropertySlot;
bool getOwnPropertySlot(ExecState *exec, const Identifier& id,
PropertySlot& sl)
{
CustomPropertyMap::iterator it = properties.find(id.ustring());
if (it == properties.end())
return JSObject::getOwnPropertySlot(exec, id, sl);
sl.setCustomValue(0, *it, getPropertyValue);
return true;
}
void registerProperty(const QString& name,
KJSPrototype::PropertyGetter g,
KJSPrototype::PropertySetter s)
{
properties.insert(toUString(name), new KJSCustomProperty(g, s));
}
void registerFunction(ExecState* exec,
const QString& name, KJSPrototype::FunctionCall f)
{
putDirect(toIdentifier(name), new KJSCustomFunction(exec, f));
}
template<typename Base>
bool setProperty(ExecState* exec, CustomObject<Base>* obj,
const Identifier& id, JSValue* value)
{
CustomPropertyMap::iterator it = properties.find(id.ustring());
if (it == properties.end())
return false;
(*it)->write(exec, obj->internalValue(), value);
return true;
}
private:
CustomPropertyMap properties;
};
template<class Base>
void CustomObject<Base>::put(ExecState* exec, const Identifier& id,
JSValue* value, int attr)
{
CustomPrototype* p = static_cast<CustomPrototype*>(this->prototype());
if (!p->setProperty(exec, this, id, value))
Base::put(exec, id, value, attr);
}
KJSPrototype::KJSPrototype()
{
CustomPrototype* p = new CustomPrototype;
gcProtect(p);
hnd = PROTOTYPE_HANDLE(p);
}
KJSPrototype::~KJSPrototype()
{
gcUnprotect(PROTOTYPE(this));
}
void KJSPrototype::defineConstant(const QString& name, double value)
{
CustomPrototype* p = PROTOTYPE(this);
p->putDirect(toIdentifier(name), jsNumber(value),
DontEnum|DontDelete|ReadOnly);
}
void KJSPrototype::defineConstant(const QString& name, const QString& value)
{
CustomPrototype* p = PROTOTYPE(this);
p->putDirect(toIdentifier(name), jsString(toUString(value)),
DontEnum|DontDelete|ReadOnly);
}
void KJSPrototype::defineConstant(const QString& name, const KJSObject& value)
{
CustomPrototype* p = PROTOTYPE(this);
p->putDirect(toIdentifier(name), JSVALUE(&value),
DontEnum|DontDelete|ReadOnly);
}
KJSObject KJSPrototype::constructObject(KJSContext* ctx, void *internalValue)
{
CustomPrototype* p = PROTOTYPE(this);
if (ctx && !p->prototype()) {
ExecState* exec = EXECSTATE(ctx);
KJS::Interpreter* i = exec->lexicalInterpreter();
JSObject* objectProto = i->builtinObjectPrototype();
p->setPrototype(objectProto);
}
CustomObject<JSObject>* newObj = new CustomObject<JSObject>(p, internalValue);
return KJSObject(JSVALUE_HANDLE(newObj));
}
KJSGlobalObject KJSPrototype::constructGlobalObject(void *internalValue)
{
CustomPrototype* p = PROTOTYPE(this);
CustomObject<JSGlobalObject>* newObj = new CustomObject<JSGlobalObject>(p, internalValue);
return KJSGlobalObject(JSVALUE_HANDLE(newObj));
}
void KJSPrototype::defineProperty(KJSContext* ctx,
const QString& name,
PropertyGetter getter,
PropertySetter setter)
{
Q_UNUSED(ctx);
assert(getter);
CustomPrototype* p = PROTOTYPE(this);
p->registerProperty(name, getter, setter);
}
void KJSPrototype::defineFunction(KJSContext* ctx,
const QString& name, FunctionCall callback)
{
assert(callback);
CustomPrototype* p = PROTOTYPE(this);
ExecState* exec = EXECSTATE(ctx);
p->registerFunction(exec, name, callback);
}
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,133 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2008 Harri Porten (porten@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef KJSPROTOTYPE_H
#define KJSPROTOTYPE_H
#include "kjsapi_export.h"
#include "kjscontext.h"
class KJSInterpreter;
class KJSArguments;
class KJSGlobalObject;
class KJSPrototypeHandle;
/**
* A class representing a JavaScript prototype object.
*
* @short Prototype object.
*/
class KJSAPI_EXPORT KJSPrototype
{
public:
/**
* Constructs a prototype object with its own prototype property
* set to the Object prototype.
*/
KJSPrototype();
/**
* Destructs this prototype object.
*/
~KJSPrototype();
/**
* Add a read-only numerical property to this object.
*/
void defineConstant(const QString& name, double value);
/**
* Add a read-only string property to this object.
*
* @overload
*/
void defineConstant(const QString& name, const QString& value);
/**
* Add a read-only object property to this object.
*
* @overload
*/
void defineConstant(const QString& name, const KJSObject& value);
/**
* Function signature for a property getter function. Describes
* one of the defineProperty() argument types.
*/
typedef KJSObject (*PropertyGetter)(KJSContext* context, void* object);
/**
* Function signature for a property setter function. Describes
* one of the defineProperty() argument types.
*/
typedef void (*PropertySetter)(KJSContext* context, void* object,
KJSObject value);
/**
* Defines a property of this prototype with C++ callback
* functions for getting and setting the property value. If the
* setter is set to 0 then the property is treated as read-only.
*/
void defineProperty(KJSContext* ctx,
const QString& name,
PropertyGetter getter,
PropertySetter setter = 0);
/**
* Signature for function call callback function. The
* defineFunction() function parameter accepts a reference to a
* function of this type as a parameter.
*/
typedef KJSObject (*FunctionCall)(KJSContext* context, void* object,
const KJSArguments& arguments);
/**
* Define a function. The specified C++ callback function will
* be called upon invocation.
*/
void defineFunction(KJSContext* ctx,
const QString& name, FunctionCall callback);
#if 0
/**
* Define a finalization function.
*
*/
void defineFinalization(FinalizeFunction callback);
#endif
/**
* Construct an object with this prototype and the specified
* internal value. The value pointer will be passed as the object
* parameter to the callbacks defined via defineProperty() and
* defineFunction().
*
* @todo Provide a better type than void*
*/
KJSObject constructObject(KJSContext* ctx, void *internalValue = 0);
/**
* Similar to constructObject() but specialized on the
* construction of global objects.
*/
KJSGlobalObject constructGlobalObject(void *internalValue = 0);
private:
KJSPrototype(const KJSPrototype&); // undefined
KJSPrototype& operator=(const KJSPrototype&); // undefined
KJSPrototypeHandle* hnd;
};
#endif

View file

@ -1,978 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2003 Peter Kelly (pmk@post.com)
* Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <config-kjs.h>
#include "array_instance.h"
#include "PropertyNameArray.h"
#include "JSVariableObject.h"
#include <wtf/Assertions.h>
#include <wtf/HashMap.h>
#include <algorithm>
#include <stdio.h>
using std::min;
using std::max;
namespace KJS {
struct ArrayEntity {
ArrayEntity()
: value(0),
attributes(0)
{
}
ArrayEntity(JSValue* jsVal, uint32_t attr)
: value(jsVal),
attributes(attr)
{
}
JSValue* value;
uint32_t attributes;
};
typedef HashMap<unsigned, ArrayEntity> SparseArrayValueMap;
struct ArrayStorage {
unsigned m_numValuesInVector;
SparseArrayValueMap* m_sparseValueMap;
ArrayEntity m_vector[1];
};
// (2^32)-1
static const unsigned maxArrayLength = 0xFFFFFFFFU;
// 0xFFFFFFFF is a bit weird -- is not an array index even though it's an integer
static const unsigned maxArrayIndex = 0xFFFFFFFEU;
// Our policy for when to use a vector and when to use a sparse map.
// For all array indices under sparseArrayCutoff, we always use a vector.
// When indices greater than sparseArrayCutoff are involved, we use a vector
// as long as it is 1/8 full. If more sparse than that, we use a map.
static const unsigned sparseArrayCutoff = 10000;
static const unsigned minDensityMultiplier = 8;
static const unsigned mergeSortCutoff = 10000;
const ClassInfo ArrayInstance::info = {"Array", 0, 0, 0};
static inline size_t storageSize(unsigned vectorLength)
{
return sizeof(ArrayStorage) - sizeof(ArrayEntity) + vectorLength * sizeof(ArrayEntity);
}
static inline unsigned increasedVectorLength(unsigned newLength)
{
return (newLength * 3 + 1) / 2;
}
static inline bool isDenseEnoughForVector(unsigned length, unsigned numValues)
{
return length / minDensityMultiplier <= numValues;
}
ArrayInstance::ArrayInstance(JSObject* prototype, unsigned initialLength)
: JSObject(prototype)
{
unsigned initialCapacity = min(initialLength, sparseArrayCutoff);
m_length = initialLength;
m_vectorLength = initialCapacity;
m_storage = static_cast<ArrayStorage*>(fastCalloc(storageSize(initialCapacity), 1));
m_lengthAttributes = DontDelete | DontEnum;
Collector::reportExtraMemoryCost(initialCapacity * sizeof(ArrayEntity));
}
ArrayInstance::ArrayInstance(JSObject* prototype, const List& list)
: JSObject(prototype)
{
unsigned length = list.size();
m_length = length;
m_vectorLength = length;
m_lengthAttributes = DontDelete | DontEnum;
ArrayStorage* storage = static_cast<ArrayStorage*>(fastMalloc(storageSize(length)));
storage->m_numValuesInVector = length;
storage->m_sparseValueMap = 0;
ListIterator it = list.begin();
for (unsigned i = 0; i < length; ++i) {
storage->m_vector[i].value = it++;
storage->m_vector[i].attributes = 0;
}
m_storage = storage;
// When the array is created non-empty, its cells are filled, so it's really no worse than
// a property map. Therefore don't report extra memory cost.
}
ArrayInstance::~ArrayInstance()
{
delete m_storage->m_sparseValueMap;
fastFree(m_storage);
}
JSValue* ArrayInstance::getItem(unsigned i) const
{
ASSERT(i <= maxArrayIndex);
ArrayEntity* ent = getArrayEntity(i);
if (ent)
return ent->value;
return jsUndefined();
}
JSValue* ArrayInstance::lengthGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot)
{
return jsNumber(static_cast<ArrayInstance*>(slot.slotBase())->m_length);
}
ALWAYS_INLINE bool ArrayInstance::inlineGetOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot)
{
if (i >= m_length) {
if (i > maxArrayIndex)
return getOwnPropertySlot(exec, Identifier::from(i), slot);
return false;
}
ArrayEntity* ent = getArrayEntity(i);
if (ent) {
if (ent->attributes & GetterSetter) {
GetterSetterImp *gs = static_cast<GetterSetterImp *>(ent->value);
JSObject *getterFunc = gs->getGetter();
if (getterFunc)
slot.setGetterSlot(this, getterFunc);
else
slot.setUndefined(this);
return true;
}
slot.setValueSlot(this, &ent->value);
return true;
}
return false;
}
ArrayEntity* ArrayInstance::getArrayEntity(unsigned int i) const
{
if (i >= m_length)
return 0;
ArrayStorage* storage = m_storage;
if (i < m_vectorLength) {
if (storage->m_vector[i].value)
return &storage->m_vector[i];
}
SparseArrayValueMap* map = storage->m_sparseValueMap;
if (map && i > 0 && i <= maxArrayIndex) {
SparseArrayValueMap::iterator it = map->find(i);
if (it != map->end()) {
return &it->second;
}
}
return 0;
}
bool ArrayInstance::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
if (propertyName == exec->propertyNames().length) {
slot.setCustom(this, lengthGetter);
return true;
}
bool isArrayIndex;
unsigned i = propertyName.toArrayIndex(&isArrayIndex);
if (isArrayIndex)
return inlineGetOwnPropertySlot(exec, i, slot);
return JSObject::getOwnPropertySlot(exec, propertyName, slot);
}
bool ArrayInstance::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot)
{
return inlineGetOwnPropertySlot(exec, i, slot);
}
// ECMA 15.4.5.1
void ArrayInstance::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attributes)
{
bool isArrayIndex;
unsigned i = propertyName.toArrayIndex(&isArrayIndex);
if (isArrayIndex) {
put(exec, i, value, attributes);
return;
}
if (propertyName == exec->propertyNames().length) {
if (m_lengthAttributes & ReadOnly)
return;
unsigned newLength = value->toUInt32(exec);
if (value->toNumber(exec) != static_cast<double>(newLength)) {
throwError(exec, RangeError, "Invalid array length.");
return;
}
m_lengthAttributes = attributes;
setLength(newLength);
return;
}
JSObject::put(exec, propertyName, value, attributes);
}
void ArrayInstance::put(ExecState* exec, unsigned i, JSValue* value, int attributes)
{
ArrayEntity *ent = getArrayEntity(i);
if (ent) {
if (ent->attributes & ReadOnly)
return;
attributes |= ent->attributes;
JSValue* gs = ent->value;
if (gs && !gs->isUndefined()) {
if (ent->attributes & GetterSetter) {
JSObject *setterFunc = static_cast<GetterSetterImp *>(gs)->getSetter();
if (!setterFunc) {
if (false) //if strict is true
throwError(exec, TypeError, "setting a property that has only a getter");
return;
}
List args;
args.append(value);
setterFunc->call(exec, this, args);
return;
}
}
}
KJS::ArrayInstance::putDirect(i, value, attributes);
}
bool ArrayInstance::deleteProperty(ExecState* exec, const Identifier& propertyName)
{
bool isArrayIndex;
unsigned i = propertyName.toArrayIndex(&isArrayIndex);
if (isArrayIndex)
return deleteProperty(exec, i);
if (propertyName == exec->propertyNames().length)
return false;
return JSObject::deleteProperty(exec, propertyName);
}
bool ArrayInstance::deleteProperty(ExecState* exec, unsigned i)
{
ArrayStorage* storage = m_storage;
if (i < m_vectorLength) {
ArrayEntity* ent = &storage->m_vector[i];
if (ent->value) {
if (ent->attributes & DontDelete)
return false;
JSValue*& valueSlot = ent->value;
bool hadValue = valueSlot;
valueSlot = 0;
storage->m_numValuesInVector -= hadValue;
ent->value = 0;
return hadValue;
}
}
if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
SparseArrayValueMap::iterator it = map->find(i);
if (it != map->end()) {
if ((*it).second.attributes & DontDelete)
return false;
map->remove(it->first);
return true;
}
}
if (i > maxArrayIndex)
return JSObject::deleteProperty(exec, Identifier::from(i));
return true;
}
void ArrayInstance::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, PropertyMap::PropertyMode mode)
{
// FIXME: Filling PropertyNameArray with an identifier for every integer
// is incredibly inefficient for large arrays. We need a different approach.
ArrayStorage* storage = m_storage;
unsigned usedVectorLength = min(m_length, m_vectorLength);
for (unsigned i = 0; i < usedVectorLength; ++i) {
if (storage->m_vector[i].value &&
(!(storage->m_vector[i].attributes & DontEnum) ||
mode == PropertyMap::IncludeDontEnumProperties))
propertyNames.add(Identifier::from(i));
}
if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
SparseArrayValueMap::iterator end = map->end();
for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it)
if (!((*it).second.attributes & DontEnum) ||
mode == PropertyMap::IncludeDontEnumProperties)
propertyNames.add(Identifier::from(it->first));
}
if (mode == PropertyMap::IncludeDontEnumProperties)
propertyNames.add(exec->propertyNames().length);
JSObject::getOwnPropertyNames(exec, propertyNames, mode);
}
bool ArrayInstance::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
if (propertyName == exec->propertyNames().length) {
descriptor.setPropertyDescriptorValues(exec, jsNumber(m_length), m_lengthAttributes);
return true;
}
bool isArrayIndex;
unsigned i = propertyName.toArrayIndex(&isArrayIndex);
if (isArrayIndex) {
ArrayEntity* ent = getArrayEntity(i);
if (ent) {
descriptor.setPropertyDescriptorValues(exec, ent->value, ent->attributes);
return true;
}
}
return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
}
//ECMAScript Edition 5.1r6 - 15.4.5.1
bool ArrayInstance::defineOwnProperty(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& desc, bool shouldThrow)
{
PropertyDescriptor oldLenDesc;
getOwnPropertyDescriptor(exec, exec->propertyNames().length, oldLenDesc);
unsigned int oldLen = oldLenDesc.value()->toUInt32(exec);
//4a
bool isArrayIndex;
unsigned index = propertyName.toArrayIndex(&isArrayIndex);
//Step 3
if (propertyName == exec->propertyNames().length) {
//a
if (!desc.value())
return JSObject::defineOwnProperty(exec, propertyName, desc, shouldThrow);
//b
PropertyDescriptor newLenDesc(desc);
//c
unsigned int newLen = desc.value()->toUInt32(exec);
//d
if (newLen != desc.value()->toNumber(exec) || desc.value()->toNumber(exec) > maxArrayLength) {
throwError(exec, RangeError, "Index out of range");
return false;
}
//e
newLenDesc.setValue(jsNumber(newLen));
//f
if (newLen >= oldLen)
return JSObject::defineOwnProperty(exec, propertyName, newLenDesc, shouldThrow);
//g
if (!oldLenDesc.writable()) {
if (shouldThrow)
throwError(exec, TypeError, "length is not writable");
return false;
}
//h
bool newWriteable;
if (!newLenDesc.writableSet() || newLenDesc.writable()) {
newWriteable = true;
} else { //i
if (anyItemHasAttribute(DontDelete))
newLenDesc.setWritable(false);
else
newLenDesc.setWritable(true);
newWriteable = false;
}
//j
bool succeeded = JSObject::defineOwnProperty(exec, propertyName, newLenDesc, shouldThrow);
//k
if (!succeeded) return false;
//l
while (newLen < oldLen) {
--oldLen;
bool deleteSucceeded = deleteProperty(exec, oldLen); // 3. argument should be false
if (!deleteSucceeded) {
newLenDesc.setValue(jsNumber(oldLen+1));
if (!newWriteable)
newLenDesc.setWritable(false);
JSObject::defineOwnProperty(exec, propertyName, newLenDesc, false);
if (shouldThrow)
throwError(exec, TypeError);
return false;
}
}
//m
if (!newWriteable) {
PropertyDescriptor writableDesc;
writableDesc.setWritable(false);
return JSObject::defineOwnProperty(exec, propertyName, writableDesc, false);
}
return true;
} else if (isArrayIndex) {//Step 4
//b
if (index >= oldLen && !oldLenDesc.writable()) {
if (shouldThrow)
throwError(exec, TypeError);
return false;
}
//c
bool succeeded = JSObject::defineOwnProperty(exec, propertyName, desc, false);
//d
if (!succeeded) {
if (shouldThrow)
throwError(exec, TypeError);
return false;
}
//e
if (index >= oldLen) {
oldLenDesc.setValue(jsNumber(index+1));
JSObject::defineOwnProperty(exec, exec->propertyNames().length, oldLenDesc, false);
}
return true;
}
return JSObject::defineOwnProperty(exec, propertyName, desc, shouldThrow);
}
bool ArrayInstance::getPropertyAttributes(const Identifier& propertyName, unsigned int& attributes) const
{
bool isArrayIndex;
unsigned i = propertyName.toArrayIndex(&isArrayIndex);
if (isArrayIndex) {
ArrayEntity* ent = getArrayEntity(i);
if (ent) {
attributes = ent->attributes;
return true;
}
}
return KJS::JSObject::getPropertyAttributes(propertyName, attributes);
}
JSValue* ArrayInstance::getDirect(const Identifier& propertyName) const
{
bool isArrayIndex;
unsigned i = propertyName.toArrayIndex(&isArrayIndex);
if (isArrayIndex) {
ArrayEntity* ent = getArrayEntity(i);
if (ent) {
if (ent->value)
return ent->value;
}
}
return KJS::JSObject::getDirect(propertyName);
}
void ArrayInstance::putDirect(unsigned i, JSValue* value, int attributes)
{
unsigned length = m_length;
if (i >= length) {
if (i > maxArrayIndex) {
KJS::JSObject::putDirect(Identifier::from(i), value, attributes);
return;
}
length = i + 1;
m_length = length;
}
ArrayStorage* storage = m_storage;
if (i < m_vectorLength) {
ArrayEntity* ent = &storage->m_vector[i];
if (!ent->value && !isExtensible())
return;
JSValue*& valueSlot = ent->value;
storage->m_numValuesInVector += !valueSlot;
valueSlot = value;
ent->attributes = attributes;
return;
}
if (!isExtensible())
return;
SparseArrayValueMap* map = storage->m_sparseValueMap;
if (i >= sparseArrayCutoff) {
// If the index is high, go to the map unless we're pretty dense.
if (!map) {
map = new SparseArrayValueMap;
storage->m_sparseValueMap = map;
// If we create a sparse map, we need to ensure that there is at least one spot
// in the vector map, however, since the sparse map can't put/get key 0.
// It's safe to do it here, since put(0) will always put it in the vector part,
// but we have to do it before a get(0) or it will crash
if (!m_vectorLength)
increaseVectorLength(1);
}
map->set(i, ArrayEntity(value, attributes));
return;
}
// note: an invariant here is that indeces < sparseArrayCutoff
// are always inside the vector portion.
// lowish indeces or high density -> we have decided that we'll put the new item into the vector.
// Fast case is when there is no sparse map, so we can increase the vector size without moving values from the sparse map.
if (!map || map->isEmpty()) {
increaseVectorLength(i + 1);
storage = m_storage;
++storage->m_numValuesInVector;
storage->m_vector[i].value = value;
storage->m_vector[i].attributes = attributes;
return;
}
// Decide just how large we want to make the vector to be.
unsigned newNumValuesInVector = storage->m_numValuesInVector + 1;
unsigned newVectorLength = increasedVectorLength(i + 1);
// First, count how much stuff we are guaranteed to move over, now
// that we've decided to at least include i in the vector.
for (unsigned j = max(m_vectorLength, sparseArrayCutoff); j < newVectorLength; ++j)
newNumValuesInVector += map->contains(j);
if (i >= sparseArrayCutoff)
newNumValuesInVector -= map->contains(i);
// Continue increasing the vector portion as long as the things in the map are dense enough
if (isDenseEnoughForVector(newVectorLength, newNumValuesInVector)) {
unsigned proposedNewNumValuesInVector = newNumValuesInVector;
while (true) {
unsigned proposedNewVectorLength = increasedVectorLength(newVectorLength + 1);
for (unsigned j = max(newVectorLength, sparseArrayCutoff); j < proposedNewVectorLength; ++j)
proposedNewNumValuesInVector += map->contains(j);
if (!isDenseEnoughForVector(proposedNewVectorLength, proposedNewNumValuesInVector))
break;
newVectorLength = proposedNewVectorLength;
newNumValuesInVector = proposedNewNumValuesInVector;
}
}
storage = static_cast<ArrayStorage*>(fastRealloc(storage, storageSize(newVectorLength)));
unsigned vectorLength = m_vectorLength;
// Special case: if we just added a single value, we don't have to scan the map
// to see what to remove from it
if (newNumValuesInVector == storage->m_numValuesInVector + 1) {
for (unsigned j = vectorLength; j < newVectorLength; ++j)
storage->m_vector[j].value = 0;
if (i > sparseArrayCutoff)
map->remove(i);
} else {
// Move over things from the map to the new array portion
for (unsigned j = vectorLength; j < max(vectorLength, sparseArrayCutoff); ++j)
storage->m_vector[j].value = 0;
for (unsigned j = max(vectorLength, sparseArrayCutoff); j < newVectorLength; ++j)
storage->m_vector[j] = map->take(j);
}
storage->m_vector[i].value = value;
storage->m_vector[i].attributes = attributes;
m_vectorLength = newVectorLength;
storage->m_numValuesInVector = newNumValuesInVector;
m_storage = storage;
}
void ArrayInstance::putDirect(const Identifier& propertyName, JSValue* value, int attr)
{
bool isArrayIndex;
unsigned i = propertyName.toArrayIndex(&isArrayIndex);
if (isArrayIndex) {
KJS::ArrayInstance::putDirect(i, value, attr);
return;
}
KJS::JSObject::putDirect(propertyName, value, attr);
}
void ArrayInstance::putDirect(const Identifier& propertyName, int value, int attr)
{
bool isArrayIndex;
unsigned i = propertyName.toArrayIndex(&isArrayIndex);
if (isArrayIndex) {
KJS::ArrayInstance::putDirect(i, jsNumber(value), attr);
return;
}
KJS::JSObject::putDirect(propertyName, jsNumber(value), attr);
}
void ArrayInstance::removeDirect(const Identifier& propertyName)
{
bool isArrayIndex;
unsigned i = propertyName.toArrayIndex(&isArrayIndex);
if (isArrayIndex) {
ArrayStorage* storage = m_storage;
if (i < m_vectorLength) {
ArrayEntity* ent = &storage->m_vector[i];
if (ent->value) {
JSValue*& valueSlot = ent->value;
bool hadValue = valueSlot;
valueSlot = 0;
storage->m_numValuesInVector -= hadValue;
ent->value = 0;
return;
}
}
if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
SparseArrayValueMap::iterator it = map->find(i);
if (it != map->end()) {
map->remove(it->first);
return;
}
}
}
JSObject::removeDirect(Identifier::from(i));
}
void ArrayInstance::increaseVectorLength(unsigned newLength)
{
// This function leaves the array in an internally inconsistent state, because it does not move any values from sparse value map
// to the vector. Callers have to account for that, because they can do it more efficiently.
ArrayStorage* storage = m_storage;
unsigned vectorLength = m_vectorLength;
ASSERT(newLength > vectorLength);
unsigned newVectorLength = increasedVectorLength(newLength);
storage = static_cast<ArrayStorage*>(fastRealloc(storage, storageSize(newVectorLength)));
m_vectorLength = newVectorLength;
for (unsigned i = vectorLength; i < newVectorLength; ++i)
storage->m_vector[i].value = 0;
m_storage = storage;
}
void ArrayInstance::setLength(unsigned newLength)
{
ArrayStorage* storage = m_storage;
unsigned length = m_length;
unsigned newLenSet = newLength;
if (newLength < length) {
unsigned usedVectorLength = min(length, m_vectorLength);
if (usedVectorLength > 0) {
for (unsigned i = usedVectorLength-1; i >= newLength && i > 0; --i) {
ArrayEntity* ent = &storage->m_vector[i];
if (ent->value) {
if (ent->attributes & DontDelete) {
newLenSet = i+1;
break;
}
JSValue*& valueSlot = ent->value;
bool hadValue = valueSlot;
valueSlot = 0;
ent->value = 0;
storage->m_numValuesInVector -= hadValue;
}
}
}
if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
SparseArrayValueMap copy = *map;
SparseArrayValueMap::iterator end = copy.end();
for (SparseArrayValueMap::iterator it = copy.begin(); it != end; ++it) {
if (it->first >= newLength) {
if (it->second.attributes & DontDelete) {
newLenSet = it->first + 1;
}
}
}
for (SparseArrayValueMap::iterator it = copy.begin(); it != end; ++it) {
if (it->first >= newLenSet) {
map->remove(it->first);
}
}
if (map->isEmpty()) {
delete map;
storage->m_sparseValueMap = 0;
}
}
}
m_length = newLenSet;
}
void ArrayInstance::mark()
{
JSObject::mark();
ArrayStorage* storage = m_storage;
unsigned usedVectorLength = min(m_length, m_vectorLength);
for (unsigned i = 0; i < usedVectorLength; ++i) {
ArrayEntity* ent = &storage->m_vector[i];
if (ent->value && !ent->value->marked())
ent->value->mark();
}
if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
SparseArrayValueMap::iterator end = map->end();
for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) {
ArrayEntity* ent = &it->second;
if (!ent->value->marked())
ent->value->mark();
}
}
}
static ExecState* execForCompareByStringForQSort;
static int compareByStringForQSort(const void* a, const void* b)
{
ExecState* exec = execForCompareByStringForQSort;
const ArrayEntity* va = static_cast<const ArrayEntity*>(a);
const ArrayEntity* vb = static_cast<const ArrayEntity*>(b);
ASSERT(va->value && !va->value->isUndefined());
ASSERT(vb->value && !vb->value->isUndefined());
return compare(va->value->toString(exec), vb->value->toString(exec));
}
void ArrayInstance::sort(ExecState* exec)
{
unsigned lengthNotIncludingUndefined = compactForSorting();
ExecState* oldExec = execForCompareByStringForQSort;
execForCompareByStringForQSort = exec;
#if HAVE(MERGESORT)
// Because mergesort usually does fewer compares, it is faster than qsort here.
// However, because it requires extra copies of the storage buffer, don't use it for very
// large arrays.
// FIXME: Since we sort by string value, a fast algorithm might be to convert all the
// values to string once up front, and then use a radix sort. That would be O(N) rather
// than O(N log N).
if (lengthNotIncludingUndefined < mergeSortCutoff) {
// During the sort, we could do a garbage collect, and it's important to still
// have references to every object in the array for ArrayInstance::mark.
// The mergesort algorithm does not guarantee this, so we sort a copy rather
// than the original.
size_t size = storageSize(m_vectorLength);
ArrayStorage* copy = static_cast<ArrayStorage*>(fastMalloc(size));
memcpy(copy, m_storage, size);
mergesort(copy->m_vector, lengthNotIncludingUndefined, sizeof(ArrayEntity), compareByStringForQSort);
fastFree(m_storage);
m_storage = copy;
execForCompareByStringForQSort = oldExec;
return;
}
#endif
qsort(m_storage->m_vector, lengthNotIncludingUndefined, sizeof(ArrayEntity), compareByStringForQSort);
execForCompareByStringForQSort = oldExec;
}
struct CompareWithCompareFunctionArguments {
CompareWithCompareFunctionArguments(ExecState *e, JSObject *cf)
: exec(e)
, compareFunction(cf)
, globalObject(e->dynamicInterpreter()->globalObject())
{
}
ExecState *exec;
JSObject *compareFunction;
List arguments;
JSObject *globalObject;
};
static CompareWithCompareFunctionArguments* compareWithCompareFunctionArguments;
static int compareWithCompareFunctionForQSort(const void* a, const void* b)
{
CompareWithCompareFunctionArguments *args = compareWithCompareFunctionArguments;
const ArrayEntity* va = static_cast<const ArrayEntity*>(a);
const ArrayEntity* vb = static_cast<const ArrayEntity*>(b);
ASSERT(va->value && !va->value->isUndefined());
ASSERT(vb->value && !vb->value->isUndefined());
args->arguments.clear();
args->arguments.append(va->value);
args->arguments.append(vb->value);
double compareResult = args->compareFunction->call
(args->exec, args->globalObject, args->arguments)->toNumber(args->exec);
return compareResult < 0 ? -1 : compareResult > 0 ? 1 : 0;
}
void ArrayInstance::sort(ExecState* exec, JSObject* compareFunction)
{
size_t lengthNotIncludingUndefined = compactForSorting();
CompareWithCompareFunctionArguments* oldArgs = compareWithCompareFunctionArguments;
CompareWithCompareFunctionArguments args(exec, compareFunction);
compareWithCompareFunctionArguments = &args;
#if HAVE(MERGESORT)
// Because mergesort usually does fewer compares, it is faster than qsort here.
// However, because it requires extra copies of the storage buffer, don't use it for very
// large arrays.
// FIXME: A tree sort using a perfectly balanced tree (e.g. an AVL tree) could do an even
// better job of minimizing compares.
if (lengthNotIncludingUndefined < mergeSortCutoff) {
// During the sort, we could do a garbage collect, and it's important to still
// have references to every object in the array for ArrayInstance::mark.
// The mergesort algorithm does not guarantee this, so we sort a copy rather
// than the original.
size_t size = storageSize(m_vectorLength);
ArrayStorage* copy = static_cast<ArrayStorage*>(fastMalloc(size));
memcpy(copy, m_storage, size);
mergesort(copy->m_vector, lengthNotIncludingUndefined, sizeof(ArrayEntity), compareWithCompareFunctionForQSort);
fastFree(m_storage);
m_storage = copy;
compareWithCompareFunctionArguments = oldArgs;
return;
}
#endif
qsort(m_storage->m_vector, lengthNotIncludingUndefined, sizeof(ArrayEntity), compareWithCompareFunctionForQSort);
compareWithCompareFunctionArguments = oldArgs;
}
unsigned ArrayInstance::compactForSorting()
{
ArrayStorage* storage = m_storage;
unsigned usedVectorLength = min(m_length, m_vectorLength);
unsigned numDefined = 0;
unsigned numUndefined = 0;
// This compacts normal values (e.g. not undefined) in a contiguous run
// at the beginning of the array, and then puts any set undefined values
// at the end
// count the first contiguous run of defined values in the vector store
for (; numDefined < usedVectorLength; ++numDefined) {
ArrayEntity* v = &storage->m_vector[numDefined];
if (!v->value || v->value->isUndefined())
break;
}
// compact the rest, counting along the way
for (unsigned i = numDefined; i < usedVectorLength; ++i) {
ArrayEntity v = storage->m_vector[i];
if (!v.value || v.value->isUndefined())
++numUndefined;
else
storage->m_vector[numDefined++] = storage->m_vector[i];
}
unsigned newUsedVectorLength = numDefined + numUndefined;
if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
newUsedVectorLength += map->size();
if (newUsedVectorLength > m_vectorLength) {
increaseVectorLength(newUsedVectorLength);
storage = m_storage;
}
SparseArrayValueMap::iterator end = map->end();
for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it)
storage->m_vector[numDefined++] = it->second;
delete map;
storage->m_sparseValueMap = 0;
}
for (unsigned i = numDefined; i < newUsedVectorLength; ++i)
storage->m_vector[i].value = 0;
for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i)
storage->m_vector[i].value = 0;
return numDefined;
}
bool KJS::ArrayInstance::anyItemHasAttribute(unsigned int attributes) const
{
ArrayStorage* storage = m_storage;
unsigned usedVectorLength = min(m_length, m_vectorLength);
for (unsigned i = 0; i < usedVectorLength; ++i) {
if (storage->m_vector[i].value && storage->m_vector[i].attributes & attributes)
return true;
}
if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
SparseArrayValueMap::iterator end = map->end();
for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it)
if ((*it).second.attributes & attributes)
return true;
}
return false;
}
}
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on; hl c++;

View file

@ -1,88 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2003, 2007 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef ARRAY_INSTANCE_H
#define ARRAY_INSTANCE_H
#include "object.h"
namespace KJS {
struct ArrayStorage;
class KJS_EXPORT ArrayInstance : public JSObject {
public:
ArrayInstance(JSObject* prototype, unsigned initialLength);
ArrayInstance(JSObject* prototype, const List& initialValues);
~ArrayInstance();
virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual void put(ExecState*, const Identifier& propertyName, JSValue*, int attributes = None);
virtual void put(ExecState*, unsigned propertyName, JSValue*, int attributes = None);
virtual bool deleteProperty(ExecState *, const Identifier& propertyName);
virtual bool deleteProperty(ExecState *, unsigned propertyName);
virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, PropertyMap::PropertyMode mode);
virtual bool defineOwnProperty(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& desc, bool shouldThrow);
virtual void mark();
virtual bool getPropertyAttributes(const Identifier& propertyName, unsigned& attributes) const;
virtual JSValue *getDirect(const Identifier& propertyName) const;
virtual void putDirect(unsigned index, JSValue *value, int attr = 0);
virtual void putDirect(const Identifier &propertyName, JSValue *value, int attr = 0);
virtual void putDirect(const Identifier &propertyName, int value, int attr = 0);
virtual void removeDirect(const Identifier &propertyName);
virtual const ClassInfo* classInfo() const { return &info; }
static const ClassInfo info;
unsigned getLength() const { return m_length; }
JSValue* getItem(unsigned) const;
void sort(ExecState*);
void sort(ExecState*, JSObject* compareFunction);
private:
static JSValue* lengthGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot&);
bool inlineGetOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
inline struct ArrayEntity* getArrayEntity(unsigned) const;
void setLength(unsigned);
void increaseVectorLength(unsigned newLength);
unsigned compactForSorting();
unsigned m_length;
unsigned m_vectorLength;
ArrayStorage* m_storage;
inline bool anyItemHasAttribute(unsigned attributes) const;
uint32_t m_lengthAttributes;
};
} // namespace KJS
#endif

View file

@ -1,741 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2003, 2007 Apple Inc. All rights reserved.
* Copyright (C) 2003 Peter Kelly (pmk@post.com)
* Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
* Copyright (C) 2008 Janusz Lewandowski (lew21st@gmail.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "array_object.h"
#include <config-kjs.h>
#include "array_object.lut.h"
#include "error_object.h"
#include "lookup.h"
#include "operations.h"
#include "PropertyNameArray.h"
#include <wtf/HashSet.h>
#include <stdio.h>
// GCC cstring uses these automatically, but not all implementations do.
using std::strlen;
using std::strcpy;
using std::strncpy;
using std::memset;
using std::memcpy;
namespace KJS {
/**
* @internal
*
* Class to implement all methods that are properties of the
* Object object
*/
class ArrayObjectFuncImp : public InternalFunctionImp {
public:
ArrayObjectFuncImp(ExecState *, FunctionPrototype *, int i, int len, const Identifier& );
virtual JSValue *callAsFunction(ExecState *, JSObject *thisObj, const List &args);
enum { IsArray };
private:
int id;
};
// ------------------------------ ArrayPrototype ----------------------------
const ClassInfo ArrayPrototype::info = {"Array", &ArrayInstance::info, &arrayTable, 0};
/* Source for array_object.lut.h
@begin arrayTable 16
toString ArrayProtoFunc::ToString DontEnum|Function 0
toLocaleString ArrayProtoFunc::ToLocaleString DontEnum|Function 0
concat ArrayProtoFunc::Concat DontEnum|Function 1
join ArrayProtoFunc::Join DontEnum|Function 1
pop ArrayProtoFunc::Pop DontEnum|Function 0
push ArrayProtoFunc::Push DontEnum|Function 1
reverse ArrayProtoFunc::Reverse DontEnum|Function 0
shift ArrayProtoFunc::Shift DontEnum|Function 0
slice ArrayProtoFunc::Slice DontEnum|Function 2
sort ArrayProtoFunc::Sort DontEnum|Function 1
splice ArrayProtoFunc::Splice DontEnum|Function 2
unshift ArrayProtoFunc::UnShift DontEnum|Function 1
every ArrayProtoFunc::Every DontEnum|Function 1
forEach ArrayProtoFunc::ForEach DontEnum|Function 1
some ArrayProtoFunc::Some DontEnum|Function 1
indexOf ArrayProtoFunc::IndexOf DontEnum|Function 1
lastIndexOf ArrayProtoFunc::LastIndexOf DontEnum|Function 1
filter ArrayProtoFunc::Filter DontEnum|Function 1
map ArrayProtoFunc::Map DontEnum|Function 1
reduce ArrayProtoFunc::Reduce DontEnum|Function 1
reduceRight ArrayProtoFunc::ReduceRight DontEnum|Function 1
@end
*/
// ECMA 15.4.4
ArrayPrototype::ArrayPrototype(ExecState*, ObjectPrototype* objProto)
: ArrayInstance(objProto, 0)
{
}
bool ArrayPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
return getStaticFunctionSlot<ArrayProtoFunc, ArrayInstance>(exec, &arrayTable, this, propertyName, slot);
}
// ------------------------------ ArrayProtoFunc ----------------------------
ArrayProtoFunc::ArrayProtoFunc(ExecState* exec, int i, int len, const Identifier& name)
: InternalFunctionImp(static_cast<FunctionPrototype*>
(exec->lexicalInterpreter()->builtinFunctionPrototype()), name)
, id(i)
{
put(exec, exec->propertyNames().length, jsNumber(len), DontDelete | ReadOnly | DontEnum);
}
static JSValue *getProperty(ExecState *exec, JSObject *obj, unsigned index)
{
PropertySlot slot;
if (!obj->getPropertySlot(exec, index, slot))
return NULL;
return slot.getValue(exec, obj, index);
}
// ECMA 15.4.4
JSValue* ArrayProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
{
unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
JSValue *result = 0; // work around gcc 4.0 bug in uninitialized variable warning
switch (id) {
case ToLocaleString:
case ToString:
if (!thisObj->inherits(&ArrayInstance::info))
return throwError(exec, TypeError);
// fall through
case Join: {
static HashSet<JSObject*> visitedElems;
static const UString* empty = new UString("");
static const UString* comma = new UString(",");
bool alreadyVisited = !visitedElems.add(thisObj).second;
if (alreadyVisited)
return jsString(*empty);
UString separator = *comma;
UString str = *empty;
if (id == Join && !args[0]->isUndefined())
separator = args[0]->toString(exec);
for (unsigned int k = 0; k < length; k++) {
if (k >= 1)
str += separator;
if (str.isNull()) {
JSObject *error = Error::create(exec, GeneralError, "Out of memory");
exec->setException(error);
break;
}
JSValue* element = thisObj->get(exec, k);
if (element->isUndefinedOrNull())
continue;
bool fallback = false;
if (id == ToLocaleString) {
JSObject* o = element->toObject(exec);
JSValue* conversionFunction = o->get(exec, exec->propertyNames().toLocaleString);
if (conversionFunction->isObject() && static_cast<JSObject*>(conversionFunction)->implementsCall())
str += static_cast<JSObject*>(conversionFunction)->call(exec, o, List())->toString(exec);
else
// try toString() fallback
fallback = true;
}
if (id == ToString || id == Join || fallback) {
str += element->toString(exec);
if (exec->hadException())
break;
if (str.isNull()) {
JSObject* error = Error::create(exec, GeneralError, "Out of memory");
exec->setException(error);
}
}
if (exec->hadException())
break;
}
visitedElems.remove(thisObj);
result = jsString(str);
break;
}
case Concat: {
JSObject *arr = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinArray()->construct(exec,List::empty()));
int n = 0;
JSValue *curArg = thisObj;
JSObject *curObj = static_cast<JSObject *>(thisObj);
ListIterator it = args.begin();
for (;;) {
if (curArg->isObject() &&
curObj->inherits(&ArrayInstance::info)) {
unsigned int k = 0;
// Older versions tried to optimize out getting the length of thisObj
// by checking for n != 0, but that doesn't work if thisObj is an empty array.
length = curObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
while (k < length) {
if (JSValue *v = getProperty(exec, curObj, k))
arr->put(exec, n, v);
n++;
k++;
}
} else {
arr->put(exec, n, curArg);
n++;
}
if (it == args.end())
break;
curArg = *it;
curObj = static_cast<JSObject *>(it++); // may be 0
}
arr->put(exec, exec->propertyNames().length, jsNumber(n), DontEnum | DontDelete);
result = arr;
break;
}
case Pop:{
if (length == 0) {
thisObj->put(exec, exec->propertyNames().length, jsNumber(length), DontEnum | DontDelete);
result = jsUndefined();
} else {
result = thisObj->get(exec, length - 1);
thisObj->put(exec, exec->propertyNames().length, jsNumber(length - 1), DontEnum | DontDelete);
}
break;
}
case Push: {
for (int n = 0; n < args.size(); n++)
thisObj->put(exec, length + n, args[n]);
length += args.size();
thisObj->put(exec, exec->propertyNames().length, jsNumber(length), DontEnum | DontDelete);
result = jsNumber(length);
break;
}
case Reverse: {
unsigned int middle = length / 2;
for (unsigned int k = 0; k < middle; k++) {
unsigned lk1 = length - k - 1;
JSValue *obj2 = getProperty(exec, thisObj, lk1);
JSValue *obj = getProperty(exec, thisObj, k);
if (obj2)
thisObj->put(exec, k, obj2);
else
thisObj->deleteProperty(exec, k);
if (obj)
thisObj->put(exec, lk1, obj);
else
thisObj->deleteProperty(exec, lk1);
}
result = thisObj;
break;
}
case Shift: {
if (length == 0) {
thisObj->put(exec, exec->propertyNames().length, jsNumber(length), DontEnum | DontDelete);
result = jsUndefined();
} else {
result = thisObj->get(exec, 0);
for(unsigned int k = 1; k < length; k++) {
if (JSValue *obj = getProperty(exec, thisObj, k))
thisObj->put(exec, k-1, obj);
else
thisObj->deleteProperty(exec, k-1);
}
thisObj->deleteProperty(exec, length - 1);
thisObj->put(exec, exec->propertyNames().length, jsNumber(length - 1), DontEnum | DontDelete);
}
break;
}
case Slice: {
// http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10
// We return a new array
JSObject *resObj = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinArray()->construct(exec,List::empty()));
result = resObj;
double begin = 0;
if (!args[0]->isUndefined()) {
begin = args[0]->toInteger(exec);
if (begin >= 0) { // false for NaN
if (begin > length)
begin = length;
} else {
begin += length;
if (!(begin >= 0)) // true for NaN
begin = 0;
}
}
double end = length;
if (!args[1]->isUndefined()) {
end = args[1]->toInteger(exec);
if (end < 0) { // false for NaN
end += length;
if (end < 0)
end = 0;
} else {
if (!(end <= length)) // true for NaN
end = length;
}
}
//printf( "Slicing from %d to %d \n", begin, end );
int n = 0;
int b = static_cast<int>(begin);
int e = static_cast<int>(end);
for(int k = b; k < e; k++, n++) {
if (JSValue *v = getProperty(exec, thisObj, k))
resObj->put(exec, n, v);
}
resObj->put(exec, exec->propertyNames().length, jsNumber(n), DontEnum | DontDelete);
break;
}
case Sort:{
#if 0
printf("KJS Array::Sort length=%d\n", length);
for ( unsigned int i = 0 ; i<length ; ++i )
printf("KJS Array::Sort: %d: %s\n", i, thisObj->get(exec, i)->toString(exec).ascii() );
#endif
JSObject *sortFunction = NULL;
if (!args[0]->isUndefined())
{
sortFunction = args[0]->toObject(exec);
if (!sortFunction->implementsCall())
sortFunction = NULL;
}
if (thisObj->classInfo() == &ArrayInstance::info) {
if (sortFunction)
((ArrayInstance *)thisObj)->sort(exec, sortFunction);
else
((ArrayInstance *)thisObj)->sort(exec);
result = thisObj;
break;
}
if (length == 0) {
thisObj->put(exec, exec->propertyNames().length, jsNumber(0), DontEnum | DontDelete);
result = thisObj;
break;
}
// "Min" sort. Not the fastest, but definitely less code than heapsort
// or quicksort, and much less swapping than bubblesort/insertionsort.
for ( unsigned int i = 0 ; i<length-1 ; ++i )
{
JSValue *iObj = thisObj->get(exec,i);
unsigned int themin = i;
JSValue *minObj = iObj;
for ( unsigned int j = i+1 ; j<length ; ++j )
{
JSValue *jObj = thisObj->get(exec,j);
double cmp;
if (jObj->isUndefined()) {
cmp = 1; // don't check minObj because there's no need to differentiate == (0) from > (1)
} else if (minObj->isUndefined()) {
cmp = -1;
} else if (sortFunction) {
List l;
l.append(jObj);
l.append(minObj);
cmp = sortFunction->call(exec, exec->dynamicInterpreter()->globalObject(), l)->toNumber(exec);
} else {
cmp = (jObj->toString(exec) < minObj->toString(exec)) ? -1 : 1;
}
if ( cmp < 0 )
{
themin = j;
minObj = jObj;
}
}
// Swap themin and i
if ( themin > i )
{
//printf("KJS Array::Sort: swapping %d and %d\n", i, themin );
thisObj->put( exec, i, minObj );
thisObj->put( exec, themin, iObj );
}
}
#if 0
printf("KJS Array::Sort -- Resulting array:\n");
for ( unsigned int i = 0 ; i<length ; ++i )
printf("KJS Array::Sort: %d: %s\n", i, thisObj->get(exec, i)->toString(exec).ascii() );
#endif
result = thisObj;
break;
}
case Splice: {
// 15.4.4.12 - oh boy this is huge
JSObject *resObj = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinArray()->construct(exec,List::empty()));
result = resObj;
double start = args[0]->toInteger(exec);
uint32_t begin = 0;
if ( start < 0 )
begin = static_cast<uint32_t>(std::max<double>(start + length, 0));
else
begin = static_cast<uint32_t>(std::min<double>(start, length));
uint32_t deleteCount = static_cast<uint32_t>(std::min<double>(std::max<double>(args[1]->toInteger(exec), 0 ), length - begin));
//printf( "Splicing from %d, deleteCount=%d \n", begin, deleteCount );
for(unsigned int k = 0; k < deleteCount; k++) {
if (JSValue *v = getProperty(exec, thisObj, k+begin))
resObj->put(exec, k, v);
}
resObj->put(exec, exec->propertyNames().length, jsNumber(deleteCount), DontEnum | DontDelete);
unsigned int additionalArgs = maxInt( args.size() - 2, 0 );
if ( additionalArgs != deleteCount )
{
if ( additionalArgs < deleteCount )
{
for ( unsigned int k = begin; k < length - deleteCount; ++k )
{
if (JSValue *v = getProperty(exec, thisObj, k+deleteCount))
thisObj->put(exec, k+additionalArgs, v);
else
thisObj->deleteProperty(exec, k+additionalArgs);
}
for ( unsigned int k = length ; k > length - deleteCount + additionalArgs; --k )
thisObj->deleteProperty(exec, k-1);
}
else
{
for ( unsigned int k = length - deleteCount; k > begin; --k )
{
if (JSValue *obj = getProperty(exec, thisObj, k + deleteCount - 1))
thisObj->put(exec, k + additionalArgs - 1, obj);
else
thisObj->deleteProperty(exec, k+additionalArgs-1);
}
}
}
for ( unsigned int k = 0; k < additionalArgs; ++k )
{
thisObj->put(exec, k+begin, args[k+2]);
}
thisObj->put(exec, exec->propertyNames().length, jsNumber(length - deleteCount + additionalArgs), DontEnum | DontDelete);
break;
}
case UnShift: { // 15.4.4.13
unsigned int nrArgs = args.size();
for ( unsigned int k = length; k > 0; --k )
{
if (JSValue *v = getProperty(exec, thisObj, k - 1))
thisObj->put(exec, k+nrArgs-1, v);
else
thisObj->deleteProperty(exec, k+nrArgs-1);
}
for ( unsigned int k = 0; k < nrArgs; ++k )
thisObj->put(exec, k, args[k]);
result = jsNumber(length + nrArgs);
thisObj->put(exec, exec->propertyNames().length, result, DontEnum | DontDelete);
break;
}
case Filter:
case Map: {
JSObject *eachFunction = args[0]->toObject(exec);
if (!eachFunction->implementsCall())
return throwError(exec, TypeError);
JSObject *applyThis = args[1]->isUndefinedOrNull() ? exec->dynamicInterpreter()->globalObject() : args[1]->toObject(exec);
JSObject *resultArray;
if (id == Filter)
resultArray = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinArray()->construct(exec, List::empty()));
else {
List args;
args.append(jsNumber(length));
resultArray = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinArray()->construct(exec, args));
}
unsigned filterIndex = 0;
for (unsigned k = 0; k < length && !exec->hadException(); ++k) {
PropertySlot slot;
if (!thisObj->getPropertySlot(exec, k, slot))
continue;
JSValue *v = slot.getValue(exec, thisObj, k);
List eachArguments;
eachArguments.append(v);
eachArguments.append(jsNumber(k));
eachArguments.append(thisObj);
JSValue *result = eachFunction->call(exec, applyThis, eachArguments);
if (id == Map)
resultArray->put(exec, k, result);
else if (result->toBoolean(exec))
resultArray->put(exec, filterIndex++, v);
}
return resultArray;
}
case Every:
case ForEach:
case Some: {
//Documentation for these three is available at:
//http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:every
//http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:forEach
//http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:some
JSObject *eachFunction = args[0]->toObject(exec);
if (!eachFunction->implementsCall())
return throwError(exec, TypeError);
JSObject *applyThis = args[1]->isUndefinedOrNull() ? exec->dynamicInterpreter()->globalObject() : args[1]->toObject(exec);
if (id == Some || id == Every)
result = jsBoolean(id == Every);
else
result = jsUndefined();
for (unsigned k = 0; k < length && !exec->hadException(); ++k) {
PropertySlot slot;
if (!thisObj->getPropertySlot(exec, k, slot))
continue;
List eachArguments;
eachArguments.append(slot.getValue(exec, thisObj, k));
eachArguments.append(jsNumber(k));
eachArguments.append(thisObj);
bool predicateResult = eachFunction->call(exec, applyThis, eachArguments)->toBoolean(exec);
if (id == Every && !predicateResult) {
result = jsBoolean(false);
break;
}
if (id == Some && predicateResult) {
result = jsBoolean(true);
break;
}
}
break;
}
case IndexOf: {
// JavaScript 1.5 Extension by Mozilla
// Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf
unsigned index = 0;
double d = args[1]->toInteger(exec);
if (d < 0)
d += length;
if (d > 0) {
if (d > length)
index = length;
else
index = static_cast<unsigned>(d);
}
JSValue* searchElement = args[0];
for (; index < length; ++index) {
JSValue* e = getProperty(exec, thisObj, index);
if (!e)
continue;
if (strictEqual(exec, searchElement, e))
return jsNumber(index);
}
return jsNumber(-1);
}
case LastIndexOf: {
// JavaScript 1.6 Extension by Mozilla
// Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf
int index = length - 1;
double d = args[1]->toIntegerPreserveNaN(exec);
if (d < 0) {
d += length;
if (d < 0)
return jsNumber(-1);
}
if (d < length)
index = static_cast<int>(d);
JSValue* searchElement = args[0];
for (; index >= 0; --index) {
JSValue* e = getProperty(exec, thisObj, index);
if (!e)
continue;
if (strictEqual(exec, searchElement, e))
return jsNumber(index);
}
return jsNumber(-1);
}
case Reduce:
case ReduceRight: {
// JavaScript 1.8 Extensions by Mozilla
// Documentation:
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight
JSObject *callback = args[0]->toObject(exec);
if (!callback->implementsCall())
return throwError(exec, TypeError);
JSObject *applyThis = args[2]->isUndefinedOrNull() ? exec->dynamicInterpreter()->globalObject() : args[2]->toObject(exec);
if (!length && args.size() < 2)
return throwError(exec, TypeError);
unsigned k = 0;
unsigned last = length - 1;
if (args.size() >= 2)
result = args[1];
else {
for (; k < length && !exec->hadException(); ++k) {
PropertySlot slot;
if (!thisObj->getPropertySlot(exec, (id == Reduce) ? k : (last - k), slot))
continue;
result = slot.getValue(exec, thisObj, (id == Reduce) ? k++ : (last - k++));
break;
}
}
for (; k < length && !exec->hadException(); ++k) {
PropertySlot slot;
if (!thisObj->getPropertySlot(exec, (id == Reduce) ? k : (last - k), slot))
continue;
JSValue* v = slot.getValue(exec, thisObj, (id == Reduce) ? k : (last - k));
List eachArguments;
eachArguments.append(result);
eachArguments.append(v);
eachArguments.append(jsNumber((id == Reduce) ? k : (last - k)));
eachArguments.append(thisObj);
result = callback->call(exec, applyThis, eachArguments);
}
break;
}
default:
assert(0);
result = 0;
break;
}
return result;
}
// ------------------------------ ArrayObjectImp -------------------------------
ArrayObjectImp::ArrayObjectImp(ExecState *exec,
FunctionPrototype *funcProto,
ArrayPrototype *arrayProto)
: InternalFunctionImp(funcProto)
{
static const Identifier* isArrayName = new Identifier("isArray");
// ECMA 15.4.3.1 Array.prototype
put(exec, exec->propertyNames().prototype, arrayProto, DontEnum|DontDelete|ReadOnly);
putDirectFunction(new ArrayObjectFuncImp(exec, funcProto, ArrayObjectFuncImp::IsArray, 1, *isArrayName), DontEnum);
// no. of arguments for constructor
put(exec, exec->propertyNames().length, jsNumber(1), ReadOnly|DontDelete|DontEnum);
}
bool ArrayObjectImp::implementsConstruct() const
{
return true;
}
// ECMA 15.4.2
JSObject *ArrayObjectImp::construct(ExecState *exec, const List &args)
{
// a single numeric argument denotes the array size (!)
if (args.size() == 1 && args[0]->isNumber()) {
uint32_t n = args[0]->toUInt32(exec);
if (n != args[0]->toNumber(exec))
return throwError(exec, RangeError, "Array size is not a small enough positive integer.");
return new ArrayInstance(exec->lexicalInterpreter()->builtinArrayPrototype(), n);
}
// otherwise the array is constructed with the arguments in it
return new ArrayInstance(exec->lexicalInterpreter()->builtinArrayPrototype(), args);
}
// ECMA 15.6.1
JSValue *ArrayObjectImp::callAsFunction(ExecState *exec, JSObject * /*thisObj*/, const List &args)
{
// equivalent to 'new Array(....)'
return construct(exec,args);
}
// ------------------------------ ArrayObjectFuncImp ----------------------------
ArrayObjectFuncImp::ArrayObjectFuncImp(ExecState* exec, FunctionPrototype* funcProto, int i, int len, const Identifier& name)
: InternalFunctionImp(funcProto, name), id(i)
{
putDirect(exec->propertyNames().length, len, DontDelete|ReadOnly|DontEnum);
}
JSValue *ArrayObjectFuncImp::callAsFunction(ExecState* exec, JSObject*, const List& args)
{
switch (id) {
case IsArray: {
JSObject* jso = args[0]->getObject();
if (!jso)
return jsBoolean(false);
return jsBoolean(jso->inherits(&ArrayInstance::info));
}
default:
return jsUndefined();
}
}
}
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on; hl c++;

View file

@ -1,70 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef ARRAY_OBJECT_H_
#define ARRAY_OBJECT_H_
#include "array_instance.h"
#include "internal.h"
#include "function_object.h"
namespace KJS {
class ArrayPrototype : public ArrayInstance {
public:
ArrayPrototype(ExecState *exec,
ObjectPrototype *objProto);
using KJS::ArrayInstance::getOwnPropertySlot;
bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
virtual const ClassInfo *classInfo() const { return &info; }
static const ClassInfo info;
};
class ArrayProtoFunc : public InternalFunctionImp {
public:
ArrayProtoFunc(ExecState *exec, int i, int len, const Identifier& name);
virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);
enum { ToString, ToLocaleString, Concat, Join, Pop, Push,
Reverse, Shift, Slice, Sort, Splice, UnShift,
Every, ForEach, Some, IndexOf, Filter, Map, LastIndexOf,
Reduce, ReduceRight };
private:
int id;
};
class ArrayObjectImp : public InternalFunctionImp {
public:
ArrayObjectImp(ExecState *exec,
FunctionPrototype *funcProto,
ArrayPrototype *arrayProto);
virtual bool implementsConstruct() const;
using KJS::JSObject::construct;
virtual JSObject *construct(ExecState *exec, const List &args);
virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);
};
} // namespace
#endif

View file

@ -1,131 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2003 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "bool_object.h"
#include <config-kjs.h>
#include "operations.h"
#include "error_object.h"
using namespace KJS;
// ------------------------------ BooleanInstance ---------------------------
const ClassInfo BooleanInstance::info = {"Boolean", 0, 0, 0};
BooleanInstance::BooleanInstance(JSObject *proto)
: JSWrapperObject(proto)
{
}
JSObject* BooleanInstance::valueClone(Interpreter* targetCtx) const
{
BooleanInstance* copy = new BooleanInstance(targetCtx->builtinBooleanPrototype());
copy->setInternalValue(internalValue());
return copy;
}
// ------------------------------ BooleanPrototype --------------------------
// ECMA 15.6.4
BooleanPrototype::BooleanPrototype(ExecState* exec, ObjectPrototype* objectProto, FunctionPrototype* funcProto)
: BooleanInstance(objectProto)
{
// The constructor will be added later by Interpreter::Interpreter()
putDirectFunction(new BooleanProtoFunc(exec, funcProto, BooleanProtoFunc::ToString, 0, exec->propertyNames().toString), DontEnum);
putDirectFunction(new BooleanProtoFunc(exec, funcProto, BooleanProtoFunc::ValueOf, 0, exec->propertyNames().valueOf), DontEnum);
setInternalValue(jsBoolean(false));
}
// ------------------------------ BooleanProtoFunc --------------------------
BooleanProtoFunc::BooleanProtoFunc(ExecState* exec, FunctionPrototype* funcProto, int i, int len, const Identifier& name)
: InternalFunctionImp(funcProto, name)
, id(i)
{
putDirect(exec->propertyNames().length, len, DontDelete|ReadOnly|DontEnum);
}
// ECMA 15.6.4.2 + 15.6.4.3
JSValue *BooleanProtoFunc::callAsFunction(ExecState* exec, JSObject *thisObj, const List &/*args*/)
{
// no generic function. "this" has to be a Boolean object
if (!thisObj->inherits(&BooleanInstance::info))
return throwError(exec, TypeError);
// execute "toString()" or "valueOf()", respectively
JSValue *v = static_cast<BooleanInstance*>(thisObj)->internalValue();
assert(v);
if (id == ToString)
return jsString(v->toString(exec));
return jsBoolean(v->toBoolean(exec)); /* TODO: optimize for bool case */
}
// ------------------------------ BooleanObjectImp -----------------------------
BooleanObjectImp::BooleanObjectImp(ExecState* exec, FunctionPrototype* funcProto, BooleanPrototype* booleanProto)
: InternalFunctionImp(funcProto)
{
putDirect(exec->propertyNames().prototype, booleanProto, DontEnum|DontDelete|ReadOnly);
// no. of arguments for constructor
putDirect(exec->propertyNames().length, jsNumber(1), ReadOnly|DontDelete|DontEnum);
}
bool BooleanObjectImp::implementsConstruct() const
{
return true;
}
// ECMA 15.6.2
JSObject *BooleanObjectImp::construct(ExecState *exec, const List &args)
{
BooleanInstance *obj(new BooleanInstance(exec->lexicalInterpreter()->builtinBooleanPrototype()));
bool b;
if (args.size() > 0)
b = args.begin()->toBoolean(exec);
else
b = false;
obj->setInternalValue(jsBoolean(b));
return obj;
}
// ECMA 15.6.1
JSValue *BooleanObjectImp::callAsFunction(ExecState *exec, JSObject * /*thisObj*/, const List &args)
{
if (args.isEmpty())
return jsBoolean(false);
else
return jsBoolean(args[0]->toBoolean(exec)); /* TODO: optimize for bool case */
}

View file

@ -1,91 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef BOOL_OBJECT_H_
#define BOOL_OBJECT_H_
#include "internal.h"
#include "function_object.h"
#include "JSWrapperObject.h"
namespace KJS {
class BooleanInstance : public JSWrapperObject {
public:
BooleanInstance(JSObject *proto);
virtual JSObject* valueClone(Interpreter* targetCtx) const;
virtual const ClassInfo *classInfo() const { return &info; }
static const ClassInfo info;
};
/**
* @internal
*
* The initial value of Boolean.prototype (and thus all objects created
* with the Boolean constructor
*/
class BooleanPrototype : public BooleanInstance {
public:
BooleanPrototype(ExecState *exec,
ObjectPrototype *objectProto,
FunctionPrototype *funcProto);
};
/**
* @internal
*
* Class to implement all methods that are properties of the
* Boolean.prototype object
*/
class BooleanProtoFunc : public InternalFunctionImp {
public:
BooleanProtoFunc(ExecState*, FunctionPrototype*, int i, int len, const Identifier&);
virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);
enum { ToString, ValueOf };
private:
int id;
};
/**
* @internal
*
* The initial value of the global variable's "Boolean" property
*/
class BooleanObjectImp : public InternalFunctionImp {
friend class BooleanProtoFunc;
public:
BooleanObjectImp(ExecState *exec, FunctionPrototype *funcProto,
BooleanPrototype *booleanProto);
virtual bool implementsConstruct() const;
using KJS::JSObject::construct;
virtual JSObject *construct(ExecState *exec, const List &args);
virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);
};
} // namespace
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,178 +0,0 @@
/*
* A utilitity for building various tables and specializations for the
* KJS Frostbyte bytecode
*
* Copyright (C) 2007, 2008 Maks Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "codeprinter.h"
#include <stdlib.h>
#include <iostream>
#include <sstream>
#include "assert.h"
#include <cctype>
#include <cstdio>
#include <wtf/ASCIICType.h>
using namespace std;
void Enum::printDeclaration(ostream& hStream)
{
hStream << "enum " << name << " {\n";
for (unsigned p = 0; p < values.size(); ++p) {
hStream << " " << prefix << values[p] << ",\n";
}
hStream << " " << prefix << "NumValues\n";
hStream << "};\n";
hStream << "extern const char* const " << name << "Vals[];\n\n";
}
void Enum::printDefinition(ostream& cppStream)
{
Array vals(cppStream, "const char* const", name + "Vals");
for (unsigned p = 0; p < values.size(); ++p)
vals.item("\"" + prefix + values[p] + "\"");
vals.endArray();
}
Array::Array(ostream& out, const std::string& type, const std::string &name):
out(out), ended(false), first(true)
{
out << type << " " << name << "[] = {\n";
}
Array::~Array()
{
assert(ended);
}
void Array::item(const std::string& val, const std::string& newComment)
{
if (!first) {
out << ", ";
if (!comment.empty())
out << "// " << comment;
out << "\n";
} else {
first = false;
}
comment = newComment;
out << " " << val;
}
void Array::endArray()
{
assert(!ended);
ended = true;
if (!comment.empty())
out << " // " << comment;
out << "\n};\n\n";
}
void CodePrinter::issueError(const string& err)
{
std::cerr << err << "\n";
exit(-1);
}
std::string CodePrinter::stringFromInt(int val)
{
std::stringstream out;
out << val;
return out.str();
}
ostream& CodePrinter::mInd(int ind)
{
for (int i = 0; i < ind; ++i)
*mStream << ' ';
return *mStream;
}
static bool isWhitespaceString(const string& str)
{
for (unsigned c = 0; c < str.length(); ++c) {
if (!WTF::isASCIISpace(str[c]))
return false;
}
return true;
}
static StringList splitLines(const string& in)
{
StringList lines;
string curLine;
for (unsigned c = 0; c < in.length(); ++c) {
if (in[c] == '\n') {
lines.push_back(curLine);
curLine = "";
} else {
curLine += in[c];
}
}
return lines;
}
void CodePrinter::printCode(ostream& out, int baseIndent, const string& code, int baseLine)
{
StringList lines = splitLines(code);
if (!lines.empty() && isWhitespaceString(lines.front())) {
++baseLine;
lines.erase(lines.begin());
}
if (!lines.empty() && isWhitespaceString(lines.back()))
lines.pop_back();
out << "#line " << baseLine << " \"codes.def\"\n";
// Compute "leading" whitespace, from codes.def indentation
unsigned minWhiteSpace = 100000;
for (unsigned c = 0; c < lines.size(); ++c) {
const string& line = lines[c];
if (isWhitespaceString(line))
continue;
unsigned ws = 0;
while (ws < line.length() && WTF::isASCIISpace(line[ws]))
++ws;
if (ws < minWhiteSpace)
minWhiteSpace = ws;
}
// Print out w/it stripped, and replaced with the indent
// specified by the generator
for (unsigned c = 0; c < lines.size(); ++c) {
const string& line = lines[c];
if (line.length() < minWhiteSpace)
out << "\n";
else {
for (int c = 0; c < baseIndent; ++c)
out << ' ';
out << line.substr(minWhiteSpace) << "\n";
}
}
}
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,105 +0,0 @@
/*
* A utilitity for building various tables and specializations for the
* KJS Frostbyte bytecode
*
* Copyright (C) 2007, 2008 Maks Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef CODE_PRINTER_H
#define CODE_PRINTER_H
#include <iostream>
#include <vector>
#include <string>
using std::ostream;
using std::vector;
using std::string;
typedef std::vector<string> StringList;
// This class generates a declaration for an enum,
// and also declares & defines instrospection tables.
class Enum {
public:
Enum(const string& name, const string& prefix, StringList values):
name(name), prefix(prefix), values(values)
{}
void printDeclaration(ostream& cppStream);
void printDefinition (ostream& hStream);
private:
string name;
string prefix;
StringList values;
};
// A helper for bracing, commas, etc., of constant array tables
class Array {
public:
Array(ostream& out, const std::string& type, const std::string &name);
void item(const std::string& val, const std::string& pendingComment = "");
void endArray();
~Array();
private:
ostream& out;
std::string comment;
bool ended, first;
};
enum CodeStream {
OpH,
OpCpp,
MaCpp
};
class CodePrinter
{
public:
CodePrinter(ostream* hStream, ostream* cppStream, ostream* mStream):
hStream(hStream), cppStream(cppStream), mStream(mStream) {}
void printCode(ostream& out, int baseIndent, const string& code, int baseLine);
ostream& operator()(CodeStream stream) {
switch (stream) {
case OpH:
return *hStream;
case OpCpp:
return *cppStream;
default:
return *mStream;
}
}
static std::string stringFromInt(int val);
// Indented print to machine.cpp.
ostream& mInd(int ind);
void issueError(const string& err);
private:
ostream* hStream;
ostream* cppStream;
ostream* mStream;
};
#endif
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,57 +0,0 @@
/*
* A utilitity for building various tables and specializations for the
* KJS Frostbyte bytecode
*
* Copyright (C) 2007, 2008 Maks Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "tablebuilder.h"
#include "filetemplate.h"
int main(int argc, char* argv[])
{
if (argc != 2) {
std::cerr << "Usage: icemaker <path>\n";
}
std::string path = std::string(argv[1]) + "/"; // krazy:exclude=doublequote_chars
ifstream def;
def.open((path + "codes.def").c_str());
if (def.fail()) {
std::cerr << "Unable to open codes.def\n";
return -1;
}
FileTemplate opcodesH (path + "opcodes.h.in", "opcodes.h");
FileTemplate opcodesCpp(path + "opcodes.cpp.in", "opcodes.cpp");
FileTemplate machineCpp(path + "machine.cpp.in", "machine.cpp");
if (!opcodesH.ok() || !opcodesCpp.ok() || !machineCpp.ok())
return -1;
std::cout << "icemaker -41.9 for KJS/FrostByte\n";
std::cout << "Generating bytecode instruction selection tables and VM dispatcher...\n";
TableBuilder build(&def, &opcodesH.out, &opcodesCpp.out, &machineCpp, &machineCpp.out);
build.generateCode();
return 0;
}
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,113 +0,0 @@
/*
* A utilitity for building various tables and specializations for the
* KJS Frostbyte bytecode
*
* Copyright (C) 2007, 2008 Maks Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include <iostream>
#include <fstream>
#include <string>
using std::ifstream;
using std::ofstream;
using std::string;
#ifndef FILE_TEMPLATE_H
#define FILE_TEMPLATE_H
static inline bool stringEndsWith(string base, string suffix)
{
if (base.length() < suffix.length())
return false;
return base.substr(base.length() - suffix.length()) == suffix;
}
struct FileTemplate
{
FileTemplate(string inFileName, string outFileName):
inFileName(inFileName), outFileName(outFileName)
{
isOK = true;
lines = 0;
in.open(inFileName.c_str());
if (in.fail()) {
std::cerr << "Unable to open:" << inFileName << "\n";
isOK = false;
}
out.open(outFileName.c_str());
if (out.fail()) {
std::cerr << "Unable to open:" << outFileName << "\n";
isOK = false;
}
if (isOK) {
out << "// WARNING: Portions of this file are autogenerated from codes.def and " << inFileName << ".\n";
out << "// (which is what the licensing terms apply to)\n";
out << "// Any changes you make here may be lost!\n";
handleUntilGenerate();
}
}
~FileTemplate()
{
if (isOK)
handleUntilGenerate();
}
// Goes until @generate..
void handleUntilGenerate()
{
out << "#line " << (lines + 1) << " \"" << inFileName << "\"\n";
while (!in.eof()) {
string line;
getline(in, line);
++lines;
if (stringEndsWith(line, "@generate"))
break;
else
out << line << "\n";
}
}
void handleSuffix()
{
out << "#line " << (lines + 1) << " \"" << inFileName << "\"\n";
while (!in.eof()) {
string line;
getline(in, line);
out << line << "\n";
}
}
string inFileName;
string outFileName;
ifstream in;
ofstream out;
bool isOK;
bool ok() { return isOK; }
int lines; // from the template
};
#endif
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,6 +0,0 @@
HEADERS = lexer.h parser.h tablebuilder.h
SOURCES = lexer.cpp parser.cpp tablebuilder.cpp driver.cpp
CONFIG+=debug

View file

@ -1,210 +0,0 @@
/*
* A utilitity for building various tables and specializations for the
* KJS Frostbyte bytecode
*
* Copyright (C) 2007, 2008 Maks Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "lexer.h"
#include <cctype>
#ifndef _WIN32
using std::isspace;
#endif
#include <wtf/ASCIICType.h>
using namespace WTF;
const char EndOfFileChar = 0;
Lexer::Lexer(istream* _stream): stream(_stream), charLoaded(false), lineNum(0)
{
keywords["type"] = Type;
keywords["conversion" ] = Conversion;
keywords["register"] = Register;
keywords["operation"] = Operation;
keywords["costs"] = Costs;
keywords["impl"] = Impl;
keywords["tile"] = Tile;
keywords["as"] = As;
keywords["runtime"] = Runtime;
lineNum = 1;
}
Lexer::Token Lexer::lexComment()
{
char in = getNext();
if (in == '/') {
// Single-line comment -- read until the end of line (or file)
do {
in = getNext();
} while (in != '\n' && in != EndOfFileChar);
} else if (in == '*') {
// Multi-line comment --- scan until */
do {
in = getNext();
if (in == EndOfFileChar)
return Token(Error, "Unterminated multiline comment");
}
while (!(in == '*' && peekNext() == '/'));
getNext(); // Eat the /
} else {
return Token(Error, string("/ can only start comments, but is followed by: ") + in);
}
// Wee. Worked fine. Recurse to get next stuff
return nextToken();
}
Lexer::Token Lexer::nextToken()
{
char begin;
// Skip any whitespace characters..
do {
begin = getNext();
}
while (isspace(begin));
if (begin == EndOfFileChar)
return Token(EndOfFile);
// Check for simple chars..
if (begin == '{')
return Token(LBrace);
else if (begin == '}')
return Token(RBrace);
if (begin == '(')
return Token(LParen);
else if (begin == ')')
return Token(RParen);
else if (begin == ':') {
if (peekNext() != ':') {
return Token(Colon);
} else {
getNext();
return Token(Scope);
}
} else if (begin == ';')
return Token(SemiColon);
else if (begin == '*')
return Token(Star);
else if (begin == ',')
return Token(Comma);
else if (begin == ']')
return Token(RBracket);
else if (begin == '[' && peekNext() != '[')
return Token(LBracket);
// =>
if (begin == '=') {
char c2 = getNext();
if (c2 == '>')
return Token(Arrow);
else
return Token(Error, "- not part of ->");
}
// Check for comments..
if (begin == '/')
return lexComment();
// Numbers
if (isASCIIDigit(begin)) {
string text;
text += begin;
while (isASCIIDigit(peekNext()))
text += getNext();
return Token(Number, text);
}
// Code..
if (begin == '[') {
char next = getNext();
if (next != '[')
return Token(Error, string("[ continued with:") + next);
int line = lineNumber();
string text;
while(true) {
char letter = getNext();
if (letter == EndOfFileChar)
return Token(Error, "Unterminated code fragment");
if (letter == ']' && peekNext() == ']') {
getNext(); //Eat 2nd ']'
return Token(Code, text, line);
}
text += letter;
}
}
// Identifiers
if (isASCIIAlpha(begin)) {
string text;
text = begin;
while (isASCIIAlphanumeric(peekNext()) || peekNext() == '_')
text += getNext();
TokenType t = Ident;
if (keywords.find(text) != keywords.end())
t = keywords[text];
return Token(t, text);
} else {
return Token(Error, string("Invalid start of token:") + begin);
}
}
char Lexer::peekNext()
{
if (charLoaded)
return nextChar;
nextChar = stream->get();
if (stream->eof())
return EndOfFileChar;
if (nextChar == '\n')
++lineNum;
charLoaded = true;
return nextChar;
}
char Lexer::getNext()
{
if (charLoaded) {
charLoaded = false;
return nextChar;
}
char in = stream->get();
if (stream->eof()) {
// Make sure to let peekNext know.
nextChar = EndOfFileChar;
charLoaded = true;
return EndOfFileChar;
}
if (in == '\n')
++lineNum;
return in;
}
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,154 +0,0 @@
/*
* A utilitity for building various tables and specializations for the
* KJS Frostbyte bytecode
*
* Copyright (C) 2007, 2008 Maks Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef LEXER_H
#define LEXER_H
#include <iostream>
#include <string>
#include <map>
using std::string;
using std::map;
using std::istream;
class Lexer
{
public:
enum TokenType {
Ident,
Number,
Code,
LBrace, // {
RBrace, // }
LParen, // (
RParen, // )
LBracket, // [
RBracket, // ]
Colon, // :
Scope, // ::
SemiColon, // ;
Star, // *
Arrow, // =>
Comma, // ,
Error,
EndOfFile,
// Keywords:
Type,
Conversion,
Register,
Operation,
Costs,
Impl,
Tile,
As,
Runtime
};
struct Token {
TokenType type;
string value;
int lineNum; //only set for code tokens.
Token() : type(Error), value("Uninitialized token") {}
Token(TokenType t): type(t) {}
Token(TokenType t, const string& v, int line = -1): type(t), value(v), lineNum(line) {}
bool isKeyword() const {
return type > EndOfFile;
}
string toString(Lexer* lex)
{
switch (type) {
case LBrace:
return "'{'";
case RBrace:
return "'}'";
case LBracket:
return "'['";
case RBracket:
return "']'";
case LParen:
return "'('";
case RParen:
return "')'";
case Scope:
return "'::'";
case Colon:
return "':'";
case SemiColon:
return "';'";
case Star:
return "'*'";
case Arrow:
return "'=>'";
case Comma:
return "','";
case EndOfFile:
return "<End of File>";
case Error:
return "<Lex Error:" + value + ">";
case Code:
return "[[" + value + "]]";
case Ident:
case Number:
return value;
default: {
// keywords
for (map<string, TokenType>::iterator it = lex->keywords.begin();
it != lex->keywords.end(); ++it) {
if (it->second == type)
return it->first;
}
return "???";
} // default :
} // switch(type)
}
};
Lexer(istream* _stream);
Token nextToken();
int lineNumber() const { return lineNum; }
private:
friend struct Token;
Token lexComment();
char peekNext();
char getNext();
istream* stream;
bool charLoaded;
char nextChar;
int lineNum;
map<string, TokenType> keywords;
};
#endif
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,363 +0,0 @@
/*
* A utilitity for building various tables and specializations for the
* KJS Frostbyte bytecode
*
* Copyright (C) 2007, 2008 Maks Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "parser.h"
#include <cstdlib>
#include <wtf/ASCIICType.h>
/**
This is a fairly straightforward affair. It's written in a
recursive descent style, but the language is actually regular.
The error recovert is even simpler: we just exit. That's it.
*/
Parser::Parser(istream* stream): tokenLoaded(false), hadError(false), lexer(new Lexer(stream))
{}
Parser::~Parser()
{
delete lexer;
}
string Parser::matchIdentifier()
{
Lexer::Token tok = getNext();
if (tok.type == Lexer::Ident)
return tok.value;
issueError("Expected identifier, got:" + tok.toString(lexer));
return "";
}
void Parser::matchCode(std::string* strOut, int* lineOut)
{
Lexer::Token tok = getNext();
if (tok.type == Lexer::Code) {
*lineOut = tok.lineNum;
*strOut = tok.value;
return;
}
issueError("Expected code, got:" + tok.toString(lexer));
}
int Parser::matchNumber()
{
Lexer::Token tok = getNext();
if (tok.type == Lexer::Number)
return std::atol(tok.value.c_str());
issueError("Expected number, got:" + tok.toString(lexer));
return 0;
}
void Parser::match(Lexer::TokenType t)
{
Lexer::Token tok = getNext();
if (tok.type != t)
issueError("Expected " + Lexer::Token(t).toString(lexer) + " got:" + tok.toString(lexer));
}
bool Parser::check(Lexer::TokenType t)
{
if (peekNext().type == t) {
getNext(); // tasty!
return true;
} else {
return false;
}
}
unsigned Parser::matchFlags(const Flag* permittedFlags)
{
unsigned flagsVal = 0;
if (check(Lexer::LBracket)) {
while (true) {
std::string flag;
// We permit keywords to double as flags.
if (peekNext().isKeyword())
flag = getNext().toString(lexer);
else
flag = matchIdentifier();
// Lookup the name.
bool found = false;
for (int pos = 0; permittedFlags[pos].name; ++pos) {
if (flag == std::string(permittedFlags[pos].name)) {
found = true;
flagsVal |= permittedFlags[pos].value;
}
}
if (!found)
issueError("invalid flag:" + flag);
// Done or more?
if (check(Lexer::RBracket))
return flagsVal;
else
match(Lexer::Comma);
}
}
return 0;
}
void Parser::issueError(const string& msg)
{
std::cerr << "Parse error:" << msg << " at about line:" << lexer->lineNumber() << "\n";
std::exit(-1);
}
Lexer::Token Parser::peekNext()
{
if (!tokenLoaded) {
nextToken = lexer->nextToken();
tokenLoaded = true;
}
return nextToken;
}
Lexer::Token Parser::getNext()
{
if (tokenLoaded) {
tokenLoaded = false;
return nextToken;
}
return lexer->nextToken();
}
void Parser::parse()
{
Lexer::Token tok = peekNext();
// The types are first..
while (tok.type == Lexer::Type) {
parseType();
tok = peekNext();
}
// Now we may have conversions or operations
while (tok.type == Lexer::Conversion || tok.type == Lexer::Operation) {
if (tok.type == Lexer::Conversion)
parseConversion();
else
parseOperation();
tok = peekNext();
}
match(Lexer::EndOfFile);
}
void Parser::parseType()
{
//type identifier: nativeName *? [immediate?, register?, ?align8]?;
match(Lexer::Type);
string name = matchIdentifier();
match(Lexer::Colon);
string nativeName = matchIdentifier();
if (nativeName == "const")
nativeName += " " + matchIdentifier(); // krazy:exclude=doublequote_chars
while (check(Lexer::Scope))
nativeName += "::" + matchIdentifier();
if (check(Lexer::Star))
nativeName += "*"; // krazy:exclude=doublequote_chars
const Flag typeFlags[] = {
{"immediate", Type_HaveImm},
{"register", Type_HaveReg},
{"align8", Type_Align8},
{0, 0}
};
unsigned flags = matchFlags(typeFlags);
match(Lexer::SemiColon);
handleType(name, nativeName, flags);
}
void Parser::parseConversion()
{
// conversion from => to { clauses .. }
// clause := tile costs number; || impl [checked?, mayThrow?]? code; || register ident costs number;
match(Lexer::Conversion);
string from = matchIdentifier();
match(Lexer::Arrow);
string to = matchIdentifier();
match(Lexer::LBrace);
// impl clause info..
const Flag conversionFlags[] = {
{"checked", Conv_Checked},
{"mayThrow", Conv_MayThrow},
{0, 0}
};
unsigned flags = 0;
string code;
int codeLine = 0;
// tile clause info
int tileCost = 0;
// register clause info
string registerIdent;
int registerCost = 0;
while (!check(Lexer::RBrace)) {
if (check(Lexer::Impl)) {
// impl [[code]]
flags = matchFlags(conversionFlags);
matchCode(&code, &codeLine);
} else if (check(Lexer::Tile)) {
// tile costs number;
match(Lexer::Costs);
tileCost = matchNumber();
match(Lexer::SemiColon);
} else if (check(Lexer::Register)) {
//register costs number;
flags |= Conv_HaveReg;
match(Lexer::Costs);
registerCost = matchNumber();
match(Lexer::SemiColon);
} else {
issueError("Invalid start of a clause within conversion block:" + peekNext().toString(lexer));
}
}
handleConversion(code, codeLine, flags, from, to, tileCost, registerCost);
}
void Parser::parseOperation()
{
// operation identifier { ... }, where ... is a list of impl or tile statements.
match(Lexer::Operation);
const Flag opFlags[] = {
{"endsBB", Op_EndsBB},
{"hint", Op_Hint},
{0, 0}
};
std::string name = matchIdentifier();
unsigned flags = matchFlags(opFlags);
handleOperation(name, flags);
match(Lexer::LBrace);
Lexer::Token tok = peekNext();
while (tok.type == Lexer::Tile || tok.type == Lexer::Impl) {
if (tok.type == Lexer::Tile)
parseTile();
else
parseImpl();
tok = peekNext();
}
match(Lexer::RBrace);
}
void Parser::parseImpl()
{
match(Lexer::Impl);
// impl identifier identifier? ( paramList? ) code
// paramList := ident ident
// paramList := ident ident , paramList
string ret = matchIdentifier();
string fn;
if (peekNext().type == Lexer::Ident)
fn = matchIdentifier();
match(Lexer::LParen);
const Flag paramFlags[] = {
{"noimm", Param_NoImm},
{"noreg", Param_NoReg},
{"exact", Param_Exact},
{0, 0}
};
// Parse parameter types and names, if any..
vector<Parameter> params;
while (peekNext().type != Lexer::RParen) {
Parameter param;
param.typeName = matchIdentifier();
param.flags = matchFlags(paramFlags);
param.name = matchIdentifier();
params.push_back(param);
if (!check(Lexer::Comma))
break;
// Make sure we have an ident next, and not an rparen..
if (peekNext().type != Lexer::Ident)
issueError("Parameter signature in impl doesn't start with an identifier!");
}
match(Lexer::RParen);
int cost = 0;
if (peekNext().type == Lexer::Costs) {
getNext();
cost = matchNumber();
}
int codeLine;
string code;
matchCode(&code, &codeLine);
handleImpl(fn, code, codeLine, cost, ret, params);
}
void Parser::parseTile()
{
// tile signature as identifier;
match(Lexer::Tile);
StringList paramSigs;
match(Lexer::LParen);
while (peekNext().type != Lexer::RParen) {
paramSigs.push_back(matchIdentifier());
if (peekNext().type != Lexer::Comma)
break;
getNext(); // Eat the comma..
// Make sure we have an ident next, and not an rparen..
if (peekNext().type != Lexer::Ident)
issueError("Parameter signature in tile doesn't start with an identifier!");
}
match(Lexer::RParen);
match(Lexer::As);
string fn = matchIdentifier();
handleTile(fn, paramSigs);
match(Lexer::SemiColon);
}
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,117 +0,0 @@
/*
* A utilitity for building various tables and specializations for the
* KJS Frostbyte bytecode
*
* Copyright (C) 2007, 2008 Maks Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef PARSER_H
#define PARSER_H
#include "lexer.h"
#include "types.h" // for various flags
#include <vector>
enum ParamFlags {
Param_NoImm = 1,
Param_NoReg = 2,
Param_Exact = 4
};
enum OpFlags {
Op_EndsBB = 1,
Op_Hint = 2
};
struct Parameter
{
string name;
string typeName; // name of the type of the parameter, set by the parser
Type type; // the actual type of the parameter, resolved by the TableBuilder.
unsigned flags;
Parameter(): flags(0) {}
};
class Parser
{
public:
Parser(istream* stream);
~Parser();
void parse();
private:
// Note: signatures here are just a list of strings;
// the last one is the return type
virtual void handleType(const string& type, const string& nativeName, unsigned flags) = 0;
virtual void handleConversion(const string& runtimeRoutine, int codeLine,
unsigned flags, const string& from, const string& to,
int tileCost, int registerCost) = 0;
virtual void handleOperation(const string& name, unsigned flags) = 0;
virtual void handleImpl(const string& fnName, const string& code, int codeLine, int cost,
const string& retType, vector<Parameter> sig) = 0;
virtual void handleTile(const string& fnName, StringList sig) = 0;
struct Flag {
const char* name;
unsigned value;
};
// Matches flags specified as a zero-terminated pair array above,
// and returns their or. In syntax, they look like
// [flag1, flag2, flag3] and are optional.
unsigned matchFlags(const Flag* permittedFlags);
// These unconditionally parse items of given type.
string matchIdentifier();
void matchCode(std::string* stringOut, int* lineOut);
int matchNumber();
void match(Lexer::TokenType t);
// These conditionally consume given token if it's there,
// and return true if so.
bool check(Lexer::TokenType t);
void parseType();
void parseConversion();
void parseOperation();
void parseImpl();
void parseTile();
bool tokenLoaded;
Lexer::Token nextToken;
void issueError(const string& msg);
bool hadError;
Lexer* lexer;
Lexer::Token peekNext();
Lexer::Token getNext();
};
#endif
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,449 +0,0 @@
/*
* A utilitity for building various tables and specializations for the
* KJS Frostbyte bytecode
*
* Copyright (C) 2007, 2008 Maks Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "tablebuilder.h"
#include <stdlib.h>
#include <iostream>
#include "assert.h"
#include <cctype>
#include <cstdio>
#include <wtf/ASCIICType.h>
using namespace std;
static string strReplace(string where, string from, string to) {
string res = where;
size_t pos;
while ((pos = res.find(from)) != string::npos) {
res = res.substr(0, pos) + to + res.substr(pos + from.length());
}
return res;
}
TableBuilder::TableBuilder(istream* inStream, ostream* hStream,
ostream* cppStream, FileTemplate* fTemplate, ostream* mStream):
Parser(inStream), out(hStream, cppStream, mStream), types(this, out), fTemplate(fTemplate)
{}
void TableBuilder::generateCode()
{
parse();
types.generateCode();
// Operations
Enum opNamesEnum("OpName", "Op_", operationNames);
opNamesEnum.printDeclaration(out(OpH));
opNamesEnum.printDefinition (out(OpCpp));
// Enumerate all the variants..
for (unsigned c = 0; c < operations.size(); ++c) {
vector<bool> parIm;
expandOperationVariants(operations[c], parIm);
}
// Return types for each..
out(OpCpp) << "static const OpType opRetTypes[] = {\n";
for (unsigned c = 0; c < operationNames.size(); ++c) {
out(OpCpp) << " OpType_" << operationRetTypes[operationNames[c]];
if (c != operationNames.size() - 1)
out(OpCpp) << ",";
out(OpCpp) << " //" << operationNames[c] << "\n";
}
out(OpCpp) << "};\n\n";
// Now we have all our bytecode names... Whee.
Enum opByteCodesEnum("OpByteCode", "OpByteCode_", variantNames);
opByteCodesEnum.printDeclaration(out(OpH));
opByteCodesEnum.printDefinition (out(OpCpp));
// We can now emit the actual tables...
// ... first descriptors for each bytecode op..
out(OpCpp) << "const Op opsForOpCodes[] = {\n";
for (unsigned c = 0; c < variants.size(); ++c) {
const OperationVariant& variant = variants[c];
if (variant.needsPadVariant)
dumpOpStructForVariant(variant, true, variant.needsPadVariant, true);
dumpOpStructForVariant(variant, false, variant.needsPadVariant, c != variants.size() - 1);
}
out(OpCpp) << "};\n\n";
// then variant tables for each main op..
for (unsigned c = 0; c < operationNames.size(); ++c) {
const string& opName = operationNames[c];
out(OpCpp) << "static const Op* const op" << opName << "Variants[] = {";
StringList variants = variantNamesForOp[opName];
for (unsigned v = 0; v < variants.size(); ++v) {
out(OpCpp) << "&opsForOpCodes[OpByteCode_" << variants[v] << "], ";
}
out(OpCpp) << "0};\n";
}
out(OpCpp) << "\n";
out(OpCpp) << "const Op* const* const opSpecializations[] = {\n";
for (unsigned o = 0; o < operationNames.size(); ++o) {
out(OpCpp) << " op" << operationNames[o] << "Variants";
if (o != (operationNames.size() - 1))
out(OpCpp) << ",";
out(OpCpp) << "\n";
}
out(OpCpp) << "};\n\n";
// Jump table, if needed
Array jumps(out(MaCpp), "static void*", "kjsVMOpHandlers");
for (unsigned c = 0; c < variants.size(); ++c) {
const OperationVariant& var = variants[c];
if (var.needsPadVariant)
jumps.item("__extension__ &&l" + var.sig + "_Pad");
jumps.item("__extension__ &&l" + var.sig);
}
jumps.endArray();
fTemplate->handleUntilGenerate();
// Now, generate the VM loop.
mInd(8) << "OpByteCode op = *reinterpret_cast<const OpByteCode*>(pc);\n";
mInd(0) << "#ifdef USE_LABEL_VALS\n";
mInd(8) << "goto *kjsVMOpHandlers[op];\n";
mInd(8) << "{\n";
mInd(0) << "#else\n";
mInd(8) << "switch (op) {\n";
mInd(0) << "#endif\n";
for (unsigned c = 0; c < variants.size(); ++c) {
const OperationVariant& var = variants[c];
if (var.needsPadVariant) {
mInd(12) << "handler(" + var.sig + "_Pad):\n";
mInd(16) << "pc += 4;\n";
mInd(16) << "// Fallthrough\n";
}
mInd(12) << "handler(" + var.sig + "): {\n";
generateVariantImpl(var);
mInd(12) << "}\n";
mInd(12) << "continue;\n\n";
}
mInd(8) << "}\n\n";
}
void TableBuilder::handleType(const string& type, const string& nativeName, unsigned flags)
{
types.handleType(type, nativeName, flags);
}
void TableBuilder::handleConversion(const string& code, int codeLine,
unsigned flags, const string& from, const string& to,
int tileCost, int registerCost)
{
types.handleConversion(code, codeLine, flags, from, to, tileCost, registerCost);
}
void TableBuilder::handleOperation(const string& name, unsigned flags)
{
operationNames.push_back(name);
operationFlags = flags;
}
void TableBuilder::handleImpl(const string& fnName, const string& code, int codeLine, int cost,
const string& retType, vector<Parameter> sig)
{
// If the return type isn't 'void', we prepend a destination register as a parameter in the encoding.
// emitOp will convert things as needed
vector<Parameter> extSig;
if (retType != "void") {
Parameter ret;
ret.typeName = "reg";
ret.name = "fbDestReg";
ret.flags = 0;
extSig.push_back(ret);
}
for (unsigned c = 0; c < sig.size(); ++c)
extSig.push_back(sig[c]);
// Now go through and resolve each type. These are also
// the types of the params of this base op.
Operation op;
for (unsigned c = 0; c < extSig.size(); ++c) {
extSig[c].type = types.resolveType(extSig[c].typeName);
op.opParamTypes.push_back(extSig[c].type);
}
op.name = operationNames.back();
op.retType = retType;
operationRetTypes[op.name] = retType;
op.isTile = false;
op.implementAs = code;
op.implParams = extSig;
op.codeLine = codeLine;
op.cost = cost;
op.flags = operationFlags;
operations.push_back(op);
if (!fnName.empty())
implementations[fnName] = op;
}
void TableBuilder::handleTile(const string& fnName, StringList sig)
{
if (implementations.find(fnName) == implementations.end())
out.issueError("Unknown implementation name " + fnName + " in a tile definition");
const Operation& impl = implementations[fnName];
// Add in a return reg if need be
StringList extSig;
if (impl.retType != "void")
extSig.push_back("reg");
for (unsigned c = 0; c < sig.size(); ++c)
extSig.push_back(sig[c]);
// Most of the stuff is the same as in the base impl,
// but we have a different external signature, and are a tile.
Operation op = impl;
op.isTile = true;
op.opParamTypes = types.resolveSignature(extSig);
// Now also include the cost of inline conversions.
for (unsigned p = 0; p < op.opParamTypes.size(); ++p)
op.cost += types.immConv(op.opParamTypes[p], op.implParams[p].type).cost;
operations.push_back(op);
}
void TableBuilder::expandOperationVariants(const Operation& op, vector<bool>& paramIsIm)
{
unsigned numParams = op.opParamTypes.size();
if (paramIsIm.size() < numParams) {
int paramPos = paramIsIm.size();
bool hasIm = (op.opParamTypes[paramPos].flags & Type_HaveImm) == Type_HaveImm;
bool hasReg = (op.opParamTypes[paramPos].flags & Type_HaveReg) == Type_HaveReg;
bool genIm = hasIm;
bool genReg = hasReg;
// Don't generate non-register variants for tiles when possible.
if (op.isTile && hasReg)
genIm = false;
// There may be hints saying not to generate some version
if (op.implParams[paramPos].flags & Param_NoImm)
genIm = false;
if (op.implParams[paramPos].flags & Param_NoReg)
genReg = false;
if (genIm) {
paramIsIm.push_back(true);
expandOperationVariants(op, paramIsIm);
paramIsIm.pop_back();
}
if (genReg) {
paramIsIm.push_back(false);
expandOperationVariants(op, paramIsIm);
paramIsIm.pop_back();
}
return;
}
// Have a full variant... Build a signature.
string sig = op.name;
for (unsigned p = 0; p < numParams; ++p) {
sig += "_"; // krazy:exclude=doublequote_chars
sig += paramIsIm[p] ? "I" : "R";
sig += op.opParamTypes[p].name;
}
// We may need padding if we have an immediate align8 param..
bool needsPad = false;
for (unsigned c = 0; c < numParams; ++c)
needsPad |= (paramIsIm[c] & op.opParamTypes[c].alignTo8());
OperationVariant var;
var.sig = sig;
var.op = op;
var.paramIsIm = paramIsIm;
var.needsPadVariant = needsPad;
// Build offset table, giving param positions..
while (var.paramOffsets.size() < numParams) // no setSize in QList..
var.paramOffsets.push_back(0);
int pos = 4;
// pad8/align ones go first.
for (unsigned c = 0; c < numParams; ++c) {
if (paramIsIm[c] & op.opParamTypes[c].alignTo8()) {
var.paramOffsets[c] = pos;
pos += 8;
}
}
// Then the rest..
for (unsigned c = 0; c < numParams; ++c) {
if (!paramIsIm[c] || !op.opParamTypes[c].alignTo8()) {
var.paramOffsets[c] = pos;
pos += 4;
}
}
var.size = pos;
variants.push_back(var);
if (needsPad) { // we put the pad before, due to the fallthrough idiom..
string pSig = sig + "_Pad";
variantNames.push_back(pSig);
variantNamesForOp[op.name].push_back(pSig);
}
variantNames.push_back(sig);
variantNamesForOp[op.name].push_back(sig);
}
void TableBuilder::dumpOpStructForVariant(const OperationVariant& variant, bool doPad,
bool hasPadVariant, bool needsComma)
{
out(OpCpp) << " {";
out(OpCpp) << "Op_" << variant.op.name << ", "; // baseInstr..
out(OpCpp) << "OpByteCode_" << (doPad ? variant.sig + "_Pad" : variant.sig) << ", "; // byteCode op
out(OpCpp) << variant.op.cost << ", "; // uhm, cost. doh.
int numParams = variant.op.opParamTypes.size();
out(OpCpp) << numParams << ", "; // # of params
// Param types.
out(OpCpp) << "{";
for (int p = 0; p < numParams; ++p) {
out(OpCpp) << "OpType_" << variant.op.opParamTypes[p].name;
if (p != numParams - 1)
out(OpCpp) << ", ";
}
out(OpCpp) << "}, ";
// Immediate flag..
out(OpCpp) << "{";
for (int p = 0; p < numParams; ++p) {
out(OpCpp) << (variant.paramIsIm[p] ? "true" : "false");
if (p != numParams - 1)
out(OpCpp) << ", ";
}
out(OpCpp) << "}, ";
// Exact params flag.
out(OpCpp) << "{";
for (int p = 0; p < numParams; ++p) {
out(OpCpp) << ((variant.op.implParams[p].flags & Param_Exact) ? "true" : "false");
if (p != numParams - 1)
out(OpCpp) << ", ";
}
out(OpCpp) << "}, ";
// Return type.
out(OpCpp) << "OpType_" << variant.op.retType << ", ";
int adjust = doPad ? 4 : 0; // padded version has 4 extra bytes,
// between the opcode and the first arg.
// Size..
out(OpCpp) << (variant.size + adjust) << ", ";
// Offset table..
out(OpCpp) << "{";
for (int p = 0; p < numParams; ++p) {
out(OpCpp) << (variant.paramOffsets[p] + adjust);
if (p != numParams - 1)
out(OpCpp) << ", ";
}
out(OpCpp) << "}, ";
// Whether this is a padded version..
out(OpCpp) << (doPad ? "true" : "false") << ", ";
// And whether a padded version exists.
out(OpCpp) << (hasPadVariant ? "true" : "false") << ", ";
// Whether this ends a basic block.
out(OpCpp) << (variant.op.flags & Op_EndsBB ? "true" : "false");
if (needsComma)
out(OpCpp) << "},\n";
else
out(OpCpp) << "}\n";
}
void TableBuilder::generateVariantImpl(const OperationVariant& variant)
{
mInd(16) << "pc += " << variant.size << ";\n";
mInd(16) << "const unsigned char* localPC = pc;\n";
int numParams = variant.paramIsIm.size();
for (int p = 0; p < numParams; ++p) {
const Type& type = variant.op.opParamTypes[p];
bool inReg = !variant.paramIsIm[p];
int negPos = variant.paramOffsets[p] - variant.size;
bool wideArg = !inReg && type.alignTo8();
char negPosStr[64];
std::sprintf(negPosStr, "%d", negPos);
string accessString = "reinterpret_cast<const ";
accessString += wideArg ? "WideArg" : "NarrowArg";
accessString += "*>(localPC ";
accessString += negPosStr;
accessString += ")->";
accessString += inReg ? string("regVal") : type.name + "Val";
if (inReg) { // Need to indirect... The register value is actually an offset, so a bit of casting, too.
accessString = "reinterpret_cast<const LocalStorageEntry*>(reinterpret_cast<const unsigned char*>(localStore) + " + accessString + ")->val." + type.name + "Val";
}
mInd(16) << variant.op.implParams[p].type.nativeName << " " << variant.op.implParams[p].name
<< " = ";
if (type == variant.op.implParams[p].type) {
// We don't need a conversion, just fetch it directly into name..
out(MaCpp) << accessString << ";\n";
} else {
ConversionInfo conv = types.immConv(type, variant.op.implParams[p].type);
out(MaCpp) << "convert" << conv.name << "(exec, " << accessString << ");\n";
if (conv.flags & Conv_MayThrow) {
// Check for an exception being raised, or perhaps a reload request
mInd(16) << "if (pc != localPC) // {// Exception or reload\n";
//mInd(20) << "if (exec->h
mInd(20) << "continue;\n";
}
}
}
// Replace $$ with destination register
string storeCode = "localStore[fbDestReg].val." + variant.op.retType + "Val";
string code = variant.op.implementAs;
code = strReplace(code, "$$", storeCode);
// Print out the impl code..
out.printCode(out(MaCpp), 16, code, variant.op.codeLine);
}
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,108 +0,0 @@
/*
* A utilitity for building various tables and specializations for the
* KJS Frostbyte bytecode
*
* Copyright (C) 2007, 2008 Maks Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef TABLE_BUILDER_H
#define TABLE_BUILDER_H
#include "filetemplate.h"
#include "codeprinter.h"
#include "types.h"
#include "parser.h"
// Actually, a specialization, but who cares?
struct Operation
{
string name;
string retType;
int cost;
int codeLine;
unsigned flags;
bool isTile;
string implementAs;
vector<Type> opParamTypes; // the types of params of the bytecode operation
vector<Parameter> implParams; // the params the [[ code ]] block takes
};
struct OperationVariant
{
string sig;
Operation op;
vector<bool> paramIsIm;
vector<int> paramOffsets;
int size;
bool needsPadVariant;
};
class TableBuilder: public Parser
{
public:
TableBuilder(istream* inStream, ostream* hStream, ostream* cppStream,
FileTemplate* fTemplate, ostream* mStream);
void generateCode();
private:
// Interface to the parser; also (ab)used by the type system to emit
// conversion ops.
friend class TypeTable;
virtual void handleType(const string& type, const string& nativeName, unsigned flags);
virtual void handleConversion(const string& runtimeRoutine, int codeLine,
unsigned flags, const string& from, const string& to,
int tileCost, int registerCost);
virtual void handleOperation(const string& name, unsigned flags);
virtual void handleImpl(const string& fnName, const string& code, int codeLine, int cost,
const string& retType, vector<Parameter> sig);
virtual void handleTile(const string& fnName, StringList sig);
// Enumerates all r/i/pad variants; plus computes the shuffle table.
void expandOperationVariants(const Operation& op, vector<bool>& paramIsIm);
void dumpOpStructForVariant(const OperationVariant& variant, bool doPad,
bool hasPadVariant, bool needsComma);
void generateVariantImpl(const OperationVariant& variant);
CodePrinter out;
TypeTable types;
ostream& mInd(int ind) {
return out.mInd(ind);
}
StringList operationNames;
unsigned operationFlags;
map<string, string> operationRetTypes; // uglily enough specified on the impl. I suck.
vector<Operation> operations;
map<string, Operation> implementations;
StringList variantNames;
vector<OperationVariant> variants;
map<string, StringList> variantNamesForOp;
FileTemplate* fTemplate;
};
#endif
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,287 +0,0 @@
/*
* A utilitity for building various tables and specializations for the
* KJS Frostbyte bytecode
*
* Copyright (C) 2007, 2008 Maks Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "types.h"
#include <stdlib.h>
#include <iostream>
#include "assert.h"
#include <cctype>
#include <cstdio>
#include <wtf/ASCIICType.h>
#include "tablebuilder.h"
using namespace std;
// # of bits store 'vals' values, e.g. 3 for 8, etc.
static unsigned neededBits(unsigned vals)
{
unsigned bits = 1;
while ((1U << bits) < vals)
++bits;
return bits;
}
TypeTable::TypeTable(TableBuilder* instrBuilder, CodePrinter& out):
instrBuilder(instrBuilder), out(out)
{
// Builtin stuff...
conversionNames.push_back("NoConversion");
conversionNames.push_back("NoOp");
// Special ones for checked; opcodes.cpp.in has code to generate these.
conversionNames.push_back("I_R_Int32_Value");
conversionNames.push_back("I_R_Number_Value");
}
void TypeTable::generateCode()
{
// Types... First we just want to list them
Enum typesEnum("OpType", "OpType_", typeNames);
typesEnum.printDeclaration(out(OpH));
typesEnum.printDefinition (out(OpCpp));
// Also, print out the width array...
Array widths(out(OpCpp), "const bool", "opTypeIsAlign8");
for (unsigned t = 0; t < typeNames.size(); ++t) {
const Type& type = types[typeNames[t]];
widths.item(type.alignTo8() ? "true": "false", type.name);
}
widths.endArray();
// Conversion ops. Those go entirely in the .cpp
Enum convOps("ConvOp", "Conv_", conversionNames);
convOps.printDeclaration(out(OpH));
convOps.printDefinition (out(OpCpp));
out(OpCpp) << "struct ConvInfo {\n";
out(OpCpp) << " ConvOp routine;\n";
out(OpCpp) << " int costCode;\n";
out(OpCpp) << "};\n\n";
// For conversion info, we use upper bit for register/immediate (immediate is set),
// and then enough bits for the from/to types as the index.
Array convArr(out(OpCpp), "ConvInfo", "conversions");
printConversionInfo(convArr, rgConversions, true);
printConversionInfo(convArr, imConversions, false);
convArr.endArray();
int numBits = neededBits(types.size());
out(OpCpp) << "static inline const ConvInfo* getConversionInfo(bool immediate, OpType from, OpType to)\n{\n";
out(OpCpp) << " return &conversions[((int)immediate << " << (2 * numBits) << ")"
<< " | ((int)from << " << numBits << ") | (int)to];\n";
out(OpCpp) << "}\n\n";
// Emit inline conversion helpers based on the [[ code ]] specified
// in codes.def
for (unsigned c = 0; c < imConversionList.size(); ++c)
printConversionRoutine(imConversionList[c]);
// Now we generate a helper that invokes those.
out(OpCpp) << "static bool emitImmediateConversion(ConvOp convType, OpValue* original, OpValue& out)\n{\n";
out(OpCpp) << " out.immediate = true;\n";
out(OpCpp) << " switch(convType) {\n";
out(OpCpp) << " case Conv_NoOp:\n";
out(OpCpp) << " out = *original;\n";
out(OpCpp) << " break;\n";
for (unsigned c = 0; c < imConversionList.size(); ++c) {
const ConversionInfo& inf = imConversionList[c];
out(OpCpp) << " case Conv_" << inf.name << ":\n";
out(OpCpp) << " out.type = OpType_" << inf.to.name << ";\n";
out(OpCpp) << " out.value." << inf.to.field() << " = "
<< "convert" << inf.name << "(0, "
<< "original->value." << inf.from.field() << ");\n";
out(OpCpp) << " break;\n";
}
out(OpCpp) << " default:\n";
out(OpCpp) << " return false;\n";
out(OpCpp) << " }\n";
out(OpCpp) << " return true;\n";
out(OpCpp) << "}\n\n";
// Similar helper for simple register conversions, which actually emits ops
out(OpCpp) << "static bool emitSimpleRegisterConversion(CompileState* comp, ConvOp convType, OpValue* original, OpValue& out)\n{\n";
out(OpCpp) << " switch(convType) {\n";
out(OpCpp) << " case Conv_NoOp:\n";
out(OpCpp) << " out = *original;\n";
out(OpCpp) << " break;\n";
for (unsigned c = 0; c < rgConversionList.size(); ++c) {
const ConversionInfo& inf = rgConversionList[c];
out(OpCpp) << " case Conv_" << inf.name << ":\n";
out(OpCpp) << " CodeGen::emitOp(comp, Op_" << inf.name << ", &out, original);\n";
out(OpCpp) << " break;\n";
}
out(OpCpp) << " default:\n";
out(OpCpp) << " return false;\n";
out(OpCpp) << " }\n";
out(OpCpp) << " return true;\n";
out(OpCpp) << "}\n\n";
}
void TypeTable::printConversionInfo(Array& outArr, map<string, map<string, ConversionInfo> >& table, bool reg)
{
unsigned numBits = neededBits(types.size());
unsigned fullRange = 1 << numBits;
for (unsigned from = 0; from < fullRange; ++from) {
for (unsigned to = 0; to < fullRange; ++to) {
if (from < types.size() && to < types.size()) {
string fromName = typeNames[from];
string toName = typeNames[to];
string item;
// For register conversion, we need it to be possible for source + dest to be in
// registers. For immediate, we only require source, since dest will just go
// into local value.
bool representable;
if (reg)
representable = types[fromName].hasReg() && types[toName].hasReg();
else
representable = types[fromName].hasImm();
if (from == to) {
item = "{Conv_NoOp, 0}";
} else if (table[fromName].find(toName) != table[fromName].end() && representable) {
const ConversionInfo& inf = table[fromName][toName];
item = "{Conv_" + inf.name + ", ";
if (inf.flags & Conv_Checked)
item += "Cost_Checked";
else
item += CodePrinter::stringFromInt(reg ? inf.cost : 0);
item += "}"; // krazy:exclude=doublequote_chars
} else {
item = "{Conv_NoConversion, Cost_NoConversion}";
}
outArr.item(item, fromName + " => " + toName);
} else {
outArr.item("{Conv_NoConversion, Cost_NoConversion}");
}
} // for to..
} // for from..
}
void TypeTable::printConversionRoutine(const ConversionInfo& conversion)
{
out(OpH) << "ALWAYS_INLINE " << conversion.to.nativeName << " convert" << conversion.name
<< "(ExecState* exec, " << conversion.from.nativeName << " in)\n";
out(OpH) << "{\n";
out(OpH) << " (void)exec;\n";
out.printCode(out(OpH), 4, conversion.impl, conversion.codeLine);
out(OpH) << "}\n\n";
}
void TypeTable::handleType(const string& type, const string& nativeName, unsigned flags)
{
typeNames.push_back(type);
Type t;
t.name = type;
t.nativeName = nativeName;
t.flags = flags;
types[type] = t;
}
static string capitalized(const string& in)
{
return WTF::toASCIIUpper(in[0]) + in.substr(1);
}
void TypeTable::handleConversion(const string& code, int codeLine,
unsigned flags, const string& from, const string& to,
int tileCost, int registerCost)
{
// Compute the conversion names. The register one (if any) would also create an operation.
string immName = "I" + capitalized(from) + "_" + capitalized(to); // krazy:exclude=doublequote_chars
string regName = "R" + capitalized(from) + "_" + capitalized(to); // krazy:exclude=doublequote_chars
// Register immediate conversion
conversionNames.push_back(immName);
ConversionInfo inf;
inf.name = immName;
inf.cost = tileCost;
inf.flags = flags;
inf.impl = code;
inf.codeLine = codeLine;
inf.from = types[from];
inf.to = types[to];
imConversions[from][to] = inf;
imConversionList.push_back(inf);
// ... and, if it exists, register one.
if (flags & Conv_HaveReg) {
conversionNames.push_back(regName);
inf.name = regName;
inf.cost = registerCost;
inf.flags &= ~Conv_Checked; // 'checked' makes no sense here
rgConversions[from][to] = inf;
rgConversionList.push_back(inf);
// We also generate the corresponding bytecode routine, using
// the immediate conversion helper we'll emit in it.
instrBuilder->handleOperation(regName, false);
vector<Parameter> sig;
Parameter param;
param.name = "in";
param.typeName = from;
param.flags = Param_Exact;
sig.push_back(param);
string code = inf.to.nativeName + " out = convertI" + inf.name.substr(1) + "(exec, in);\n";
code += "$$ = out;\n";
instrBuilder->handleImpl("", code, codeLine, 0, to, sig);
}
}
Type TypeTable::resolveType(const string& type)
{
if (types.find(type) != types.end())
return types[type];
else
out.issueError("Unknown type:" + type);
// return something in nonvoid function
Type t;
return t;
}
vector<Type> TypeTable::resolveSignature(const StringList& in)
{
vector<Type> sig;
for (unsigned c = 0; c < in.size(); ++c)
sig.push_back(resolveType(in[c]));
return sig;
}
ConversionInfo TypeTable::immConv(const Type& from, const Type& to)
{
return imConversions[from.name][to.name];
}
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,135 +0,0 @@
/*
* A utilitity for building various tables and specializations for the
* KJS Frostbyte bytecode
*
* Copyright (C) 2007, 2008 Maks Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef TYPES_H
#define TYPES_H
#include <iostream>
#include <vector>
#include <map>
#include "codeprinter.h"
using std::ostream;
using std::vector;
using std::map;
enum TypeFlags {
Type_HaveImm = 1,
Type_HaveReg = 2,
Type_Align8 = 4
};
enum ConvFlags {
Conv_NoFlags,
Conv_HaveReg = 2,
Conv_Checked = 4,
Conv_MayThrow = 8
};
struct Type
{
string name;
string nativeName;
unsigned flags;
// may not be the same as Type_Align8 in the feature..
bool alignTo8() const {
return (flags & Type_Align8) == Type_Align8;
}
bool hasReg() const {
return (flags & Type_HaveReg) == Type_HaveReg;
}
bool hasImm() const {
return (flags & Type_HaveImm) == Type_HaveImm;
}
// field in store cells to access for this type
string field() const {
return ((flags & Type_Align8) ? "wide" : "narrow") +
std::string(".") + name + "Val";
}
bool operator==(const Type& other) const {
return name == other.name;
}
};
struct ConversionInfo
{
string name;
string impl;
int cost; // for w/in tile for immediate, for external for reg
unsigned flags;
Type from;
Type to;
int codeLine;
ConversionInfo(): cost(0), flags(Conv_NoFlags)
{} //Can be called for trivial conversion
};
class TableBuilder;
// This class is responsible for managing types & conversions, and generating
// conversion-selection routines.
class TypeTable
{
public:
TypeTable(TableBuilder* instrBuilder, CodePrinter& out);
void generateCode();
void handleType(const string& type, const string& nativeName, unsigned flags);
void handleConversion(const string& runtimeRoutine, int codeLine,
unsigned flags, const string& from, const string& to,
int tileCost, int registerCost);
// issues error if there is a problem..
vector<Type> resolveSignature(const StringList& in);
Type resolveType(const string& type);
ConversionInfo immConv(const Type& from, const Type& to);
private:
TableBuilder* instrBuilder;
CodePrinter& out;
void printConversionInfo(Array& array, map<string, map<string, ConversionInfo> >& table, bool reg);
void printConversionRoutine(const ConversionInfo& conversion);
map<string, Type> types;
StringList typeNames;
StringList conversionNames;
vector<ConversionInfo> imConversionList;
vector<ConversionInfo> rgConversionList;
map<string, map<string, ConversionInfo> > imConversions;
map<string, map<string, ConversionInfo> > rgConversions;
};
#endif
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,260 +0,0 @@
/*
* Main VM dispatch loop and related routines for KJS/Frostbyte
* This file is part of the KDE libraries
* Copyright (C) 2008 Maksim Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "completion.h"
#include "ExecState.h"
#include "value.h"
#include "nodes.h"
#include "opcodes.h"
#include "LocalStorage.h"
#include "bytecode/opargs.h"
#include "bytecode/machine.h"
#include "scriptfunction.h"
#include "internal.h" // for printInfo
#include "ustring.h"
#include "debugger.h"
#include <stdio.h>
// maximum global call stack size. Protects against accidental or
// malicious infinite recursions. Define to -1 if you want no limit.
#if PLATFORM(DARWIN)
// Given OS X stack sizes we run out of stack at about 350 levels.
// If we improve our stack usage, we can bump this number.
#define KJS_MAX_STACK 100
#else
#define KJS_MAX_STACK 1000 // ### set system specific
#endif
namespace KJS {
#if defined(__GNUC__)
#define USE_LABEL_VALS
#endif
// We can either do jumps via switch or a GCC extension
#ifdef USE_LABEL_VALS
#define handler(X) l##X
#else
#define handler(X) case OpByteCode_##X
#endif
// #define COUNT_INSTRS
// A little profiling aid -- counts the # of dynamic instances of each instruction.
#ifdef COUNT_INSTRS
static unsigned instrCounts[OpByteCode_NumValues];
struct InstrCountPrinter
{
~InstrCountPrinter() {
for (int c = 0; c < OpByteCode_NumValues; ++c) {
printf("%9d %s\n", instrCounts[c], OpByteCodeVals[c]);
}
}
};
static InstrCountPrinter dumpCounts;
#endif
// ### Need to consolidate this w/things remaining in nodes.cpp somehow.
static void substitute(UString &string, const UString &substring)
{
int position = string.find("%s");
assert(position != -1);
UString newString = string.substr(0, position);
newString.append(substring);
newString.append(string.substr(position + 2));
string = newString;
}
NEVER_INLINE void throwUndefinedVariableError(ExecState* exec, const Identifier& ident)
{
UString msg = "Can't find variable: %s";
substitute(msg, ident.ustring());
throwError(exec, ReferenceError, msg);
}
static JSValue* typeStringForValue(JSValue* v)
{
switch (v->type()) {
case UndefinedType:
return jsString("undefined");
case NullType:
return jsString("object");
case BooleanType:
return jsString("boolean");
case NumberType:
return jsString("number");
case StringType:
return jsString("string");
default:
if (v->isObject()) {
// Return "undefined" for objects that should be treated
// as null when doing comparisons.
if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
return jsString("undefined");
else if (static_cast<JSObject*>(v)->isFunctionType())
return jsString("function");
}
return jsString("object");
}
}
template<bool errorOut, bool trySkipOne, bool replaceActivations>
ALWAYS_INLINE void lookupScopeAndFetch(ExecState* exec, Identifier* varName, JSValue*& scopeOut, JSValue*& valOut)
{
const ScopeChain& chain = exec->scopeChain();
ScopeChainIterator iter = chain.begin();
ScopeChainIterator end = chain.end();
// we must always have something in the scope chain
assert(iter != end);
JSObject *scopeObj = *iter;
if (trySkipOne && !scopeObj->isLocalInjected()) {
// Unless eval introduced new variables dynamically,
// we know this isn't in the top scope
++iter;
}
PropertySlot slot;
do {
scopeObj = *iter;
++iter;
if (scopeObj->getPropertySlot(exec, *varName, slot)) {
if (!replaceActivations) {
scopeOut = scopeObj;
} else {
// Common case: we found it in global object -- no need to check
// if it's an activation
if (iter == end || !scopeObj->isActivation())
scopeOut = scopeObj;
else
scopeOut = exec->dynamicInterpreter()->globalObject();
}
valOut = slot.getValue(exec, scopeObj, *varName);
return;
}
} while (iter != end);
scopeOut = scopeObj;
valOut = jsUndefined();
if (errorOut) {
throwUndefinedVariableError(exec, *varName);
}
}
static int depth;
NEVER_INLINE JSValue* handleStackOverflow(ExecState* exec) {
depth -= 11; //Give the debugger some room..
JSValue *ret = throwError(exec, RangeError, "Maximum call stack size exceeded.");
depth += 10; //Put it back..
return ret;
}
enum Dir { Enter, Exit };
NEVER_INLINE void changeDebugContext(Dir d, ExecState* exec, Node* n) {
FunctionBodyNode* body = static_cast<FunctionBodyNode*>(n);
Debugger* dbg = exec->dynamicInterpreter()->debugger();
List args;
FunctionImp* fn = 0;
// Find the activation that contains arguments, fn
const ScopeChain& chain = exec->scopeChain();
for (ScopeChainIterator iter = chain.begin(); iter != chain.end(); ++iter) {
JSObject* scopeObj = *iter;
if (scopeObj->isActivation()) {
ActivationImp* act = static_cast<ActivationImp*>(scopeObj);
args = act->passedInArguments();
fn = static_cast<FunctionImp*>(act->function());
break;
}
}
if (d == Enter)
dbg->enterContext(exec, body->sourceId(), body->firstLine(), fn, args);
else
dbg->exitContext(exec, body->sourceId(), body->lastLine(), fn);
}
class ForInState: public JSObject {
public:
PropertyNameArray* array;
int pos;
ForInState() {
array = new PropertyNameArray;
pos = 0;
}
~ForInState() {
delete array;
}
};
struct DepthCleanup
{
~DepthCleanup() { --depth; }
};
ALWAYS_INLINE_INTO JSValue*
Machine::runBlock(ExecState* exec, const CodeBlock& codeBlock, ExecState* parentExec) {
#ifdef USE_LABEL_VALS
// Jump table, if needed
@generate
#endif
++depth;
if (depth > KJS_MAX_STACK)
return handleStackOverflow(exec);
DepthCleanup dc;
const unsigned char* base = codeBlock.data();
const unsigned char* pc = base;
List workList;
LocalStorageEntry* localStore = exec->localStorage();
exec->setMachineRegisters(base, &pc, &localStore);
JSObject* globalObject = exec->dynamicInterpreter()->globalObject();
while (true) {
begin:
#ifdef COUNT_INSTRS
OpByteCode opCodeLog = *reinterpret_cast<const OpByteCode*>(pc);
++instrCounts[opCodeLog];
#endif
@generate
}
}
}
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on; hl c++;

View file

@ -1,42 +0,0 @@
/*
* Main VM dispatch loop and related routines for KJS/Frostbyte
* This file is part of the KDE libraries
* Copyright (C) 2008 Maksim Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef KJS_MACHINE_H
#define KJS_MACHINE_H
#include "completion.h"
#include "ExecState.h"
#include "value.h"
#include "nodes.h"
#include "opcodes.h"
namespace KJS {
class Machine {
public:
static JSValue* runBlock(ExecState* exec, const CodeBlock& block, ExecState* parentExec = 0);
};
}
#endif
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on; hl c++;

View file

@ -1,101 +0,0 @@
/*
* Opcode argument data structures KJS/Frostbyte
* This file is part of the KDE libraries
* Copyright (C) 2008 Maksim Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef OP_ARGS_H
#define OP_ARGS_H
#include "opcodes.h"
namespace KJS {
class Node;
class RegDescriptor;
// The NarrowArg and WideArg unions correspond to the encoding of
// 4- and 8-byte arguments in the bytecode.
// Note that the union field names should correspond to codes.def types ---
// type foo will be accessed as fooVal
union NarrowArg
{
bool boolVal;
int32_t int32Val;
Addr addrVal;
Register regVal;
unsigned char asBytes[4];
};
union WideArg
{
JSValue* valueVal;
Identifier* identVal;
UString* stringVal;
double numberVal;
Node* nodeVal;
const char* cstrVal;
unsigned char asBytes[8];
};
// This describes where result of evaluating an expression, or an argument
// to a function, is stored. If immediate is true, it is included directly inside
// the structure. Otherwise, it's passed by the register number specified in
// ownedReg->reg()
// Note: there is a difference between values stored in registers, and register names.
// The former have immediate = false, and some type such as OpType_Bool; the latter have
// immediate = true, and type = OpType_reg.
struct OpValue
{
bool immediate;
OpType type;
RefPtr<RegDescriptor> ownedReg; // Register the lifetime of which we reserve, including the register #
union {
NarrowArg narrow;
WideArg wide;
} value;
OpValue();
// A few helpers for making immediate values... These are actually inside CompileState.h
// due to them touching the ownedTemp;
static void initImm(OpValue* val, OpType type) {
val->immediate = true;
val->type = type;
}
// A placeholder address value, will be patched up later
static OpValue* dummyAddr();
static OpValue immInt32(int32_t in);
static OpValue immNumber(double in);
static OpValue immValue(JSValue* in);
static OpValue immBool(bool in);
static OpValue immString(UString* in);
static OpValue immIdent(Identifier* in);
static OpValue immNode(Node* in);
static OpValue immCStr(const char* in);
static OpValue immAddr(Addr in);
};
}
#endif
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,435 +0,0 @@
/*
* Opcode data structure and selection routines for KJS/Frostbyte
* This file is part of the KDE libraries
* Copyright (C) 2008 Maksim Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "opcodes.h"
#include "CompileState.h"
#include <cstdio>
#if PLATFORM(SOLARIS_OS)
using std::printf;
#endif
// Enable this to dump instruction selection instructions.
// #define TRACE_INSTR_SELECT
namespace KJS {
const int Cost_NoConversion = -100000; // small enough so that adding actual costs doesn't
// make it positive
const int Cost_Checked = -2;
@generate
// Note: costOut will be negative if no conversion is possible
ConvOp computeCast(const OpValue* in, OpType outType, bool outImmediate, int& costOut, bool exact)
{
bool inImmediate = (in->immediate != 0);
OpType inType = in->type;
// Obviously, we can't make a register result into an an immediate value
if (outImmediate && !inImmediate) {
costOut = Cost_NoConversion;
return Conv_NoConversion;
}
if (exact) {
if (inType == outType) {
costOut = 0;
// We want to prefer these even if they require a spill,
// (since the implementation is more immediate),
// but we do want a slight cost to the spill so we don't do it for no good reason
if (!outImmediate && inImmediate)
costOut = 1;
return Conv_NoOp;
}
// as a special case, int32 -> number conversion is always safe; otherwise
// exact matching can't happen
if (inType != OpType_int32 || outType != OpType_number) {
costOut = Cost_NoConversion;
return Conv_NoConversion;
}
}
// In general, if we're converting immediate to register, we first try to
// convert the immediate value to the right type. That will either produce
// a fresh immediate value that be spilled directly, or may even emit the
// conversion for us. If it produces the value --- and hence the basic conversion ---
// all we have to do is spill it.
// Look up in the table..
const ConvInfo* inf = getConversionInfo(inImmediate, inType, outType);
if (inf->costCode == Cost_Checked) {
ASSERT(inImmediate);
ASSERT(outType == OpType_value);
ASSERT(inType == OpType_int32 || inType == OpType_number);
// Where a conversion is checked, we may not be able to get an
// immediate<->immediate match, so we may have to generate
// a special immediate<->register conversion.
bool inlineOK = inType == OpType_int32 ? JSImmediate::from(in->value.narrow.int32Val) :
JSImmediate::from(in->value.wide.numberVal);
if (outImmediate) {
// immediate -> immediate..
if (inlineOK)
costOut = 0;
else
costOut = Cost_NoConversion;
return inf->routine;
} else {
// immediate -> register.
// If we know inline op OK, we follow the normal path below which adds in a spill cost.
// Otherwise we emit the op directly.
if (!inlineOK) {
// cost about the same as register int32-> number conversion
costOut = getConversionInfo(false, OpType_int32, OpType_value)->costCode;
return inType == OpType_int32 ? Conv_I_R_Int32_Value :
Conv_I_R_Number_Value;
}
}
}
costOut = inf->costCode;
// Add some cost for a spill...
if (inImmediate && !outImmediate)
costOut += 25;
return inf->routine;
}
void emitConversion(CompileState* comp, bool outImm,
ConvOp convType, OpValue* original, OpValue& out)
{
if (emitImmediateConversion(convType, original, out)) {
// Emit a spill if needed, after the value gets converted..
if (!outImm && original->immediate) { // Need both checks since NoOp might get here..
OpValue spillVal, spillRef;
comp->requestTemporary(out.type, &spillVal, &spillRef);
CodeGen::emitRegStore(comp, &spillRef, &out);
out = spillVal;
}
return;
}
if (emitSimpleRegisterConversion(comp, convType, original, out))
return;
switch (convType) {
case Conv_I_R_Int32_Value:
CodeGen::emitOp(comp, Op_RInt32_Value_NonImm, &out, original);
break;
case Conv_I_R_Number_Value:
CodeGen::emitOp(comp, Op_RNum_Value_NonImm, &out, original);
break;
default:
fprintf(stderr, "Unable to emit conversion:%s, in:%c, out:%c\n", ConvOpVals[convType],
original->immediate ? 'I' : 'R', outImm ? 'I' : 'R');
CRASH();
};
}
static inline void setArg(unsigned char* argBase, const OpValue& val)
{
if (val.immediate) {
if (opTypeIsAlign8[val.type]) {
*reinterpret_cast<WideArg*>(argBase) = val.value.wide;
} else {
*reinterpret_cast<NarrowArg*>(argBase) = val.value.narrow;
}
} else {
// For arguments, we actually output the byte offset.
reinterpret_cast<NarrowArg*>(argBase)->regVal = val.ownedReg->reg() * sizeof(LocalStorageEntry);
}
}
static void emitArg(unsigned char* basePtr, const Op* opDescr, int pos, const OpValue& val)
{
ASSERT(opDescr->immediateParams[pos] == val.immediate);
ASSERT(opDescr->paramTypes[pos] == val.type);
unsigned char* argBase = basePtr + opDescr->paramOffsets[pos];
setArg(argBase, val);
}
void CodeGen::emitConvertTo(CompileState* comp, OpValue* in,
OpType outType, OpValue* out)
{
int cost;
ConvOp op = computeCast(in, outType, in->immediate, cost, false);
ASSERT(cost >= 0);
emitConversion(comp, in->immediate, op, in, *out);
}
void CodeGen::emitRegStore(CompileState* comp, OpValue* regNum, OpValue* val)
{
ASSERT(regNum->immediate && regNum->type == OpType_reg);
switch (val->type) {
case OpType_bool:
emitOp(comp, Op_RegPutBool, 0, regNum, val);
break;
case OpType_int32:
emitOp(comp, Op_RegPutInt32, 0, regNum, val);
break;
case OpType_value:
emitOp(comp, Op_RegPutValue, 0, regNum, val);
break;
case OpType_number:
emitOp(comp, Op_RegPutNumber, 0, regNum, val);
break;
default:
fprintf(stderr, "Don't know how to store type to register:%s\n", OpTypeVals[val->type]);
CRASH();
}
}
static void printType(const char* prefix, int pos, OpValue* v) {
fprintf(stderr, "%s%d:%s/imm:%d\n", prefix, pos, OpTypeVals[v->type], v->immediate);
}
Addr CodeGen::emitOp(CompileState* comp, OpName baseInstr,
OpValue* retOut, OpValue* a0, OpValue* a1, OpValue* a2, OpValue* a3)
{
CodeBlock& block = comp->codeBlock();
const Op* const* cands = opSpecializations[baseInstr];
const Op* cheapest = 0;
int cheapestCost = 0;
ConvOp cheapestConvOps[4] = {Conv_NoConversion, Conv_NoConversion, Conv_NoConversion};
// Here, we assume that all methods either return or not.
OpType retType = opRetTypes[baseInstr];
OpValue retVal, retReg;
if (retType != OpType_void) {
// Add in a register argument.. For now just a dummy #;
// will fill in w/appropriate type later
ASSERT(!a3);
retReg.immediate = true;
retReg.type = OpType_reg;
a3 = a2;
a2 = a1;
a1 = a0;
a0 = &retReg;
} else {
ASSERT(!retOut);
}
OpValue* args[4] = {a0, a1, a2, a3};
int numArgs = 0;
while (numArgs < 4 && args[numArgs])
++numArgs;
#ifdef TRACE_INSTR_SELECT
fprintf(stderr, "\n\nTrying to select variant for:%s\n", OpNameVals[baseInstr]);
for (int i = 0; i < numArgs; ++i)
printType("\targ", i, args[i]);
#endif
// First, scan through, and determine the cheapest non-align variant.
// We can't select whether to align or not, since we may have to emit
// cast ops, which could change where we are.
for (int c = 0; cands[c]; ++c) {
const Op* cand = cands[c];
ASSERT(cand->baseInstr == baseInstr);
ASSERT(cand->numParams == numArgs);
if (cand->padAlign)
continue;
int costs[4];
ConvOp convOps[4];
int totalCost = cand->cost;
for (int i = 0; i < numArgs; ++i) {
convOps[i] = computeCast(args[i], cand->paramTypes[i],
cand->immediateParams[i], costs[i], cand->exactParams[i]);
totalCost += costs[i];
}
#ifdef TRACE_INSTR_SELECT
fprintf(stderr, "Candidate:%s, totalCost:%d, variant cost:%d\n", OpByteCodeVals[cand->opCode], totalCost, cand->cost);
for (int i = 0; i < numArgs; ++i) {
fprintf(stderr, "\tconv:%s, costs:%d\n", ConvOpVals[convOps[i]], costs[i]);
}
#endif
if (totalCost < 0) // Cost_NoConversion in the sum...
continue;
if (totalCost < cheapestCost || !cheapest) {
cheapest = cand;
cheapestCost = totalCost;
cheapestConvOps[0] = convOps[0];
cheapestConvOps[1] = convOps[1];
cheapestConvOps[2] = convOps[2];
cheapestConvOps[3] = convOps[3];
}
}
if (!cheapest) {
fprintf(stderr, "Unable to find an acceptable conversion for:%s\n", OpNameVals[baseInstr]);
for (int i = 0; i < numArgs; ++i)
printType("\ta", i, args[i]);
CRASH(); // Should never happen!
}
if (cheapest->endsBB)
comp->localFlushAll(block);
// Now that we have a candidate, actually grab a register of the proper return type.
retType = cheapest->retType;
if (retType != OpType_void) {
comp->requestTemporary(retType, &retVal, &retReg);
// Set return value, if needed
if (retOut)
*retOut = retVal;
}
OpValue c[4]; // converted version
for (int i = 0; i < numArgs; ++i)
emitConversion(comp, cheapest->immediateParams[i], cheapestConvOps[i], args[i], c[i]);
// Now figure out if we need to do align.. We need it if the PC is 8-aligned, since
// the instr will mess that up, and the instruction need it..
if (cheapest->hasPadVariant && ((block.size() % 8) == 0)) {
// The padded variant of the instruction always preceeds the unpadded one..
cheapest = &opsForOpCodes[cheapest->opCode - 1];
}
// Phewww. Now we can actually write out stuff.
size_t pos = block.size();
block.resize(pos + cheapest->length);
unsigned char* basePtr = block.data() + pos;
// Write out the opcode..
*reinterpret_cast<OpByteCode*>(basePtr) = cheapest->opCode;
// ... and the args, as needed.
for (int i = 0; i < numArgs; ++i) {
emitArg(basePtr, cheapest, i, c[i]);
}
return basePtr - block.data();
}
Addr CodeGen::nextPC(CompileState* comp)
{
CodeBlock& block = comp->codeBlock();
comp->localFlushAll(block);
return block.size();
}
void CodeGen::patchOpArgument(CodeBlock& block, Addr baseAddr, int pos, OpValue& newVal)
{
OpByteCode* base = reinterpret_cast<OpByteCode*>(block.data() + baseAddr);
const Op& variant = opsForOpCodes[*base];
// We only permit patching immediate arguments for now..
ASSERT(variant.immediateParams[pos] && newVal.immediate);
ASSERT(variant.paramTypes[pos] == newVal.type);
ASSERT(pos < variant.numParams);
unsigned char* argBase = reinterpret_cast<unsigned char*>(base) + variant.paramOffsets[pos];
setArg(argBase, newVal);
}
void CodeGen::patchJumpToNext(CompileState* comp, Addr op, int argNum)
{
OpValue destAddr = OpValue::immAddr(nextPC(comp));
patchOpArgument(comp->codeBlock(), op, argNum, destAddr);
}
static void dumpParam(CodeBlock& block, size_t offset, OpType type, bool wasImm)
{
switch (type) {
case OpType_bool:
if (reinterpret_cast<NarrowArg*>(block.data() + offset)->boolVal)
std::fprintf(stderr, "true");
else
std::fprintf(stderr, "false");
break;
case OpType_int32:
std::fprintf(stderr, "%d", reinterpret_cast<NarrowArg*>(block.data() + offset)->int32Val);
break;
case OpType_value:
// Immediate value -- should go through JSImmediate stuff..
std::fprintf(stderr, "<ival:%s>", reinterpret_cast<WideArg*>(block.data() + offset)->valueVal->toString(0).ascii());
break;
case OpType_ident:
std::fprintf(stderr, "%s", reinterpret_cast<WideArg*>(block.data() + offset)->identVal->ustring().ascii());
break;
case OpType_string:
std::fprintf(stderr, "\"%s\"", reinterpret_cast<WideArg*>(block.data() + offset)->stringVal->ascii());
break;
case OpType_number:
std::fprintf(stderr, "%f", reinterpret_cast<WideArg*>(block.data() + offset)->numberVal);
break;
case OpType_addr:
std::fprintf(stderr, "A%08x", reinterpret_cast<NarrowArg*>(block.data() + offset)->addrVal);
break;
case OpType_reg:
std::fprintf(stderr, "r%lu", reinterpret_cast<NarrowArg*>(block.data() + offset)->regVal / (wasImm ?
1lu : sizeof(LocalStorageEntry)));
break;
case OpType_node:
std::fprintf(stderr,"N%p", (void*)(reinterpret_cast<WideArg*>(block.data() + offset)->nodeVal));
break;
case OpType_cstr:
std::fprintf(stderr, "c\"%s\"", reinterpret_cast<WideArg*>(block.data() + offset)->cstrVal);
break;
default:
std::fprintf(stderr, "???:%s", OpTypeVals[type]);
};
std::fprintf(stderr, " ");
}
void CodeGen::disassembleBlock(CodeBlock& block)
{
size_t pc = 0;
while (pc < block.size()) {
OpByteCode opCode = *reinterpret_cast<OpByteCode*>(block.data() + pc);
const Op& opDescr = opsForOpCodes[opCode];
std::fprintf(stderr, "%08lx %s ", pc, OpNameVals[opDescr.baseInstr]);
for (int p = 0; p < opDescr.numParams; ++p) {
dumpParam(block, pc + opDescr.paramOffsets[p],
opDescr.immediateParams[p] ? opDescr.paramTypes[p] : OpType_reg, opDescr.immediateParams[p]);
}
std::fprintf(stderr, "\t\t// %s\n", OpByteCodeVals[opCode]);
pc += opDescr.length;
}
}
} //namespace KJS
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on; hl c++;

View file

@ -1,136 +0,0 @@
/*
* Opcode data structure and selection routines for KJS/Frostbyte
* This file is part of the KDE libraries
* Copyright (C) 2008 Maksim Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <wtf/Assertions.h>
// be nice to our fruity overlords and their silly assert-unfriendly environment
#include <wtf/RefPtr.h>
#include <wtf/Vector.h>
#include "value.h"
#include "identifier.h"
#include "ExecState.h"
#ifndef OPCODES_H
#define OPCODES_H
namespace KJS {
typedef unsigned Register;
class CompileState;
@generate
/**
There are 2 levels at which instructions exist. First of all, there is
an actual operation name, represent by the OpName enum. This is something like
Op_IfJump. For each one of these, we have multiple bytecode instructions, such as
OpByteCode_IfJump_Ibool_Iaddr and OpByteCode_IfJump_Rbool_Iaddr, with their
names given in the OpByteCode_ enum.
For each of these bytecode codes, there is an entry in the opsForOpCodes
array, which provides an Op structure, which describes which parameters
go where, and so on. The opSpecializations array lets one look up
all these structures relevant for each OpName, so one can select
the specific operation for each conceptual instruction.
Besides parameter variants, there is also variation based on padding, with
some bytecodes skipping 4 extra bytes after the opcode to make things 8-aligned.
Those bytecodes are always 1 below their unaligned version
*/
struct Op {
OpName baseInstr;
OpByteCode opCode;
int cost;
int numParams;
OpType paramTypes[4];
bool immediateParams[4];
bool exactParams[4]; // if true, we should not perform any
// (non-injective) conversions for the given parameter
OpType retType; // type of this specialization
int length; // Length of instruction, including opcode + args
// This contains offsets of arguments, starting from before the instruction
int paramOffsets[4];
// If this is true, this version of the instruction has an
// extra word inserted after the opcode, for alignment reasons.
bool padAlign;
// If this is true, this version has both padded and unpadded flavors
bool hasPadVariant;
// If this is true, this instruction performs a jump, and hence
// should flush per-BB info
bool endsBB;
};
// The main array of Op instances, mapped by OpByteCode
extern const Op opsForOpCodes[];
// Lists all the specialized versions of each Op class, mapped by OpName,
// 0 terminated.
extern const Op* const* const opSpecializations[];
// Describes whether the type is align8 or not.
extern const bool opTypeIsAlign8[];
struct OpValue;
typedef Vector<unsigned char> CodeBlock;
class CodeGen {
public:
// All of these emit the instruction of given type, and return its base.
// If retVal isn't 0, the return value will be placed there
static Addr emitOp(CompileState* comp, OpName baseInstr,
OpValue* retOut = 0, OpValue* a0 = 0, OpValue* a1 = 0,
OpValue* a2 = 0, OpValue* a3 = 0);
static void emitConvertTo(CompileState* comp, OpValue* in,
OpType outType, OpValue* out);
// Emits a register store of appropriate type
static void emitRegStore(CompileState* comp, OpValue* regNum, OpValue* val);
static void patchOpArgument(CodeBlock& block, Addr base, int pos, OpValue& newVal);
// Patches op at address 'op' to jump to next instr.
static void patchJumpToNext(CompileState* comp, Addr op, int argNum);
// This requests the address of next instruction, for use in control flow, and
// designates a basic block boundary, flushing everything BB-dependent;
static Addr nextPC(CompileState* comp);
static void disassembleBlock(CodeBlock& block);
};
} //namespace KJS
#endif
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on; hl c++;

View file

@ -1,938 +0,0 @@
// -*- mode: c++; c-basic-offset: 4 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Computer, Inc.
* Copyright (C) 2007 Eric Seidel <eric@webkit.org>
* Copyright (C) 2007 Maksim Orlovich <maksim@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "collector.h"
#include <config-kjs.h>
#include <wtf/FastMalloc.h>
#include <wtf/HashCountedSet.h>
#include "internal.h"
#include "list.h"
#include "value.h"
#include <setjmp.h>
#include <limits.h>
#include <algorithm>
#if PLATFORM(DARWIN)
#include <pthread.h>
#include <mach/mach_port.h>
#include <mach/mach_init.h>
#include <mach/task.h>
#include <mach/thread_act.h>
#include <mach/vm_map.h>
#elif PLATFORM(WIN_OS) || COMPILER(CYGWIN)
#include <windows.h>
#include <winnt.h>
#elif PLATFORM(UNIX)
#include <stdlib.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <pthread.h> //krazy:exclude=includes (yes, it's duplicate, but in a different #if branch)
#include <unistd.h>
#if PLATFORM(SOLARIS_OS)
#include <thread.h>
#include <signal.h>
using std::memset;
#endif
#if HAVE(PTHREAD_NP_H)
#include <pthread_np.h>
#endif
#endif
#define DEBUG_COLLECTOR 0
#if HAVE(VALGRIND_MEMCHECK_H) && !defined(NDEBUG)
#include <valgrind/memcheck.h>
#if defined(VALGRIND_MAKE_MEM_DEFINED)
#define VG_DEFINED(p) VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(void*))
#else
#define VG_DEFINED(p)
#endif
#else
#define VG_DEFINED(p)
#endif
using std::max;
namespace KJS {
// tunable parameters
const size_t SPARE_EMPTY_BLOCKS = 2;
const size_t MIN_ARRAY_SIZE = 14;
const size_t GROWTH_FACTOR = 2;
const size_t LOW_WATER_FACTOR = 4;
const size_t ALLOCATIONS_PER_COLLECTION = 4000;
// A whee bit like a WTF::Vector, but perfectly POD, so can be used in global context
// w/o worries.
struct BlockList {
CollectorBlock** m_data;
size_t m_used;
size_t m_capacity;
CollectorBlock* operator[](size_t pos) {
return m_data[pos];
}
size_t used() const {
return m_used;
}
void append(CollectorBlock* block) {
if (m_used == m_capacity) {
static const size_t maxNumBlocks = ULONG_MAX / sizeof(CollectorBlock*) / GROWTH_FACTOR;
if (m_capacity > maxNumBlocks)
CRASH();
m_capacity = max(MIN_ARRAY_SIZE, m_capacity * GROWTH_FACTOR);
m_data = static_cast<CollectorBlock **>(fastRealloc(m_data, m_capacity * sizeof(CollectorBlock *)));
}
m_data[m_used] = block;
++m_used;
}
void remove(CollectorBlock* block) {
size_t c;
for (c = 0; c < m_used; ++c)
if (m_data[c] == block)
break;
if (c == m_used)
return;
// Move things up, and shrink..
--m_used;
for (; c < m_used; ++c)
m_data[c] = m_data[c+1];
}
};
struct CollectorHeap {
// This contains the list of both normal and oversize blocks
BlockList allBlocks;
// Just the normal blocks
BlockList blocks;
size_t firstBlockWithPossibleSpace;
// The oversize block handling is a bit tricky, since we do not wish to slow down
// the usual paths. Hence, we do the following:
// 1) We set the marked bits for any extension portions of the block.
// this way the stack GC doesn't have to do anything special if a pointer
// happens to go that way.
// 2) We keep track of an allBlocks list to help the stack GC tests things.
//
// The oversize heap itself represents blocks as follows:
// 1) free: marked = false, allocd = false, trailer = false, zeroIfFree = 0
// 2) alloc'd, head: marked = depends, allocd = true, trailer = false, zeroIfFree is uncertain
// 3) alloc'd, trailer: marked = true (see above), allocd = true, trailer = true, zeroIfFree is uncertain
//
// For now, we don't use a freelist, so performance may be quite bad if
// this is used heavily; this is just because the cell does not have
// back and forward links; which we need since we can pick a non-first cell
// ### actually, it may be possible to shuffle the list. Not now, though
BlockList oversizeBlocks;
size_t numLiveObjects;
size_t numLiveObjectsAtLastCollect;
size_t extraCost;
};
static CollectorHeap heap;
bool Collector::memoryFull = false;
static CollectorBlock* allocateBlock()
{
#if PLATFORM(DARWIN)
vm_address_t address = 0;
vm_map(current_task(), &address, BLOCK_SIZE, BLOCK_OFFSET_MASK, VM_FLAGS_ANYWHERE, MEMORY_OBJECT_NULL, 0, FALSE, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_DEFAULT);
#elif PLATFORM(WIN_OS) || COMPILER(CYGWIN)
// windows virtual address granularity is naturally 64k
LPVOID address = VirtualAlloc(NULL, BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#elif HAVE(POSIX_MEMALIGN)
void* address;
posix_memalign(address, BLOCK_SIZE, BLOCK_SIZE);
memset(reinterpret_cast<void*>(address), 0, BLOCK_SIZE);
#else
static size_t pagesize = getpagesize();
size_t extra = 0;
if (BLOCK_SIZE > pagesize)
extra = BLOCK_SIZE - pagesize;
void* mmapResult = mmap(NULL, BLOCK_SIZE + extra, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
uintptr_t address = reinterpret_cast<uintptr_t>(mmapResult);
size_t adjust = 0;
if ((address & BLOCK_OFFSET_MASK) != 0)
adjust = BLOCK_SIZE - (address & BLOCK_OFFSET_MASK);
if (adjust > 0)
munmap(reinterpret_cast<void*>(address), adjust);
if (adjust < extra)
munmap(reinterpret_cast<void*>(address + adjust + BLOCK_SIZE), extra - adjust);
address += adjust;
memset(reinterpret_cast<void*>(address), 0, BLOCK_SIZE);
#endif
CollectorBlock* ptr = reinterpret_cast<CollectorBlock*>(address);
heap.allBlocks.append(ptr); // Register with the heap
return ptr;
}
static void freeBlock(CollectorBlock* block)
{
// Unregister the block first
heap.allBlocks.remove(block);
#if PLATFORM(DARWIN)
vm_deallocate(current_task(), reinterpret_cast<vm_address_t>(block), BLOCK_SIZE);
#elif PLATFORM(WIN_OS) || COMPILER(CYGWIN)
VirtualFree(block, BLOCK_SIZE, MEM_RELEASE);
#elif HAVE(POSIX_MEMALIGN)
free(block);
#else
munmap(block, BLOCK_SIZE);
#endif
}
void Collector::recordExtraCost(size_t cost)
{
// Our frequency of garbage collection tries to balance memory use against speed
// by collecting based on the number of newly created values. However, for values
// that hold on to a great deal of memory that's not in the form of other JS values,
// that is not good enough - in some cases a lot of those objects can pile up and
// use crazy amounts of memory without a GC happening. So we track these extra
// memory costs. Only unusually large objects are noted, and we only keep track
// of this extra cost until the next GC. In garbage collected languages, most values
// are either very short lived temporaries, or have extremely long lifetimes. So
// if a large value survives one garbage collection, there is not much point to
// collecting more frequently as long as it stays alive.
heap.extraCost += cost;
}
static void* allocOversize(size_t s)
{
size_t cellsNeeded = (s + (CELL_SIZE - 1)) / CELL_SIZE;
// printf("allocOversize, size:%d, cellsNeeded:%d\n", s, cellsNeeded);
// We are not oversize enough to deal with things close to 64K in size
assert(cellsNeeded <= CELLS_PER_BLOCK);
// Look through the blocks, see if one has enough, and where.
CollectorBlock* sufficientBlock = 0;
size_t startOffset = -1;
for (size_t b = 0; b < heap.oversizeBlocks.used() && !sufficientBlock; ++b) {
CollectorBlock* candidate = heap.oversizeBlocks[b];
if (cellsNeeded <= CELLS_PER_BLOCK - candidate->usedCells) {
// Well, there is a chance we will fit.. Let's see if we can find a batch long enough..
for (size_t i = 0; i < CELLS_PER_BLOCK; i++) {
if (i % 32 == 0 && candidate->allocd.bits[i/32] == 0xFFFFFFFF) {
// Can skip this and 31 other cells
i += 31;
continue;
}
if (candidate->allocd.get(i))
continue;
// This cell is free -- are there enough free cells after it?
startOffset = i;
size_t last = i + cellsNeeded - 1;
if (last >= CELLS_PER_BLOCK) // No way it will fit
break;
++i;
while (i <= last && !candidate->allocd.get(i))
++i;
// Did we get through enough?
if (i == last + 1) {
sufficientBlock = candidate;
break;
}
// Not enough room -- and the current entry has a non-zero zeroIfFree,
// so we should go on at i + 1 on next iteration
} // for each cell per block.
} // if enough room in block
} // for each block
if (!sufficientBlock) {
sufficientBlock = allocateBlock();
startOffset = 0;
heap.oversizeBlocks.append(sufficientBlock);
}
sufficientBlock->usedCells += cellsNeeded;
// Set proper bits for trailers and the head
sufficientBlock->allocd.set(startOffset);
for (size_t t = startOffset + 1; t < startOffset + cellsNeeded; ++t) {
sufficientBlock->trailer.set(t);
sufficientBlock->marked.set(t);
sufficientBlock->allocd.set(t);
}
void* result = sufficientBlock->cells + startOffset;
memset(result, 0, s);
heap.numLiveObjects = heap.numLiveObjects + 1;
return result;
}
void* Collector::allocate(size_t s)
{
assert(JSLock::lockCount() > 0);
// collect if needed
size_t numLiveObjects = heap.numLiveObjects;
size_t numLiveObjectsAtLastCollect = heap.numLiveObjectsAtLastCollect;
size_t numNewObjects = numLiveObjects - numLiveObjectsAtLastCollect;
size_t newCost = numNewObjects + heap.extraCost;
if (newCost >= ALLOCATIONS_PER_COLLECTION && newCost >= numLiveObjectsAtLastCollect) {
collect();
numLiveObjects = heap.numLiveObjects;
}
if (s > CELL_SIZE) {
return allocOversize(s);
}
// slab allocator
size_t usedBlocks = heap.blocks.used();
size_t i = heap.firstBlockWithPossibleSpace;
CollectorBlock *targetBlock;
size_t targetBlockUsedCells;
if (i != usedBlocks) {
targetBlock = heap.blocks[i];
targetBlockUsedCells = targetBlock->usedCells;
assert(targetBlockUsedCells <= CELLS_PER_BLOCK);
while (targetBlockUsedCells == CELLS_PER_BLOCK) {
if (++i == usedBlocks)
goto allocateNewBlock;
targetBlock = heap.blocks[i];
targetBlockUsedCells = targetBlock->usedCells;
assert(targetBlockUsedCells <= CELLS_PER_BLOCK);
}
heap.firstBlockWithPossibleSpace = i;
} else {
allocateNewBlock:
// didn't find one, need to allocate a new block
targetBlock = allocateBlock();
targetBlock->freeList = targetBlock->cells;
targetBlockUsedCells = 0;
heap.blocks.append(targetBlock);
heap.firstBlockWithPossibleSpace = usedBlocks; // previous usedBlocks -> new one's index
}
// find a free spot in the block and detach it from the free list
CollectorCell *newCell = targetBlock->freeList;
// "next" field is a byte offset -- 0 means next cell, so a zeroed block is already initialized
// could avoid the casts by using a cell offset, but this avoids a relatively-slow multiply
targetBlock->freeList = reinterpret_cast<CollectorCell *>(reinterpret_cast<char *>(newCell + 1) + newCell->u.freeCell.next);
targetBlock->usedCells = targetBlockUsedCells + 1;
heap.numLiveObjects = numLiveObjects + 1;
return newCell;
}
#if USE(MULTIPLE_THREADS)
struct Collector::Thread {
Thread(pthread_t pthread, mach_port_t mthread) : posixThread(pthread), machThread(mthread) {}
Thread *next;
pthread_t posixThread;
mach_port_t machThread;
};
pthread_key_t registeredThreadKey;
pthread_once_t registeredThreadKeyOnce = PTHREAD_ONCE_INIT;
Collector::Thread *registeredThreads;
static void destroyRegisteredThread(void *data)
{
Collector::Thread *thread = (Collector::Thread *)data;
if (registeredThreads == thread) {
registeredThreads = registeredThreads->next;
} else {
Collector::Thread *last = registeredThreads;
for (Collector::Thread *t = registeredThreads->next; t != NULL; t = t->next) {
if (t == thread) {
last->next = t->next;
break;
}
last = t;
}
}
delete thread;
}
static void initializeRegisteredThreadKey()
{
pthread_key_create(&registeredThreadKey, destroyRegisteredThread);
}
void Collector::registerThread()
{
pthread_once(&registeredThreadKeyOnce, initializeRegisteredThreadKey);
if (!pthread_getspecific(registeredThreadKey)) {
pthread_t pthread = pthread_self();
WTF::fastMallocRegisterThread(pthread);
Collector::Thread *thread = new Collector::Thread(pthread, pthread_mach_thread_np(pthread));
thread->next = registeredThreads;
registeredThreads = thread;
pthread_setspecific(registeredThreadKey, thread);
}
}
#endif
#define IS_POINTER_ALIGNED(p) (((intptr_t)(p) & (sizeof(char *) - 1)) == 0)
// cell size needs to be a power of two for this to be valid
#define IS_CELL_ALIGNED(p) (((intptr_t)(p) & CELL_MASK) == 0)
void Collector::markStackObjectsConservatively(void *start, void *end)
{
if (start > end) {
void *tmp = start;
start = end;
end = tmp;
}
assert(((char *)end - (char *)start) < 0x1000000);
assert(IS_POINTER_ALIGNED(start));
assert(IS_POINTER_ALIGNED(end));
char **p = (char **)start;
char **e = (char **)end;
// We use allBlocks here since we want to mark oversize cells as well.
// Their trailers will have the mark bit set already, to avoid trouble.
size_t usedBlocks = heap.allBlocks.used();
CollectorBlock **blocks = heap.allBlocks.m_data;
const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1);
while (p != e) {
char *x = *p++;
VG_DEFINED(x);
if (IS_CELL_ALIGNED(x) && x) {
uintptr_t offset = reinterpret_cast<uintptr_t>(x) & BLOCK_OFFSET_MASK;
CollectorBlock* blockAddr = reinterpret_cast<CollectorBlock*>(x - offset);
for (size_t block = 0; block < usedBlocks; block++) {
if ((blocks[block] == blockAddr) && (offset <= lastCellOffset)) {
if (((CollectorCell *)x)->u.freeCell.zeroIfFree != 0) {
JSCell *imp = reinterpret_cast<JSCell *>(x);
if (!imp->marked())
imp->mark();
}
} // if valid block
} // for each block
} // if cell-aligned
} // for each pointer
}
static inline void* currentThreadStackBase()
{
#if PLATFORM(DARWIN)
pthread_t thread = pthread_self();
void *stackBase = pthread_get_stackaddr_np(thread);
#elif (PLATFORM(WIN_OS) || COMPILER(CYGWIN))
// tested with mingw32, mingw64, msvc2008, cygwin
NT_TIB *pTib = (NT_TIB*)NtCurrentTeb();
void *stackBase = (void *)pTib->StackBase;
#elif PLATFORM(SOLARIS_OS)
stack_t s;
thr_stksegment(&s);
return s.ss_sp;
// NOTREACHED
void *stackBase = 0;
#elif PLATFORM(UNIX)
static void *stackBase = 0;
static pthread_t stackThread;
pthread_t thread = pthread_self();
if (stackBase == 0 || thread != stackThread) {
pthread_attr_t sattr;
#if HAVE(PTHREAD_NP_H) || defined(__NetBSD__)
// e.g. on FreeBSD 5.4, neundorf@kde.org
// also on NetBSD 3 and 4, raphael.langerhorst@kdemail.net
// HIGHLY RECCOMENDED by manpage to allocate storage, avoids
// crashing in JS immediately in FreeBSD.
pthread_attr_init(&sattr);
pthread_attr_get_np(thread, &sattr);
#else
// FIXME: this function is non-portable; other POSIX systems may have different np alternatives
pthread_getattr_np(thread, &sattr);
#endif // picking the _np function to use --- Linux or BSD
size_t stackSize;
pthread_attr_getstack(&sattr, &stackBase, &stackSize);
stackBase = (char *)stackBase + stackSize; // a matter of interpretation, apparently...
pthread_attr_destroy(&sattr);
assert(stackBase);
stackThread = thread;
}
#else
#error Need a way to get the stack base on this platform
#endif
return stackBase;
}
void Collector::markCurrentThreadConservatively()
{
// setjmp forces volatile registers onto the stack
jmp_buf registers;
#if COMPILER(MSVC)
#pragma warning(push)
#pragma warning(disable: 4611)
#endif
setjmp(registers);
#if COMPILER(MSVC)
#pragma warning(pop)
#endif
void* dummy;
void* stackPointer = &dummy;
void* stackBase = currentThreadStackBase();
markStackObjectsConservatively(stackPointer, stackBase);
}
#if USE(MULTIPLE_THREADS)
typedef unsigned long usword_t; // word size, assumed to be either 32 or 64 bit
void Collector::markOtherThreadConservatively(Thread *thread)
{
thread_suspend(thread->machThread);
#if PLATFORM(X86)
i386_thread_state_t regs;
unsigned user_count = sizeof(regs)/sizeof(int);
thread_state_flavor_t flavor = i386_THREAD_STATE;
#elif PLATFORM(X86_64)
x86_thread_state64_t regs;
unsigned user_count = x86_THREAD_STATE64_COUNT;
thread_state_flavor_t flavor = x86_THREAD_STATE64;
#elif PLATFORM(PPC)
ppc_thread_state_t regs;
unsigned user_count = PPC_THREAD_STATE_COUNT;
thread_state_flavor_t flavor = PPC_THREAD_STATE;
#elif PLATFORM(PPC64)
ppc_thread_state64_t regs;
unsigned user_count = PPC_THREAD_STATE64_COUNT;
thread_state_flavor_t flavor = PPC_THREAD_STATE64;
#else
#error Unknown Architecture
#endif
// get the thread register state
thread_get_state(thread->machThread, flavor, (thread_state_t)&regs, &user_count);
// scan the registers
markStackObjectsConservatively((void *)&regs, (void *)((char *)&regs + (user_count * sizeof(usword_t))));
// scan the stack
#if PLATFORM(X86) && __DARWIN_UNIX03
markStackObjectsConservatively((void *)regs.__esp, pthread_get_stackaddr_np(thread->posixThread));
#elif PLATFORM(X86)
markStackObjectsConservatively((void *)regs.esp, pthread_get_stackaddr_np(thread->posixThread));
#elif PLATFORM(X86_64) && __DARWIN_UNIX03
markStackObjectsConservatively((void *)regs.__rsp, pthread_get_stackaddr_np(thread->posixThread));
#elif PLATFORM(X86_64)
markStackObjectsConservatively((void *)regs.rsp, pthread_get_stackaddr_np(thread->posixThread));
#elif (PLATFORM(PPC) || PLATFORM(PPC64)) && __DARWIN_UNIX03
markStackObjectsConservatively((void *)regs.__r1, pthread_get_stackaddr_np(thread->posixThread));
#elif PLATFORM(PPC) || PLATFORM(PPC64)
markStackObjectsConservatively((void *)regs.r1, pthread_get_stackaddr_np(thread->posixThread));
#else
#error Unknown Architecture
#endif
thread_resume(thread->machThread);
}
#endif
void Collector::markStackObjectsConservatively()
{
markCurrentThreadConservatively();
#if USE(MULTIPLE_THREADS)
for (Thread *thread = registeredThreads; thread != NULL; thread = thread->next) {
if (thread->posixThread != pthread_self()) {
markOtherThreadConservatively(thread);
}
}
#endif
}
typedef HashCountedSet<JSCell *> ProtectCounts;
static ProtectCounts& protectedValues()
{
static ProtectCounts pv;
return pv;
}
void Collector::protect(JSValue *k)
{
assert(k);
assert(JSLock::lockCount() > 0);
if (JSImmediate::isImmediate(k))
return;
protectedValues().add(k->asCell());
}
void Collector::unprotect(JSValue *k)
{
assert(k);
assert(JSLock::lockCount() > 0);
if (JSImmediate::isImmediate(k))
return;
protectedValues().remove(k->asCell());
}
void Collector::markProtectedObjects()
{
ProtectCounts& pv = protectedValues();
ProtectCounts::iterator end = pv.end();
for (ProtectCounts::iterator it = pv.begin(); it != end; ++it) {
JSCell *val = it->first;
if (!val->marked())
val->mark();
}
}
bool Collector::collect()
{
assert(JSLock::lockCount() > 0);
#if USE(MULTIPLE_THREADS)
bool currentThreadIsMainThread = pthread_main_np();
#else
bool currentThreadIsMainThread = true;
#endif
Interpreter::markSourceCachedObjects();
if (Interpreter::s_hook) {
Interpreter* scr = Interpreter::s_hook;
do {
scr->mark(currentThreadIsMainThread);
scr = scr->next;
} while (scr != Interpreter::s_hook);
}
// MARK: first mark all referenced objects recursively starting out from the set of root objects
markStackObjectsConservatively();
markProtectedObjects();
List::markProtectedLists();
#if USE(MULTIPLE_THREADS)
if (!currentThreadIsMainThread)
markMainThreadOnlyObjects();
#endif
// SWEEP: delete everything with a zero refcount (garbage) and unmark everything else
// Note: if a cell has zeroIfFree == 0, it is either free,
// or in the middle of being constructed and has not yet
// had its vtable filled. Hence, such cells should not be cleaned up
size_t emptyBlocks = 0;
size_t numLiveObjects = heap.numLiveObjects;
for (size_t block = 0; block < heap.blocks.used(); block++) {
CollectorBlock *curBlock = heap.blocks[block];
size_t usedCells = curBlock->usedCells;
CollectorCell *freeList = curBlock->freeList;
if (usedCells == CELLS_PER_BLOCK) {
// special case with a block where all cells are used -- testing indicates this happens often
for (size_t i = 0; i < CELLS_PER_BLOCK; i++) {
CollectorCell *cell = curBlock->cells + i;
JSCell *imp = reinterpret_cast<JSCell *>(cell);
if (!curBlock->marked.get(i) && currentThreadIsMainThread) {
// special case for allocated but uninitialized object
// (We don't need this check earlier because nothing prior this point assumes the object has a valid vptr.)
if (cell->u.freeCell.zeroIfFree == 0)
continue;
imp->~JSCell();
--usedCells;
--numLiveObjects;
// put cell on the free list
cell->u.freeCell.zeroIfFree = 0;
cell->u.freeCell.next = reinterpret_cast<char *>(freeList) - reinterpret_cast<char *>(cell + 1);
freeList = cell;
}
}
} else {
size_t minimumCellsToProcess = usedCells;
for (size_t i = 0; (i < minimumCellsToProcess) & (i < CELLS_PER_BLOCK); i++) {
CollectorCell *cell = curBlock->cells + i;
if (cell->u.freeCell.zeroIfFree == 0) {
++minimumCellsToProcess;
} else {
JSCell *imp = reinterpret_cast<JSCell *>(cell);
if (!curBlock->marked.get(i) && currentThreadIsMainThread) {
imp->~JSCell();
--usedCells;
--numLiveObjects;
// put cell on the free list
cell->u.freeCell.zeroIfFree = 0;
cell->u.freeCell.next = reinterpret_cast<char *>(freeList) - reinterpret_cast<char *>(cell + 1);
freeList = cell;
}
}
}
}
curBlock->marked.clearAll();
curBlock->usedCells = usedCells;
curBlock->freeList = freeList;
if (usedCells == 0) {
emptyBlocks++;
if (emptyBlocks > SPARE_EMPTY_BLOCKS) {
#if !DEBUG_COLLECTOR
freeBlock(curBlock);
#endif
// swap with the last block so we compact as we go
heap.blocks.m_data[block] = heap.blocks[heap.blocks.used() - 1];
heap.blocks.m_used--;
block--; // Don't move forward a step in this case
}
}
}
if (heap.numLiveObjects != numLiveObjects)
heap.firstBlockWithPossibleSpace = 0;
// Now sweep oversize blocks.
emptyBlocks = 0;
for (size_t ob = 0; ob < heap.oversizeBlocks.used(); ++ob) {
CollectorBlock* curBlock = heap.oversizeBlocks[ob];
CollectorCell *freeList = curBlock->freeList;
size_t usedCells = curBlock->usedCells;
// Go through the cells
for (size_t i = 0; i < CELLS_PER_BLOCK; i++) {
if (i % 32 == 0 && curBlock->allocd.bits[i/32] == 0) {
// Nothing used around here, skip this and 31 next cells
i += 31;
continue;
}
CollectorCell *cell = curBlock->cells + i;
if (cell->u.freeCell.zeroIfFree == 0)
continue;
if (!curBlock->allocd.get(i))
continue;
JSCell *imp = reinterpret_cast<JSCell *>(cell);
// Live and trailer cells will all have the mark set,
// so we only have to collect with it clear --
// and we already took care of those that are
// already free (or being initialized) above
if (!curBlock->marked.get(i)) {
// Free this block...
imp->~JSCell();
--numLiveObjects;
--usedCells;
// Mark the block and the trailers as available
cell->u.freeCell.zeroIfFree = 0;
curBlock->allocd.clear(i);
++i; // Go to the potential trailer..
while (curBlock->trailer.get(i) && i < CELLS_PER_BLOCK) {
--usedCells;
curBlock->allocd.clear(i);
curBlock->trailer.clear(i);
curBlock->marked.clear (i);
curBlock->cells[i].u.freeCell.zeroIfFree = 0;
++i;
}
--i; // Last item we processed.
} else {
// If this is not a trailer cell, clear the mark
if (!curBlock->trailer.get(i))
curBlock->marked.clear(i);
}
} // each cell
curBlock->usedCells = usedCells;
curBlock->freeList = freeList;
if (usedCells == 0) {
emptyBlocks++;
if (emptyBlocks > SPARE_EMPTY_BLOCKS) {
freeBlock(curBlock);
// swap with the last block so we compact as we go
heap.oversizeBlocks.m_data[ob] = heap.oversizeBlocks[heap.oversizeBlocks.used() - 1];
heap.oversizeBlocks.m_used--;
ob--; // Don't move forward a step in this case
}
}
} // each oversize block
bool deleted = heap.numLiveObjects != numLiveObjects;
heap.numLiveObjects = numLiveObjects;
heap.numLiveObjectsAtLastCollect = numLiveObjects;
heap.extraCost = 0;
bool newMemoryFull = (numLiveObjects >= KJS_MEM_LIMIT);
if (newMemoryFull && newMemoryFull != memoryFull)
reportOutOfMemoryToAllInterpreters();
memoryFull = newMemoryFull;
return deleted;
}
size_t Collector::size()
{
return heap.numLiveObjects;
}
#ifdef KJS_DEBUG_MEM
void Collector::finalCheck()
{
}
#endif
size_t Collector::numInterpreters()
{
size_t count = 0;
if (Interpreter::s_hook) {
Interpreter* scr = Interpreter::s_hook;
do {
++count;
scr = scr->next;
} while (scr != Interpreter::s_hook);
}
return count;
}
size_t Collector::numProtectedObjects()
{
return protectedValues().size();
}
static const char *typeName(JSCell *val)
{
const char *name = "???";
switch (val->type()) {
case UnspecifiedType:
break;
case UndefinedType:
name = "undefined";
break;
case NullType:
name = "null";
break;
case BooleanType:
name = "boolean";
break;
case StringType:
name = "string";
break;
case NumberType:
name = "number";
break;
case ObjectType: {
const ClassInfo *info = static_cast<JSObject *>(val)->classInfo();
name = info ? info->className : "Object";
break;
}
case GetterSetterType:
name = "gettersetter";
break;
}
return name;
}
HashCountedSet<const char*>* Collector::rootObjectTypeCounts()
{
HashCountedSet<const char*>* counts = new HashCountedSet<const char*>;
ProtectCounts& pv = protectedValues();
ProtectCounts::iterator end = pv.end();
for (ProtectCounts::iterator it = pv.begin(); it != end; ++it)
counts->add(typeName(it->first));
return counts;
}
void Collector::reportOutOfMemoryToAllInterpreters()
{
if (!Interpreter::s_hook)
return;
Interpreter* interpreter = Interpreter::s_hook;
do {
ExecState* exec = interpreter->execState();
exec->setException(Error::create(exec, GeneralError, "Out of memory"));
interpreter = interpreter->next;
} while(interpreter != Interpreter::s_hook);
}
} // namespace KJS

View file

@ -1,192 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
* Copyright (C) 2007 Maksim Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef KJSCOLLECTOR_H_
#define KJSCOLLECTOR_H_
#include <wtf/HashCountedSet.h>
#include <cstring>
#include <cstddef>
#define KJS_MEM_LIMIT 500000
namespace KJS {
class JSCell;
class JSValue;
class CollectorBlock;
/**
* @short Garbage collector.
*/
class KJS_EXPORT Collector {
// disallow direct construction/destruction
Collector();
public:
/**
* Register an object with the collector. The following assumptions are
* made:
* @li the operator new() of the object class is overloaded.
* @li operator delete() has been overloaded as well and does not free
* the memory on its own.
*
* @param s Size of the memory to be registered.
* @return A pointer to the allocated memory.
*/
static void* allocate(size_t s);
/**
* Run the garbage collection. This involves calling the delete operator
* on each object and freeing the used memory.
*/
static bool collect();
static const size_t minExtraCostSize = 256;
static void reportExtraMemoryCost(size_t cost);
static size_t size();
static bool isOutOfMemory() { return memoryFull; }
#ifdef KJS_DEBUG_MEM
/**
* Check that nothing is left when the last interpreter gets deleted
*/
static void finalCheck();
#endif
static void protect(JSValue *);
static void unprotect(JSValue *);
static size_t numInterpreters();
static size_t numProtectedObjects();
static HashCountedSet<const char*>* rootObjectTypeCounts();
class Thread;
static void registerThread();
static bool isCellMarked(const JSCell*);
static void markCell(JSCell*);
private:
static const CollectorBlock* cellBlock(const JSCell*);
static CollectorBlock* cellBlock(JSCell*);
static size_t cellOffset(const JSCell*);
static void recordExtraCost(size_t);
static void markProtectedObjects();
static void markCurrentThreadConservatively();
static void markOtherThreadConservatively(Thread*);
static void markStackObjectsConservatively();
static void markStackObjectsConservatively(void *start, void *end);
static bool memoryFull;
static void reportOutOfMemoryToAllInterpreters();
};
// tunable parameters
template<size_t bytesPerWord> struct CellSize;
// cell size needs to be a power of two for certain optimizations in collector.cpp
// below also assume it's divisible by 8, and that block size is divisible by it
template<> struct CellSize<4> { static const size_t m_value = 32; }; // 32-bit
template<> struct CellSize<8> { static const size_t m_value = 64; }; // 64-bit
const size_t BLOCK_SIZE = 16 * 4096; // 64k
const size_t BLOCK_OFFSET_MASK = BLOCK_SIZE - 1;
const size_t BLOCK_MASK = ~BLOCK_OFFSET_MASK;
const size_t CELL_SIZE = CellSize<sizeof(void*)>::m_value;
const size_t CELL_ARRAY_LENGTH = (CELL_SIZE / sizeof(double));
const size_t CELL_MASK = CELL_SIZE - 1;
// For each block, we can have at /most/ BLOCK_SIZE/CELL_SIZE entries.
// Sice the bitmap accordingly, don't try to be fancy
const size_t BITMAP_SIZE = (BLOCK_SIZE / CELL_SIZE + 7) / 8;
const size_t BITMAP_WORDS = (BITMAP_SIZE + 3) / sizeof(uint32_t);
// In each block, we have 3 bitmaps (mark for all blocks, extension + allocd for oversize cell blocks),
// as well as an int and a pointer
const size_t BLOCK_METADATA_SIZE = 3 * 4 * BITMAP_WORDS + sizeof(uint32_t) + sizeof(void*);
const size_t CELLS_PER_BLOCK = (BLOCK_SIZE - BLOCK_METADATA_SIZE) / CELL_SIZE;
struct CollectorBitmap {
uint32_t bits[BITMAP_WORDS];
bool get(size_t n) const { return !!(bits[n >> 5] & (1 << (n & 0x1F))); }
void set(size_t n) { bits[n >> 5] |= (1 << (n & 0x1F)); }
void clear(size_t n) { bits[n >> 5] &= ~(1 << (n & 0x1F)); }
void clearAll() { std::memset(bits, 0, sizeof(bits)); }
};
struct CollectorCell {
union {
double memory[CELL_ARRAY_LENGTH];
struct {
void* zeroIfFree;
ptrdiff_t next;
} freeCell;
} u;
};
class CollectorBlock {
public:
CollectorCell cells[CELLS_PER_BLOCK];
uint32_t usedCells;
CollectorCell* freeList;
CollectorBitmap marked;
CollectorBitmap allocd;
CollectorBitmap trailer;
};
inline const CollectorBlock* Collector::cellBlock(const JSCell* cell)
{
return reinterpret_cast<const CollectorBlock*>(reinterpret_cast<uintptr_t>(cell) & BLOCK_MASK);
}
inline CollectorBlock* Collector::cellBlock(JSCell* cell)
{
return const_cast<CollectorBlock*>(cellBlock(const_cast<const JSCell*>(cell)));
}
inline size_t Collector::cellOffset(const JSCell* cell)
{
return (reinterpret_cast<uintptr_t>(cell) & BLOCK_OFFSET_MASK) / CELL_SIZE;
}
inline bool Collector::isCellMarked(const JSCell* cell)
{
return cellBlock(cell)->marked.get(cellOffset(cell));
}
inline void Collector::markCell(JSCell* cell)
{
cellBlock(cell)->marked.set(cellOffset(cell));
}
inline void Collector::reportExtraMemoryCost(size_t cost)
{
if (cost > minExtraCostSize)
recordExtraCost(cost / (CELL_SIZE * 2));
}
}
#endif /* _KJSCOLLECTOR_H_ */

View file

@ -1,83 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2003 Apple Computer, Inc.
* Copyright (C) 2012 Bernd Buschinski (b.buschinski@googlemail.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef COMMONUNICODE_H_
#define COMMONUNICODE_H_
namespace KJS {
namespace CommonUnicode {
inline bool isLineTerminator(unsigned short c)
{
switch (c) {
case 0x000A: // LINE FEED
case 0x000D: // CARRIAGE RETURN
case 0x2028: // LINE SEPARATOR
case 0x2029: // PARAGRAPH SEPARATOR
return true;
default:
return false;
}
}
inline bool isWhiteSpace(unsigned short c)
{
switch (c) {
case 0x0009:
case 0x000B:
case 0x000C:
// Unicode category Zs
case 0x0020: // SPACE
case 0x00A0: // NO-BREAK SPACE
case 0x1680: // OGHAM SPACE MARK
case 0x180E: // MONGOLIAN VOWEL SEPARATOR
case 0x2000: // EN QUAD
case 0x2001: // EM QUAD
case 0x2002: // EN SPACE
case 0x2003: // EM SPACE
case 0x2004: // THREE-PER-EM SPACE
case 0x2005: // FOUR-PER-EM SPACE
case 0x2006: // SIX-PER-EM SPACE
case 0x2007: // FIGURE SPACE
case 0x2008: // PUNCTUATION SPACE
case 0x2009: // THIN SPACE
case 0x200A: // HAIR SPACE
case 0x202F: // NARROW NO-BREAK SPACE
case 0x205F: // MEDIUM MATHEMATICAL SPACE
case 0x3000: // IDEOGRAPHIC SPACE
// Unicode Byte-Order-Mark, Ecmascript 5.1r6 - 7.2
case 0xFEFF: // ZERO WIDTH NO-BREAK SPACE, BOM
return true;
default:
return false;
}
}
inline bool isStrWhiteSpace(unsigned short c)
{
return isWhiteSpace(c) || isLineTerminator(c);
}
} //namespace CommonUnicode
} //namespace KJS
#endif //COMMONUNICODE_H_

View file

@ -1,85 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2003 Apple Computer, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef _KJS_COMPLETION_H_
#define _KJS_COMPLETION_H_
#include "CommonIdentifiers.h"
namespace KJS {
typedef unsigned Addr; // ### should there be some separare types h?
class Node;
class JSValue;
/**
* Completion types.
*/
enum ComplType { Normal, Break, Continue, ReturnValue, Throw, Interrupted };
/**
* Completion objects are used to convey the return status and value
* from functions.
*
* See FunctionImp::execute()
*
* @see FunctionImp
*
* @short Handle for a Completion type.
*/
class KJS_EXPORT Completion {
public:
explicit Completion(ComplType c = Normal, JSValue *v = NULL, Addr t = 0 )
: comp(c), val(v), tar(t) { }
/**
* Returns the type of this completion.
*/
ComplType complType() const { return comp; }
/**
* Returns the value of this completion if it is of type
* value-completion, 0 otherwise.
*/
JSValue *value() const { return val; }
/**
* Returns the address a break or a continue statement targets
*/
Addr target() const { return tar; }
/**
* Returns true if this is a value completion, false otherwise.
*/
bool isValueCompletion() const { return !!val; }
private:
ComplType comp;
JSValue *val;
Addr tar;
};
}
#endif

View file

@ -1,38 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2002 David Faure (faure@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "../config.h"
#cmakedefine HAVE_PTHREAD_ATTR_GET_NP 1
#cmakedefine HAVE_PTHREAD_GETATTR_NP 1
#cmakedefine HAVE_PCREPOSIX 1
#cmakedefine HAVE_SYS_TIMEB_H 1
#cmakedefine HAVE_FLOAT_H 1
#cmakedefine HAVE_IEEEFP_H 1
#cmakedefine HAVE_PTHREAD_NP_H 1
#cmakedefine HAVE_MEMCHECK_H 1
#cmakedefine HAVE_FUNC__FINITE 1
#cmakedefine HAVE_FUNC_FINITE 1
#cmakedefine HAVE_FUNC_ISINF 1
#cmakedefine HAVE_FUNC_ISNAN 1
#cmakedefine HAVE_FUNC_POSIX_MEMALIGN 1
/* Defined to 1 if you have a tm_gmtoff member in struct tm */
#cmakedefine HAVE_TM_GMTOFF 1

View file

@ -1 +0,0 @@
#include <ExecState.h>

View file

@ -1,274 +0,0 @@
#! /usr/bin/perl -w
#
# Static Hashtable Generator
#
# (c) 2000-2002 by Harri Porten <porten@kde.org> and
# David Faure <faure@kde.org>
# Modified (c) 2004 by Nikolas Zimmermann <wildfox@kde.org>
#
# Part of the KJS library.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
use strict;
my $file = $ARGV[0];
shift;
my $findSize = 0;
my $includelookup = 0;
my $useNameSpace;
# Use -s as second argument to make it try many hash sizes
if (defined($ARGV[0]) && $ARGV[0] eq "-s") { $findSize = 1; shift; }
# Use -i as second argument to make it include "lookup.h"
if (defined($ARGV[0]) && $ARGV[0] eq "-i") { $includelookup = 1; shift; }
# Use -n as second argument to make it use the third argument as namespace parameter ie. -n KDOM
if (defined($ARGV[0]) && $ARGV[0] eq "-n") { $useNameSpace = $ARGV[1]; shift; shift; }
open(IN, $file) or die "No such file $file";
my @keys = ();
my @values = ();
my @attrs = ();
my @params = ();
my @hashes = ();
my @table = ();
my @links = ();
my $inside = 0;
my $name;
my $size;
my $hashsize;
my $banner = 0;
sub calcTable();
sub output();
sub hashValue($);
while (<IN>) {
chop;
s/^\s*//g;
if (/^\#|^$/) {
# comment. do nothing
} elsif (/^\@begin/ && !$inside) {
if (/^\@begin\s*([:_\w]+)\s*(\d+)\s*$/) {
$inside = 1;
$name = $1;
$hashsize = $2;
} else {
printf STDERR "WARNING: \@begin without table name and hashsize, skipping $_\n";
}
} elsif (/^\@end\s*$/ && $inside) {
if($findSize) {
my $entriesnum=@keys;
print STDERR "Table: $name $entriesnum entries\n";
for( my $i=3 ; $i<79 ; ++$i) { $hashsize=$i ; calcTable(); }
} else {
calcTable();
}
output();
@keys = ();
@values = ();
@attrs = ();
@params = ();
@table = ();
@links = ();
@hashes = ();
$inside = 0;
} elsif (/^(\S+)\s*(\S+)\s*([\w\|]*)\s*(\w*)\s*$/ && $inside) {
my $key = $1;
my $val = $2;
my $att = $3;
my $param = $4;
push(@keys, $key);
push(@values, $val);
push(@hashes, hashValue($key));
printf STDERR "WARNING: Number of arguments missing for $key/$val\n"
if ( $att =~ m/Function/ && length($param) == 0);
push(@attrs, length($att) > 0 ? $att : "0");
push(@params, length($param) > 0 ? $param : "0");
} elsif ($inside) {
die "invalid data {" . $_ . "}";
}
}
die "missing closing \@end" if ($inside);
sub calcTable() {
$size = $hashsize;
my $collisions = 0;
my $maxdepth = 0;
my $i = 0;
foreach my $key (@keys) {
my $depth = 0;
my $h = hashValue($key) % $hashsize;
while (defined($table[$h])) {
if (defined($links[$h])) {
$h = $links[$h];
$depth++;
} else {
$collisions++;
$links[$h] = $size;
$h = $size;
$size++;
}
}
#print STDERR "table[$h] = $i\n";
$table[$h] = $i;
$i++;
$maxdepth = $depth if ( $depth > $maxdepth);
}
# Ensure table is big enough (in case of undef entries at the end)
if ( $#table+1 < $size ) {
$#table = $size-1;
}
#print STDERR "After loop: size=$size table=".($#table+1)."\n";
if ($findSize) {
my $emptycount = 0;
foreach my $entry (@table) {
$emptycount++ if (!defined($entry));
}
print STDERR "Hashsize: $hashsize Total Size: $size Empty: $emptycount MaxDepth: $maxdepth Collisions: $collisions\n";
}
# my $debugtable = 0;
# foreach my $entry (@table) {
# print STDERR "$debugtable " . (defined $entry ? $entry : '<undefined>');
# print STDERR " -> " . $links[$debugtable] if (defined($links[$debugtable]));
# print STDERR "\n";
# $debugtable++;
# }
}
sub leftShift($$) {
my ($value, $distance) = @_;
return (($value << $distance) & 0xFFFFFFFF);
}
# Paul Hsieh's SuperFastHash
# http://www.azillionmonkeys.com/qed/hash.html
# Ported from UString..
sub hashValue($) {
my @chars = split(/ */, $_[0]);
# This hash is designed to work on 16-bit chunks at a time. But since the normal case
# (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
# were 16-bit chunks, which should give matching results
my $EXP2_32 = 4294967296;
my $hash = 0x9e3779b9;
my $l = scalar @chars; #I wish this was in Ruby --- Maks
my $rem = $l & 1;
$l = $l >> 1;
my $s = 0;
# Main loop
for (; $l > 0; $l--) {
$hash += ord($chars[$s]);
my $tmp = leftShift(ord($chars[$s+1]), 11) ^ $hash;
$hash = (leftShift($hash, 16)% $EXP2_32) ^ $tmp;
$s += 2;
$hash += $hash >> 11;
$hash %= $EXP2_32;
}
# Handle end case
if ($rem !=0) {
$hash += ord($chars[$s]);
$hash ^= (leftShift($hash, 11)% $EXP2_32);
$hash += $hash >> 17;
}
# Force "avalanching" of final 127 bits
$hash ^= leftShift($hash, 3);
$hash += ($hash >> 5);
$hash = ($hash% $EXP2_32);
$hash ^= (leftShift($hash, 2)% $EXP2_32);
$hash += ($hash >> 15);
$hash = $hash% $EXP2_32;
$hash ^= (leftShift($hash, 10)% $EXP2_32);
# this avoids ever returning a hash code of 0, since that is used to
# signal "hash not computed yet", using a value that is likely to be
# effectively the same as 0 when the low bits are masked
$hash = 0x80000000 if ($hash == 0);
return $hash;
}
sub output() {
if (!$banner) {
$banner = 1;
print "/* Automatically generated from $file using $0. DO NOT EDIT ! */\n";
}
my $nameEntries = "${name}Entries";
$nameEntries =~ s/:/_/g;
print "\n#include \"lookup.h\"\n" if ($includelookup);
if ($useNameSpace) {
print "\nnamespace ${useNameSpace}\n{\n";
} else {
print "\nnamespace KJS {\n";
}
print "\nstatic const struct KJS::HashEntry ".$nameEntries."[] = {\n";
my $i = 0;
#print STDERR "writing out table with ".($#table+1)." entries\n";
if ($hashsize eq 0) {
# To make the hash table lookup code fast, we don't allow tables of size 0.
# That way it can do a modulo by the size without a special case to avoid division by 0.
print " \{ 0, 0, 0, 0, 0 \}\n";
$hashsize = 1;
$size = 1;
} else {
foreach my $entry (@table) {
if (defined($entry)) {
my $key = $keys[$entry];
print " \{ \"" . $key . "\"";
print ", " . $values[$entry];
my $kjsattrs = $attrs[$entry];
if ($kjsattrs ne "0") {
$kjsattrs =~ s/([^|]+)/KJS::$1/g; # DontDelete|Function -> KJS::DontDelete|KJS::Function
}
print ", " . $kjsattrs;
print ", " . $params[$entry];
print ", ";
if (defined($links[$i])) {
print "&" . $nameEntries . "[" . $links[$i] . "]" . " \}";
} else {
print "0 \}"
}
print "/* " . $hashes[$entry] . " */ ";
} else {
print " \{ 0, 0, 0, 0, 0 \}";
}
print "," unless ($i == $size - 1);
print "\n";
$i++;
}
}
print "};\n\n";
print "const struct KJS::HashTable $name = ";
print "\{ 2, $size, ".$nameEntries.", $hashsize \};\n\n";
print "} // namespace\n";
}

View file

@ -1,16 +0,0 @@
#!/bin/sh
#
# A replacement for the make parser target until someone figures out
# how to do that in CMake.
#
bison -d -p kjsyy grammar.y && mv grammar.tab.c grammar.cpp;
if test -f grammar.tab.h;
then
if cmp -s grammar.tab.h grammar.h; then rm -f grammar.tab.h;
else mv grammar.tab.h grammar.h;
fi
else :;
fi

File diff suppressed because it is too large Load diff

View file

@ -1,109 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef DATE_OBJECT_H
#define DATE_OBJECT_H
#include "function.h"
#include "JSWrapperObject.h"
struct tm;
namespace KJS {
class FunctionPrototype;
class ObjectPrototype;
class DateInstance : public JSWrapperObject {
public:
DateInstance(JSObject *proto);
bool getTime(tm &t, int &gmtoffset) const;
bool getUTCTime(tm &t) const;
bool getTime(double &ms, int &gmtoffset) const;
bool getUTCTime(double &ms) const;
virtual const ClassInfo *classInfo() const { return &info; }
static const ClassInfo info;
virtual JSObject* valueClone(Interpreter* targetCtx) const;
};
/**
* @internal
*
* The initial value of Date.prototype (and thus all objects created
* with the Date constructor
*/
class DatePrototype : public DateInstance {
public:
DatePrototype(ExecState *, ObjectPrototype *);
using KJS::JSObject::getOwnPropertySlot;
virtual bool getOwnPropertySlot(ExecState *, const Identifier &, PropertySlot&);
virtual const ClassInfo *classInfo() const { return &info; }
static const ClassInfo info;
};
/**
* @internal
*
* Class to implement all methods that are properties of the
* Date.prototype object
*/
class DateProtoFunc : public InternalFunctionImp {
public:
DateProtoFunc(ExecState *, int i, int len, const Identifier& date);
virtual JSValue *callAsFunction(ExecState *, JSObject *thisObj, const List &args);
enum { ToString, ToDateString, ToTimeString, ToLocaleString,
ToLocaleDateString, ToLocaleTimeString, ValueOf, GetTime,
GetFullYear, GetMonth, GetDate, GetDay, GetHours, GetMinutes,
GetSeconds, GetMilliSeconds, GetTimezoneOffset, SetTime,
SetMilliSeconds, SetSeconds, SetMinutes, SetHours, SetDate,
SetMonth, SetFullYear, ToUTCString, ToISOString, ToJSON,
// non-normative properties (Appendix B)
GetYear, SetYear, ToGMTString };
private:
short id;
bool utc;
};
/**
* @internal
*
* The initial value of the global variable's "Date" property
*/
class DateObjectImp : public InternalFunctionImp {
using InternalFunctionImp::construct;
public:
DateObjectImp(ExecState *, FunctionPrototype *, DatePrototype *);
virtual bool implementsConstruct() const;
virtual JSObject *construct(ExecState *, const List &args);
virtual JSValue *callAsFunction(ExecState *, JSObject *thisObj, const List &args);
Completion execute(const List &);
JSObject *construct(const List &);
};
} // namespace
#endif

View file

@ -1,162 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "debugger.h"
#include "nodes.h"
#include <config-kjs.h>
#include "ustring.h"
#include "internal.h"
using namespace KJS;
// ------------------------------ Debugger -------------------------------------
namespace KJS {
struct AttachedInterpreter
{
AttachedInterpreter(Interpreter *i, AttachedInterpreter *ai) : interp(i), next(ai) { ++Debugger::debuggersPresent; }
~AttachedInterpreter() { --Debugger::debuggersPresent; }
Interpreter *interp;
AttachedInterpreter *next;
};
}
int Debugger::debuggersPresent = 0;
Debugger::Debugger()
{
lastLineRan = 0;
rep = new DebuggerImp();
lastSourceParsed = -1;
}
Debugger::~Debugger()
{
detach(0);
delete rep;
}
void Debugger::attach(Interpreter* interp)
{
Debugger *other = interp->debugger();
if (other == this)
return;
if (other)
other->detach(interp);
interp->setDebugger(this);
rep->interps = new AttachedInterpreter(interp, rep->interps);
}
void Debugger::detach(Interpreter* interp)
{
// iterate the addresses where AttachedInterpreter pointers are stored
// so we can unlink items from the list
AttachedInterpreter **p = &rep->interps;
AttachedInterpreter *q;
while ((q = *p)) {
if (!interp || q->interp == interp) {
*p = q->next;
q->interp->setDebugger(0);
delete q;
} else
p = &q->next;
}
if (interp)
latestExceptions.remove(interp);
else
latestExceptions.clear();
}
bool Debugger::hasHandledException(ExecState *exec, JSValue *exception)
{
if (latestExceptions.get(exec->dynamicInterpreter()).get() == exception)
return true;
latestExceptions.set(exec->dynamicInterpreter(), exception);
return false;
}
bool Debugger::sourceParsed(ExecState * /*exec*/, int /*sourceId*/, const UString &/*sourceURL*/,
const UString &/*source*/, int /*startingLineNumber*/, int /*errorLine*/, const UString & /*errorMsg*/)
{
return true;
}
bool Debugger::exception(ExecState * /*exec*/, int /*sourceId*/, int /*lineno*/,
JSValue * /*exception*/)
{
return true;
}
bool Debugger::atStatement(ExecState * /*exec*/, int /*sourceId*/, int /*firstLine*/,
int /*lastLine*/)
{
return true;
}
void Debugger::reportAtStatement(ExecState *exec, int sourceId, int firstLine, int lastLine)
{
lastLineRan = firstLine;
atStatement(exec, sourceId, firstLine, lastLine);
}
void Debugger::reportException(ExecState *exec, JSValue *exceptionVal)
{
if (!hasHandledException(exec, exceptionVal))
exception(exec, exec->currentBody() ? exec->currentBody()->sourceId() : lastSourceParsed, lastLineRan, exceptionVal);
}
bool Debugger::enterContext(ExecState * /*exec*/, int /*sourceId*/, int /*lineno*/,
JSObject * /*function*/, const List & /*args*/)
{
return true;
}
bool Debugger::exitContext(ExecState * /*exec*/, int /*sourceId*/, int /*lineno*/,
JSObject * /*function*/)
{
return true;
}
bool Debugger::shouldReindentSources() const
{
return false;
}
bool Debugger::shouldReportCaught() const
{
return false;
}
void Debugger::reportSourceParsed(ExecState *exec, FunctionBodyNode *body,
int sourceId, UString sourceURL, const UString &source,
int startingLineNumber, int errorLine, const UString &errorMsg)
{
lastSourceParsed = sourceId;
UString code = source;
if (shouldReindentSources() && body)
code = body->reindent(startingLineNumber);
sourceParsed(exec, sourceId, sourceURL, code, startingLineNumber, errorLine, errorMsg);
}

View file

@ -1,240 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef _KJSDEBUGGER_H_
#define _KJSDEBUGGER_H_
#include "global.h"
#include <wtf/HashMap.h>
#include "protect.h"
namespace KJS {
class DebuggerImp;
class Interpreter;
class ExecState;
class JSObject;
class JSValue;
class UString;
class List;
class FunctionBodyNode;
/**
* @internal
*
* Provides an interface which receives notification about various
* script-execution related events such as statement execution and function
* calls.
*
* WARNING: This interface is still a work in progress and is not yet
* officially publicly available. It is likely to change in binary incompatible
* (and possibly source incompatible) ways in future versions. It is
* anticipated that at some stage the interface will be frozen and made
* available for general use.
*/
class KJS_EXPORT Debugger {
public:
/**
* Creates a new debugger
*/
Debugger();
/**
* Destroys the debugger. If the debugger is attached to any interpreters,
* it is automatically detached.
*/
virtual ~Debugger();
DebuggerImp *imp() const { return rep; }
/**
* Attaches the debugger to specified interpreter. This will cause this
* object to receive notification of events from the interpreter.
*
* If the interpreter is deleted, the debugger will automatically be
* detached.
*
* Note: only one debugger can be attached to an interpreter at a time.
* Attaching another debugger to the same interpreter will cause the
* original debugger to be detached from that interpreter.
*
* @param interp The interpreter to attach to
*
* @see detach()
*/
virtual void attach(Interpreter *interp);
/**
* Detach the debugger from an interpreter
*
* @param interp The interpreter to detach from. If 0, the debugger will be
* detached from all interpreters to which it is attached.
*
* @see attach()
*/
virtual void detach(Interpreter *interp);
/**
* Called to notify the debugger that some javascript source code has
* been parsed. For calls to Interpreter::evaluate(), this will be called
* with the supplied source code before any other code is parsed.
* Other situations in which this may be called include creation of a
* function using the Function() constructor, or the eval() function.
*
* The default implementation does nothing. Override this method if
* you want to process this event.
*
* @param exec The current execution state
* @param sourceId The ID of the source code (corresponds to the
* sourceId supplied in other functions such as atStatement()
* @param sourceURL Where the source code that was parsed came from
* @param source The source code that was parsed
* @param startingLineNumber The line number at which parsing started
* @param errorLine The line number at which parsing encountered an
* error, or -1 if the source code was valid and parsed successfully
* @param errorMsg The error description, or null if the source code
was valid and parsed successfully
* @return true if execution should be continue, false if it should
* be aborted
*/
virtual bool sourceParsed(ExecState *exec, int sourceId, const UString &sourceURL,
const UString &source, int startingLineNumber, int errorLine, const UString &errorMsg);
/**
* Called when an exception is thrown during script execution.
*
* The default implementation does nothing. Override this method if
* you want to process this event.
*
* @param exec The current execution state
* @param sourceId The ID of the source code being executed
* @param lineno The line at which the error occurred
* @param exception The exception object
* @return true if execution should be continue, false if it should
* be aborted
*/
virtual bool exception(ExecState *exec, int sourceId, int lineno,
JSValue *exception);
bool hasHandledException(ExecState *, JSValue *);
/**
* Called when a line of the script is reached (before it is executed)
*
* The default implementation does nothing. Override this method if
* you want to process this event.
*
* @param exec The current execution state
* @param sourceId The ID of the source code being executed
* @param firstLine The starting line of the statement that is about to be
* executed
* @param lastLine The ending line of the statement that is about to be
* executed (usually the same as firstLine)
* @return true if execution should be continue, false if it should
* be aborted
*/
virtual bool atStatement(ExecState *exec, int sourceId, int firstLine,
int lastLine);
/**
* Called when the interpreter enters a new execution context (stack
* frame). This can happen in three situations:
*
* <ul>
* <li>A call to Interpreter::evaluate(). This has a codeType of
* GlobalCode </li>
* <li>A call to the builtin eval() function. The sourceId corresponds to
* the code passed in to eval. This has a codeType of EvalCode. The
* lineno here is always 0 since execution starts at the beginning of
* the script.</li>
* <li>A function call. This only occurs for functions defined in
* ECMAScript code, whether via the normal function() { ... } syntax or
* a call to the built-in Function() constructor (anonymous functions).
* In the former case, the sourceId and lineno indicate the location at
* which the function was defined. For anonymous functions, the sourceId
* corresponds to the code passed into the Function() constructor.</li>
* </ul>
*
* enterContext() is not called for functions implemented in the native
* code, since these do not use an execution context.
*
* @param exec The current execution state (corresponding to the new stack)
* @param sourceId The ID of the source code being executed
* @param lineno The line that is about to be executed
* @param function The function being called. 0 in non-function context.
* @param args The arguments that were passed to the function
* line is being executed. Empty in non-function contexts.
*
* @return true if execution should be continued, false if it should
* be aborted
*/
virtual bool enterContext(ExecState *exec, int sourceId, int lineno,
JSObject *function, const List &args);
/**
* Called when the inteprreter exits an execution context. This always
* corresponds to a previous call to enterContext()
*
* The default implementation does nothing. Override this method if
* you want to process this event.
*
* @param exec The current execution state
* @param sourceId The ID of the source code being executed
* @param lineno The line that is about to be executed
* @param function The function being returned from, if there is one
* @return true if execution should be continue, false if it should
* be aborted
*/
virtual bool exitContext(ExecState *exec, int sourceId, int lineno,
JSObject *function);
// Override this and return true if you want the debugger to report
// pretty-printed versions of the source.
virtual bool shouldReindentSources() const;
// Override this to return true if the debugger should report
// exceptions even if there is a try block waiting for it.
virtual bool shouldReportCaught() const;
// The two methods below call the events but also keep track/use of line # information
// so we can associate it with exceptions
void reportAtStatement(ExecState *exec, int sourceId, int firstLine, int lastLine);
void reportException (ExecState *exec, JSValue *exception);
// This notifies the debugger of source being parsed, reindenting it if need be.
void reportSourceParsed(ExecState *exec, FunctionBodyNode *body, int sourceId, UString sourceURL,
const UString &source, int startingLineNumber, int errorLine, const UString &errorMsg);
private:
DebuggerImp *rep;
HashMap<Interpreter*, ProtectedPtr<JSValue> > latestExceptions;
int lastLineRan;
int lastSourceParsed; // Needed for attributing syntax exceptions at top-level
public:
static int debuggersPresent;
};
}
#endif
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

File diff suppressed because it is too large Load diff

View file

@ -1,31 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 2003 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef _KJS_DTOA_H_
#define _KJS_DTOA_H_
extern "C" double kjs_strtod(const char *s00, char **se);
extern "C" char *kjs_dtoa(double d, int mode, int ndigits,
int *decpt, int *sign, char **rve);
extern "C" void kjs_freedtoa(char *s);
#endif /* _KJS_DTOA_H */

View file

@ -1,175 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2003 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "error_object.h"
#include <config-kjs.h>
#include "value.h"
#include "object.h"
#include "types.h"
#include "interpreter.h"
#include "operations.h"
//#include "debugger.h"
using namespace KJS;
// ------------------------------ ErrorInstance ----------------------------
const ClassInfo ErrorInstance::info = {"Error", 0, 0, 0};
ErrorInstance::ErrorInstance(JSObject *proto)
: JSObject(proto)
{
}
// ------------------------------ ErrorPrototype ----------------------------
// ECMA 15.9.4
ErrorPrototype::ErrorPrototype(ExecState* exec,
ObjectPrototype* objectProto,
FunctionPrototype* funcProto)
: ErrorInstance(objectProto)
{
// Interpreter::initGlobalObject sets the constructor property
// on the prototypes for this and the native error types
put(exec, exec->propertyNames().name, jsString("Error"), DontEnum);
// ECMA Edition 5.1r6 - 15.11.4.3
// The initial value of Error.prototype.message is the empty String.
put(exec, exec->propertyNames().message, jsString(""), DontEnum);
putDirectFunction(new ErrorProtoFunc(exec, funcProto, exec->propertyNames().toString), DontEnum);
}
// ------------------------------ ErrorProtoFunc ----------------------------
ErrorProtoFunc::ErrorProtoFunc(ExecState* exec, FunctionPrototype* funcProto, const Identifier& name)
: InternalFunctionImp(funcProto, name)
{
putDirect(exec->propertyNames().length, jsNumber(0), DontDelete|ReadOnly|DontEnum);
}
JSValue* ErrorProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, const List &/*args*/)
{
// toString()
UString name;
JSValue* v = thisObj->get(exec, exec->propertyNames().name);
if (!v->isUndefined())
name = v->toString(exec);
else
name = "Error";
UString message;
v = thisObj->get(exec, exec->propertyNames().message);
if (!v->isUndefined())
message = v->toString(exec);
if (name.isEmpty())
return jsString(message);
if (message.isEmpty())
return jsString(name);
return jsString(name + ": " + message);
}
// ------------------------------ ErrorObjectImp -------------------------------
ErrorObjectImp::ErrorObjectImp(ExecState* exec, FunctionPrototype* funcProto, ErrorPrototype* errorProto)
: InternalFunctionImp(funcProto)
{
// ECMA 15.11.3.1 Error.prototype
putDirect(exec->propertyNames().prototype, errorProto, DontEnum|DontDelete|ReadOnly);
putDirect(exec->propertyNames().length, jsNumber(1), DontDelete|ReadOnly|DontEnum);
//putDirect(namePropertyName, jsString(n));
}
bool ErrorObjectImp::implementsConstruct() const
{
return true;
}
// ECMA 15.9.3
JSObject* ErrorObjectImp::construct(ExecState* exec, const List& args)
{
JSObject* proto = static_cast<JSObject*>(exec->lexicalInterpreter()->builtinErrorPrototype());
JSObject* imp = new ErrorInstance(proto);
JSObject* obj(imp);
if (!args[0]->isUndefined())
imp->putDirect(exec->propertyNames().message, jsString(args[0]->toString(exec)));
return obj;
}
// ECMA 15.9.2
JSValue* ErrorObjectImp::callAsFunction(ExecState* exec, JSObject* /*thisObj*/, const List &args)
{
// "Error()" gives the sames result as "new Error()"
return construct(exec, args);
}
// ------------------------------ NativeErrorPrototype ----------------------
NativeErrorPrototype::NativeErrorPrototype(ExecState* exec, ErrorPrototype* errorProto, ErrorType et, UString name, UString message)
: JSObject(errorProto)
{
errType = et;
putDirect(exec->propertyNames().name, jsString(name), 0);
putDirect(exec->propertyNames().message, jsString(message), 0);
}
// ------------------------------ NativeErrorImp -------------------------------
const ClassInfo NativeErrorImp::info = {"Function", &InternalFunctionImp::info, 0, 0};
NativeErrorImp::NativeErrorImp(ExecState* exec, FunctionPrototype* funcProto, JSObject* prot)
: InternalFunctionImp(funcProto)
, proto(prot)
{
putDirect(exec->propertyNames().length, jsNumber(1), DontDelete|ReadOnly|DontEnum); // ECMA 15.11.7.5
putDirect(exec->propertyNames().prototype, proto, DontDelete|ReadOnly|DontEnum);
}
bool NativeErrorImp::implementsConstruct() const
{
return true;
}
JSObject* NativeErrorImp::construct(ExecState* exec, const List& args)
{
JSObject* imp = new ErrorInstance(proto);
JSObject* obj(imp);
if (!args[0]->isUndefined())
imp->putDirect(exec->propertyNames().message, jsString(args[0]->toString(exec)));
return obj;
}
JSValue* NativeErrorImp::callAsFunction(ExecState* exec, JSObject*, const List& args)
{
return construct(exec, args);
}
void NativeErrorImp::mark()
{
InternalFunctionImp::mark();
if (proto && !proto->marked())
proto->mark();
}

View file

@ -1,90 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef ERROR_OBJECT_H_
#define ERROR_OBJECT_H_
#include "function_object.h"
namespace KJS {
class ErrorInstance : public JSObject {
public:
ErrorInstance(JSObject *proto);
virtual const ClassInfo *classInfo() const { return &info; }
static const ClassInfo info;
};
class ErrorPrototype : public ErrorInstance {
public:
ErrorPrototype(ExecState *exec,
ObjectPrototype *objectProto,
FunctionPrototype *funcProto);
};
class ErrorProtoFunc : public InternalFunctionImp {
public:
ErrorProtoFunc(ExecState*, FunctionPrototype*, const Identifier&);
virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);
};
class ErrorObjectImp : public InternalFunctionImp {
public:
ErrorObjectImp(ExecState *exec, FunctionPrototype *funcProto,
ErrorPrototype *errorProto);
virtual bool implementsConstruct() const;
using KJS::JSObject::construct;
virtual JSObject *construct(ExecState *exec, const List &args);
virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);
};
class NativeErrorPrototype : public JSObject {
public:
NativeErrorPrototype(ExecState *exec, ErrorPrototype *errorProto,
ErrorType et, UString name, UString message);
private:
ErrorType errType;
};
class NativeErrorImp : public InternalFunctionImp {
public:
NativeErrorImp(ExecState *exec, FunctionPrototype *funcProto,
JSObject *prot);
virtual bool implementsConstruct() const;
using KJS::JSObject::construct;
virtual JSObject *construct(ExecState *exec, const List &args);
virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);
virtual void mark();
virtual const ClassInfo *classInfo() const { return &info; }
static const ClassInfo info;
private:
JSObject *proto;
};
} // namespace
#endif

View file

@ -1,87 +0,0 @@
/*
* Copyright (C) 2003, 2006 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*/
#include <math.h>
#include "global.h"
namespace KJS {
// This file exists because JavaScriptCore needs to define the NaN and Inf globals in a way
// that does not use a static initializer so we don't have a framework initialization routine.
// The trick is to define the NaN and Inf globals with a different type than the declaration.
// This trick works because the mangled name of the globals does not include the type, although
// I'm not sure that's guaranteed. There could be alignment issues with this, since arrays of
// characters don't necessarily need the same alignment doubles do, but for now it seems to work.
// It would be good to figure out a 100% clean way that still avoids code that runs at init time.
#if (defined(AVOID_STATIC_CONSTRUCTORS) && !AVOID_STATIC_CONSTRUCTORS)
KJS_EXPORT extern const double NaN = NAN;
KJS_EXPORT extern const double Inf = INFINITY;
#elif PLATFORM(DARWIN)
#if PLATFORM(BIG_ENDIAN)
KJS_EXPORT extern const unsigned char NaN[sizeof(double)] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 };
KJS_EXPORT extern const unsigned char Inf[sizeof(double)] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 };
#elif PLATFORM(MIDDLE_ENDIAN)
KJS_EXPORT extern const unsigned char NaN[] = { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 };
KJS_EXPORT extern const unsigned char Inf[] = { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 };
#else
KJS_EXPORT extern const unsigned char NaN[sizeof(double)] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f };
KJS_EXPORT extern const unsigned char Inf[sizeof(double)] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f };
#endif // PLATFORM(MIDDLE_ENDIAN)
#else // !PLATFORM(DARWIN)
// Note, we have to use union to ensure alignment. Otherwise, NaN_Bytes can start anywhere,
// while NaN_double has to be 4-byte aligned for 32-bits.
// With -fstrict-aliasing enabled, unions are the only safe way to do type masquerading.
static const union {
struct {
unsigned char NaN_Bytes[8];
unsigned char Inf_Bytes[8];
} bytes;
struct {
double NaN_Double;
double Inf_Double;
} doubles;
} NaNInf = { {
#if PLATFORM(BIG_ENDIAN)
{ 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 },
{ 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }
#elif PLATFORM(MIDDLE_ENDIAN)
{ 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 },
{ 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 }
#else
{ 0, 0, 0, 0, 0, 0, 0xf8, 0x7f },
{ 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }
#endif
} } ;
KJS_EXPORT extern const double NaN = NaNInf.doubles.NaN_Double;
KJS_EXPORT extern const double Inf = NaNInf.doubles.Inf_Double;
#endif // !PLATFORM(DARWIN)
} // namespace KJS

File diff suppressed because it is too large Load diff

View file

@ -1,235 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
* Copyright (C) 2007, 2008 Maksim Orlovich <maksim@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef KJS_FUNCTION_H
#define KJS_FUNCTION_H
#include "SymbolTable.h"
#include "LocalStorage.h"
#include "JSVariableObject.h"
#include "object.h"
#include <wtf/OwnPtr.h>
namespace KJS {
class ActivationImp;
class FunctionPrototype;
class KJS_EXPORT InternalFunctionImp : public JSObject {
public:
InternalFunctionImp();
InternalFunctionImp(FunctionPrototype*);
InternalFunctionImp(FunctionPrototype*, const Identifier&);
virtual bool implementsCall() const;
virtual JSValue* callAsFunction(ExecState*, JSObject* thisObjec, const List& args) = 0;
virtual bool implementsHasInstance() const;
virtual const ClassInfo* classInfo() const { return &info; }
static const ClassInfo info;
const Identifier& functionName() const { return m_name; }
void setFunctionName(const Identifier& name) { m_name = name; }
private:
Identifier m_name;
#ifdef WIN32
InternalFunctionImp(const InternalFunctionImp&);
InternalFunctionImp& operator=(const InternalFunctionImp&);
#endif
};
/**
* A minimal object that just throws an exception if executed.
*/
class Thrower : public JSObject {
public:
Thrower(ErrorType type);
virtual JSValue *callAsFunction(ExecState* exec, JSObject*, const List& args);
virtual bool implementsCall() const { return true; };
private:
ErrorType m_type;
};
class BoundFunction : public InternalFunctionImp {
public:
explicit BoundFunction(ExecState* exec, JSObject* targetFunction, JSObject* boundThis, List boundArgs);
void setTargetFunction(JSObject* targetFunction);
void setBoundThis(JSObject* boundThis);
void setBoundArgs(const List& boundArgs);
virtual JSValue *callAsFunction(ExecState* exec, JSObject* thisObj, const List& extraArgs);
virtual bool implementsCall() const { return true; };
using KJS::JSObject::construct;
virtual JSObject* construct(ExecState* exec, const List& extraArgs);
virtual bool implementsConstruct() const { return true; };
virtual bool hasInstance(ExecState *exec, JSValue *value);
virtual bool implementsHasInstance() const { return true; };
private:
ProtectedPtr<JSObject> m_targetFunction;
ProtectedPtr<JSObject> m_boundThis;
List m_boundArgs;
};
/**
* @internal
*
* The initial value of Function.prototype (and thus all objects created
* with the Function constructor)
*/
class FunctionPrototype : public InternalFunctionImp {
public:
FunctionPrototype(ExecState *exec);
virtual ~FunctionPrototype();
virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);
};
class IndexToNameMap {
public:
IndexToNameMap(FunctionImp *func, const List &args);
~IndexToNameMap();
Identifier& operator[](int index);
Identifier& operator[](const Identifier &indexIdentifier);
bool isMapped(const Identifier &index) const;
void unMap(const Identifier &index);
int size() const;
private:
IndexToNameMap(); // prevent construction w/o parameters
int _size;
Identifier * _map;
};
class Arguments : public JSObject {
public:
Arguments(ExecState *exec, FunctionImp *func, const List &args, ActivationImp *act);
virtual void mark();
using KJS::JSObject::getOwnPropertySlot;
virtual bool getOwnPropertySlot(ExecState *, const Identifier &, PropertySlot&);
using KJS::JSObject::put;
virtual void put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr = None);
using KJS::JSObject::deleteProperty;
virtual bool deleteProperty(ExecState *exec, const Identifier &propertyName);
virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, PropertyMap::PropertyMode mode);
virtual bool defineOwnProperty(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& desc, bool shouldThrow);
virtual const ClassInfo *classInfo() const { return &info; }
static const ClassInfo info;
private:
static JSValue *mappedIndexGetter(ExecState *exec, JSObject *, const Identifier &, const PropertySlot& slot);
ActivationImp *_activationObject;
mutable IndexToNameMap indexToNameMap;
};
class ActivationImp : public JSVariableObject {
public:
enum {
FunctionSlot = NumVarObjectSlots,
ArgumentsObjectSlot,
NumReservedSlots = ArgumentsObjectSlot + 1
};
void setup(ExecState* exec, FunctionImp *function, const List* arguments,
LocalStorageEntry* stackSpace);
// Request that this activation be torn off when the code using it stops running
void requestTearOff();
void performTearOff();
using KJS::JSObject::getOwnPropertySlot;
virtual bool getOwnPropertySlot(ExecState *exec, const Identifier &, PropertySlot&);
using KJS::JSObject::put;
virtual void put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr = None);
using KJS::JSObject::deleteProperty;
virtual bool deleteProperty(ExecState *exec, const Identifier &propertyName);
virtual void putDirect(const Identifier &propertyName, JSValue *value, int attr = 0);
using JSObject::putDirect;
virtual JSValue *getDirect(const Identifier& propertyName) const;
virtual bool getPropertyAttributes(const Identifier& propertyName, unsigned& attributes) const;
bool isLocalReadOnly(int propertyID) const {
return (localStorage[propertyID].attributes & ReadOnly) == ReadOnly;
}
virtual const ClassInfo *classInfo() const { return &info; }
static const ClassInfo info;
virtual bool isActivation() const { return true; }
void setupLocals(FunctionBodyNode* fbody);
void setupFunctionLocals(FunctionBodyNode* fbody, ExecState *exec);
const List& passedInArguments() const { return *arguments; }
// really FunctionImp, but type isn't declared yet
JSValue* function() { return functionSlot(); }
private:
JSValue*& functionSlot() {
return localStorage[FunctionSlot].val.valueVal;
}
JSValue*& argumentsObjectSlot() {
return localStorage[ArgumentsObjectSlot].val.valueVal;
}
static PropertySlot::GetValueFunc getArgumentsGetter();
static JSValue *argumentsGetter(ExecState *exec, JSObject *, const Identifier &, const PropertySlot& slot);
void createArgumentsObject(ExecState *exec);
int numLocals() const { return lengthSlot(); }
bool validLocal(int id) const { return 0 <= id && id < numLocals(); }
const List* arguments;
};
class GlobalFuncImp : public InternalFunctionImp {
public:
GlobalFuncImp(ExecState*, FunctionPrototype*, int i, int len, const Identifier&);
virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);
enum { Eval, ParseInt, ParseFloat, IsNaN, IsFinite, Escape, UnEscape,
DecodeURI, DecodeURIComponent, EncodeURI, EncodeURIComponent
#ifndef NDEBUG
, KJSPrint
#endif
};
private:
int id;
};
static const double mantissaOverflowLowerBound = 9007199254740992.0;
double parseIntOverflow(const char* s, int length, int radix);
double parseInt(const UString &s, int radix);
double parseFloat(const UString &s);
} // namespace
#endif

View file

@ -1,307 +0,0 @@
// -*- c-basic-offset: 2 -*-
// krazy:excludeall=doublequote_chars (UStrings aren't QStrings)
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "function_object.h"
#include <config-kjs.h>
#include "internal.h"
#include "function.h"
#include "scriptfunction.h"
#include "array_object.h"
#include "nodes.h"
#include "lexer.h"
#include "debugger.h"
#include "object.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
using namespace KJS;
// ------------------------------ FunctionPrototype -------------------------
FunctionPrototype::FunctionPrototype(ExecState *exec)
{
static const Identifier* applyPropertyName = new Identifier("apply");
static const Identifier* callPropertyName = new Identifier("call");
static const Identifier* bindPropertyName = new Identifier("bind");
putDirect(exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
putDirectFunction(new FunctionProtoFunc(exec, this, FunctionProtoFunc::ToString, 0, exec->propertyNames().toString), DontEnum);
putDirectFunction(new FunctionProtoFunc(exec, this, FunctionProtoFunc::Apply, 2, *applyPropertyName), DontEnum);
putDirectFunction(new FunctionProtoFunc(exec, this, FunctionProtoFunc::Call, 1, *callPropertyName), DontEnum);
putDirectFunction(new FunctionProtoFunc(exec, this, FunctionProtoFunc::Bind, 1, *bindPropertyName), DontEnum);
}
FunctionPrototype::~FunctionPrototype()
{
}
// ECMA 15.3.4
JSValue *FunctionPrototype::callAsFunction(ExecState * /*exec*/, JSObject * /*thisObj*/, const List &/*args*/)
{
return jsUndefined();
}
// ------------------------------ FunctionProtoFunc -------------------------
FunctionProtoFunc::FunctionProtoFunc(ExecState* exec, FunctionPrototype* funcProto, int i, int len, const Identifier& name)
: InternalFunctionImp(funcProto, name)
, id(i)
{
putDirect(exec->propertyNames().length, len, DontDelete | ReadOnly | DontEnum);
}
JSValue* FunctionProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, const List &args)
{
JSValue* result = NULL;
switch (id) {
case ToString:
if (!thisObj || !thisObj->inherits(&InternalFunctionImp::info)) {
#ifndef NDEBUG
fprintf(stderr,"attempted toString() call on null or non-function object\n");
#endif
return throwError(exec, TypeError);
}
if (thisObj->inherits(&FunctionImp::info)) {
return jsString(static_cast<FunctionImp*>(thisObj)->toSource());
} else if (thisObj->inherits(&InternalFunctionImp::info) &&
!static_cast<InternalFunctionImp*>(thisObj)->functionName().isNull()) {
result = jsString("\nfunction " + static_cast<InternalFunctionImp*>(thisObj)->functionName().ustring() + "() {\n"
" [native code]\n}\n");
} else {
result = jsString("[function]");
}
break;
case Apply: {
JSValue *thisArg = args[0];
JSValue *argArray = args[1];
JSObject *func = thisObj;
if (!func->implementsCall())
return throwError(exec, TypeError);
JSObject *applyThis;
if (thisArg->isUndefinedOrNull())
applyThis = exec->dynamicInterpreter()->globalObject();
else
applyThis = thisArg->toObject(exec);
List applyArgs;
if (!argArray->isUndefinedOrNull()) {
if (argArray->isObject() &&
(static_cast<JSObject *>(argArray)->inherits(&ArrayInstance::info) ||
static_cast<JSObject *>(argArray)->inherits(&Arguments::info))) {
JSObject *argArrayObj = static_cast<JSObject *>(argArray);
unsigned int length = argArrayObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
for (unsigned int i = 0; i < length; i++)
applyArgs.append(argArrayObj->get(exec,i));
}
else
return throwError(exec, TypeError);
}
result = func->call(exec,applyThis,applyArgs);
}
break;
case Call: {
JSValue *thisArg = args[0];
JSObject *func = thisObj;
if (!func->implementsCall())
return throwError(exec, TypeError);
JSObject *callThis;
if (thisArg->isUndefinedOrNull())
callThis = exec->dynamicInterpreter()->globalObject();
else
callThis = thisArg->toObject(exec);
result = func->call(exec,callThis,args.copyTail());
}
break;
case Bind: { //ECMA Edition 5.1r6 - 15.3.4.5
JSObject* target(thisObj);
if (!target->implementsCall())
return throwError(exec, TypeError, "object is not callable");
List newArgs;
for (int i = 1; i < args.size(); ++i)
newArgs.append(args[i]);
JSObject* boundThis = 0;
// As call does not accept JSValue(undefined/null),
// do it like in call and use the global object
if (args[0]->isUndefinedOrNull())
boundThis = exec->dynamicInterpreter()->globalObject();
else
boundThis = args[0]->toObject(exec);
BoundFunction* bfunc = new BoundFunction(exec, target, boundThis, newArgs);
unsigned length;
if (target->inherits(&FunctionImp::info)) {
double L = target->get(exec, exec->propertyNames().length)->getNumber() - newArgs.size();
length = (unsigned)std::max<int>((int)L, 0);
} else {
length = 0;
}
bfunc->put(exec, exec->propertyNames().length, jsNumber(length), ReadOnly|DontEnum|DontDelete);
JSObject *thrower = new Thrower(TypeError);
PropertyDescriptor callerDesc;
GetterSetterImp* gs = new GetterSetterImp();
gs->setGetter(thrower);
gs->setSetter(thrower);
callerDesc.setPropertyDescriptorValues(exec, gs, DontEnum|DontDelete);
bfunc->defineOwnProperty(exec, exec->propertyNames().caller, callerDesc, false);
PropertyDescriptor argumentsDesc;
argumentsDesc.setPropertyDescriptorValues(exec, gs, DontEnum|DontDelete);
bfunc->defineOwnProperty(exec, exec->propertyNames().arguments, argumentsDesc, false);
return bfunc;
}
break;
}
return result;
}
// ------------------------------ FunctionObjectImp ----------------------------
FunctionObjectImp::FunctionObjectImp(ExecState* exec, FunctionPrototype* funcProto)
: InternalFunctionImp(funcProto)
{
putDirect(exec->propertyNames().prototype, funcProto, DontEnum|DontDelete|ReadOnly);
// no. of arguments for constructor
putDirect(exec->propertyNames().length, jsNumber(1), ReadOnly|DontDelete|DontEnum);
}
FunctionObjectImp::~FunctionObjectImp()
{
}
bool FunctionObjectImp::implementsConstruct() const
{
return true;
}
// ECMA 15.3.2 The Function Constructor
JSObject* FunctionObjectImp::construct(ExecState* exec, const List& args, const Identifier& functionName, const UString& sourceURL, int lineNumber)
{
UString p("");
UString body;
int argsSize = args.size();
if (argsSize == 0) {
body = "";
} else if (argsSize == 1) {
body = args[0]->toString(exec);
} else {
p = args[0]->toString(exec);
for (int k = 1; k < argsSize - 1; k++)
p += "," + args[k]->toString(exec);
body = args[argsSize-1]->toString(exec);
}
// parse the source code
int sourceId;
int errLine;
UString errMsg;
RefPtr<FunctionBodyNode> functionBody = parser().parseFunctionBody(sourceURL, lineNumber, body.data(), body.size(), &sourceId, &errLine, &errMsg);
// notify debugger that source has been parsed
Debugger *dbg = exec->dynamicInterpreter()->debugger();
if (dbg) {
// make sure to pass in sourceURL, since it's useful for lazy event listeners, and empty for actual function ctor
dbg->reportSourceParsed(exec, functionBody.get(), sourceId, sourceURL, body, lineNumber, errLine, errMsg);
}
// no program node == syntax error - throw a syntax error
if (!functionBody)
// we can't return a Completion(Throw) here, so just set the exception
// and return it
return throwError(exec, SyntaxError, errMsg, errLine, sourceId, sourceURL);
ScopeChain scopeChain;
scopeChain.push(exec->lexicalInterpreter()->globalObject());
FunctionImp* fimp = new FunctionImp(exec, functionName, functionBody.get(), scopeChain);
// parse parameter list. throw syntax error on illegal identifiers
int len = p.size();
const UChar *c = p.data();
int i = 0, params = 0;
UString param;
while (i < len) {
while (*c == ' ' && i < len)
c++, i++;
if (Lexer::isIdentStart(c->uc)) { // else error
param = UString(c, 1);
c++, i++;
while (i < len && (Lexer::isIdentPart(c->uc))) {
param += UString(c, 1);
c++, i++;
}
while (i < len && *c == ' ')
c++, i++;
if (i == len) {
functionBody->addParam(Identifier(param));
params++;
break;
} else if (*c == ',') {
functionBody->addParam(Identifier(param));
params++;
c++, i++;
continue;
} // else error
}
return throwError(exec, SyntaxError, "Syntax error in parameter list");
}
List consArgs;
JSObject* objCons = exec->lexicalInterpreter()->builtinObject();
JSObject* prototype = objCons->construct(exec,List::empty());
prototype->put(exec, exec->propertyNames().constructor, fimp, DontEnum|DontDelete|ReadOnly);
// ECMA Edition 5.1r6 - 15.3.5.2 - [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false
fimp->put(exec, exec->propertyNames().prototype, prototype, Internal|DontDelete|DontEnum);
return fimp;
}
// ECMA 15.3.2 The Function Constructor
JSObject* FunctionObjectImp::construct(ExecState* exec, const List& args)
{
return construct(exec, args, "anonymous", UString(), 0);
}
// ECMA 15.3.1 The Function Constructor Called as a Function
JSValue* FunctionObjectImp::callAsFunction(ExecState* exec, JSObject* /*thisObj*/, const List &args)
{
return construct(exec, args);
}

View file

@ -1,66 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2006 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef FUNCTION_OBJECT_H_
#define FUNCTION_OBJECT_H_
#include "object_object.h"
#include "function.h"
namespace KJS {
/**
* @internal
*
* Class to implement all methods that are properties of the
* Function.prototype object
*/
class FunctionProtoFunc : public InternalFunctionImp {
public:
FunctionProtoFunc(ExecState*, FunctionPrototype*, int i, int len, const Identifier&);
virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);
enum { ToString, Apply, Call, Bind };
private:
int id;
};
/**
* @internal
*
* The initial value of the global variable's "Function" property
*/
class FunctionObjectImp : public InternalFunctionImp {
public:
FunctionObjectImp(ExecState*, FunctionPrototype*);
virtual ~FunctionObjectImp();
virtual bool implementsConstruct() const;
virtual JSObject* construct(ExecState*, const List& args);
virtual JSObject* construct(ExecState*, const List& args, const Identifier& functionName, const UString& sourceURL, int lineNumber);
virtual JSValue* callAsFunction(ExecState*, JSObject* thisObj, const List& args);
};
} // namespace
#endif // _FUNCTION_OBJECT_H_

View file

@ -1,92 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 2002 David Faure (faure@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef KJS_GLOBAL_H
#define KJS_GLOBAL_H
#include <wtf/Platform.h>
// we don't want any padding between UChars (ARM processor)
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
#define KJS_PACKED __attribute__((__packed__))
#else
#define KJS_PACKED
#endif
#if defined(_MSC_VER)
#pragma warning(disable: 4355)
#endif
#cmakedefine __KDE_HAVE_GCC_VISIBILITY
#ifndef KJS_EXPORT
# ifdef __KDE_HAVE_GCC_VISIBILITY
# define KJS_EXPORT __attribute__ ((visibility("default")))
# elif defined(_WIN32) || defined(_WIN64)
# ifdef MAKE_KJS_LIB
# define KJS_EXPORT __declspec(dllexport)
# else
# define KJS_EXPORT __declspec(dllimport)
# endif
# else
# define KJS_EXPORT
# endif
#endif
// some methods are declared inside kjs and defined outside (currently only in khtml)
// KJS_EXTERNAL_EXPORT should be prefixed to each related method
#ifndef KJS_EXTERNAL_EXPORT
# if defined(MAKE_KJS_LIB)
# define KJS_EXTERNAL_EXPORT
# elif (defined(_WIN32) || defined(_WIN64)) && defined(__GNUC__)
# if defined(MAKE_KHTML_LIB) || defined(MAKE_KJSEMBED_LIB) || defined(MAKE_KATEPART_LIB)
# define KJS_EXTERNAL_EXPORT __declspec(dllexport)
# else
# define KJS_EXTERNAL_EXPORT
# endif
# else
# define KJS_EXTERNAL_EXPORT
# endif
#endif
#ifndef NDEBUG // protection against problems if committing with KJS_VERBOSE on
// Uncomment this to enable very verbose output from KJS
//#define KJS_VERBOSE
// Uncomment this to debug memory allocation and garbage collection
//#define KJS_DEBUG_MEM
#endif
// Apple feature which we don't use
#define KJS_MULTIPLE_THREADS 0
// Debugging features, turned off by default
#define DEBUG_COLLECTOR 0
#ifndef HAVE_STDINT_H
#cmakedefine HAVE_STDINT_H 1
#endif
/* Valgrind memcheck presence */
#cmakedefine HAVE_VALGRIND_MEMCHECK_H 1
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,186 +0,0 @@
/* A Bison parser, made by GNU Bison 2.7.12-4996. */
/* Bison interface for Yacc-like parsers in C
Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
#ifndef YY_KJSYY_GRAMMAR_TAB_H_INCLUDED
# define YY_KJSYY_GRAMMAR_TAB_H_INCLUDED
/* Enabling traces. */
#ifndef YYDEBUG
# define YYDEBUG 0
#endif
#if YYDEBUG
extern int kjsyydebug;
#endif
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
/* Put the tokens into the symbol table, so that GDB and other debuggers
know about them. */
enum yytokentype {
NULLTOKEN = 258,
TRUETOKEN = 259,
FALSETOKEN = 260,
BREAK = 261,
CASE = 262,
DEFAULT = 263,
FOR = 264,
NEW = 265,
VAR = 266,
CONSTTOKEN = 267,
CONTINUE = 268,
FUNCTION = 269,
RETURN = 270,
VOIDTOKEN = 271,
DELETETOKEN = 272,
IF = 273,
THISTOKEN = 274,
DO = 275,
WHILE = 276,
INTOKEN = 277,
INSTANCEOF = 278,
TYPEOF = 279,
SWITCH = 280,
WITH = 281,
RESERVED = 282,
THROW = 283,
TRY = 284,
CATCH = 285,
FINALLY = 286,
DEBUGGER = 287,
IMPORT = 288,
IF_WITHOUT_ELSE = 289,
ELSE = 290,
EQEQ = 291,
NE = 292,
STREQ = 293,
STRNEQ = 294,
LE = 295,
GE = 296,
OR = 297,
AND = 298,
PLUSPLUS = 299,
MINUSMINUS = 300,
LSHIFT = 301,
RSHIFT = 302,
URSHIFT = 303,
PLUSEQUAL = 304,
MINUSEQUAL = 305,
MULTEQUAL = 306,
DIVEQUAL = 307,
LSHIFTEQUAL = 308,
RSHIFTEQUAL = 309,
URSHIFTEQUAL = 310,
ANDEQUAL = 311,
MODEQUAL = 312,
XOREQUAL = 313,
OREQUAL = 314,
NUMBER = 315,
STRING = 316,
IDENT = 317,
AUTOPLUSPLUS = 318,
AUTOMINUSMINUS = 319
};
#endif
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
{
/* Line 2053 of yacc.c */
#line 64 "grammar.y"
int ival;
double dval;
UString *ustr;
Identifier *ident;
Node *node;
StatementNode *stat;
ParameterNode *param;
FunctionBodyNode *body;
FuncDeclNode *func;
FuncExprNode *funcExpr;
ProgramNode *prog;
AssignExprNode *init;
SourceElementsNode *srcs;
ArgumentsNode *args;
ArgumentListNode *alist;
VarDeclNode *decl;
VarDeclListNode *vlist;
CaseBlockNode *cblk;
ClauseListNode *clist;
CaseClauseNode *ccl;
ElementNode *elm;
Operator op;
PropertyListNode *plist;
PropertyNode *pnode;
PropertyNameNode *pname;
PackageNameNode *pkgn;
/* Line 2053 of yacc.c */
#line 151 "grammar.tab.h"
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
#endif
#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
typedef struct YYLTYPE
{
int first_line;
int first_column;
int last_line;
int last_column;
} YYLTYPE;
# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
# define YYLTYPE_IS_DECLARED 1
# define YYLTYPE_IS_TRIVIAL 1
#endif
extern YYSTYPE kjsyylval;
extern YYLTYPE kjsyylloc;
#ifdef YYPARSE_PARAM
#if defined __STDC__ || defined __cplusplus
int kjsyyparse (void *YYPARSE_PARAM);
#else
int kjsyyparse ();
#endif
#else /* ! YYPARSE_PARAM */
#if defined __STDC__ || defined __cplusplus
int kjsyyparse (void);
#else
int kjsyyparse ();
#endif
#endif /* ! YYPARSE_PARAM */
#endif /* !YY_KJSYY_GRAMMAR_TAB_H_INCLUDED */

View file

@ -1,942 +0,0 @@
%{
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <config-kjs.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "value.h"
#include "object.h"
#include "types.h"
#include "interpreter.h"
#include "nodes.h"
#include "makenodes.h"
#include "lexer.h"
#include "internal.h"
// Not sure why, but yacc doesn't add this define along with the others.
#define yylloc kjsyylloc
/* default values for bison */
#define YYDEBUG 0 // Set to 1 to debug a parse error.
#define kjsyydebug 0 // Set to 1 to debug a parse error.
#if !PLATFORM(DARWIN)
// avoid triggering warnings in older bison
#define YYERROR_VERBOSE
#endif
extern int kjsyylex();
int kjsyyerror(const char *);
static bool allowAutomaticSemicolon();
#define AUTO_SEMICOLON do { if (!allowAutomaticSemicolon()) YYABORT; } while (0)
#define DBG(l, s, e) (l)->setLoc((s).first_line, (e).last_line)
#ifndef __GNUC__
# define __attribute__(x)
#endif
using namespace KJS;
%}
%union {
int ival;
double dval;
UString *ustr;
Identifier *ident;
Node *node;
StatementNode *stat;
ParameterNode *param;
FunctionBodyNode *body;
FuncDeclNode *func;
FuncExprNode *funcExpr;
ProgramNode *prog;
AssignExprNode *init;
SourceElementsNode *srcs;
ArgumentsNode *args;
ArgumentListNode *alist;
VarDeclNode *decl;
VarDeclListNode *vlist;
CaseBlockNode *cblk;
ClauseListNode *clist;
CaseClauseNode *ccl;
ElementNode *elm;
Operator op;
PropertyListNode *plist;
PropertyNode *pnode;
PropertyNameNode *pname;
PackageNameNode *pkgn;
}
%start Program
/* literals */
%token NULLTOKEN TRUETOKEN FALSETOKEN
/* keywords */
%token BREAK CASE DEFAULT FOR NEW VAR CONSTTOKEN CONTINUE
%token FUNCTION RETURN VOIDTOKEN DELETETOKEN
%token IF THISTOKEN DO WHILE INTOKEN INSTANCEOF TYPEOF
%token SWITCH WITH RESERVED
%token THROW TRY CATCH FINALLY
%token DEBUGGER IMPORT
/* give an if without an else higher precedence than an else to resolve the ambiguity */
%nonassoc IF_WITHOUT_ELSE
%nonassoc ELSE
/* punctuators */
%token EQEQ NE /* == and != */
%token STREQ STRNEQ /* === and !== */
%token LE GE /* < and > */
%token OR AND /* || and && */
%token PLUSPLUS MINUSMINUS /* ++ and -- */
%token LSHIFT /* << */
%token RSHIFT URSHIFT /* >> and >>> */
%token PLUSEQUAL MINUSEQUAL /* += and -= */
%token MULTEQUAL DIVEQUAL /* *= and /= */
%token LSHIFTEQUAL /* <<= */
%token RSHIFTEQUAL URSHIFTEQUAL /* >>= and >>>= */
%token ANDEQUAL MODEQUAL /* &= and %= */
%token XOREQUAL OREQUAL /* ^= and |= */
/* terminal types */
%token <dval> NUMBER
%token <ustr> STRING
%token <ident> IDENT
/* automatically inserted semicolon */
%token AUTOPLUSPLUS AUTOMINUSMINUS
/* non-terminal types */
%type <node> Literal ArrayLiteral
%type <node> PrimaryExpr PrimaryExprNoBrace
%type <node> MemberExpr MemberExprNoBF /* BF => brace or function */
%type <node> NewExpr NewExprNoBF
%type <node> CallExpr CallExprNoBF
%type <node> LeftHandSideExpr LeftHandSideExprNoBF
%type <node> PostfixExpr PostfixExprNoBF
%type <node> UnaryExpr UnaryExprNoBF UnaryExprCommon
%type <node> MultiplicativeExpr MultiplicativeExprNoBF
%type <node> AdditiveExpr AdditiveExprNoBF
%type <node> ShiftExpr ShiftExprNoBF
%type <node> RelationalExpr RelationalExprNoIn RelationalExprNoBF
%type <node> EqualityExpr EqualityExprNoIn EqualityExprNoBF
%type <node> BitwiseANDExpr BitwiseANDExprNoIn BitwiseANDExprNoBF
%type <node> BitwiseXORExpr BitwiseXORExprNoIn BitwiseXORExprNoBF
%type <node> BitwiseORExpr BitwiseORExprNoIn BitwiseORExprNoBF
%type <node> LogicalANDExpr LogicalANDExprNoIn LogicalANDExprNoBF
%type <node> LogicalORExpr LogicalORExprNoIn LogicalORExprNoBF
%type <node> ConditionalExpr ConditionalExprNoIn ConditionalExprNoBF
%type <node> AssignmentExpr AssignmentExprNoIn AssignmentExprNoBF
%type <node> Expr ExprNoIn ExprNoBF
%type <node> ExprOpt ExprNoInOpt
%type <stat> Statement Block
%type <stat> VariableStatement ConstStatement EmptyStatement ExprStatement
%type <stat> IfStatement IterationStatement ContinueStatement
%type <stat> BreakStatement ReturnStatement WithStatement
%type <stat> SwitchStatement LabelledStatement
%type <stat> ThrowStatement TryStatement
%type <stat> DebuggerStatement ImportStatement
%type <stat> SourceElement
%type <init> Initializer InitializerNoIn
%type <func> FunctionDeclaration
%type <funcExpr> FunctionExpr
%type <body> FunctionBody
%type <srcs> SourceElements
%type <param> FormalParameterList
%type <op> AssignmentOperator
%type <args> Arguments
%type <alist> ArgumentList
%type <vlist> VariableDeclarationList VariableDeclarationListNoIn ConstDeclarationList
%type <decl> VariableDeclaration VariableDeclarationNoIn ConstDeclaration
%type <cblk> CaseBlock
%type <ccl> CaseClause DefaultClause
%type <clist> CaseClauses CaseClausesOpt
%type <ival> Elision ElisionOpt
%type <elm> ElementList
%type <pname> PropertyName
%type <pnode> Property
%type <plist> PropertyList
%type <pkgn> PackageName
%type <ident> Keywords
%type <ident> IdentifierName
%%
Keywords:
BREAK { $$ = new Identifier("break"); }
| CASE { $$ = new Identifier("case"); }
| DEFAULT { $$ = new Identifier("default"); }
| FOR { $$ = new Identifier("for"); }
| NEW { $$ = new Identifier("new"); }
| VAR { $$ = new Identifier("var"); }
| CONSTTOKEN { $$ = new Identifier("const"); }
| CONTINUE { $$ = new Identifier("continue"); }
| FUNCTION { $$ = new Identifier("function"); }
| RETURN { $$ = new Identifier("return"); }
| VOIDTOKEN { $$ = new Identifier("void"); }
| DELETETOKEN { $$ = new Identifier("delete"); }
| IF { $$ = new Identifier("if"); }
| THISTOKEN { $$ = new Identifier("this"); }
| DO { $$ = new Identifier("do"); }
| WHILE { $$ = new Identifier("while"); }
| INTOKEN { $$ = new Identifier("in"); }
| INSTANCEOF { $$ = new Identifier("instanceof"); }
| TYPEOF { $$ = new Identifier("typeof"); }
| SWITCH { $$ = new Identifier("switch"); }
| WITH { $$ = new Identifier("with"); }
| THROW { $$ = new Identifier("throw"); }
| TRY { $$ = new Identifier("try"); }
| CATCH { $$ = new Identifier("catch"); }
| FINALLY { $$ = new Identifier("finally"); }
| DEBUGGER { $$ = new Identifier("debugger"); }
| IMPORT { $$ = new Identifier("import"); }
| NULLTOKEN { $$ = new Identifier("null"); }
| TRUETOKEN { $$ = new Identifier("true"); }
| FALSETOKEN { $$ = new Identifier("false"); }
| ELSE { $$ = new Identifier("else"); }
;
IdentifierName:
IDENT { $$ = $1; }
| Keywords { $$ = $1; }
;
Literal:
NULLTOKEN { $$ = new NullNode(); }
| TRUETOKEN { $$ = new BooleanNode(true); }
| FALSETOKEN { $$ = new BooleanNode(false); }
| NUMBER { $$ = new NumberNode($1); }
| STRING { $$ = new StringNode($1); }
| '/' /* regexp */ {
Lexer& l = lexer();
if (!l.scanRegExp())
YYABORT;
$$ = new RegExpNode(l.pattern(), l.flags());
}
| DIVEQUAL /* regexp with /= */ {
Lexer& l = lexer();
if (!l.scanRegExp())
YYABORT;
$$ = new RegExpNode("=" + l.pattern(), l.flags());
}
;
PropertyName:
IdentifierName { $$ = new PropertyNameNode(*$1); }
| STRING { $$ = new PropertyNameNode(Identifier(*$1)); }
| NUMBER { $$ = new PropertyNameNode(Identifier(UString::from($1))); }
;
Property:
PropertyName ':' AssignmentExpr { $$ = new PropertyNode($1, $3, PropertyNode::Constant); }
| IDENT IdentifierName '(' ')' {inFuncExpr();} FunctionBody {
if (!makeGetterOrSetterPropertyNode($$, *$1, *$2, 0, $6))
YYABORT;
}
| IDENT IdentifierName '(' FormalParameterList ')' {inFuncExpr();} FunctionBody {
if (!makeGetterOrSetterPropertyNode($$, *$1, *$2, $4, $7))
YYABORT;
}
;
PropertyList:
Property { $$ = new PropertyListNode($1); }
| PropertyList ',' Property { $$ = new PropertyListNode($3, $1); }
;
PrimaryExpr:
PrimaryExprNoBrace
| '{' '}' { $$ = new ObjectLiteralNode(); }
| '{' PropertyList '}' { $$ = new ObjectLiteralNode($2); }
/* allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939 */
| '{' PropertyList ',' '}' { $$ = new ObjectLiteralNode($2); }
;
PrimaryExprNoBrace:
THISTOKEN { $$ = new ThisNode(); }
| Literal
| ArrayLiteral
| IDENT { $$ = new VarAccessNode(*$1); }
| '(' Expr ')' { $$ = makeGroupNode($2); }
;
ArrayLiteral:
'[' ElisionOpt ']' { $$ = new ArrayNode($2); }
| '[' ElementList ']' { $$ = new ArrayNode($2); }
| '[' ElementList ',' ElisionOpt ']' { $$ = new ArrayNode($4, $2); }
;
ElementList:
ElisionOpt AssignmentExpr { $$ = new ElementNode($1, $2); }
| ElementList ',' ElisionOpt AssignmentExpr
{ $$ = new ElementNode($1, $3, $4); }
;
ElisionOpt:
/* nothing */ { $$ = 0; }
| Elision
;
Elision:
',' { $$ = 1; }
| Elision ',' { $$ = $1 + 1; }
;
MemberExpr:
PrimaryExpr
| FunctionExpr { $$ = $1; }
| MemberExpr '[' Expr ']' { $$ = new BracketAccessorNode($1, $3); }
| MemberExpr '.' IdentifierName { $$ = new DotAccessorNode($1, *$3); }
| NEW MemberExpr Arguments { $$ = new NewExprNode($2, $3); }
;
MemberExprNoBF:
PrimaryExprNoBrace
| MemberExprNoBF '[' Expr ']' { $$ = new BracketAccessorNode($1, $3); }
| MemberExprNoBF '.' IdentifierName { $$ = new DotAccessorNode($1, *$3); }
| NEW MemberExpr Arguments { $$ = new NewExprNode($2, $3); }
;
NewExpr:
MemberExpr
| NEW NewExpr { $$ = new NewExprNode($2); }
;
NewExprNoBF:
MemberExprNoBF
| NEW NewExpr { $$ = new NewExprNode($2); }
;
CallExpr:
MemberExpr Arguments { $$ = makeFunctionCallNode($1, $2); }
| CallExpr Arguments { $$ = makeFunctionCallNode($1, $2); }
| CallExpr '[' Expr ']' { $$ = new BracketAccessorNode($1, $3); }
| CallExpr '.' IdentifierName { $$ = new DotAccessorNode($1, *$3); }
;
CallExprNoBF:
MemberExprNoBF Arguments { $$ = makeFunctionCallNode($1, $2); }
| CallExprNoBF Arguments { $$ = makeFunctionCallNode($1, $2); }
| CallExprNoBF '[' Expr ']' { $$ = new BracketAccessorNode($1, $3); }
| CallExprNoBF '.' IdentifierName { $$ = new DotAccessorNode($1, *$3); }
;
Arguments:
'(' ')' { $$ = new ArgumentsNode(); }
| '(' ArgumentList ')' { $$ = new ArgumentsNode($2); }
;
ArgumentList:
AssignmentExpr { $$ = new ArgumentListNode($1); }
| ArgumentList ',' AssignmentExpr { $$ = new ArgumentListNode($1, $3); }
;
LeftHandSideExpr:
NewExpr
| CallExpr
;
LeftHandSideExprNoBF:
NewExprNoBF
| CallExprNoBF
;
PostfixExpr:
LeftHandSideExpr
| LeftHandSideExpr PLUSPLUS { $$ = makePostfixNode($1, OpPlusPlus); }
| LeftHandSideExpr MINUSMINUS { $$ = makePostfixNode($1, OpMinusMinus); }
;
PostfixExprNoBF:
LeftHandSideExprNoBF
| LeftHandSideExprNoBF PLUSPLUS { $$ = makePostfixNode($1, OpPlusPlus); }
| LeftHandSideExprNoBF MINUSMINUS { $$ = makePostfixNode($1, OpMinusMinus); }
;
UnaryExprCommon:
DELETETOKEN UnaryExpr { $$ = makeDeleteNode($2); }
| VOIDTOKEN UnaryExpr { $$ = new VoidNode($2); }
| TYPEOF UnaryExpr { $$ = makeTypeOfNode($2); }
| PLUSPLUS UnaryExpr { $$ = makePrefixNode($2, OpPlusPlus); }
| AUTOPLUSPLUS UnaryExpr { $$ = makePrefixNode($2, OpPlusPlus); }
| MINUSMINUS UnaryExpr { $$ = makePrefixNode($2, OpMinusMinus); }
| AUTOMINUSMINUS UnaryExpr { $$ = makePrefixNode($2, OpMinusMinus); }
| '+' UnaryExpr { $$ = makeUnaryPlusNode($2); }
| '-' UnaryExpr { $$ = makeNegateNode($2); }
| '~' UnaryExpr { $$ = makeBitwiseNotNode($2); }
| '!' UnaryExpr { $$ = makeLogicalNotNode($2); }
UnaryExpr:
PostfixExpr
| UnaryExprCommon
;
UnaryExprNoBF:
PostfixExprNoBF
| UnaryExprCommon
;
MultiplicativeExpr:
UnaryExpr
| MultiplicativeExpr '*' UnaryExpr { $$ = makeMultNode($1, $3, OpMult); }
| MultiplicativeExpr '/' UnaryExpr { $$ = makeMultNode($1, $3, OpDiv); }
| MultiplicativeExpr '%' UnaryExpr { $$ = makeMultNode($1, $3, OpMod); }
;
MultiplicativeExprNoBF:
UnaryExprNoBF
| MultiplicativeExprNoBF '*' UnaryExpr
{ $$ = makeMultNode($1, $3, OpMult); }
| MultiplicativeExprNoBF '/' UnaryExpr
{ $$ = makeMultNode($1, $3, OpDiv); }
| MultiplicativeExprNoBF '%' UnaryExpr
{ $$ = makeMultNode($1, $3, OpMod); }
;
AdditiveExpr:
MultiplicativeExpr
| AdditiveExpr '+' MultiplicativeExpr { $$ = makeAddNode($1, $3, OpPlus); }
| AdditiveExpr '-' MultiplicativeExpr { $$ = makeAddNode($1, $3, OpMinus); }
;
AdditiveExprNoBF:
MultiplicativeExprNoBF
| AdditiveExprNoBF '+' MultiplicativeExpr
{ $$ = makeAddNode($1, $3, OpPlus); }
| AdditiveExprNoBF '-' MultiplicativeExpr
{ $$ = makeAddNode($1, $3, OpMinus); }
;
ShiftExpr:
AdditiveExpr
| ShiftExpr LSHIFT AdditiveExpr { $$ = makeShiftNode($1, $3, OpLShift); }
| ShiftExpr RSHIFT AdditiveExpr { $$ = makeShiftNode($1, $3, OpRShift); }
| ShiftExpr URSHIFT AdditiveExpr { $$ = makeShiftNode($1, $3, OpURShift); }
;
ShiftExprNoBF:
AdditiveExprNoBF
| ShiftExprNoBF LSHIFT AdditiveExpr { $$ = makeShiftNode($1, $3, OpLShift); }
| ShiftExprNoBF RSHIFT AdditiveExpr { $$ = makeShiftNode($1, $3, OpRShift); }
| ShiftExprNoBF URSHIFT AdditiveExpr { $$ = makeShiftNode($1, $3, OpURShift); }
;
RelationalExpr:
ShiftExpr
| RelationalExpr '<' ShiftExpr { $$ = makeRelationalNode($1, OpLess, $3); }
| RelationalExpr '>' ShiftExpr { $$ = makeRelationalNode($1, OpGreater, $3); }
| RelationalExpr LE ShiftExpr { $$ = makeRelationalNode($1, OpLessEq, $3); }
| RelationalExpr GE ShiftExpr { $$ = makeRelationalNode($1, OpGreaterEq, $3); }
| RelationalExpr INSTANCEOF ShiftExpr { $$ = makeRelationalNode($1, OpInstanceOf, $3); }
| RelationalExpr INTOKEN ShiftExpr { $$ = makeRelationalNode($1, OpIn, $3); }
;
RelationalExprNoIn:
ShiftExpr
| RelationalExprNoIn '<' ShiftExpr { $$ = makeRelationalNode($1, OpLess, $3); }
| RelationalExprNoIn '>' ShiftExpr { $$ = makeRelationalNode($1, OpGreater, $3); }
| RelationalExprNoIn LE ShiftExpr { $$ = makeRelationalNode($1, OpLessEq, $3); }
| RelationalExprNoIn GE ShiftExpr { $$ = makeRelationalNode($1, OpGreaterEq, $3); }
| RelationalExprNoIn INSTANCEOF ShiftExpr
{ $$ = makeRelationalNode($1, OpInstanceOf, $3); }
;
RelationalExprNoBF:
ShiftExprNoBF
| RelationalExprNoBF '<' ShiftExpr { $$ = makeRelationalNode($1, OpLess, $3); }
| RelationalExprNoBF '>' ShiftExpr { $$ = makeRelationalNode($1, OpGreater, $3); }
| RelationalExprNoBF LE ShiftExpr { $$ = makeRelationalNode($1, OpLessEq, $3); }
| RelationalExprNoBF GE ShiftExpr { $$ = makeRelationalNode($1, OpGreaterEq, $3); }
| RelationalExprNoBF INSTANCEOF ShiftExpr
{ $$ = makeRelationalNode($1, OpInstanceOf, $3); }
| RelationalExprNoBF INTOKEN ShiftExpr { $$ = makeRelationalNode($1, OpIn, $3); }
;
EqualityExpr:
RelationalExpr
| EqualityExpr EQEQ RelationalExpr { $$ = makeEqualNode($1, OpEqEq, $3); }
| EqualityExpr NE RelationalExpr { $$ = makeEqualNode($1, OpNotEq, $3); }
| EqualityExpr STREQ RelationalExpr { $$ = makeEqualNode($1, OpStrEq, $3); }
| EqualityExpr STRNEQ RelationalExpr { $$ = makeEqualNode($1, OpStrNEq, $3);}
;
EqualityExprNoIn:
RelationalExprNoIn
| EqualityExprNoIn EQEQ RelationalExprNoIn
{ $$ = makeEqualNode($1, OpEqEq, $3); }
| EqualityExprNoIn NE RelationalExprNoIn
{ $$ = makeEqualNode($1, OpNotEq, $3); }
| EqualityExprNoIn STREQ RelationalExprNoIn
{ $$ = makeEqualNode($1, OpStrEq, $3); }
| EqualityExprNoIn STRNEQ RelationalExprNoIn
{ $$ = makeEqualNode($1, OpStrNEq, $3);}
;
EqualityExprNoBF:
RelationalExprNoBF
| EqualityExprNoBF EQEQ RelationalExpr
{ $$ = makeEqualNode($1, OpEqEq, $3); }
| EqualityExprNoBF NE RelationalExpr { $$ = makeEqualNode($1, OpNotEq, $3); }
| EqualityExprNoBF STREQ RelationalExpr
{ $$ = makeEqualNode($1, OpStrEq, $3); }
| EqualityExprNoBF STRNEQ RelationalExpr
{ $$ = makeEqualNode($1, OpStrNEq, $3);}
;
BitwiseANDExpr:
EqualityExpr
| BitwiseANDExpr '&' EqualityExpr { $$ = makeBitOperNode($1, OpBitAnd, $3); }
;
BitwiseANDExprNoIn:
EqualityExprNoIn
| BitwiseANDExprNoIn '&' EqualityExprNoIn
{ $$ = makeBitOperNode($1, OpBitAnd, $3); }
;
BitwiseANDExprNoBF:
EqualityExprNoBF
| BitwiseANDExprNoBF '&' EqualityExpr { $$ = makeBitOperNode($1, OpBitAnd, $3); }
;
BitwiseXORExpr:
BitwiseANDExpr
| BitwiseXORExpr '^' BitwiseANDExpr { $$ = makeBitOperNode($1, OpBitXOr, $3); }
;
BitwiseXORExprNoIn:
BitwiseANDExprNoIn
| BitwiseXORExprNoIn '^' BitwiseANDExprNoIn
{ $$ = makeBitOperNode($1, OpBitXOr, $3); }
;
BitwiseXORExprNoBF:
BitwiseANDExprNoBF
| BitwiseXORExprNoBF '^' BitwiseANDExpr
{ $$ = makeBitOperNode($1, OpBitXOr, $3); }
;
BitwiseORExpr:
BitwiseXORExpr
| BitwiseORExpr '|' BitwiseXORExpr { $$ = makeBitOperNode($1, OpBitOr, $3); }
;
BitwiseORExprNoIn:
BitwiseXORExprNoIn
| BitwiseORExprNoIn '|' BitwiseXORExprNoIn
{ $$ = makeBitOperNode($1, OpBitOr, $3); }
;
BitwiseORExprNoBF:
BitwiseXORExprNoBF
| BitwiseORExprNoBF '|' BitwiseXORExpr
{ $$ = makeBitOperNode($1, OpBitOr, $3); }
;
LogicalANDExpr:
BitwiseORExpr
| LogicalANDExpr AND BitwiseORExpr { $$ = makeBinaryLogicalNode($1, OpAnd, $3); }
;
LogicalANDExprNoIn:
BitwiseORExprNoIn
| LogicalANDExprNoIn AND BitwiseORExprNoIn
{ $$ = makeBinaryLogicalNode($1, OpAnd, $3); }
;
LogicalANDExprNoBF:
BitwiseORExprNoBF
| LogicalANDExprNoBF AND BitwiseORExpr
{ $$ = makeBinaryLogicalNode($1, OpAnd, $3); }
;
LogicalORExpr:
LogicalANDExpr
| LogicalORExpr OR LogicalANDExpr { $$ = makeBinaryLogicalNode($1, OpOr, $3); }
;
LogicalORExprNoIn:
LogicalANDExprNoIn
| LogicalORExprNoIn OR LogicalANDExprNoIn
{ $$ = makeBinaryLogicalNode($1, OpOr, $3); }
;
LogicalORExprNoBF:
LogicalANDExprNoBF
| LogicalORExprNoBF OR LogicalANDExpr { $$ = makeBinaryLogicalNode($1, OpOr, $3); }
;
ConditionalExpr:
LogicalORExpr
| LogicalORExpr '?' AssignmentExpr ':' AssignmentExpr
{ $$ = makeConditionalNode($1, $3, $5); }
;
ConditionalExprNoIn:
LogicalORExprNoIn
| LogicalORExprNoIn '?' AssignmentExprNoIn ':' AssignmentExprNoIn
{ $$ = makeConditionalNode($1, $3, $5); }
;
ConditionalExprNoBF:
LogicalORExprNoBF
| LogicalORExprNoBF '?' AssignmentExpr ':' AssignmentExpr
{ $$ = makeConditionalNode($1, $3, $5); }
;
AssignmentExpr:
ConditionalExpr
| LeftHandSideExpr AssignmentOperator AssignmentExpr
{ $$ = makeAssignNode($1, $2, $3); }
;
AssignmentExprNoIn:
ConditionalExprNoIn
| LeftHandSideExpr AssignmentOperator AssignmentExprNoIn
{ $$ = makeAssignNode($1, $2, $3); }
;
AssignmentExprNoBF:
ConditionalExprNoBF
| LeftHandSideExprNoBF AssignmentOperator AssignmentExpr
{ $$ = makeAssignNode($1, $2, $3); }
;
AssignmentOperator:
'=' { $$ = OpEqual; }
| PLUSEQUAL { $$ = OpPlusEq; }
| MINUSEQUAL { $$ = OpMinusEq; }
| MULTEQUAL { $$ = OpMultEq; }
| DIVEQUAL { $$ = OpDivEq; }
| LSHIFTEQUAL { $$ = OpLShift; }
| RSHIFTEQUAL { $$ = OpRShift; }
| URSHIFTEQUAL { $$ = OpURShift; }
| ANDEQUAL { $$ = OpAndEq; }
| XOREQUAL { $$ = OpXOrEq; }
| OREQUAL { $$ = OpOrEq; }
| MODEQUAL { $$ = OpModEq; }
;
Expr:
AssignmentExpr
| Expr ',' AssignmentExpr { $$ = new CommaNode($1, $3); }
;
ExprNoIn:
AssignmentExprNoIn
| ExprNoIn ',' AssignmentExprNoIn { $$ = new CommaNode($1, $3); }
;
ExprNoBF:
AssignmentExprNoBF
| ExprNoBF ',' AssignmentExpr { $$ = new CommaNode($1, $3); }
;
Statement:
Block
| VariableStatement
| ConstStatement
| EmptyStatement
| ExprStatement
| IfStatement
| IterationStatement
| ContinueStatement
| BreakStatement
| ReturnStatement
| WithStatement
| SwitchStatement
| LabelledStatement
| ThrowStatement
| TryStatement
| DebuggerStatement
| ImportStatement
;
Block:
'{' '}' { $$ = new BlockNode(0); DBG($$, @2, @2); }
| '{' SourceElements '}' { $$ = new BlockNode($2); DBG($$, @3, @3); }
;
VariableStatement:
VAR VariableDeclarationList ';' { $$ = new VarStatementNode($2); DBG($$, @1, @3); }
| VAR VariableDeclarationList error { $$ = new VarStatementNode($2); DBG($$, @1, @2); AUTO_SEMICOLON; }
;
VariableDeclarationList:
VariableDeclaration { $$ = new VarDeclListNode($1); }
| VariableDeclarationList ',' VariableDeclaration
{ $$ = new VarDeclListNode($1, $3); }
;
VariableDeclarationListNoIn:
VariableDeclarationNoIn { $$ = new VarDeclListNode($1); }
| VariableDeclarationListNoIn ',' VariableDeclarationNoIn
{ $$ = new VarDeclListNode($1, $3); }
;
VariableDeclaration:
IDENT { $$ = new VarDeclNode(*$1, 0, VarDeclNode::Variable); }
| IDENT Initializer { $$ = new VarDeclNode(*$1, $2, VarDeclNode::Variable); }
;
VariableDeclarationNoIn:
IDENT { $$ = new VarDeclNode(*$1, 0, VarDeclNode::Variable); }
| IDENT InitializerNoIn { $$ = new VarDeclNode(*$1, $2, VarDeclNode::Variable); }
;
ConstStatement:
CONSTTOKEN ConstDeclarationList ';' { $$ = new VarStatementNode($2); DBG($$, @1, @3); }
| CONSTTOKEN ConstDeclarationList error
{ $$ = new VarStatementNode($2); DBG($$, @1, @2); AUTO_SEMICOLON; }
;
ConstDeclarationList:
ConstDeclaration { $$ = new VarDeclListNode($1); }
| ConstDeclarationList ',' ConstDeclaration
{ $$ = new VarDeclListNode($1, $3); }
;
ConstDeclaration:
IDENT { $$ = new VarDeclNode(*$1, 0, VarDeclNode::Constant); }
| IDENT Initializer { $$ = new VarDeclNode(*$1, $2, VarDeclNode::Constant); }
;
Initializer:
'=' AssignmentExpr { $$ = new AssignExprNode($2); }
;
InitializerNoIn:
'=' AssignmentExprNoIn { $$ = new AssignExprNode($2); }
;
EmptyStatement:
';' { $$ = new EmptyStatementNode(); }
;
ExprStatement:
ExprNoBF ';' { $$ = new ExprStatementNode($1); DBG($$, @1, @2); }
| ExprNoBF error { $$ = new ExprStatementNode($1); DBG($$, @1, @1); AUTO_SEMICOLON; }
;
IfStatement:
IF '(' Expr ')' Statement %prec IF_WITHOUT_ELSE
{ $$ = makeIfNode($3, $5, 0); DBG($$, @1, @4); }
| IF '(' Expr ')' Statement ELSE Statement
{ $$ = makeIfNode($3, $5, $7); DBG($$, @1, @4); }
;
IterationStatement:
DO Statement WHILE '(' Expr ')' ';' { $$ = new DoWhileNode($2, $5); DBG($$, @1, @3);}
| DO Statement WHILE '(' Expr ')' error { $$ = new DoWhileNode($2, $5); DBG($$, @1, @3); AUTO_SEMICOLON; }
| WHILE '(' Expr ')' Statement { $$ = new WhileNode($3, $5); DBG($$, @1, @4); }
| FOR '(' ExprNoInOpt ';' ExprOpt ';' ExprOpt ')' Statement
{ $$ = new ForNode($3, $5, $7, $9); DBG($$, @1, @8); }
| FOR '(' VAR VariableDeclarationListNoIn ';' ExprOpt ';' ExprOpt ')' Statement
{ $$ = new ForNode($4, $6, $8, $10); DBG($$, @1, @9); }
| FOR '(' LeftHandSideExpr INTOKEN Expr ')' Statement
{
Node *n = $3->nodeInsideAllParens();
if (!n->isLocation())
YYABORT;
$$ = new ForInNode(n, $5, $7);
DBG($$, @1, @6);
}
| FOR '(' VAR IDENT INTOKEN Expr ')' Statement
{ $$ = new ForInNode(*$4, 0, $6, $8); DBG($$, @1, @7); }
| FOR '(' VAR IDENT InitializerNoIn INTOKEN Expr ')' Statement
{ $$ = new ForInNode(*$4, $5, $7, $9); DBG($$, @1, @8); }
;
ExprOpt:
/* nothing */ { $$ = 0; }
| Expr
;
ExprNoInOpt:
/* nothing */ { $$ = 0; }
| ExprNoIn
;
ContinueStatement:
CONTINUE ';' { $$ = new ContinueNode(); DBG($$, @1, @2); }
| CONTINUE error { $$ = new ContinueNode(); DBG($$, @1, @1); AUTO_SEMICOLON; }
| CONTINUE IDENT ';' { $$ = new ContinueNode(*$2); DBG($$, @1, @3); }
| CONTINUE IDENT error { $$ = new ContinueNode(*$2); DBG($$, @1, @2); AUTO_SEMICOLON; }
;
BreakStatement:
BREAK ';' { $$ = new BreakNode(); DBG($$, @1, @2); }
| BREAK error { $$ = new BreakNode(); DBG($$, @1, @1); AUTO_SEMICOLON; }
| BREAK IDENT ';' { $$ = new BreakNode(*$2); DBG($$, @1, @3); }
| BREAK IDENT error { $$ = new BreakNode(*$2); DBG($$, @1, @2); AUTO_SEMICOLON; }
;
ReturnStatement:
RETURN ';' { $$ = new ReturnNode(0); DBG($$, @1, @2); }
| RETURN error { $$ = new ReturnNode(0); DBG($$, @1, @1); AUTO_SEMICOLON; }
| RETURN Expr ';' { $$ = new ReturnNode($2); DBG($$, @1, @3); }
| RETURN Expr error { $$ = new ReturnNode($2); DBG($$, @1, @2); AUTO_SEMICOLON; }
;
WithStatement:
WITH '(' Expr ')' Statement { $$ = new WithNode($3, $5); DBG($$, @1, @4); }
;
SwitchStatement:
SWITCH '(' Expr ')' CaseBlock { $$ = new SwitchNode($3, $5); DBG($$, @1, @4); }
;
CaseBlock:
'{' CaseClausesOpt '}' { $$ = new CaseBlockNode($2, 0, 0); }
| '{' CaseClausesOpt DefaultClause CaseClausesOpt '}'
{ $$ = new CaseBlockNode($2, $3, $4); }
;
CaseClausesOpt:
/* nothing */ { $$ = 0; }
| CaseClauses
;
CaseClauses:
CaseClause { $$ = new ClauseListNode($1); }
| CaseClauses CaseClause { $$ = new ClauseListNode($1, $2); }
;
CaseClause:
CASE Expr ':' { $$ = new CaseClauseNode($2); }
| CASE Expr ':' SourceElements { $$ = new CaseClauseNode($2, $4); }
;
DefaultClause:
DEFAULT ':' { $$ = new CaseClauseNode(0); }
| DEFAULT ':' SourceElements { $$ = new CaseClauseNode(0, $3); }
;
LabelledStatement:
IDENT ':' Statement { $$ = makeLabelNode(*$1, $3); }
;
ThrowStatement:
THROW Expr ';' { $$ = new ThrowNode($2); DBG($$, @1, @3); }
| THROW Expr error { $$ = new ThrowNode($2); DBG($$, @1, @2); AUTO_SEMICOLON; }
;
TryStatement:
TRY Block FINALLY Block { $$ = new TryNode($2, CommonIdentifiers::shared()->nullIdentifier, 0, $4); DBG($$, @1, @2); }
| TRY Block CATCH '(' IDENT ')' Block { $$ = new TryNode($2, *$5, $7, 0); DBG($$, @1, @2); }
| TRY Block CATCH '(' IDENT ')' Block FINALLY Block
{ $$ = new TryNode($2, *$5, $7, $9); DBG($$, @1, @2); }
;
DebuggerStatement:
DEBUGGER ';' { $$ = new EmptyStatementNode(); DBG($$, @1, @2); }
| DEBUGGER error { $$ = new EmptyStatementNode(); DBG($$, @1, @1); AUTO_SEMICOLON; }
;
PackageName:
IDENT { $$ = new PackageNameNode(*$1); }
| PackageName '.' IDENT { $$ = new PackageNameNode($1, *$3); }
;
ImportStatement:
IMPORT PackageName '.' '*' ';' { $$ = makeImportNode($2, true, 0);
DBG($$, @1, @5); }
| IMPORT PackageName '.' '*' error { $$ = makeImportNode($2, true, 0);
DBG($$, @1, @5); AUTO_SEMICOLON; }
| IMPORT PackageName ';' { $$ = makeImportNode($2, false, 0);
DBG($$, @1, @3); }
| IMPORT PackageName error { $$ = makeImportNode($2, false, 0);
DBG($$, @1, @3); AUTO_SEMICOLON; }
| IMPORT IDENT '=' PackageName ';' { $$ = makeImportNode($4, false, *$2);
DBG($$, @1, @5); }
| IMPORT IDENT '=' PackageName error { $$ = makeImportNode($4, false, *$2);
DBG($$, @1, @5); AUTO_SEMICOLON; }
;
FunctionDeclaration:
FUNCTION IDENT '(' ')' {inFuncDecl();} FunctionBody { $$ = new FuncDeclNode(*$2, $6); }
| FUNCTION IDENT '(' FormalParameterList ')' {inFuncDecl();} FunctionBody
{ $$ = new FuncDeclNode(*$2, $4, $7); }
;
FunctionExpr:
FUNCTION '(' ')' {inFuncExpr();} FunctionBody {
$$ = new FuncExprNode(CommonIdentifiers::shared()->nullIdentifier, $5);
}
| FUNCTION '(' FormalParameterList ')' {inFuncExpr();} FunctionBody {
$$ = new FuncExprNode(CommonIdentifiers::shared()->nullIdentifier, $6, $3);
}
| FUNCTION IDENT '(' ')' {inFuncExpr();} FunctionBody { $$ = new FuncExprNode(*$2, $6); }
| FUNCTION IDENT '(' FormalParameterList ')' {inFuncExpr();} FunctionBody {
$$ = new FuncExprNode(*$2, $7, $4);
}
;
FormalParameterList:
IDENT { $$ = new ParameterNode(*$1); }
| FormalParameterList ',' IDENT { $$ = new ParameterNode($1, *$3); }
;
FunctionBody:
'{' '}' /* not in spec */ { $$ = new FunctionBodyNode(0); DBG($$, @1, @2); }
| '{' SourceElements '}' { $$ = new FunctionBodyNode($2); DBG($$, @1, @3); }
;
Program:
/* not in spec */ { parser().didFinishParsing(new ProgramNode(0)); }
| SourceElements { parser().didFinishParsing(new ProgramNode($1)); }
;
SourceElements:
SourceElement { $$ = new SourceElementsNode($1); }
| SourceElements SourceElement { $$ = new SourceElementsNode($1, $2); }
;
SourceElement:
FunctionDeclaration { $$ = $1; }
| Statement { $$ = $1; }
;
%%
/* called by yyparse on error */
int yyerror(const char *)
{
// fprintf(stderr, "ERROR: %s at line %d\n", s, KJS::Lexer::curr()->lineNo());
return 1;
}
/* may we automatically insert a semicolon ? */
static bool allowAutomaticSemicolon()
{
return yychar == '}' || yychar == 0 || lexer().prevTerminator();
}
// kate: indent-width 2; replace-tabs on; tab-width 4; space-indent on;

View file

@ -1,169 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2003 Apple Computer, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "identifier.h"
#include <config-kjs.h>
#include <wtf/FastMalloc.h>
#include <wtf/HashSet.h>
#include <string.h> // for strlen
#include <new> // for placement new
namespace KJS {
typedef HashSet<UString::Rep *> IdentifierTable;
static IdentifierTable *table;
static inline IdentifierTable& identifierTable()
{
if (!table)
table = new IdentifierTable;
return *table;
}
bool Identifier::equal(const UString::Rep *r, const char *s)
{
int length = r->len;
const UChar *d = r->data();
for (int i = 0; i != length; ++i)
if (d[i].uc != (unsigned char)s[i])
return false;
return s[length] == 0;
}
bool Identifier::equal(const UString::Rep *r, const UChar *s, int length)
{
if (r->len != length)
return false;
const UChar *d = r->data();
for (int i = 0; i != length; ++i)
if (d[i].uc != s[i].uc)
return false;
return true;
}
struct CStringTranslator
{
static unsigned hash(const char *c)
{
return UString::Rep::computeHash(c);
}
static bool equal(UString::Rep *r, const char *s)
{
return Identifier::equal(r, s);
}
static void translate(UString::Rep*& location, const char *c, unsigned hash)
{
size_t length = strlen(c);
UChar *d = static_cast<UChar *>(fastMalloc(sizeof(UChar) * length));
for (size_t i = 0; i != length; i++)
d[i] = c[i];
UString::Rep *r = UString::Rep::create(d, static_cast<int>(length)).releaseRef();
r->isIdentifier = 1;
r->rc = 0;
r->_hash = hash;
location = r;
}
};
PassRefPtr<UString::Rep> Identifier::add(const char *c)
{
if (!c) {
UString::Rep::null.hash();
return &UString::Rep::null;
}
if (!c[0]) {
UString::Rep::empty.hash();
return &UString::Rep::empty;
}
return *identifierTable().add<const char *, CStringTranslator>(c).first;
}
struct UCharBuffer {
const UChar *s;
unsigned int length;
};
struct UCharBufferTranslator
{
static unsigned hash(const UCharBuffer& buf)
{
return UString::Rep::computeHash(buf.s, buf.length);
}
static bool equal(UString::Rep *str, const UCharBuffer& buf)
{
return Identifier::equal(str, buf.s, buf.length);
}
static void translate(UString::Rep *& location, const UCharBuffer& buf, unsigned hash)
{
UChar *d = static_cast<UChar *>(fastMalloc(sizeof(UChar) * buf.length));
for (unsigned i = 0; i != buf.length; i++)
d[i] = buf.s[i];
UString::Rep *r = UString::Rep::create(d, buf.length).releaseRef();
r->isIdentifier = 1;
r->rc = 0;
r->_hash = hash;
location = r;
}
};
PassRefPtr<UString::Rep> Identifier::add(const UChar *s, int length)
{
if (!length) {
UString::Rep::empty.hash();
return &UString::Rep::empty;
}
UCharBuffer buf = {s, static_cast<unsigned int>(length)};
return *identifierTable().add<UCharBuffer, UCharBufferTranslator>(buf).first;
}
PassRefPtr<UString::Rep> Identifier::addSlowCase(UString::Rep *r)
{
assert(!r->isIdentifier);
if (r->len == 0) {
UString::Rep::empty.hash();
return &UString::Rep::empty;
}
UString::Rep *result = *identifierTable().add(r).first;
if (result == r)
r->isIdentifier = true;
return result;
}
void Identifier::remove(UString::Rep *r)
{
identifierTable().remove(r);
}
} // namespace KJS

View file

@ -1,132 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2003 Apple Computer, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef KJS_IDENTIFIER_H
#define KJS_IDENTIFIER_H
#include "ustring.h"
#include <wtf/HashFunctions.h>
#include <wtf/HashTraits.h>
namespace KJS {
/**
* Represents an Identifier for a Javascript object.
*/
class KJS_EXPORT Identifier {
friend class PropertyMap;
public:
/**
* Creates an empty identifier
*/
Identifier() { }
/**
* Creates an identifier with the name of the string
* @code
* KJS::Identifier method("someJSMethod");
* @endcode
*/
Identifier(const char* s) : _ustring(add(s)) { }
Identifier(const UChar* s, int length) : _ustring(add(s, length)) { }
explicit Identifier(UString::Rep* rep) : _ustring(add(rep)) { }
explicit Identifier(const UString& s) : _ustring(add(s.rep())) { }
/**
* returns a UString of the identifier
*/
const UString& ustring() const { return _ustring; }
KJS_EXTERNAL_EXPORT DOM::DOMString domString() const;
/**
* returns a QString of the identifier
*/
KJS_EXTERNAL_EXPORT QString qstring() const;
/**
* returns a UChar pointer to the string of the identifier with a size defined by size().
*/
const UChar* data() const { return _ustring.data(); }
/**
* The size of the UChar string returned.
*/
int size() const { return _ustring.size(); }
/**
* Char * of the identifier's string.
*/
const char* ascii() const { return _ustring.ascii(); }
static Identifier from(unsigned y) { return Identifier(UString::from(y)); }
/**
* Returns the identfiers state of being unset.
*/
bool isNull() const { return _ustring.isNull(); }
/**
* Returns that the identifiers string is set, but is empty.
*/
bool isEmpty() const { return _ustring.isEmpty(); }
uint32_t toStrictUInt32(bool* ok) const { return _ustring.toStrictUInt32(ok); }
unsigned toArrayIndex(bool* ok) const { return _ustring.toArrayIndex(ok); }
double toDouble() const { return _ustring.toDouble(); }
friend bool operator==(const Identifier&, const Identifier&);
friend bool operator!=(const Identifier&, const Identifier&);
friend bool operator==(const Identifier&, const char*);
static void remove(UString::Rep*);
static bool equal(const UString::Rep*, const char*);
static bool equal(const UString::Rep*, const UChar*, int length);
private:
UString _ustring;
static bool equal(const Identifier& a, const Identifier& b)
{ return a._ustring.rep() == b._ustring.rep(); }
static bool equal(const Identifier& a, const char* b)
{ return equal(a._ustring.rep(), b); }
static PassRefPtr<UString::Rep> add(const char*);
static PassRefPtr<UString::Rep> add(const UChar*, int length);
static PassRefPtr<UString::Rep> add(UString::Rep* r)
{
if (r->isIdentifier)
return r;
return addSlowCase(r);
}
static PassRefPtr<UString::Rep> addSlowCase(UString::Rep *r);
};
inline bool operator==(const Identifier& a, const Identifier& b)
{ return Identifier::equal(a, b); }
inline bool operator!=(const Identifier& a, const Identifier& b)
{ return !Identifier::equal(a, b); }
inline bool operator==(const Identifier& a, const char* b)
{ return Identifier::equal(a, b); }
} // namespace KJS
#endif // KJS_IDENTIFIER_H

View file

@ -1,365 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2004 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "internal.h"
#include <config-kjs.h>
#include "array_object.h"
#include "bool_object.h"
#include "collector.h"
#include "date_object.h"
#include "debugger.h"
#include "error_object.h"
#include "function_object.h"
#include "lexer.h"
#include "math_object.h"
#include "nodes.h"
#include "number_object.h"
#include "object.h"
#include "object_object.h"
#include "operations.h"
#include "regexp_object.h"
#include "string_object.h"
#include <assert.h>
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/Vector.h>
#include <math.h>
#include <stdio.h>
namespace KJS {
#if PLATFORM(WIN_OS)
#define copysign _copysign
#endif
static const double D16 = 65536.0;
static const double D32 = 4294967296.0;
// ------------------------------ StringImp ------------------------------------
JSValue *StringImp::toPrimitive(ExecState *, JSType) const
{
return const_cast<StringImp *>(this);
}
bool GetterSetterImp::getPrimitiveNumber(ExecState*, double& number, JSValue*& value)
{
ASSERT_NOT_REACHED();
number = 0;
value = 0;
return true;
}
bool StringImp::getPrimitiveNumber(ExecState*, double& number, JSValue*& value)
{
value = this;
number = val.toDouble();
return false;
}
bool StringImp::toBoolean(ExecState *) const
{
return (val.size() > 0);
}
double StringImp::toNumber(ExecState *) const
{
return val.toDouble();
}
UString StringImp::toString(ExecState *) const
{
return val;
}
JSObject* StringImp::toObject(ExecState *exec) const
{
return new StringInstance(exec->lexicalInterpreter()->builtinStringPrototype(), const_cast<StringImp*>(this));
}
// ------------------------------ NumberImp ------------------------------------
JSValue *NumberImp::toPrimitive(ExecState *, JSType) const
{
return const_cast<NumberImp *>(this);
}
bool NumberImp::getPrimitiveNumber(ExecState*, double& number, JSValue*& value)
{
number = val;
value = this;
return true;
}
bool NumberImp::toBoolean(ExecState *) const
{
return val < 0.0 || val > 0.0; // false for NaN
}
double NumberImp::toNumber(ExecState *) const
{
return val;
}
UString NumberImp::toString(ExecState *) const
{
if (val == 0.0) // +0.0 or -0.0
return "0";
return UString::from(val);
}
JSObject *NumberImp::toObject(ExecState *exec) const
{
List args;
args.append(const_cast<NumberImp*>(this));
return static_cast<JSObject *>(exec->lexicalInterpreter()->builtinNumber()->construct(exec,args));
}
bool NumberImp::getUInt32(uint32_t& uint32) const
{
uint32 = static_cast<uint32_t>(val);
return uint32 == val;
}
bool NumberImp::getTruncatedInt32(int32_t& int32) const
{
if (!(val >= -2147483648.0 && val < 2147483648.0))
return false;
int32 = static_cast<int32_t>(val);
return true;
}
bool NumberImp::getTruncatedUInt32(uint32_t& uint32) const
{
if (!(val >= 0.0 && val < 4294967296.0))
return false;
uint32 = static_cast<uint32_t>(val);
return true;
}
// --------------------------- GetterSetterImp ---------------------------------
void GetterSetterImp::mark()
{
JSCell::mark();
if (getter && !getter->marked())
getter->mark();
if (setter && !setter->marked())
setter->mark();
}
JSValue *GetterSetterImp::toPrimitive(ExecState*, JSType) const
{
assert(false);
return jsNull();
}
bool GetterSetterImp::toBoolean(ExecState*) const
{
assert(false);
return false;
}
double GetterSetterImp::toNumber(ExecState *) const
{
assert(false);
return 0.0;
}
UString GetterSetterImp::toString(ExecState *) const
{
assert(false);
return UString::null();
}
JSObject *GetterSetterImp::toObject(ExecState *exec) const
{
assert(false);
return jsNull()->toObject(exec);
}
// ------------------------------ InternalFunctionImp --------------------------
const ClassInfo InternalFunctionImp::info = {"Function", 0, 0, 0};
InternalFunctionImp::InternalFunctionImp()
{
}
InternalFunctionImp::InternalFunctionImp(FunctionPrototype* funcProto)
: JSObject(funcProto)
{
}
InternalFunctionImp::InternalFunctionImp(FunctionPrototype* funcProto, const Identifier& name)
: JSObject(funcProto)
, m_name(name)
{
}
bool InternalFunctionImp::implementsCall() const
{
return true;
}
bool InternalFunctionImp::implementsHasInstance() const
{
return true;
}
// ------------------------------ global functions -----------------------------
double roundValue(double d)
{
double ad = fabs(d);
if (ad == 0 || isNaN(d) || isInf(d))
return d;
return copysign(floor(ad), d);
}
int32_t toInt32(double d)
{
if (isNaN(d) || isInf(d))
return 0;
double d32 = fmod(roundValue(d), D32);
if (d32 >= D32 / 2)
d32 -= D32;
else if (d32 < -D32 / 2)
d32 += D32;
return static_cast<int32_t>(d32);
}
int32_t toInt32(double d, bool &ok)
{
ok = true;
if (isNaN(d) || isInf(d)) {
ok = false;
return 0;
}
return toInt32(d);
}
uint32_t toUInt32(double dd)
{
double d = roundValue(dd);
if (isNaN(d) || isInf(d))
return 0;
double d32 = fmod(d, D32);
if (d32 < 0)
d32 += D32;
return static_cast<uint32_t>(d32);
}
uint16_t toUInt16(double dd)
{
double d = roundValue(dd);
if (isNaN(d) || isInf(d))
return 0;
double d16 = fmod(d, D16);
if (d16 < 0)
d16 += D16;
return static_cast<uint16_t>(d16);
}
//#ifndef NDEBUG
void printInfo(ExecState *exec, const char *s, JSValue *o, int lineno)
{
UString vString;
if (!o)
fprintf(stderr, "KJS: %s: (null)", s);
else {
JSValue *v = o;
unsigned int arrayLength = 0;
bool hadExcep = exec->hadException();
UString name;
switch (v->type()) {
case UnspecifiedType:
name = "Unspecified";
break;
case UndefinedType:
name = "Undefined";
break;
case NullType:
name = "Null";
break;
case BooleanType:
name = "Boolean";
break;
case StringType:
name = "String";
break;
case NumberType:
name = "Number";
break;
case ObjectType: {
JSObject* obj = static_cast<JSObject *>(v);
name = obj->className();
if (name.isNull())
name = "(unknown class)";
if ( obj->inherits(&ArrayInstance::info) )
arrayLength = obj->get(exec, exec->propertyNames().length)->toUInt32(exec);
vString = "[object " + name + "]"; // krazy:exclude=doublequote_chars
break;
}
case GetterSetterType:
name = "GetterSetter";
break;
}
// Avoid calling toString on a huge array (e.g. 4 billion elements, in mozilla/js/js1_5/Array/array-001.js)
if ( arrayLength > 100 )
vString = UString( "[ Array with " ) + UString::from( arrayLength ) + " elements ]";
else if ( v->type() != ObjectType ) // Don't want to call a user toString function!
vString = v->toString(exec);
if ( !hadExcep )
exec->clearException();
if ( vString.size() > 350 )
vString = vString.substr( 0, 350 ) + "...";
// Can't use two UString::ascii() in the same fprintf call
CString tempString( vString.cstring() );
fprintf(stderr, "KJS: %s: %s : %s (%p)",
s, tempString.c_str(), name.ascii(), (void*)v);
if (lineno >= 0)
fprintf(stderr, ", line %d\n",lineno);
else
fprintf(stderr, "\n");
}
}
//#endif
}

View file

@ -1,131 +0,0 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef INTERNAL_H
#define INTERNAL_H
#include "JSType.h"
#include "interpreter.h"
#include "object.h"
#include "protect.h"
#include "scope_chain.h"
#include "types.h"
#include "ustring.h"
#include <wtf/Noncopyable.h>
#ifndef I18N_NOOP
#define I18N_NOOP(s) s
#endif
namespace KJS {
// ---------------------------------------------------------------------------
// Primitive impls
// ---------------------------------------------------------------------------
class StringImp : public JSCell {
public:
StringImp() : val(UString::empty) { }
StringImp(const UString& v) : val(v) { Collector::reportExtraMemoryCost(v.cost()); }
enum HasOtherOwnerType { HasOtherOwner }; // e.g. storage cost already accounted for
StringImp(const UString& value, HasOtherOwnerType) : val(value) { }
StringImp(const char* v) : val(v) { }
StringImp(const char* v, int len) : val(v, len) { }
const UString& value() const { return val; }
virtual JSType type() const { return StringType; }
virtual JSValue *toPrimitive(ExecState *exec, JSType preferred = UnspecifiedType) const;
virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*& value);
virtual bool toBoolean(ExecState *exec) const;
virtual double toNumber(ExecState *exec) const;
virtual UString toString(ExecState *exec) const;
virtual JSObject *toObject(ExecState *exec) const;
private:
UString val;
};
class NumberImp : public JSCell {
friend class ConstantValues;
friend KJS_EXPORT JSValue *jsNumberCell(double);
public:
double value() const { return val; }
JSType type() const { return NumberType; }
JSValue *toPrimitive(ExecState *exec, JSType preferred = UnspecifiedType) const;
virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*& value);
bool toBoolean(ExecState *exec) const;
double toNumber(ExecState *exec) const;
UString toString(ExecState *exec) const;
JSObject *toObject(ExecState *exec) const;
private:
NumberImp(double v) : val(v) { }
virtual bool getUInt32(uint32_t&) const;
virtual bool getTruncatedInt32(int32_t&) const;
virtual bool getTruncatedUInt32(uint32_t&) const;
double val;
};
// ---------------------------------------------------------------------------
// Evaluation
// ---------------------------------------------------------------------------
struct AttachedInterpreter;
class DebuggerImp {
public:
DebuggerImp() {
interps = 0;
isAborted = false;
}
void abort() { isAborted = true; }
bool aborted() const { return isAborted; }
AttachedInterpreter *interps;
bool isAborted;
};
// helper function for toInteger, toInt32, toUInt32 and toUInt16
double roundValue(double d);
inline double roundValue(ExecState *e, JSValue *v) { return roundValue(v->toNumber(e)); }
int32_t toInt32(double dd);
uint32_t toUInt32(double dd);
uint16_t toUInt16(double dd);
//#ifndef NDEBUG
void printInfo(ExecState *exec, const char *s, JSValue *, int lineno = -1);
//#endif
} // namespace
#endif // INTERNAL_H

File diff suppressed because it is too large Load diff

View file

@ -1,564 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2003 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef _KJS_INTERPRETER_H_
#define _KJS_INTERPRETER_H_
#include "ExecState.h"
#include "protect.h"
#include "value.h"
#include "types.h"
#include <wtf/HashMap.h>
namespace KJS {
class Debugger;
class SavedBuiltins;
class TimeoutChecker;
class Package;
class ActivationImp;
class JSGlobalObject;
class StringImp;
#if USE(BINDINGS)
namespace Bindings {
class RootObject;
}
#endif
/**
* Interpreter objects can be used to evaluate ECMAScript code. Each
* interpreter has a global object which is used for the purposes of code
* evaluation, and also provides access to built-in properties such as
* " Object" and "Number".
*/
class KJS_EXPORT Interpreter {
friend class Collector;
friend class TimeoutChecker;
public:
/**
* Creates a new interpreter. The supplied object will be used as the global
* object for all scripts executed with this interpreter. During
* construction, all the standard properties such as "Object" and "Number"
* will be added to the global object.
*
* Note: You should not use the same global object for multiple
* interpreters.
*
* This is due do the fact that the built-in properties are set in the
* constructor, and if these objects have been modified from another
* interpreter (e.g. a script modifying String.prototype), the changes will
* be overridden.
*
* @param globalObject The object to use as the global object for this interpreter
*/
Interpreter(JSGlobalObject* globalObject);
/**
* Creates a new interpreter. A global object will be created and
* initialized with the standard global properties.
*/
Interpreter();
/**
* Returns the object that is used as the global object during all script
* execution performed by this interpreter
*/
JSGlobalObject* globalObject() const;
void initGlobalObject();
/**
* Returns the execution state object which can be used to execute
* scripts using this interpreter at a the "global" level, i.e. one
* with a execution context that has the global object as the "this"
* value, and who's scope chain contains only the global object.
*
* Note: this pointer remains constant for the life of the interpreter
* and should not be manually deleted.
*
* @return The interpreter global execution state object
*/
virtual ExecState *globalExec();
/**
* Sets the package instance that will be used to resolve the
* first level of identifiers of import statements.
*
* If no package is set which will make any "import" script
* statement fail with an error. This is the default in e.g. a
* Web browser where package imports should be disabled for
* security reasons.
*/
void setGlobalPackage(Package* p);
/**
* Returns the package that was installed to handle top level
* package requests. Returns 0, the default, when no package was
* set.
*
* @return The global package
*/
Package* globalPackage();
/**
* Parses the supplied ECMAScript code and checks for syntax errors.
*
* @param code The code to check
* @param sourceURL A URL denoting the origin of the code
* @param startingLineNumber The line offset within an embedding context
* @return A normal completion if there were no syntax errors in the code,
* otherwise a throw completion with the syntax error as its value.
*/
Completion checkSyntax(const UString& sourceURL, int startingLineNumber, const UString& code);
Completion checkSyntax(const UString& sourceURL, int startingLineNumber, const UChar* code, int codeLength);
/**
* Evaluates the supplied ECMAScript code.
*
* Since this method returns a Completion, you should check the type of
* completion to detect an error or before attempting to access the returned
* value. For example, if an error occurs during script execution and is not
* caught by the script, the completion type will be Throw.
*
* If the supplied code is invalid, a SyntaxError will be thrown.
*
* @param sourceURL A URL denoting the origin of the code
* @param startingLineNumber The line offset within an embedding context
* @param code The code to evaluate
* @param codeLength The length of the code to evaluate
* @param thisV The value to pass in as the "this" value for the script
* execution. This should either be jsNull() or an Object.
* @return A completion object representing the result of the execution.
*/
Completion evaluate(const UString& sourceURL, int startingLineNumber, const UChar* code, int codeLength, JSValue* thisV = 0);
Completion evaluate(const UString& sourceURL, int startingLineNumber, const UString& code, JSValue* thisV = 0);
/**
* Pretty-prints the supplied ECMAScript code after checking it
* for syntax errors.
*
* @param sourceURL A URL denoting the origin of the code
* @param startingLineNumber The line offset within an embedding context
* @param codeIn The code to check
* @param codeIn Pointer to string that will contain reformatted code
* upon successful parsing.
* @return A normal completion if there were no syntax errors in the code,
* otherwise a throw completion with the syntax error as its value.
*/
static bool normalizeCode(const UString& codeIn, UString* codeOut,
int* errLine = 0, UString* errMsg = 0);
/**
* Returns the builtin "Object" object. This is the object that was set
* as a property of the global object during construction; if the property
* is replaced by script code, this method will still return the original
* object.
*
* @return The builtin "Object" object
*/
JSObject *builtinObject() const;
/**
* Returns the builtin "Function" object.
*/
JSObject *builtinFunction() const;
/**
* Returns the builtin "Array" object.
*/
JSObject *builtinArray() const;
/**
* Returns the builtin "Boolean" object.
*/
JSObject *builtinBoolean() const;
/**
* Returns the builtin "String" object.
*/
JSObject *builtinString() const;
/**
* Returns the builtin "Number" object.
*/
JSObject *builtinNumber() const;
/**
* Returns the builtin "Date" object.
*/
JSObject *builtinDate() const;
/**
* Returns the builtin "RegExp" object.
*/
JSObject *builtinRegExp() const;
/**
* Returns the builtin "Error" object.
*/
JSObject *builtinError() const;
/**
* Returns the builtin "Object.prototype" object.
*/
JSObject *builtinObjectPrototype() const;
/**
* Returns the builtin "Function.prototype" object.
*/
JSObject *builtinFunctionPrototype() const;
/**
* Returns the builtin "Array.prototype" object.
*/
JSObject *builtinArrayPrototype() const;
/**
* Returns the builtin "Boolean.prototype" object.
*/
JSObject *builtinBooleanPrototype() const;
/**
* Returns the builtin "String.prototype" object.
*/
JSObject *builtinStringPrototype() const;
/**
* Returns the builtin "Number.prototype" object.
*/
JSObject *builtinNumberPrototype() const;
/**
* Returns the builtin "Date.prototype" object.
*/
JSObject *builtinDatePrototype() const;
/**
* Returns the builtin "RegExp.prototype" object.
*/
JSObject *builtinRegExpPrototype() const;
/**
* Returns the builtin "Error.prototype" object.
*/
JSObject *builtinErrorPrototype() const;
/**
* The initial value of "Error" global property
*/
JSObject *builtinEvalError() const;
JSObject *builtinRangeError() const;
JSObject *builtinReferenceError() const;
JSObject *builtinSyntaxError() const;
JSObject *builtinTypeError() const;
JSObject *builtinURIError() const;
JSObject *builtinEvalErrorPrototype() const;
JSObject *builtinRangeErrorPrototype() const;
JSObject *builtinReferenceErrorPrototype() const;
JSObject *builtinSyntaxErrorPrototype() const;
JSObject *builtinTypeErrorPrototype() const;
JSObject *builtinURIErrorPrototype() const;
enum CompatMode { NativeMode, IECompat, NetscapeCompat };
/**
* Call this to enable a compatibility mode with another browser.
* (by default konqueror is in "native mode").
* Currently, in KJS, this only changes the behavior of Date::getYear()
* which returns the full year under IE.
*/
void setCompatMode(CompatMode mode) { m_compatMode = mode; }
CompatMode compatMode() const { return m_compatMode; }
/**
* Run the garbage collection. Returns true when at least one object
* was collected; false otherwise.
*/
static bool collect();
/**
* Called during the mark phase of the garbage collector. Subclasses
* implementing custom mark methods must make sure to chain to this one.
*/
virtual void mark(bool currentThreadIsMainThread);
/**
* This marks all GC heap resources stored as optimizations;
* and which have their lifetime managed by the appropriate AST.
* It's static since code can survive the interpreter by a bit.
*/
static void markSourceCachedObjects();
/**
* Provides a way to distinguish derived classes.
* Only useful if you reimplement Interpreter and if different kind of
* interpreters are created in the same process.
* The base class returns 0, the ECMA-bindings interpreter returns 1.
*/
virtual int rtti() { return 0; }
static bool shouldPrintExceptions();
static void setShouldPrintExceptions(bool);
void saveBuiltins (SavedBuiltins&) const;
void restoreBuiltins (const SavedBuiltins&);
/**
* Determine if the it is 'safe' to execute code in the target interpreter from an
* object that originated in this interpreter. This check is used to enforce WebCore
* cross frame security rules. In particular, attempts to access 'bound' objects are
* not allowed unless isSafeScript returns true.
*/
virtual bool isSafeScript(const Interpreter*) { return true; }
#if USE(BINDINGS)
virtual void *createLanguageInstanceForValue(ExecState*, int language, JSObject* value, const Bindings::RootObject* origin, const Bindings::RootObject* current);
#endif
// Chained list of interpreters (ring)
static Interpreter* firstInterpreter() { return s_hook; }
Interpreter* nextInterpreter() const { return next; }
Interpreter* prevInterpreter() const { return prev; }
Debugger* debugger() const { return m_debugger; }
void setDebugger(Debugger* d) { m_debugger = d; }
void setExecState(ExecState* e) { m_execState = e; }
// Note: may be 0, if in globalExec
ExecState* execState() { return m_execState ? m_execState : &m_globalExec; }
void setTimeoutTime(unsigned timeoutTime) { m_timeoutTime = timeoutTime; }
void startTimeoutCheck();
void stopTimeoutCheck();
// Resets the timer to full time if it's running
void restartTimeoutCheck();
void pauseTimeoutCheck();
void resumeTimeoutCheck();
bool checkTimeout();
void ref() { ++m_refCount; }
void deref() { if (--m_refCount <= 0) delete this; }
int refCount() const { return m_refCount; }
unsigned char* stackAlloc(size_t size) {
unsigned char* nextPtr = stackPtr + size;
if (nextPtr <= stackEnd) {
unsigned char* toRet = stackPtr;
stackPtr = nextPtr;
return toRet;
}
return extendStack(size);
}
void stackFree(size_t size) { stackPtr-= size; } // ### shrink it?
ActivationImp* getRecycledActivation() {
ActivationImp* out = 0;
if (m_numCachedActivations) {
m_numCachedActivations--;
out = m_cachedActivations[m_numCachedActivations];
}
return out;
}
void recycleActivation(ActivationImp* act);
// Global string table management. This is used from StringNode
// to cache StringImp's for string literals. We keep refcounts
// to permit multiple ones to use the same value.
static StringImp* internString(const UString& literal);
static void releaseInternedString(const UString& literal);
typedef WTF::HashMap<UString::Rep*, std::pair<KJS::StringImp*, int> > InternedStringsTable;
private:
static void markInternedStringsTable();
// This creates a table if needed
static void initInternedStringsTable();
static InternedStringsTable* s_internedStrings;
protected:
virtual ~Interpreter(); // only deref should delete us
virtual bool shouldInterruptScript() const { return true; }
long m_timeoutTime;
private:
bool handleTimeout();
void init();
void printException(const Completion& c, const UString& sourceURL);
/**
* This constructor is not implemented, in order to prevent
* copy-construction of Interpreter objects. You should always pass around
* pointers to an interpreter instance instead.
*/
Interpreter(const Interpreter&);
/**
* This operator is not implemented, in order to prevent assignment of
* Interpreter objects. You should always pass around pointers to an
* interpreter instance instead.
*/
Interpreter operator=(const Interpreter&);
int m_refCount;
JSGlobalObject* m_globalObject;
GlobalExecState m_globalExec;
Package *globPkg;
// Execution stack stuff for this interpreter.
unsigned char* stackBase; // lowest address in the array
unsigned char* stackPtr; // current top/next to allocate
unsigned char* stackEnd; // last address in the stack
unsigned char* extendStack(size_t needed);
// A list of cached activations
enum {MaxCachedActivations = 32};
ActivationImp* m_cachedActivations[MaxCachedActivations];
int m_numCachedActivations;
// Chained list of interpreters (ring) - for collector
static Interpreter* s_hook;
Interpreter *next, *prev;
int m_recursion;
Debugger* m_debugger;
ExecState* m_execState;
CompatMode m_compatMode;
TimeoutChecker* m_timeoutChecker;
bool m_timedOut;
unsigned m_startTimeoutCheckCount;
unsigned m_pauseTimeoutCheckCount;
// Helper for setting constructors, making sure their function names are OK
void putNamedConstructor(const char* name, JSObject* value);
ProtectedPtr<JSObject> m_Object;
ProtectedPtr<JSObject> m_Function;
ProtectedPtr<JSObject> m_Array;
ProtectedPtr<JSObject> m_Boolean;
ProtectedPtr<JSObject> m_String;
ProtectedPtr<JSObject> m_Number;
ProtectedPtr<JSObject> m_Date;
ProtectedPtr<JSObject> m_RegExp;
ProtectedPtr<JSObject> m_Error;
ProtectedPtr<JSObject> m_ObjectPrototype;
ProtectedPtr<JSObject> m_FunctionPrototype;
ProtectedPtr<JSObject> m_ArrayPrototype;
ProtectedPtr<JSObject> m_BooleanPrototype;
ProtectedPtr<JSObject> m_StringPrototype;
ProtectedPtr<JSObject> m_NumberPrototype;
ProtectedPtr<JSObject> m_DatePrototype;
ProtectedPtr<JSObject> m_RegExpPrototype;
ProtectedPtr<JSObject> m_ErrorPrototype;
ProtectedPtr<JSObject> m_EvalError;
ProtectedPtr<JSObject> m_RangeError;
ProtectedPtr<JSObject> m_ReferenceError;
ProtectedPtr<JSObject> m_SyntaxError;
ProtectedPtr<JSObject> m_TypeError;
ProtectedPtr<JSObject> m_UriError;
ProtectedPtr<JSObject> m_EvalErrorPrototype;
ProtectedPtr<JSObject> m_RangeErrorPrototype;
ProtectedPtr<JSObject> m_ReferenceErrorPrototype;
ProtectedPtr<JSObject> m_SyntaxErrorPrototype;
ProtectedPtr<JSObject> m_TypeErrorPrototype;
ProtectedPtr<JSObject> m_UriErrorPrototype;
};
inline bool Interpreter::checkTimeout()
{
if (!m_timedOut)
return false;
return handleTimeout();
}
/**
* Interface to set enhanced Unicode support functions. By default
* the interpreter will use the standard C library functions.
*
* @internal
*/
class KJS_EXPORT UnicodeSupport
{
public:
UnicodeSupport();
typedef bool (*CharCategoryFunction)(int c);
static void setIdentStartChecker(CharCategoryFunction f);
static void setIdentPartChecker(CharCategoryFunction f);
typedef int (*StringConversionFunction)(uint16_t* str, int strLength,
uint16_t*& destIfNeeded);
static void setToLowerFunction(StringConversionFunction f);
static void setToUpperFunction(StringConversionFunction f);
};
/**
* Define a Qt-based version of the Unicode support functions.
*
* @internal
*/
#define KJS_QT_UNICODE_IMPL \
namespace KJS { \
static bool qtIdentStart(int c) { if (c & 0xffff0000) return false; QChar::Category cat = QChar((unsigned short)c).category(); return cat == QChar::Letter_Uppercase || cat == QChar::Letter_Lowercase || cat == QChar::Letter_Titlecase || cat == QChar::Letter_Modifier || cat == QChar::Letter_Other || c == '$' || c == '_'; } \
static bool qtIdentPart(int c) { if (c & 0xffff0000) return false; QChar::Category cat = QChar((unsigned short)c).category(); return cat == QChar::Letter_Uppercase || cat == QChar::Letter_Lowercase || cat == QChar::Letter_Titlecase || cat == QChar::Letter_Modifier || cat == QChar::Letter_Other || cat == QChar::Mark_NonSpacing || cat == QChar::Mark_SpacingCombining || cat == QChar::Number_DecimalDigit || cat == QChar::Punctuation_Connector || c == '$' || c == '_'; } \
static int qtToLower(uint16_t* str, int strLength, uint16_t*& destIfNeeded) { \
destIfNeeded = 0; \
for (int i = 0; i < strLength; ++i) \
str[i] = QChar(str[i]).toLower().unicode(); \
return strLength; } \
static int qtToUpper(uint16_t* str, int strLength, uint16_t*& destIfNeeded) { \
destIfNeeded = 0; \
for (int i = 0; i < strLength; ++i) \
str[i] = QChar(str[i]).toUpper().unicode(); \
return strLength; } \
}
/**
* Set the Qt-based version of the Unicode support functions.
*
* @internal
*/
#define KJS_QT_UNICODE_SET \
{ KJS::UnicodeSupport::setIdentStartChecker(KJS::qtIdentStart); \
KJS::UnicodeSupport::setIdentPartChecker(KJS::qtIdentPart); \
KJS::UnicodeSupport::setToLowerFunction(KJS::qtToLower); \
KJS::UnicodeSupport::setToUpperFunction(KJS::qtToUpper); }
} // namespace
#endif // _KJS_INTERPRETER_H_

View file

@ -1,186 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (C) 2012 Bernd Buschinski (b.buschinski@googlemail.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "json_object.h"
#include "jsonlexer.h"
#include <config-kjs.h>
#include "lookup.h"
#include "array_instance.h"
#include "jsonstringify.h"
#include "json_object.lut.h"
using namespace KJS;
// ------------------------------ JSONObjectImp --------------------------------
const ClassInfo JSONObjectImp::info = { "JSON", 0, &jsonTable, 0 };
/* Source for json_object.lut.h
@begin jsonTable 2
parse JSONObjectImp::Parse DontEnum|Function 2
stringify JSONObjectImp::Stringify DontEnum|Function 3
@end
*/
JSONObjectImp::JSONObjectImp(ExecState*, ObjectPrototype *objProto)
: JSObject(objProto)
{
}
bool JSONObjectImp::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
{
// As of ECMA 5.1r6 JSON only has 2 functions, so only functionSlot is needed
return getStaticFunctionSlot<JSONFuncImp, JSObject>(exec, &jsonTable, this, propertyName, slot);
}
// ------------------------------ JSONFuncImp --------------------------------
JSONFuncImp::JSONFuncImp(ExecState* exec, int i, int l, const Identifier& name)
: InternalFunctionImp(static_cast<FunctionPrototype*>(exec->lexicalInterpreter()->builtinFunctionPrototype()), name),
id(i)
{
putDirect(exec->propertyNames().length, l, DontDelete|ReadOnly|DontEnum);
}
static void reviver(ExecState* exec, JSValue* value, JSObject* func)
{
if (exec->hadException())
return;
JSType type = value->type();
switch (type) {
case ObjectType: {
JSObject* obj = value->getObject();
bool isArray = obj->inherits(&ArrayInstance::info);
bool validArrayIndex = false;
PropertyNameArray names;
obj->getOwnPropertyNames(exec, names, KJS::PropertyMap::ExcludeDontEnumProperties);
const int nameSize = names.size();
for (int i = 0; i < nameSize; ++i) {
// For Array only take properties that are valid Array indexes
if (isArray) {
names[i].toArrayIndex(&validArrayIndex);
if (!validArrayIndex)
continue;
}
JSValue* val = obj->get(exec, names[i]);
List args;
args.append(jsString(names[i].ustring()));
args.append(val);
JSValue* ret = func->call(exec, obj, args);
if (exec->hadException())
return;
if (ret->isUndefined())
obj->deleteProperty(exec, names[i]);
else {
obj->put(exec, names[i], ret);
reviver(exec, ret, func);
}
}
break;
}
case NullType:
case NumberType:
case BooleanType:
case StringType:
break;
case UnspecifiedType:
case GetterSetterType:
case UndefinedType:
// should never be reached, as JSON doesn't know them
// and we only have json data here
ASSERT_NOT_REACHED();
break;
}
}
JSValue *JSONFuncImp::callAsFunction(ExecState* exec, JSObject* /*thisObj*/, const List& args)
{
switch (id) {
case JSONObjectImp::Parse: {
if (args.size() < 1)
return throwError(exec, SyntaxError, "Invalid JSON Syntax");
JSONParser parser(args[0]->toString(exec));
if (exec->hadException())
return jsUndefined();
JSValue* val = parser.tryParse(exec);
if (!val)
return throwError(exec, SyntaxError, "Invalid JSON Syntax");
if (args.size() < 2)
return val;
JSValue* func = args[1];
if (func->implementsCall()) {
JSObject* function = func->getObject();
List args;
args.append(jsString(""));
args.append(val);
JSObject* jsobjectArg = val->toObject(exec);
if (exec->hadException())
return jsUndefined();
JSValue* ret = function->call(exec, jsobjectArg, args);
if (ret->isUndefined())
return ret;
else {
reviver(exec, ret, function);
if (exec->hadException())
return jsUndefined();
}
}
return val;
}
case JSONObjectImp::Stringify: {
JSValue* object = args[0];
JSONStringify stringifier(exec, args[1], args[2]);
JSONStringify::StringifyState state;
JSValue* ret = stringifier.stringify(exec, object, state);
switch (state) {
case JSONStringify::Success:
return ret;
case JSONStringify::FailedCyclic:
return throwError(exec, TypeError, "cyclic object value");
case JSONStringify::FailedStackLimitExceeded:
return throwError(exec, TypeError, "object stack limit exceeded");
case JSONStringify::FailedException:
//stringify already got an exception
return jsUndefined();
}
}
default:
ASSERT_NOT_REACHED();
}
return jsUndefined();
}

Some files were not shown because too many files have changed in this diff Show more