mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-23 18:32:49 +00:00
removed kjs and kjsembed
This commit is contained in:
parent
38427d5c45
commit
6141d2ef50
371 changed files with 2 additions and 74184 deletions
|
@ -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 )
|
||||||
|
|
|
@ -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 )
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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;
|
|
|
@ -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;
|
|
110
kjs/DESIGN.ideas
110
kjs/DESIGN.ideas
|
@ -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;
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -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;
|
|
306
kjs/ExecState.h
306
kjs/ExecState.h
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
85
kjs/JSLock.h
85
kjs/JSLock.h
|
@ -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
|
|
43
kjs/JSType.h
43
kjs/JSType.h
|
@ -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
|
|
|
@ -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
|
|
|
@ -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;
|
|
|
@ -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
|
|
|
@ -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++;
|
|
|
@ -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
|
|
|
@ -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
|
|
147
kjs/Parser.cpp
147
kjs/Parser.cpp
|
@ -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
|
|
106
kjs/Parser.h
106
kjs/Parser.h
|
@ -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;
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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
|
|
27
kjs/README
27
kjs/README
|
@ -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>
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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})
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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"
|
|
|
@ -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));
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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));
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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()))
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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;
|
|
|
@ -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
|
|
|
@ -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++;
|
|
|
@ -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
|
|
|
@ -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++;
|
|
|
@ -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
|
|
|
@ -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 */
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
@ -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;
|
|
|
@ -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;
|
|
|
@ -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;
|
|
|
@ -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;
|
|
|
@ -1,6 +0,0 @@
|
||||||
HEADERS = lexer.h parser.h tablebuilder.h
|
|
||||||
SOURCES = lexer.cpp parser.cpp tablebuilder.cpp driver.cpp
|
|
||||||
CONFIG+=debug
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
|
@ -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;
|
|
|
@ -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;
|
|
|
@ -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;
|
|
||||||
|
|
|
@ -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;
|
|
|
@ -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;
|
|
|
@ -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;
|
|
|
@ -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;
|
|
|
@ -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++;
|
|
|
@ -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++;
|
|
|
@ -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;
|
|
|
@ -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++;
|
|
|
@ -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++;
|
|
||||||
|
|
|
@ -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(®isteredThreadKey, destroyRegisteredThread);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Collector::registerThread()
|
|
||||||
{
|
|
||||||
pthread_once(®isteredThreadKeyOnce, 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)®s, &user_count);
|
|
||||||
|
|
||||||
// scan the registers
|
|
||||||
markStackObjectsConservatively((void *)®s, (void *)((char *)®s + (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
|
|
192
kjs/collector.h
192
kjs/collector.h
|
@ -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_ */
|
|
|
@ -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_
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -1 +0,0 @@
|
||||||
#include <ExecState.h>
|
|
|
@ -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";
|
|
||||||
}
|
|
|
@ -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
|
|
1491
kjs/date_object.cpp
1491
kjs/date_object.cpp
File diff suppressed because it is too large
Load diff
|
@ -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
|
|
162
kjs/debugger.cpp
162
kjs/debugger.cpp
|
@ -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);
|
|
||||||
}
|
|
240
kjs/debugger.h
240
kjs/debugger.h
|
@ -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;
|
|
3204
kjs/dtoa.cpp
3204
kjs/dtoa.cpp
File diff suppressed because it is too large
Load diff
31
kjs/dtoa.h
31
kjs/dtoa.h
|
@ -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 */
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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
|
|
1216
kjs/function.cpp
1216
kjs/function.cpp
File diff suppressed because it is too large
Load diff
235
kjs/function.h
235
kjs/function.h
|
@ -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
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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_
|
|
|
@ -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
|
|
4398
kjs/grammar.cpp
4398
kjs/grammar.cpp
File diff suppressed because it is too large
Load diff
186
kjs/grammar.h
186
kjs/grammar.h
|
@ -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 */
|
|
942
kjs/grammar.y
942
kjs/grammar.y
|
@ -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;
|
|
|
@ -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
|
|
132
kjs/identifier.h
132
kjs/identifier.h
|
@ -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
|
|
365
kjs/internal.cpp
365
kjs/internal.cpp
|
@ -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
|
|
||||||
|
|
||||||
}
|
|
131
kjs/internal.h
131
kjs/internal.h
|
@ -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
|
|
1033
kjs/interpreter.cpp
1033
kjs/interpreter.cpp
File diff suppressed because it is too large
Load diff
|
@ -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_
|
|
|
@ -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
Loading…
Add table
Reference in a new issue