Browse Source

Merge remote branch 'origin/master'

Conflicts:
	src/node_net.cc
	src/node_os.cc
v0.7.4-release
Bert Belder 14 years ago
parent
commit
33118df8f9
  1. 6
      Makefile
  2. 5
      Makefile.cmake
  3. 12
      README.cmake
  4. 22
      cmake/codesourcery-arm-toolchain.cmake
  5. 10
      cmake/configure.cmake
  6. 7
      cmake/libs.cmake
  7. 20
      cmake/node_build.cmake
  8. 5
      cmake/v8_build.cmake
  9. 11
      deps/v8/ChangeLog
  10. 13
      deps/v8/SConstruct
  11. 15
      deps/v8/include/v8.h
  12. 3
      deps/v8/src/SConscript
  13. 29
      deps/v8/src/api.cc
  14. 105
      deps/v8/src/arm/code-stubs-arm.cc
  15. 9
      deps/v8/src/arm/lithium-arm.cc
  16. 15
      deps/v8/src/arm/lithium-codegen-arm.cc
  17. 38
      deps/v8/src/arm/macro-assembler-arm.cc
  18. 13
      deps/v8/src/arm/macro-assembler-arm.h
  19. 67
      deps/v8/src/array.js
  20. 23
      deps/v8/src/assembler.cc
  21. 2
      deps/v8/src/assembler.h
  22. 53
      deps/v8/src/builtins.cc
  23. 3
      deps/v8/src/code-stubs.h
  24. 11
      deps/v8/src/codegen.cc
  25. 3
      deps/v8/src/counters.h
  26. 33
      deps/v8/src/date.js
  27. 2
      deps/v8/src/debug.cc
  28. 2
      deps/v8/src/deoptimizer.cc
  29. 2
      deps/v8/src/deoptimizer.h
  30. 5
      deps/v8/src/flag-definitions.h
  31. 9
      deps/v8/src/full-codegen.cc
  32. 4
      deps/v8/src/heap-profiler.cc
  33. 95
      deps/v8/src/heap.cc
  34. 16
      deps/v8/src/heap.h
  35. 7
      deps/v8/src/hydrogen-instructions.cc
  36. 6
      deps/v8/src/hydrogen-instructions.h
  37. 12
      deps/v8/src/hydrogen.cc
  38. 2
      deps/v8/src/hydrogen.h
  39. 232
      deps/v8/src/ia32/code-stubs-ia32.cc
  40. 29
      deps/v8/src/ia32/code-stubs-ia32.h
  41. 9
      deps/v8/src/ia32/codegen-ia32.cc
  42. 9
      deps/v8/src/ia32/full-codegen-ia32.cc
  43. 28
      deps/v8/src/ia32/lithium-codegen-ia32.cc
  44. 2
      deps/v8/src/ia32/lithium-codegen-ia32.h
  45. 2
      deps/v8/src/ia32/lithium-ia32.cc
  46. 826
      deps/v8/src/objects-debug.cc
  47. 131
      deps/v8/src/objects.cc
  48. 343
      deps/v8/src/objects.h
  49. 4
      deps/v8/src/parser.cc
  50. 13
      deps/v8/src/platform-nullos.cc
  51. 27
      deps/v8/src/platform-posix.cc
  52. 14
      deps/v8/src/platform-win32.cc
  53. 4
      deps/v8/src/platform.h
  54. 8
      deps/v8/src/profile-generator.cc
  55. 62
      deps/v8/src/property.cc
  56. 8
      deps/v8/src/property.h
  57. 27
      deps/v8/src/regexp.js
  58. 2
      deps/v8/src/runtime.cc
  59. 53
      deps/v8/src/spaces.cc
  60. 9
      deps/v8/src/spaces.h
  61. 6
      deps/v8/src/string-stream.cc
  62. 3
      deps/v8/src/string-stream.h
  63. 67
      deps/v8/src/string.js
  64. 12
      deps/v8/src/utils.cc
  65. 2
      deps/v8/src/v8-counters.h
  66. 10
      deps/v8/src/v8utils.h
  67. 4
      deps/v8/src/version.cc
  68. 4
      deps/v8/src/x64/codegen-x64.cc
  69. 64
      deps/v8/test/cctest/test-heap.cc
  70. 13
      deps/v8/test/mjsunit/array-slice.js
  71. 17
      deps/v8/test/mjsunit/array-sort.js
  72. 43
      deps/v8/test/mjsunit/with-readonly.js
  73. 3
      deps/v8/tools/gyp/v8.gyp
  74. 3
      deps/v8/tools/v8.xcodeproj/project.pbxproj
  75. 2
      deps/v8/tools/visual_studio/debug.vsprops
  76. 4
      doc/api/addons.markdown
  77. 2
      doc/api/appendix_1.markdown
  78. 4
      doc/api/assert.markdown
  79. 97
      doc/api/os.markdown
  80. 17
      doc/api/process.markdown
  81. 4
      doc/api/repl.markdown
  82. 57
      doc/api/streams.markdown
  83. 8
      doc/index.html
  84. 9
      lib/assert.js
  85. 16
      lib/console.js
  86. 2
      lib/events.js
  87. 9
      lib/os.js
  88. 34
      lib/readline.js
  89. 83
      lib/repl.js
  90. 41
      lib/stream.js
  91. 33
      src/node.cc
  92. 31
      src/node.js
  93. 6
      src/node_crypto.cc
  94. 35
      src/node_net.cc
  95. 94
      src/node_os.cc
  96. 281
      src/node_script.cc
  97. 48
      src/node_script.h
  98. 9
      src/platform.h
  99. 124
      src/platform_cygwin.cc
  100. 131
      src/platform_darwin.cc

6
Makefile

@ -25,9 +25,15 @@ uninstall:
test: all test: all
python tools/test.py --mode=release simple message python tools/test.py --mode=release simple message
test-valgrind: all
python tools/test.py --mode=release --valgrind simple message
test-all: all test-all: all
python tools/test.py --mode=debug,release python tools/test.py --mode=debug,release
test-all-valgrind: all
python tools/test.py --mode=debug,release --valgrind
test-release: all test-release: all
python tools/test.py --mode=release python tools/test.py --mode=release

5
Makefile.cmake

@ -2,12 +2,13 @@ BUILD?=build
VERBOSE?=0 VERBOSE?=0
PARALLEL_JOBS?=1 PARALLEL_JOBS?=1
CMAKE?=cmake CMAKE?=cmake
TOOLCHAIN_FILE=#./cmake/codesourcery-arm-toolchain.cmake
all: doc package all: package
$(BUILD)/Makefile: $(BUILD)/Makefile:
mkdir $(BUILD) || exit 0 mkdir $(BUILD) || exit 0
cd $(BUILD) && $(CMAKE) -DCMAKE_VERBOSE_MAKEFILE=$(VERBOSE) .. cd $(BUILD) && $(CMAKE) -DCMAKE_VERBOSE_MAKEFILE=$(VERBOSE) -DCMAKE_TOOLCHAIN_FILE=$(TOOLCHAIN_FILE) ..
build: $(BUILD)/Makefile build: $(BUILD)/Makefile
cd $(BUILD) && make -j $(PARALLEL_JOBS) cd $(BUILD) && make -j $(PARALLEL_JOBS)

12
README.cmake

@ -38,6 +38,18 @@ To submit valgrind test results:
make -f Makefile.cmake cdash-mem make -f Makefile.cmake cdash-mem
Cross-compiling:
An example toolchain file for the CodeSourcery ARM toolchain is included in
the cmake directory: codesourcery-arm-toolchain.cmake.
Install the CodeSourcery toolchain, set the path to the toolchain in
cmake/codesourcery-arm-toolchain.cmake, and uncomment the TOOLCHAIN_FILE
variable in Makefile.cmake to use it.
If you are using cmake directly, just add the flag
"-DCMAKE_TOOLCHAIN_FILE=/path/to/toolchain-file" when
running cmake.
Using cmake directly: Using cmake directly:
cd ~/your-node-source-dir cd ~/your-node-source-dir
mkdir name-of-build-dir (can be anything) mkdir name-of-build-dir (can be anything)

22
cmake/codesourcery-arm-toolchain.cmake

@ -0,0 +1,22 @@
set(toolchain_dir #SET THIS TO YOUR TOOLCHAIN PATH)
set(toolchain_bin_dir ${toolchain_dir}/bin)
set(toolchain_libc_dir ${toolchain_dir}/arm-none-linux-gnueabi/libc)
set(toolchain_inc_dir ${toolchain_libc_dir}/include)
set(toolchain_lib_dir ${toolchain_libc_dir}/usr/lib)
set(CMAKE_SYSTEM_NAME Linux CACHE INTERNAL "system name")
set(CMAKE_SYSTEM_PROCESSOR arm CACHE INTERNAL "processor")
set(CMAKE_C_COMPILER ${toolchain_bin_dir}/arm-none-linux-gnueabi-gcc)
set(CMAKE_CXX_COMPILER ${toolchain_bin_dir}/arm-none-linux-gnueabi-g++)
set(CMAKE_C_FLAGS "-isystem ${toolchain_inc_dir}" CACHE INTERNAL "c compiler flags")
set(CMAKE_CXX_FLAGS "-isystem ${toolchain_inc_dir}" CACHE INTERNAL "cxx compiler flags")
set(link_flags -L${toolchain_lib_dir})
set(CMAKE_EXE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "exe link flags")
set(CMAKE_MODULE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "module link flags")
set(CMAKE_SHARED_LINKER_FLAGS ${link_flags} CACHE INTERNAL "shared lnk flags")
set(CMAKE_FIND_ROOT_PATH ${toolchain_libc_dir} CACHE INTERNAL "cross root directory")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH CACHE INTERNAL "")
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY CACHE INTERNAL "")
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY CACHE INTERNAL "")

10
cmake/configure.cmake

@ -80,13 +80,3 @@ file(GLOB js2c_files ${PROJECT_SOURCE_DIR}/lib/*.js)
set(js2c_files ${PROJECT_SOURCE_DIR}/src/node.js ${js2c_files}) set(js2c_files ${PROJECT_SOURCE_DIR}/src/node.js ${js2c_files})
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/src) file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/src)
set(PREFIX ${CMAKE_INSTALL_PREFIX})
if(${CMAKE_BUILD_TYPE} MATCHES Debug)
set(CCFLAGS "${CMAKE_C_FLAGS_DEBUG} ${CMAKE_C_FLAGS}")
else()
set(CCFLAGS "${CMAKE_C_FLAGS_RELEASE} ${CMAKE_C_FLAGS}")
endif()
get_directory_property(compile_defs COMPILE_DEFINITIONS)
foreach(def ${compile_defs})
set(CPPFLAGS "${CPPFLAGS} -D${def}")
endforeach()

7
cmake/libs.cmake

@ -13,6 +13,7 @@ find_library(RT rt)
find_library(DL dl) find_library(DL dl)
check_library_exists(socket socket "" HAVE_SOCKET_LIB) check_library_exists(socket socket "" HAVE_SOCKET_LIB)
check_library_exists(nsl gethostbyname "" HAVE_NSL_LIB) check_library_exists(nsl gethostbyname "" HAVE_NSL_LIB)
check_library_exists(util openpty "" HAVE_UTIL_LIB)
if(RT) if(RT)
set(extra_libs ${extra_libs} ${RT}) set(extra_libs ${extra_libs} ${RT})
@ -35,7 +36,11 @@ if(${HAVE_NSL_LIB})
set(extra_libs ${extra_libs} nsl) set(extra_libs ${extra_libs} nsl)
endif() endif()
if(${OPENSSL_FOUND} MATCHES True) if(HAVE_UTIL_LIB)
set(extra_libs ${extra_libs} util)
endif()
if(OPENSSL_FOUND)
add_definitions(-DHAVE_OPENSSL=1) add_definitions(-DHAVE_OPENSSL=1)
set(HAVE_OPENSSL True) set(HAVE_OPENSSL True)
set(node_extra_src ${node_extra_src} src/node_crypto.cc) set(node_extra_src ${node_extra_src} src/node_crypto.cc)

20
cmake/node_build.cmake

@ -7,10 +7,12 @@ add_custom_command(
COMMAND ${PYTHON_EXECUTABLE} tools/js2c.py ${PROJECT_BINARY_DIR}/src/node_natives.h ${js2c_files} COMMAND ${PYTHON_EXECUTABLE} tools/js2c.py ${PROJECT_BINARY_DIR}/src/node_natives.h ${js2c_files}
DEPENDS ${js2c_files}) DEPENDS ${js2c_files})
set(node_extra_src "src/platform_${node_platform}.cc") set(node_platform_src "src/platform_${node_platform}.cc")
if(NOT EXISTS ${CMAKE_SOURCE_DIR}/${node_extra_src}) if(NOT EXISTS ${CMAKE_SOURCE_DIR}/${node_platform_src})
set(node_extra_src "src/platform_none.cc") set(node_extra_src ${node_extra_src} "src/platform_none.cc")
else()
set(node_extra_src ${node_extra_src} ${node_platform_src})
endif() endif()
set(node_sources set(node_sources
@ -36,6 +38,18 @@ set(node_sources
src/node_natives.h src/node_natives.h
${node_extra_src}) ${node_extra_src})
# Set up PREFIX, CCFLAGS, and CPPFLAGS for node_config.h
set(PREFIX ${CMAKE_INSTALL_PREFIX})
if(${CMAKE_BUILD_TYPE} MATCHES Debug)
set(CCFLAGS "${CMAKE_C_FLAGS_DEBUG} ${CMAKE_C_FLAGS}")
else()
set(CCFLAGS "${CMAKE_C_FLAGS_RELEASE} ${CMAKE_C_FLAGS}")
endif()
get_directory_property(compile_defs COMPILE_DEFINITIONS)
foreach(def ${compile_defs})
set(CPPFLAGS "${CPPFLAGS} -D${def}")
endforeach()
configure_file(src/node_config.h.in ${PROJECT_BINARY_DIR}/src/node_config.h) configure_file(src/node_config.h.in ${PROJECT_BINARY_DIR}/src/node_config.h)
configure_file(config.h.cmake ${PROJECT_BINARY_DIR}/config.h) configure_file(config.h.cmake ${PROJECT_BINARY_DIR}/config.h)

5
cmake/v8_build.cmake

@ -38,6 +38,7 @@ if(NOT SHARED_V8)
set_property(TARGET v8 set_property(TARGET v8
PROPERTY IMPORTED_LOCATION ${PROJECT_BINARY_DIR}/deps/v8/${v8_fn}) PROPERTY IMPORTED_LOCATION ${PROJECT_BINARY_DIR}/deps/v8/${v8_fn})
set(compile_env_vars "CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} AR=${CMAKE_AR} RANLIB=${CMAKE_RANLIB} CFLAGS=\"${CMAKE_C_FLAGS}\" CXXFLAGS=\"${CMAKE_CXX_FLAGS}\" LDFLAGS=\"${CMAKE_EXE_LINKER_FLAGS}\"")
if(CMAKE_VERSION VERSION_GREATER 2.8 OR CMAKE_VERSION VERSION_EQUAL 2.8) if(CMAKE_VERSION VERSION_GREATER 2.8 OR CMAKE_VERSION VERSION_EQUAL 2.8)
# use ExternalProject for CMake >2.8 # use ExternalProject for CMake >2.8
@ -47,7 +48,7 @@ if(NOT SHARED_V8)
URL ${PROJECT_SOURCE_DIR}/deps/v8 URL ${PROJECT_SOURCE_DIR}/deps/v8
BUILD_IN_SOURCE True BUILD_IN_SOURCE True
BUILD_COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_BINARY_DIR}/tools/scons/scons.py library=static visibility=default ${v8snapshot} mode=${v8mode} verbose=on arch=${v8arch} -j ${parallel_jobs} BUILD_COMMAND sh -c "${compile_env_vars} ${PYTHON_EXECUTABLE} ${PROJECT_BINARY_DIR}/tools/scons/scons.py library=static visibility=default ${v8snapshot} mode=${v8mode} verbose=on arch=${v8arch} -j ${parallel_jobs}"
SOURCE_DIR ${PROJECT_BINARY_DIR}/deps/v8 SOURCE_DIR ${PROJECT_BINARY_DIR}/deps/v8
# ignore this stuff, it's not needed for building v8 but ExternalProject # ignore this stuff, it's not needed for building v8 but ExternalProject
@ -78,7 +79,7 @@ if(NOT SHARED_V8)
add_custom_command( add_custom_command(
OUTPUT ${PROJECT_BINARY_DIR}/deps/v8/${v8_fn} OUTPUT ${PROJECT_BINARY_DIR}/deps/v8/${v8_fn}
COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_BINARY_DIR}/tools/scons/scons.py library=static visibility=default ${v8snapshot} mode=${v8mode} verbose=on arch=${v8arch} -j ${parallel_jobs} COMMAND sh -c "${compile_env_vars} ${PYTHON_EXECUTABLE} ${PROJECT_BINARY_DIR}/tools/scons/scons.py library=static visibility=default ${v8snapshot} mode=${v8mode} verbose=on arch=${v8arch} -j ${parallel_jobs}"
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/deps/v8/ WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/deps/v8/
DEPENDS ${v8_sources_dest} DEPENDS ${v8_sources_dest}
) )

11
deps/v8/ChangeLog

@ -1,3 +1,14 @@
2010-12-21: Version 3.0.4
Added Date::ResetCache() to the API so that the cached values in the
Date object can be reset to allow live DST / timezone changes.
Extended existing support for printing (while debugging) the contents
of objects. Added support for printing objects from release builds.
Fixed V8 issues 989, 1006, and 1007.
2010-12-17: Version 3.0.3 2010-12-17: Version 3.0.3
Reapplied all changes for version 3.0.1. Reapplied all changes for version 3.0.1.

13
deps/v8/SConstruct

@ -108,11 +108,14 @@ LIBRARY_FLAGS = {
'CPPDEFINES': ['V8_INTERPRETED_REGEXP'] 'CPPDEFINES': ['V8_INTERPRETED_REGEXP']
}, },
'mode:debug': { 'mode:debug': {
'CPPDEFINES': ['V8_ENABLE_CHECKS'] 'CPPDEFINES': ['V8_ENABLE_CHECKS', 'OBJECT_PRINT']
}, },
'vmstate:on': { 'vmstate:on': {
'CPPDEFINES': ['ENABLE_VMSTATE_TRACKING'], 'CPPDEFINES': ['ENABLE_VMSTATE_TRACKING'],
}, },
'objectprint:on': {
'CPPDEFINES': ['OBJECT_PRINT'],
},
'protectheap:on': { 'protectheap:on': {
'CPPDEFINES': ['ENABLE_VMSTATE_TRACKING', 'ENABLE_HEAP_PROTECTION'], 'CPPDEFINES': ['ENABLE_VMSTATE_TRACKING', 'ENABLE_HEAP_PROTECTION'],
}, },
@ -225,8 +228,7 @@ LIBRARY_FLAGS = {
'LINKFLAGS': ['-m64'], 'LINKFLAGS': ['-m64'],
}, },
'prof:oprofile': { 'prof:oprofile': {
'CPPDEFINES': ['ENABLE_OPROFILE_AGENT'], 'CPPDEFINES': ['ENABLE_OPROFILE_AGENT']
'LIBS': ['opagent', 'bfd']
} }
}, },
'msvc': { 'msvc': {
@ -711,6 +713,11 @@ SIMPLE_OPTIONS = {
'default': 'off', 'default': 'off',
'help': 'enable VM state tracking' 'help': 'enable VM state tracking'
}, },
'objectprint': {
'values': ['on', 'off'],
'default': 'off',
'help': 'enable object printing'
},
'protectheap': { 'protectheap': {
'values': ['on', 'off'], 'values': ['on', 'off'],
'default': 'off', 'default': 'off',

15
deps/v8/include/v8.h

@ -1355,6 +1355,21 @@ class Date : public Value {
V8EXPORT double NumberValue() const; V8EXPORT double NumberValue() const;
static inline Date* Cast(v8::Value* obj); static inline Date* Cast(v8::Value* obj);
/**
* Notification that the embedder has changed the time zone,
* daylight savings time, or other date / time configuration
* parameters. V8 keeps a cache of various values used for
* date / time computation. This notification will reset
* those cached values for the current context so that date /
* time configuration changes would be reflected in the Date
* object.
*
* This API should not be called more than needed as it will
* negatively impact the performance of date operations.
*/
V8EXPORT static void DateTimeConfigurationChangeNotification();
private: private:
V8EXPORT static void CheckCast(v8::Value* obj); V8EXPORT static void CheckCast(v8::Value* obj);
}; };

3
deps/v8/src/SConscript

@ -231,7 +231,8 @@ SOURCES = {
'mode:release': [], 'mode:release': [],
'mode:debug': [ 'mode:debug': [
'objects-debug.cc', 'prettyprinter.cc', 'regexp-macro-assembler-tracer.cc' 'objects-debug.cc', 'prettyprinter.cc', 'regexp-macro-assembler-tracer.cc'
] ],
'objectprint:on': ['objects-debug.cc']
} }

29
deps/v8/src/api.cc

@ -3802,6 +3802,35 @@ double v8::Date::NumberValue() const {
} }
void v8::Date::DateTimeConfigurationChangeNotification() {
ON_BAILOUT("v8::Date::DateTimeConfigurationChangeNotification()", return);
LOG_API("Date::DateTimeConfigurationChangeNotification");
ENTER_V8;
HandleScope scope;
// Get the function ResetDateCache (defined in date-delay.js).
i::Handle<i::String> func_name_str =
i::Factory::LookupAsciiSymbol("ResetDateCache");
i::MaybeObject* result = i::Top::builtins()->GetProperty(*func_name_str);
i::Object* object_func;
if (!result->ToObject(&object_func)) {
return;
}
if (object_func->IsJSFunction()) {
i::Handle<i::JSFunction> func =
i::Handle<i::JSFunction>(i::JSFunction::cast(object_func));
// Call ResetDateCache(0 but expect no exceptions:
bool caught_exception = false;
i::Handle<i::Object> result =
i::Execution::TryCall(func, i::Top::builtins(), 0, NULL,
&caught_exception);
}
}
static i::Handle<i::String> RegExpFlagsToString(RegExp::Flags flags) { static i::Handle<i::String> RegExpFlagsToString(RegExp::Flags flags) {
char flags_buf[3]; char flags_buf[3];
int num_flags = 0; int num_flags = 0;

105
deps/v8/src/arm/code-stubs-arm.cc

@ -2893,80 +2893,97 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
} }
// This stub performs an instanceof, calling the builtin function if // Uses registers r0 to r4. Expected input is
// necessary. Uses r1 for the object, r0 for the function that it may // function in r0 (or at sp+1*ptrsz) and object in
// be an instance of (these are fetched from the stack). // r1 (or at sp), depending on whether or not
// args_in_registers() is true.
void InstanceofStub::Generate(MacroAssembler* masm) { void InstanceofStub::Generate(MacroAssembler* masm) {
// Get the object - slow case for smis (we may need to throw an exception // Fixed register usage throughout the stub:
// depending on the rhs). const Register object = r1; // Object (lhs).
Label slow, loop, is_instance, is_not_instance; const Register map = r3; // Map of the object.
__ ldr(r0, MemOperand(sp, 1 * kPointerSize)); const Register function = r0; // Function (rhs).
__ BranchOnSmi(r0, &slow); const Register prototype = r4; // Prototype of the function.
const Register scratch = r2;
// Check that the left hand is a JS object and put map in r3. Label slow, loop, is_instance, is_not_instance, not_js_object;
__ CompareObjectType(r0, r3, r2, FIRST_JS_OBJECT_TYPE); if (!args_in_registers()) {
__ b(lt, &slow); __ ldr(function, MemOperand(sp, 1 * kPointerSize));
__ cmp(r2, Operand(LAST_JS_OBJECT_TYPE)); __ ldr(object, MemOperand(sp, 0));
__ b(gt, &slow); }
// Get the prototype of the function (r4 is result, r2 is scratch). // Check that the left hand is a JS object and load map.
__ ldr(r1, MemOperand(sp, 0)); __ BranchOnSmi(object, &slow);
// r1 is function, r3 is map. __ IsObjectJSObjectType(object, map, scratch, &slow);
// Look up the function and the map in the instanceof cache. // Look up the function and the map in the instanceof cache.
Label miss; Label miss;
__ LoadRoot(ip, Heap::kInstanceofCacheFunctionRootIndex); __ LoadRoot(ip, Heap::kInstanceofCacheFunctionRootIndex);
__ cmp(r1, ip); __ cmp(object, ip);
__ b(ne, &miss); __ b(ne, &miss);
__ LoadRoot(ip, Heap::kInstanceofCacheMapRootIndex); __ LoadRoot(ip, Heap::kInstanceofCacheMapRootIndex);
__ cmp(r3, ip); __ cmp(map, ip);
__ b(ne, &miss); __ b(ne, &miss);
__ LoadRoot(r0, Heap::kInstanceofCacheAnswerRootIndex); __ LoadRoot(function, Heap::kInstanceofCacheAnswerRootIndex);
__ pop(); __ Ret(args_in_registers() ? 0 : 2);
__ pop();
__ mov(pc, Operand(lr));
__ bind(&miss); __ bind(&miss);
__ TryGetFunctionPrototype(r1, r4, r2, &slow); __ TryGetFunctionPrototype(object, prototype, scratch, &slow);
// Check that the function prototype is a JS object. // Check that the function prototype is a JS object.
__ BranchOnSmi(r4, &slow); __ BranchOnSmi(prototype, &slow);
__ CompareObjectType(r4, r5, r5, FIRST_JS_OBJECT_TYPE); __ IsObjectJSObjectType(prototype, scratch, scratch, &slow);
__ b(lt, &slow);
__ cmp(r5, Operand(LAST_JS_OBJECT_TYPE));
__ b(gt, &slow);
__ StoreRoot(r1, Heap::kInstanceofCacheFunctionRootIndex); __ StoreRoot(object, Heap::kInstanceofCacheFunctionRootIndex);
__ StoreRoot(r3, Heap::kInstanceofCacheMapRootIndex); __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex);
// Register mapping: r3 is object map and r4 is function prototype. // Register mapping: r3 is object map and r4 is function prototype.
// Get prototype of object into r2. // Get prototype of object into r2.
__ ldr(r2, FieldMemOperand(r3, Map::kPrototypeOffset)); __ ldr(scratch, FieldMemOperand(map, Map::kPrototypeOffset));
// Loop through the prototype chain looking for the function prototype. // Loop through the prototype chain looking for the function prototype.
__ bind(&loop); __ bind(&loop);
__ cmp(r2, Operand(r4)); __ cmp(scratch, Operand(prototype));
__ b(eq, &is_instance); __ b(eq, &is_instance);
__ LoadRoot(ip, Heap::kNullValueRootIndex); __ LoadRoot(ip, Heap::kNullValueRootIndex);
__ cmp(r2, ip); __ cmp(scratch, ip);
__ b(eq, &is_not_instance); __ b(eq, &is_not_instance);
__ ldr(r2, FieldMemOperand(r2, HeapObject::kMapOffset)); __ ldr(scratch, FieldMemOperand(scratch, HeapObject::kMapOffset));
__ ldr(r2, FieldMemOperand(r2, Map::kPrototypeOffset)); __ ldr(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset));
__ jmp(&loop); __ jmp(&loop);
__ bind(&is_instance); __ bind(&is_instance);
__ mov(r0, Operand(Smi::FromInt(0))); __ mov(r0, Operand(Smi::FromInt(0)));
__ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex); __ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
__ pop(); __ Ret(args_in_registers() ? 0 : 2);
__ pop();
__ mov(pc, Operand(lr)); // Return.
__ bind(&is_not_instance); __ bind(&is_not_instance);
__ mov(r0, Operand(Smi::FromInt(1))); __ mov(r0, Operand(Smi::FromInt(1)));
__ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex); __ Ret(args_in_registers() ? 0 : 2);
__ pop();
__ pop(); Label object_not_null, object_not_null_or_smi;
__ mov(pc, Operand(lr)); // Return. __ bind(&not_js_object);
// Before null, smi and string value checks, check that the rhs is a function
// as for a non-function rhs an exception needs to be thrown.
__ BranchOnSmi(function, &slow);
__ CompareObjectType(function, map, scratch, JS_FUNCTION_TYPE);
__ b(ne, &slow);
// Null is not instance of anything.
__ cmp(scratch, Operand(Factory::null_value()));
__ b(ne, &object_not_null);
__ mov(r0, Operand(Smi::FromInt(1)));
__ Ret(args_in_registers() ? 0 : 2);
__ bind(&object_not_null);
// Smi values are not instances of anything.
__ BranchOnNotSmi(object, &object_not_null_or_smi);
__ mov(r0, Operand(Smi::FromInt(1)));
__ Ret(args_in_registers() ? 0 : 2);
__ bind(&object_not_null_or_smi);
// String values are not instances of anything.
__ IsObjectJSStringType(object, scratch, &slow);
__ mov(r0, Operand(Smi::FromInt(1)));
__ Ret(args_in_registers() ? 0 : 2);
// Slow-case. Tail call builtin. // Slow-case. Tail call builtin.
__ bind(&slow); __ bind(&slow);

9
deps/v8/src/arm/lithium-arm.cc

@ -1316,7 +1316,8 @@ LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) { LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
LInstruction* result = LInstruction* result =
new LInstanceOf(Use(instr->left()), Use(instr->right())); new LInstanceOf(UseFixed(instr->left(), r1),
UseFixed(instr->right(), r0));
return MarkAsCall(DefineFixed(result, r0), instr); return MarkAsCall(DefineFixed(result, r0), instr);
} }
@ -1375,6 +1376,12 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
case kMathLog: case kMathLog:
Abort("MathLog LUnaryMathOperation not implemented"); Abort("MathLog LUnaryMathOperation not implemented");
return NULL; return NULL;
case kMathCos:
Abort("MathCos LUnaryMathOperation not implemented");
return NULL;
case kMathSin:
Abort("MathSin LUnaryMathOperation not implemented");
return NULL;
default: default:
UNREACHABLE(); UNREACHABLE();
return NULL; return NULL;

15
deps/v8/src/arm/lithium-codegen-arm.cc

@ -1337,7 +1337,14 @@ void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
void LCodeGen::DoInstanceOf(LInstanceOf* instr) { void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
Abort("DoInstanceOf unimplemented."); // We expect object and function in registers r1 and r0.
InstanceofStub stub(InstanceofStub::kArgsInRegisters);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
Label true_value, done;
__ tst(r0, r0);
__ mov(r0, Operand(Factory::false_value()), LeaveCC, eq);
__ mov(r0, Operand(Factory::true_value()), LeaveCC, ne);
} }
@ -1547,7 +1554,7 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
Abort("LUnaryMathOperation unimplemented."); Abort("DoMathAbs unimplemented.");
} }
@ -1562,9 +1569,6 @@ void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
ASSERT(instr->op() == kMathFloor ||
instr->op() == kMathAbs);
switch (instr->op()) { switch (instr->op()) {
case kMathAbs: case kMathAbs:
DoMathAbs(instr); DoMathAbs(instr);
@ -1576,6 +1580,7 @@ void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
DoMathSqrt(instr); DoMathSqrt(instr);
break; break;
default: default:
Abort("Unimplemented type of LUnaryMathOperation.");
UNREACHABLE(); UNREACHABLE();
} }
} }

38
deps/v8/src/arm/macro-assembler-arm.cc

@ -178,6 +178,12 @@ void MacroAssembler::Drop(int count, Condition cond) {
} }
void MacroAssembler::Ret(int drop, Condition cond) {
Drop(drop, cond);
Ret(cond);
}
void MacroAssembler::Swap(Register reg1, void MacroAssembler::Swap(Register reg1,
Register reg2, Register reg2,
Register scratch, Register scratch,
@ -821,6 +827,38 @@ void MacroAssembler::InvokeFunction(JSFunction* function,
} }
void MacroAssembler::IsObjectJSObjectType(Register heap_object,
Register map,
Register scratch,
Label* fail) {
ldr(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
IsInstanceJSObjectType(map, scratch, fail);
}
void MacroAssembler::IsInstanceJSObjectType(Register map,
Register scratch,
Label* fail) {
ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
cmp(scratch, Operand(FIRST_JS_OBJECT_TYPE));
b(lt, fail);
cmp(scratch, Operand(LAST_JS_OBJECT_TYPE));
b(gt, fail);
}
void MacroAssembler::IsObjectJSStringType(Register object,
Register scratch,
Label* fail) {
ASSERT(kNotStringTag != 0);
ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
tst(scratch, Operand(kIsNotStringMask));
b(nz, fail);
}
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
void MacroAssembler::DebugBreak() { void MacroAssembler::DebugBreak() {
ASSERT(allow_stub_calls()); ASSERT(allow_stub_calls());

13
deps/v8/src/arm/macro-assembler-arm.h

@ -96,6 +96,7 @@ class MacroAssembler: public Assembler {
// from the stack, clobbering only the sp register. // from the stack, clobbering only the sp register.
void Drop(int count, Condition cond = al); void Drop(int count, Condition cond = al);
void Ret(int drop, Condition cond = al);
// Swap two registers. If the scratch register is omitted then a slightly // Swap two registers. If the scratch register is omitted then a slightly
// less efficient form using xor instead of mov is emitted. // less efficient form using xor instead of mov is emitted.
@ -298,6 +299,18 @@ class MacroAssembler: public Assembler {
const ParameterCount& actual, const ParameterCount& actual,
InvokeFlag flag); InvokeFlag flag);
void IsObjectJSObjectType(Register heap_object,
Register map,
Register scratch,
Label* fail);
void IsInstanceJSObjectType(Register map,
Register scratch,
Label* fail);
void IsObjectJSStringType(Register object,
Register scratch,
Label* fail);
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

67
deps/v8/src/array.js

@ -1,4 +1,4 @@
// Copyright 2006-2008 the V8 project authors. All rights reserved. // Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
@ -677,39 +677,76 @@ function ArraySort(comparefn) {
function QuickSort(a, from, to) { function QuickSort(a, from, to) {
// Insertion sort is faster for short arrays. // Insertion sort is faster for short arrays.
if (to - from <= 22) { if (to - from <= 10) {
InsertionSort(a, from, to); InsertionSort(a, from, to);
return; return;
} }
var pivot_index = $floor($random() * (to - from)) + from; // Find a pivot as the median of first, last and middle element.
var pivot = a[pivot_index]; var v0 = a[from];
// Issue 95: Keep the pivot element out of the comparisons to avoid var v1 = a[to - 1];
// infinite recursion if comparefn(pivot, pivot) != 0. var middle_index = from + ((to - from) >> 1);
%_SwapElements(a, from, pivot_index); var v2 = a[middle_index];
var low_end = from; // Upper bound of the elements lower than pivot. var c01 = %_CallFunction(global_receiver, v0, v1, comparefn);
var high_start = to; // Lower bound of the elements greater than pivot. if (c01 > 0) {
// v1 < v0, so swap them.
var tmp = v0;
v0 = v1;
v1 = tmp;
} // v0 <= v1.
var c02 = %_CallFunction(global_receiver, v0, v2, comparefn);
if (c02 >= 0) {
// v2 <= v0 <= v1.
var tmp = v0;
v0 = v2;
v2 = v1;
v1 = tmp;
} else {
// v0 <= v1 && v0 < v2
var c12 = %_CallFunction(global_receiver, v1, v2, comparefn);
if (c12 > 0) {
// v0 <= v2 < v1
var tmp = v1;
v1 = v2;
v2 = tmp;
}
}
// v0 <= v1 <= v2
a[from] = v0;
a[to - 1] = v2;
var pivot = v1;
var low_end = from + 1; // Upper bound of elements lower than pivot.
var high_start = to - 1; // Lower bound of elements greater than pivot.
a[middle_index] = a[low_end];
a[low_end] = pivot;
// From low_end to i are elements equal to pivot. // From low_end to i are elements equal to pivot.
// From i to high_start are elements that haven't been compared yet. // From i to high_start are elements that haven't been compared yet.
for (var i = from + 1; i < high_start; ) { partition: for (var i = low_end + 1; i < high_start; i++) {
var element = a[i]; var element = a[i];
var order = %_CallFunction(global_receiver, element, pivot, comparefn); var order = %_CallFunction(global_receiver, element, pivot, comparefn);
if (order < 0) { if (order < 0) {
%_SwapElements(a, i, low_end); %_SwapElements(a, i, low_end);
i++;
low_end++; low_end++;
} else if (order > 0) { } else if (order > 0) {
do {
high_start--; high_start--;
if (high_start == i) break partition;
var top_elem = a[high_start];
order = %_CallFunction(global_receiver, top_elem, pivot, comparefn);
} while (order > 0);
%_SwapElements(a, i, high_start); %_SwapElements(a, i, high_start);
} else { // order == 0 if (order < 0) {
i++; %_SwapElements(a, i, low_end);
low_end++;
}
} }
} }
QuickSort(a, from, low_end); QuickSort(a, from, low_end);
QuickSort(a, high_start, to); QuickSort(a, high_start, to);
} }
// Copies elements in the range 0..length from obj's prototype chain // Copy elements in the range 0..length from obj's prototype chain
// to obj itself, if obj has holes. Returns one more than the maximal index // to obj itself, if obj has holes. Return one more than the maximal index
// of a prototype property. // of a prototype property.
function CopyFromPrototype(obj, length) { function CopyFromPrototype(obj, length) {
var max = 0; var max = 0;

23
deps/v8/src/assembler.cc

@ -467,34 +467,35 @@ const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) {
} }
void RelocInfo::Print() { void RelocInfo::Print(FILE* out) {
PrintF("%p %s", pc_, RelocModeName(rmode_)); PrintF(out, "%p %s", pc_, RelocModeName(rmode_));
if (IsComment(rmode_)) { if (IsComment(rmode_)) {
PrintF(" (%s)", reinterpret_cast<char*>(data_)); PrintF(out, " (%s)", reinterpret_cast<char*>(data_));
} else if (rmode_ == EMBEDDED_OBJECT) { } else if (rmode_ == EMBEDDED_OBJECT) {
PrintF(" ("); PrintF(out, " (");
target_object()->ShortPrint(); target_object()->ShortPrint(out);
PrintF(")"); PrintF(out, ")");
} else if (rmode_ == EXTERNAL_REFERENCE) { } else if (rmode_ == EXTERNAL_REFERENCE) {
ExternalReferenceEncoder ref_encoder; ExternalReferenceEncoder ref_encoder;
PrintF(" (%s) (%p)", PrintF(out, " (%s) (%p)",
ref_encoder.NameOfAddress(*target_reference_address()), ref_encoder.NameOfAddress(*target_reference_address()),
*target_reference_address()); *target_reference_address());
} else if (IsCodeTarget(rmode_)) { } else if (IsCodeTarget(rmode_)) {
Code* code = Code::GetCodeFromTargetAddress(target_address()); Code* code = Code::GetCodeFromTargetAddress(target_address());
PrintF(" (%s) (%p)", Code::Kind2String(code->kind()), target_address()); PrintF(out, " (%s) (%p)", Code::Kind2String(code->kind()),
target_address());
} else if (IsPosition(rmode_)) { } else if (IsPosition(rmode_)) {
PrintF(" (%" V8_PTR_PREFIX "d)", data()); PrintF(out, " (%" V8_PTR_PREFIX "d)", data());
} else if (rmode_ == RelocInfo::RUNTIME_ENTRY) { } else if (rmode_ == RelocInfo::RUNTIME_ENTRY) {
// Depotimization bailouts are stored as runtime entries. // Depotimization bailouts are stored as runtime entries.
int id = Deoptimizer::GetDeoptimizationId( int id = Deoptimizer::GetDeoptimizationId(
target_address(), Deoptimizer::EAGER); target_address(), Deoptimizer::EAGER);
if (id != Deoptimizer::kNotDeoptimizationEntry) { if (id != Deoptimizer::kNotDeoptimizationEntry) {
PrintF(" (deoptimization bailout %d)", id); PrintF(out, " (deoptimization bailout %d)", id);
} }
} }
PrintF("\n"); PrintF(out, "\n");
} }
#endif // ENABLE_DISASSEMBLER #endif // ENABLE_DISASSEMBLER

2
deps/v8/src/assembler.h

@ -322,7 +322,7 @@ class RelocInfo BASE_EMBEDDED {
#ifdef ENABLE_DISASSEMBLER #ifdef ENABLE_DISASSEMBLER
// Printing // Printing
static const char* RelocModeName(Mode rmode); static const char* RelocModeName(Mode rmode);
void Print(); void Print(FILE* out);
#endif // ENABLE_DISASSEMBLER #endif // ENABLE_DISASSEMBLER
#ifdef DEBUG #ifdef DEBUG
// Debugging // Debugging

53
deps/v8/src/builtins.cc

@ -515,10 +515,10 @@ BUILTIN(ArrayShift) {
Object* elms_obj; Object* elms_obj;
{ MaybeObject* maybe_elms_obj = { MaybeObject* maybe_elms_obj =
EnsureJSArrayWithWritableFastElements(receiver); EnsureJSArrayWithWritableFastElements(receiver);
if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayShift", args);
if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
} }
if (elms_obj == NULL || if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
return CallJsBuiltin("ArrayShift", args); return CallJsBuiltin("ArrayShift", args);
} }
FixedArray* elms = FixedArray::cast(elms_obj); FixedArray* elms = FixedArray::cast(elms_obj);
@ -557,10 +557,10 @@ BUILTIN(ArrayUnshift) {
Object* elms_obj; Object* elms_obj;
{ MaybeObject* maybe_elms_obj = { MaybeObject* maybe_elms_obj =
EnsureJSArrayWithWritableFastElements(receiver); EnsureJSArrayWithWritableFastElements(receiver);
if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayUnshift", args);
if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
} }
if (elms_obj == NULL || if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
return CallJsBuiltin("ArrayUnshift", args); return CallJsBuiltin("ArrayUnshift", args);
} }
FixedArray* elms = FixedArray::cast(elms_obj); FixedArray* elms = FixedArray::cast(elms_obj);
@ -611,21 +611,46 @@ BUILTIN(ArrayUnshift) {
BUILTIN(ArraySlice) { BUILTIN(ArraySlice) {
Object* receiver = *args.receiver(); Object* receiver = *args.receiver();
Object* elms_obj; FixedArray* elms;
int len = -1;
{ MaybeObject* maybe_elms_obj = { MaybeObject* maybe_elms_obj =
EnsureJSArrayWithWritableFastElements(receiver); EnsureJSArrayWithWritableFastElements(receiver);
if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; Object* elms_obj;
} if (maybe_elms_obj != NULL && maybe_elms_obj->ToObject(&elms_obj)) {
if (elms_obj == NULL || if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
return CallJsBuiltin("ArraySlice", args); return CallJsBuiltin("ArraySlice", args);
} }
FixedArray* elms = FixedArray::cast(elms_obj); elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver); JSArray* array = JSArray::cast(receiver);
ASSERT(array->HasFastElements()); ASSERT(array->HasFastElements());
int len = Smi::cast(array->length())->value(); len = Smi::cast(array->length())->value();
} else {
// Array.slice(arguments, ...) is quite a common idiom (notably more
// than 50% of invocations in Web apps). Treat it in C++ as well.
Map* arguments_map =
Top::context()->global_context()->arguments_boilerplate()->map();
bool is_arguments_object_with_fast_elements =
receiver->IsJSObject()
&& JSObject::cast(receiver)->map() == arguments_map
&& JSObject::cast(receiver)->HasFastElements();
if (!is_arguments_object_with_fast_elements) {
return CallJsBuiltin("ArraySlice", args);
}
elms = FixedArray::cast(JSObject::cast(receiver)->elements());
len = elms->length();
#ifdef DEBUG
// Arguments object by construction should have no holes, check it.
if (FLAG_enable_slow_asserts) {
for (int i = 0; i < len; i++) {
ASSERT(elms->get(i) != Heap::the_hole_value());
}
}
#endif
}
}
ASSERT(len >= 0);
int n_arguments = args.length() - 1; int n_arguments = args.length() - 1;
// Note carefully choosen defaults---if argument is missing, // Note carefully choosen defaults---if argument is missing,
@ -693,10 +718,10 @@ BUILTIN(ArraySplice) {
Object* elms_obj; Object* elms_obj;
{ MaybeObject* maybe_elms_obj = { MaybeObject* maybe_elms_obj =
EnsureJSArrayWithWritableFastElements(receiver); EnsureJSArrayWithWritableFastElements(receiver);
if (maybe_elms_obj == NULL) return CallJsBuiltin("ArraySplice", args);
if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
} }
if (elms_obj == NULL || if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
return CallJsBuiltin("ArraySplice", args); return CallJsBuiltin("ArraySplice", args);
} }
FixedArray* elms = FixedArray::cast(elms_obj); FixedArray* elms = FixedArray::cast(elms_obj);

3
deps/v8/src/code-stubs.h

@ -47,7 +47,7 @@ namespace internal {
V(Compare) \ V(Compare) \
V(CompareIC) \ V(CompareIC) \
V(MathPow) \ V(MathPow) \
V(TranscendentalCacheSSE2) \ V(TranscendentalCache) \
V(RecordWrite) \ V(RecordWrite) \
V(ConvertToDouble) \ V(ConvertToDouble) \
V(WriteInt32ToHeapNumber) \ V(WriteInt32ToHeapNumber) \
@ -56,7 +56,6 @@ namespace internal {
V(FastNewClosure) \ V(FastNewClosure) \
V(FastNewContext) \ V(FastNewContext) \
V(FastCloneShallowArray) \ V(FastCloneShallowArray) \
V(TranscendentalCache) \
V(GenericUnaryOp) \ V(GenericUnaryOp) \
V(RevertToNumber) \ V(RevertToNumber) \
V(ToBoolean) \ V(ToBoolean) \

11
deps/v8/src/codegen.cc

@ -215,8 +215,17 @@ void CodeGenerator::PrintCode(Handle<Code> code, CompilationInfo* info) {
} }
PrintF("\n\n"); PrintF("\n\n");
} }
if (info->IsOptimizing()) {
if (FLAG_print_unopt_code) {
PrintF("--- Unoptimized code ---\n");
info->closure()->shared()->code()->Disassemble(
*function->debug_name()->ToCString());
}
PrintF("--- Optimized code ---\n");
} else {
PrintF("--- Code ---\n"); PrintF("--- Code ---\n");
code->Disassemble(*function->name()->ToCString()); }
code->Disassemble(*function->debug_name()->ToCString());
} }
#endif // ENABLE_DISASSEMBLER #endif // ENABLE_DISASSEMBLER
} }

3
deps/v8/src/counters.h

@ -28,6 +28,9 @@
#ifndef V8_COUNTERS_H_ #ifndef V8_COUNTERS_H_
#define V8_COUNTERS_H_ #define V8_COUNTERS_H_
#include "../include/v8.h"
#include "allocation.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {

33
deps/v8/src/date.js

@ -1007,6 +1007,39 @@ function DateToJSON(key) {
} }
function ResetDateCache() {
// Reset the local_time_offset:
local_time_offset = %DateLocalTimeOffset();
// Reset the DST offset cache:
var cache = DST_offset_cache;
cache.offset = 0;
cache.start = 0;
cache.end = -1;
cache.increment = 0;
cache.initial_increment = 19 * msPerDay;
// Reset the timezone cache:
timezone_cache_time = $NaN;
timezone_cache_timezone = undefined;
// Reset the ltcache:
ltcache.key = null;
ltcache.val = null;
// Reset the ymd_from_time_cache:
ymd_from_time_cache = [$NaN, $NaN, $NaN];
ymd_from_time_cached_time = $NaN;
// Reset the date cache:
cache = Date_cache;
cache.time = $NaN;
cache.year = $NaN;
cache.string = null;
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
function SetupDate() { function SetupDate() {

2
deps/v8/src/debug.cc

@ -858,7 +858,7 @@ bool Debug::Load() {
if (caught_exception) return false; if (caught_exception) return false;
// Debugger loaded. // Debugger loaded.
debug_context_ = Handle<Context>::cast(GlobalHandles::Create(*context)); debug_context_ = context;
return true; return true;
} }

2
deps/v8/src/deoptimizer.cc

@ -1096,7 +1096,7 @@ int Translation::NumberOfOperandsFor(Opcode opcode) {
} }
#ifdef DEBUG #ifdef OBJECT_PRINT
const char* Translation::StringFor(Opcode opcode) { const char* Translation::StringFor(Opcode opcode) {
switch (opcode) { switch (opcode) {

2
deps/v8/src/deoptimizer.h

@ -476,7 +476,7 @@ class Translation BASE_EMBEDDED {
static int NumberOfOperandsFor(Opcode opcode); static int NumberOfOperandsFor(Opcode opcode);
#ifdef DEBUG #ifdef OBJECT_PRINT
static const char* StringFor(Opcode opcode); static const char* StringFor(Opcode opcode);
#endif #endif

5
deps/v8/src/flag-definitions.h

@ -296,6 +296,9 @@ DEFINE_int(max_map_space_pages, MapSpace::kMaxMapPageIndex - 1,
DEFINE_bool(h, false, "print this message") DEFINE_bool(h, false, "print this message")
DEFINE_bool(new_snapshot, true, "use new snapshot implementation") DEFINE_bool(new_snapshot, true, "use new snapshot implementation")
// objects.cc
DEFINE_bool(use_verbose_printer, true, "allows verbose printing")
// parser.cc // parser.cc
DEFINE_bool(allow_natives_syntax, false, "allow natives syntax") DEFINE_bool(allow_natives_syntax, false, "allow natives syntax")
@ -503,6 +506,8 @@ DEFINE_bool(print_code_stubs, false, "print code stubs")
// codegen-ia32.cc / codegen-arm.cc // codegen-ia32.cc / codegen-arm.cc
DEFINE_bool(print_code, false, "print generated code") DEFINE_bool(print_code, false, "print generated code")
DEFINE_bool(print_opt_code, false, "print optimized code") DEFINE_bool(print_opt_code, false, "print optimized code")
DEFINE_bool(print_unopt_code, false, "print unoptimized code before "
"printing optimized code based on it")
DEFINE_bool(print_code_verbose, false, "print more information for code") DEFINE_bool(print_code_verbose, false, "print more information for code")
DEFINE_bool(print_builtin_code, false, "print generated code for builtins") DEFINE_bool(print_builtin_code, false, "print generated code for builtins")

9
deps/v8/src/full-codegen.cc

@ -671,8 +671,12 @@ const FullCodeGenerator::InlineFunctionGenerator
FullCodeGenerator::InlineFunctionGenerator FullCodeGenerator::InlineFunctionGenerator
FullCodeGenerator::FindInlineFunctionGenerator(Runtime::FunctionId id) { FullCodeGenerator::FindInlineFunctionGenerator(Runtime::FunctionId id) {
return kInlineFunctionGenerators[ int lookup_index =
static_cast<int>(id) - static_cast<int>(Runtime::kFirstInlineFunction)]; static_cast<int>(id) - static_cast<int>(Runtime::kFirstInlineFunction);
ASSERT(lookup_index >= 0);
ASSERT(static_cast<size_t>(lookup_index) <
ARRAY_SIZE(kInlineFunctionGenerators));
return kInlineFunctionGenerators[lookup_index];
} }
@ -684,7 +688,6 @@ void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* node) {
ASSERT(function->intrinsic_type == Runtime::INLINE); ASSERT(function->intrinsic_type == Runtime::INLINE);
InlineFunctionGenerator generator = InlineFunctionGenerator generator =
FindInlineFunctionGenerator(function->function_id); FindInlineFunctionGenerator(function->function_id);
ASSERT(generator != NULL);
((*this).*(generator))(args); ((*this).*(generator))(args);
} }

4
deps/v8/src/heap-profiler.cc

@ -367,7 +367,6 @@ HeapSnapshot* HeapProfiler::TakeSnapshot(String* name,
HeapSnapshot* HeapProfiler::TakeSnapshotImpl(const char* name, HeapSnapshot* HeapProfiler::TakeSnapshotImpl(const char* name,
int type, int type,
v8::ActivityControl* control) { v8::ActivityControl* control) {
Heap::CollectAllGarbage(true);
HeapSnapshot::Type s_type = static_cast<HeapSnapshot::Type>(type); HeapSnapshot::Type s_type = static_cast<HeapSnapshot::Type>(type);
HeapSnapshot* result = HeapSnapshot* result =
snapshots_->NewSnapshot(s_type, name, next_snapshot_uid_++); snapshots_->NewSnapshot(s_type, name, next_snapshot_uid_++);
@ -379,6 +378,7 @@ HeapSnapshot* HeapProfiler::TakeSnapshotImpl(const char* name,
break; break;
} }
case HeapSnapshot::kAggregated: { case HeapSnapshot::kAggregated: {
Heap::CollectAllGarbage(true);
AggregatedHeapSnapshot agg_snapshot; AggregatedHeapSnapshot agg_snapshot;
AggregatedHeapSnapshotGenerator generator(&agg_snapshot); AggregatedHeapSnapshotGenerator generator(&agg_snapshot);
generator.GenerateSnapshot(); generator.GenerateSnapshot();
@ -808,7 +808,7 @@ void AggregatedHeapSnapshotGenerator::CollectStats(HeapObject* obj) {
void AggregatedHeapSnapshotGenerator::GenerateSnapshot() { void AggregatedHeapSnapshotGenerator::GenerateSnapshot() {
HeapIterator iterator(HeapIterator::kPreciseFiltering); HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
CollectStats(obj); CollectStats(obj);
agg_snapshot_->js_cons_profile()->CollectStats(obj); agg_snapshot_->js_cons_profile()->CollectStats(obj);

95
deps/v8/src/heap.cc

@ -4483,7 +4483,7 @@ void Heap::RecordStats(HeapStats* stats, bool take_snapshot) {
MemoryAllocator::Size() + MemoryAllocator::Available(); MemoryAllocator::Size() + MemoryAllocator::Available();
*stats->os_error = OS::GetLastError(); *stats->os_error = OS::GetLastError();
if (take_snapshot) { if (take_snapshot) {
HeapIterator iterator(HeapIterator::kPreciseFiltering); HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
for (HeapObject* obj = iterator.next(); for (HeapObject* obj = iterator.next();
obj != NULL; obj != NULL;
obj = iterator.next()) { obj = iterator.next()) {
@ -4917,13 +4917,20 @@ ObjectIterator* SpaceIterator::CreateIterator() {
} }
class FreeListNodesFilter { class HeapObjectsFilter {
public:
virtual ~HeapObjectsFilter() {}
virtual bool SkipObject(HeapObject* object) = 0;
};
class FreeListNodesFilter : public HeapObjectsFilter {
public: public:
FreeListNodesFilter() { FreeListNodesFilter() {
MarkFreeListNodes(); MarkFreeListNodes();
} }
inline bool IsFreeListNode(HeapObject* object) { bool SkipObject(HeapObject* object) {
if (object->IsMarked()) { if (object->IsMarked()) {
object->ClearMark(); object->ClearMark();
return true; return true;
@ -4955,6 +4962,65 @@ class FreeListNodesFilter {
}; };
class UnreachableObjectsFilter : public HeapObjectsFilter {
public:
UnreachableObjectsFilter() {
MarkUnreachableObjects();
}
bool SkipObject(HeapObject* object) {
if (object->IsMarked()) {
object->ClearMark();
return true;
} else {
return false;
}
}
private:
class UnmarkingVisitor : public ObjectVisitor {
public:
UnmarkingVisitor() : list_(10) {}
void VisitPointers(Object** start, Object** end) {
for (Object** p = start; p < end; p++) {
if (!(*p)->IsHeapObject()) continue;
HeapObject* obj = HeapObject::cast(*p);
if (obj->IsMarked()) {
obj->ClearMark();
list_.Add(obj);
}
}
}
bool can_process() { return !list_.is_empty(); }
void ProcessNext() {
HeapObject* obj = list_.RemoveLast();
obj->Iterate(this);
}
private:
List<HeapObject*> list_;
};
void MarkUnreachableObjects() {
HeapIterator iterator;
for (HeapObject* obj = iterator.next();
obj != NULL;
obj = iterator.next()) {
obj->SetMark();
}
UnmarkingVisitor visitor;
Heap::IterateRoots(&visitor, VISIT_ONLY_STRONG);
while (visitor.can_process())
visitor.ProcessNext();
}
AssertNoAllocation no_alloc;
};
HeapIterator::HeapIterator() HeapIterator::HeapIterator()
: filtering_(HeapIterator::kNoFiltering), : filtering_(HeapIterator::kNoFiltering),
filter_(NULL) { filter_(NULL) {
@ -4962,7 +5028,7 @@ HeapIterator::HeapIterator()
} }
HeapIterator::HeapIterator(HeapIterator::FreeListNodesFiltering filtering) HeapIterator::HeapIterator(HeapIterator::HeapObjectsFiltering filtering)
: filtering_(filtering), : filtering_(filtering),
filter_(NULL) { filter_(NULL) {
Init(); Init();
@ -4976,12 +5042,17 @@ HeapIterator::~HeapIterator() {
void HeapIterator::Init() { void HeapIterator::Init() {
// Start the iteration. // Start the iteration.
if (filtering_ == kPreciseFiltering) { space_iterator_ = filtering_ == kNoFiltering ? new SpaceIterator :
filter_ = new FreeListNodesFilter;
space_iterator_ =
new SpaceIterator(MarkCompactCollector::SizeOfMarkedObject); new SpaceIterator(MarkCompactCollector::SizeOfMarkedObject);
} else { switch (filtering_) {
space_iterator_ = new SpaceIterator; case kFilterFreeListNodes:
filter_ = new FreeListNodesFilter;
break;
case kFilterUnreachable:
filter_ = new UnreachableObjectsFilter;
break;
default:
break;
} }
object_iterator_ = space_iterator_->next(); object_iterator_ = space_iterator_->next();
} }
@ -4989,9 +5060,9 @@ void HeapIterator::Init() {
void HeapIterator::Shutdown() { void HeapIterator::Shutdown() {
#ifdef DEBUG #ifdef DEBUG
// Assert that in precise mode we have iterated through all // Assert that in filtering mode we have iterated through all
// objects. Otherwise, heap will be left in an inconsistent state. // objects. Otherwise, heap will be left in an inconsistent state.
if (filtering_ == kPreciseFiltering) { if (filtering_ != kNoFiltering) {
ASSERT(object_iterator_ == NULL); ASSERT(object_iterator_ == NULL);
} }
#endif #endif
@ -5008,7 +5079,7 @@ HeapObject* HeapIterator::next() {
if (filter_ == NULL) return NextObject(); if (filter_ == NULL) return NextObject();
HeapObject* obj = NextObject(); HeapObject* obj = NextObject();
while (obj != NULL && filter_->IsFreeListNode(obj)) obj = NextObject(); while (obj != NULL && filter_->SkipObject(obj)) obj = NextObject();
return obj; return obj;
} }

16
deps/v8/src/heap.h

@ -1585,17 +1585,18 @@ class SpaceIterator : public Malloced {
// nodes filtering uses GC marks, it can't be used during MS/MC GC // nodes filtering uses GC marks, it can't be used during MS/MC GC
// phases. Also, it is forbidden to interrupt iteration in this mode, // phases. Also, it is forbidden to interrupt iteration in this mode,
// as this will leave heap objects marked (and thus, unusable). // as this will leave heap objects marked (and thus, unusable).
class FreeListNodesFilter; class HeapObjectsFilter;
class HeapIterator BASE_EMBEDDED { class HeapIterator BASE_EMBEDDED {
public: public:
enum FreeListNodesFiltering { enum HeapObjectsFiltering {
kNoFiltering, kNoFiltering,
kPreciseFiltering kFilterFreeListNodes,
kFilterUnreachable
}; };
HeapIterator(); HeapIterator();
explicit HeapIterator(FreeListNodesFiltering filtering); explicit HeapIterator(HeapObjectsFiltering filtering);
~HeapIterator(); ~HeapIterator();
HeapObject* next(); HeapObject* next();
@ -1608,8 +1609,8 @@ class HeapIterator BASE_EMBEDDED {
void Shutdown(); void Shutdown();
HeapObject* NextObject(); HeapObject* NextObject();
FreeListNodesFiltering filtering_; HeapObjectsFiltering filtering_;
FreeListNodesFilter* filter_; HeapObjectsFilter* filter_;
// Space iterator for iterating all the spaces. // Space iterator for iterating all the spaces.
SpaceIterator* space_iterator_; SpaceIterator* space_iterator_;
// Object iterator for the space currently being iterated. // Object iterator for the space currently being iterated.
@ -1968,6 +1969,8 @@ class GCTracer BASE_EMBEDDED {
class TranscendentalCache { class TranscendentalCache {
public: public:
enum Type {ACOS, ASIN, ATAN, COS, EXP, LOG, SIN, TAN, kNumberOfCaches}; enum Type {ACOS, ASIN, ATAN, COS, EXP, LOG, SIN, TAN, kNumberOfCaches};
static const int kTranscendentalTypeBits = 3;
STATIC_ASSERT((1 << kTranscendentalTypeBits) >= kNumberOfCaches);
explicit TranscendentalCache(Type t); explicit TranscendentalCache(Type t);
@ -2056,7 +2059,6 @@ class TranscendentalCache {
friend class ExternalReference; friend class ExternalReference;
// Inline implementation of the cache. // Inline implementation of the cache.
friend class TranscendentalCacheStub; friend class TranscendentalCacheStub;
friend class TranscendentalCacheSSE2Stub;
static TranscendentalCache* caches_[kNumberOfCaches]; static TranscendentalCache* caches_[kNumberOfCaches];
Element elements_[kCacheSize]; Element elements_[kCacheSize];

7
deps/v8/src/hydrogen-instructions.cc

@ -579,6 +579,13 @@ void HBranch::PrintDataTo(StringStream* stream) const {
} }
void HCompareMapAndBranch::PrintDataTo(StringStream* stream) const {
stream->Add("on ");
value()->PrintNameTo(stream);
stream->Add(" (%p)", *map());
}
void HGoto::PrintDataTo(StringStream* stream) const { void HGoto::PrintDataTo(StringStream* stream) const {
stream->Add("B%d", FirstSuccessor()->block_id()); stream->Add("B%d", FirstSuccessor()->block_id());
} }

6
deps/v8/src/hydrogen-instructions.h

@ -905,6 +905,8 @@ class HCompareMapAndBranch: public HUnaryControlInstruction {
virtual HBasicBlock* FirstSuccessor() const { return true_destination_; } virtual HBasicBlock* FirstSuccessor() const { return true_destination_; }
virtual HBasicBlock* SecondSuccessor() const { return false_destination_; } virtual HBasicBlock* SecondSuccessor() const { return false_destination_; }
virtual void PrintDataTo(StringStream* stream) const;
Handle<Map> map() const { return map_; } Handle<Map> map() const { return map_; }
DECLARE_CONCRETE_INSTRUCTION(CompareMapAndBranch, "compare_map_and_branch") DECLARE_CONCRETE_INSTRUCTION(CompareMapAndBranch, "compare_map_and_branch")
@ -1387,6 +1389,8 @@ class HUnaryMathOperation: public HUnaryOperation {
case kMathSqrt: case kMathSqrt:
case kMathPowHalf: case kMathPowHalf:
case kMathLog: case kMathLog:
case kMathSin:
case kMathCos:
set_representation(Representation::Double()); set_representation(Representation::Double());
break; break;
default: default:
@ -1409,6 +1413,8 @@ class HUnaryMathOperation: public HUnaryOperation {
case kMathSqrt: case kMathSqrt:
case kMathPowHalf: case kMathPowHalf:
case kMathLog: case kMathLog:
case kMathSin:
case kMathCos:
return Representation::Double(); return Representation::Double();
break; break;
case kMathAbs: case kMathAbs:

12
deps/v8/src/hydrogen.cc

@ -3165,6 +3165,9 @@ HInstruction* HGraphBuilder::BuildStoreNamedField(HValue* object,
if (lookup->type() == MAP_TRANSITION) { if (lookup->type() == MAP_TRANSITION) {
Handle<Map> transition(lookup->GetTransitionMapFromMap(*type)); Handle<Map> transition(lookup->GetTransitionMapFromMap(*type));
instr->set_transition(transition); instr->set_transition(transition);
// TODO(fschneider): Record the new map type of the object in the IR to
// enable elimination of redundant checks after the transition store.
instr->SetFlag(HValue::kChangesMaps);
} }
return instr; return instr;
} }
@ -3529,9 +3532,10 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr,
maps.Add(map); maps.Add(map);
HSubgraph* subgraph = CreateBranchSubgraph(environment()); HSubgraph* subgraph = CreateBranchSubgraph(environment());
SubgraphScope scope(this, subgraph); SubgraphScope scope(this, subgraph);
HInstruction* instr = HLoadNamedField* instr =
BuildLoadNamedField(object, expr, map, &lookup, false); BuildLoadNamedField(object, expr, map, &lookup, false);
instr->set_position(expr->position()); instr->set_position(expr->position());
instr->ClearFlag(HValue::kUseGVN); // Don't do GVN on polymorphic loads.
PushAndAdd(instr); PushAndAdd(instr);
subgraphs.Add(subgraph); subgraphs.Add(subgraph);
} else { } else {
@ -3570,7 +3574,7 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr,
} }
HInstruction* HGraphBuilder::BuildLoadNamedField(HValue* object, HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object,
Property* expr, Property* expr,
Handle<Map> type, Handle<Map> type,
LookupResult* lookup, LookupResult* lookup,
@ -4093,6 +4097,8 @@ bool HGraphBuilder::TryMathFunctionInline(Call* expr) {
case kMathAbs: case kMathAbs:
case kMathSqrt: case kMathSqrt:
case kMathLog: case kMathLog:
case kMathSin:
case kMathCos:
if (argument_count == 2) { if (argument_count == 2) {
HValue* argument = Pop(); HValue* argument = Pop();
Drop(1); // Receiver. Drop(1); // Receiver.
@ -4169,7 +4175,7 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
if (args->length() != 2) return false; if (args->length() != 2) return false;
VariableProxy* arg_two = args->at(1)->AsVariableProxy(); VariableProxy* arg_two = args->at(1)->AsVariableProxy();
if (arg_two == NULL) return false; if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
HValue* arg_two_value = environment()->Lookup(arg_two->var()); HValue* arg_two_value = environment()->Lookup(arg_two->var());
if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;

2
deps/v8/src/hydrogen.h

@ -786,7 +786,7 @@ class HGraphBuilder: public AstVisitor {
HValue* left, HValue* left,
HValue* right); HValue* right);
HInstruction* BuildIncrement(HValue* value, bool increment); HInstruction* BuildIncrement(HValue* value, bool increment);
HInstruction* BuildLoadNamedField(HValue* object, HLoadNamedField* BuildLoadNamedField(HValue* object,
Property* expr, Property* expr,
Handle<Map> type, Handle<Map> type,
LookupResult* result, LookupResult* result,

232
deps/v8/src/ia32/code-stubs-ia32.cc

@ -2472,12 +2472,25 @@ void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
void TranscendentalCacheStub::Generate(MacroAssembler* masm) { void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
// Input on stack: // TAGGED case:
// esp[4]: argument (should be number). // Input:
// esp[4]: tagged number input argument (should be number).
// esp[0]: return address. // esp[0]: return address.
// Test that eax is a number. // Output:
// eax: tagged double result.
// UNTAGGED case:
// Input::
// esp[0]: return address.
// xmm1: untagged double input argument
// Output:
// xmm1: untagged double result.
Label runtime_call; Label runtime_call;
Label runtime_call_clear_stack; Label runtime_call_clear_stack;
Label skip_cache;
const bool tagged = (argument_type_ == TAGGED);
if (tagged) {
// Test that eax is a number.
NearLabel input_not_smi; NearLabel input_not_smi;
NearLabel loaded; NearLabel loaded;
__ mov(eax, Operand(esp, kPointerSize)); __ mov(eax, Operand(esp, kPointerSize));
@ -2506,7 +2519,18 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
__ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset)); __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset));
__ bind(&loaded); __ bind(&loaded);
// ST[0] == double value } else { // UNTAGGED.
if (CpuFeatures::IsSupported(SSE4_1)) {
CpuFeatures::Scope sse4_scope(SSE4_1);
__ pextrd(Operand(edx), xmm1, 0x1); // copy xmm1[63..32] to edx.
} else {
__ pshufd(xmm0, xmm1, 0x1);
__ movd(Operand(edx), xmm0);
}
__ movd(Operand(ebx), xmm1);
}
// ST[0] or xmm1 == double value
// ebx = low 32 bits of double value // ebx = low 32 bits of double value
// edx = high 32 bits of double value // edx = high 32 bits of double value
// Compute hash (the shifts are arithmetic): // Compute hash (the shifts are arithmetic):
@ -2522,7 +2546,7 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize)); ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize));
__ and_(Operand(ecx), Immediate(TranscendentalCache::kCacheSize - 1)); __ and_(Operand(ecx), Immediate(TranscendentalCache::kCacheSize - 1));
// ST[0] == double value. // ST[0] or xmm1 == double value.
// ebx = low 32 bits of double value. // ebx = low 32 bits of double value.
// edx = high 32 bits of double value. // edx = high 32 bits of double value.
// ecx = TranscendentalCache::hash(double value). // ecx = TranscendentalCache::hash(double value).
@ -2559,31 +2583,80 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
__ j(not_equal, &cache_miss); __ j(not_equal, &cache_miss);
// Cache hit! // Cache hit!
__ mov(eax, Operand(ecx, 2 * kIntSize)); __ mov(eax, Operand(ecx, 2 * kIntSize));
if (tagged) {
__ fstp(0); __ fstp(0);
__ ret(kPointerSize); __ ret(kPointerSize);
} else { // UNTAGGED.
__ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
__ Ret();
}
__ bind(&cache_miss); __ bind(&cache_miss);
// Update cache with new value. // Update cache with new value.
// We are short on registers, so use no_reg as scratch. // We are short on registers, so use no_reg as scratch.
// This gives slightly larger code. // This gives slightly larger code.
if (tagged) {
__ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack); __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack);
} else { // UNTAGGED.
__ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
__ sub(Operand(esp), Immediate(kDoubleSize));
__ movdbl(Operand(esp, 0), xmm1);
__ fld_d(Operand(esp, 0));
__ add(Operand(esp), Immediate(kDoubleSize));
}
GenerateOperation(masm); GenerateOperation(masm);
__ mov(Operand(ecx, 0), ebx); __ mov(Operand(ecx, 0), ebx);
__ mov(Operand(ecx, kIntSize), edx); __ mov(Operand(ecx, kIntSize), edx);
__ mov(Operand(ecx, 2 * kIntSize), eax); __ mov(Operand(ecx, 2 * kIntSize), eax);
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
if (tagged) {
__ ret(kPointerSize); __ ret(kPointerSize);
} else { // UNTAGGED.
__ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
__ Ret();
// Skip cache and return answer directly, only in untagged case.
__ bind(&skip_cache);
__ sub(Operand(esp), Immediate(kDoubleSize));
__ movdbl(Operand(esp, 0), xmm1);
__ fld_d(Operand(esp, 0));
GenerateOperation(masm);
__ fstp_d(Operand(esp, 0));
__ movdbl(xmm1, Operand(esp, 0));
__ add(Operand(esp), Immediate(kDoubleSize));
// We return the value in xmm1 without adding it to the cache, but
// we cause a scavenging GC so that future allocations will succeed.
__ EnterInternalFrame();
// Allocate an unused object bigger than a HeapNumber.
__ push(Immediate(Smi::FromInt(2 * kDoubleSize)));
__ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
__ LeaveInternalFrame();
__ Ret();
}
// Call runtime, doing whatever allocation and cleanup is necessary.
if (tagged) {
__ bind(&runtime_call_clear_stack); __ bind(&runtime_call_clear_stack);
__ fstp(0); __ fstp(0);
__ bind(&runtime_call); __ bind(&runtime_call);
__ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1);
} else { // UNTAGGED.
__ bind(&runtime_call_clear_stack);
__ bind(&runtime_call);
__ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm1);
__ EnterInternalFrame();
__ push(eax);
__ CallRuntime(RuntimeFunction(), 1);
__ LeaveInternalFrame();
__ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
__ Ret();
}
} }
Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
switch (type_) { switch (type_) {
// Add more cases when necessary.
case TranscendentalCache::SIN: return Runtime::kMath_sin; case TranscendentalCache::SIN: return Runtime::kMath_sin;
case TranscendentalCache::COS: return Runtime::kMath_cos; case TranscendentalCache::COS: return Runtime::kMath_cos;
case TranscendentalCache::LOG: return Runtime::kMath_log; case TranscendentalCache::LOG: return Runtime::kMath_log;
@ -2596,14 +2669,14 @@ Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) { void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
// Only free register is edi. // Only free register is edi.
// Input value is on FP stack, and also in ebx/edx. Address of result // Input value is on FP stack, and also in ebx/edx.
// (a newly allocated HeapNumber) is in eax. // Input value is possibly in xmm1.
NearLabel done; // Address of result (a newly allocated HeapNumber) may be in eax.
if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) { if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) {
// Both fsin and fcos require arguments in the range +/-2^63 and // Both fsin and fcos require arguments in the range +/-2^63 and
// return NaN for infinities and NaN. They can share all code except // return NaN for infinities and NaN. They can share all code except
// the actual fsin/fcos operation. // the actual fsin/fcos operation.
NearLabel in_range; NearLabel in_range, done;
// If argument is outside the range -2^63..2^63, fsin/cos doesn't // If argument is outside the range -2^63..2^63, fsin/cos doesn't
// work. We must reduce it to the appropriate range. // work. We must reduce it to the appropriate range.
__ mov(edi, edx); __ mov(edi, edx);
@ -2683,145 +2756,6 @@ void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
} }
void TranscendentalCacheSSE2Stub::Generate(MacroAssembler* masm) {
// Input on stack:
// esp[0]: return address.
// Input in registers:
// xmm1: untagged double input argument.
// Output:
// xmm1: untagged double result.
Label skip_cache;
Label call_runtime;
// Input is an untagged double in xmm1.
// Compute hash (the shifts are arithmetic):
// h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
if (CpuFeatures::IsSupported(SSE4_1)) {
CpuFeatures::Scope sse4_scope(SSE4_1);
__ pextrd(Operand(edx), xmm1, 0x1); // copy xmm1[63..32] to edx.
} else {
__ pshufd(xmm0, xmm1, 0x1);
__ movd(Operand(edx), xmm0);
}
__ movd(Operand(ebx), xmm1);
// xmm1 = double value
// ebx = low 32 bits of double value
// edx = high 32 bits of double value
// Compute hash (the shifts are arithmetic):
// h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
__ mov(ecx, ebx);
__ xor_(ecx, Operand(edx));
__ mov(eax, ecx);
__ sar(eax, 16);
__ xor_(ecx, Operand(eax));
__ mov(eax, ecx);
__ sar(eax, 8);
__ xor_(ecx, Operand(eax));
ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize));
__ and_(Operand(ecx), Immediate(TranscendentalCache::kCacheSize - 1));
// xmm1 = double value.
// ebx = low 32 bits of double value.
// edx = high 32 bits of double value.
// ecx = TranscendentalCache::hash(double value).
__ mov(eax,
Immediate(ExternalReference::transcendental_cache_array_address()));
// Eax points to cache array.
__ mov(eax, Operand(eax, type_ * sizeof(TranscendentalCache::caches_[0])));
// Eax points to the cache for the type type_.
// If NULL, the cache hasn't been initialized yet, so go through runtime.
__ test(eax, Operand(eax));
__ j(zero, &call_runtime);
#ifdef DEBUG
// Check that the layout of cache elements match expectations.
{ TranscendentalCache::Element test_elem[2];
char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer.
CHECK_EQ(0, elem_in0 - elem_start);
CHECK_EQ(kIntSize, elem_in1 - elem_start);
CHECK_EQ(2 * kIntSize, elem_out - elem_start);
}
#endif
// Find the address of the ecx'th entry in the cache, i.e., &eax[ecx*12].
__ lea(ecx, Operand(ecx, ecx, times_2, 0));
__ lea(ecx, Operand(eax, ecx, times_4, 0));
// Check if cache matches: Double value is stored in uint32_t[2] array.
NearLabel cache_miss;
__ cmp(ebx, Operand(ecx, 0));
__ j(not_equal, &cache_miss);
__ cmp(edx, Operand(ecx, kIntSize));
__ j(not_equal, &cache_miss);
// Cache hit!
__ mov(eax, Operand(ecx, 2 * kIntSize));
__ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
__ Ret();
__ bind(&cache_miss);
// Update cache with new value.
// We are short on registers, so use no_reg as scratch.
// This gives slightly larger code.
__ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
__ sub(Operand(esp), Immediate(kDoubleSize));
__ movdbl(Operand(esp, 0), xmm1);
__ fld_d(Operand(esp, 0));
__ add(Operand(esp), Immediate(kDoubleSize));
GenerateOperation(masm);
__ mov(Operand(ecx, 0), ebx);
__ mov(Operand(ecx, kIntSize), edx);
__ mov(Operand(ecx, 2 * kIntSize), eax);
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
__ Ret();
__ bind(&skip_cache);
__ sub(Operand(esp), Immediate(kDoubleSize));
__ movdbl(Operand(esp, 0), xmm1);
__ fld_d(Operand(esp, 0));
GenerateOperation(masm);
__ fstp_d(Operand(esp, 0));
__ movdbl(xmm1, Operand(esp, 0));
__ add(Operand(esp), Immediate(kDoubleSize));
__ Ret();
__ bind(&call_runtime);
__ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm1);
__ EnterInternalFrame();
__ push(eax);
__ CallRuntime(RuntimeFunction(), 1);
__ LeaveInternalFrame();
__ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
__ Ret();
}
Runtime::FunctionId TranscendentalCacheSSE2Stub::RuntimeFunction() {
switch (type_) {
// Add more cases when necessary.
case TranscendentalCache::LOG: return Runtime::kMath_log;
default:
UNIMPLEMENTED();
return Runtime::kAbort;
}
}
void TranscendentalCacheSSE2Stub::GenerateOperation(MacroAssembler* masm) {
// Only free register is edi.
// Input value is on FP stack and in xmm1.
ASSERT(type_ == TranscendentalCache::LOG);
__ fldln2();
__ fxch();
__ fyl2x();
}
// Get the integer part of a heap number. Surprisingly, all this bit twiddling // Get the integer part of a heap number. Surprisingly, all this bit twiddling
// is faster than using the built-in instructions on floating point registers. // is faster than using the built-in instructions on floating point registers.
// Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the

29
deps/v8/src/ia32/code-stubs-ia32.h

@ -40,32 +40,21 @@ namespace internal {
// TranscendentalCache runtime function. // TranscendentalCache runtime function.
class TranscendentalCacheStub: public CodeStub { class TranscendentalCacheStub: public CodeStub {
public: public:
explicit TranscendentalCacheStub(TranscendentalCache::Type type) enum ArgumentType {
: type_(type) {} TAGGED = 0,
void Generate(MacroAssembler* masm); UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
private:
TranscendentalCache::Type type_;
Major MajorKey() { return TranscendentalCache; }
int MinorKey() { return type_; }
Runtime::FunctionId RuntimeFunction();
void GenerateOperation(MacroAssembler* masm);
}; };
explicit TranscendentalCacheStub(TranscendentalCache::Type type,
// Check the transcendental cache, or generate the result, using SSE2. ArgumentType argument_type)
// The argument and result will be in xmm1. : type_(type), argument_type_(argument_type) {}
// Only supports TranscendentalCache::LOG at this point.
class TranscendentalCacheSSE2Stub: public CodeStub {
public:
explicit TranscendentalCacheSSE2Stub(TranscendentalCache::Type type)
: type_(type) {}
void Generate(MacroAssembler* masm); void Generate(MacroAssembler* masm);
private: private:
TranscendentalCache::Type type_; TranscendentalCache::Type type_;
ArgumentType argument_type_;
Major MajorKey() { return TranscendentalCacheSSE2; } Major MajorKey() { return TranscendentalCache; }
int MinorKey() { return type_; } int MinorKey() { return type_ | argument_type_; }
Runtime::FunctionId RuntimeFunction(); Runtime::FunctionId RuntimeFunction();
void GenerateOperation(MacroAssembler* masm); void GenerateOperation(MacroAssembler* masm);
}; };

9
deps/v8/src/ia32/codegen-ia32.cc

@ -7912,7 +7912,8 @@ void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) {
void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) { void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
ASSERT_EQ(args->length(), 1); ASSERT_EQ(args->length(), 1);
Load(args->at(0)); Load(args->at(0));
TranscendentalCacheStub stub(TranscendentalCache::SIN); TranscendentalCacheStub stub(TranscendentalCache::SIN,
TranscendentalCacheStub::TAGGED);
Result result = frame_->CallStub(&stub, 1); Result result = frame_->CallStub(&stub, 1);
frame_->Push(&result); frame_->Push(&result);
} }
@ -7921,7 +7922,8 @@ void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) { void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
ASSERT_EQ(args->length(), 1); ASSERT_EQ(args->length(), 1);
Load(args->at(0)); Load(args->at(0));
TranscendentalCacheStub stub(TranscendentalCache::COS); TranscendentalCacheStub stub(TranscendentalCache::COS,
TranscendentalCacheStub::TAGGED);
Result result = frame_->CallStub(&stub, 1); Result result = frame_->CallStub(&stub, 1);
frame_->Push(&result); frame_->Push(&result);
} }
@ -7930,7 +7932,8 @@ void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
void CodeGenerator::GenerateMathLog(ZoneList<Expression*>* args) { void CodeGenerator::GenerateMathLog(ZoneList<Expression*>* args) {
ASSERT_EQ(args->length(), 1); ASSERT_EQ(args->length(), 1);
Load(args->at(0)); Load(args->at(0));
TranscendentalCacheStub stub(TranscendentalCache::LOG); TranscendentalCacheStub stub(TranscendentalCache::LOG,
TranscendentalCacheStub::TAGGED);
Result result = frame_->CallStub(&stub, 1); Result result = frame_->CallStub(&stub, 1);
frame_->Push(&result); frame_->Push(&result);
} }

9
deps/v8/src/ia32/full-codegen-ia32.cc

@ -3067,7 +3067,8 @@ void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) { void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
// Load the argument on the stack and call the stub. // Load the argument on the stack and call the stub.
TranscendentalCacheStub stub(TranscendentalCache::SIN); TranscendentalCacheStub stub(TranscendentalCache::SIN,
TranscendentalCacheStub::TAGGED);
ASSERT(args->length() == 1); ASSERT(args->length() == 1);
VisitForStackValue(args->at(0)); VisitForStackValue(args->at(0));
__ CallStub(&stub); __ CallStub(&stub);
@ -3077,7 +3078,8 @@ void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) { void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
// Load the argument on the stack and call the stub. // Load the argument on the stack and call the stub.
TranscendentalCacheStub stub(TranscendentalCache::COS); TranscendentalCacheStub stub(TranscendentalCache::COS,
TranscendentalCacheStub::TAGGED);
ASSERT(args->length() == 1); ASSERT(args->length() == 1);
VisitForStackValue(args->at(0)); VisitForStackValue(args->at(0));
__ CallStub(&stub); __ CallStub(&stub);
@ -3087,7 +3089,8 @@ void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) { void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
// Load the argument on the stack and call the stub. // Load the argument on the stack and call the stub.
TranscendentalCacheStub stub(TranscendentalCache::LOG); TranscendentalCacheStub stub(TranscendentalCache::LOG,
TranscendentalCacheStub::TAGGED);
ASSERT(args->length() == 1); ASSERT(args->length() == 1);
VisitForStackValue(args->at(0)); VisitForStackValue(args->at(0));
__ CallStub(&stub); __ CallStub(&stub);

28
deps/v8/src/ia32/lithium-codegen-ia32.cc

@ -686,7 +686,8 @@ void LCodeGen::DoCallStub(LCallStub* instr) {
break; break;
} }
case CodeStub::TranscendentalCache: { case CodeStub::TranscendentalCache: {
TranscendentalCacheStub stub(instr->transcendental_type()); TranscendentalCacheStub stub(instr->transcendental_type(),
TranscendentalCacheStub::TAGGED);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
break; break;
} }
@ -2314,7 +2315,24 @@ void LCodeGen::DoPower(LPower* instr) {
void LCodeGen::DoMathLog(LUnaryMathOperation* instr) { void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
TranscendentalCacheSSE2Stub stub(TranscendentalCache::LOG); TranscendentalCacheStub stub(TranscendentalCache::LOG,
TranscendentalCacheStub::UNTAGGED);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
}
void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
TranscendentalCacheStub stub(TranscendentalCache::COS,
TranscendentalCacheStub::UNTAGGED);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
}
void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
TranscendentalCacheStub stub(TranscendentalCache::SIN,
TranscendentalCacheStub::UNTAGGED);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
} }
@ -2336,6 +2354,12 @@ void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
case kMathPowHalf: case kMathPowHalf:
DoMathPowHalf(instr); DoMathPowHalf(instr);
break; break;
case kMathCos:
DoMathCos(instr);
break;
case kMathSin:
DoMathSin(instr);
break;
case kMathLog: case kMathLog:
DoMathLog(instr); DoMathLog(instr);
break; break;

2
deps/v8/src/ia32/lithium-codegen-ia32.h

@ -177,6 +177,8 @@ class LCodeGen BASE_EMBEDDED {
void DoMathSqrt(LUnaryMathOperation* instr); void DoMathSqrt(LUnaryMathOperation* instr);
void DoMathPowHalf(LUnaryMathOperation* instr); void DoMathPowHalf(LUnaryMathOperation* instr);
void DoMathLog(LUnaryMathOperation* instr); void DoMathLog(LUnaryMathOperation* instr);
void DoMathCos(LUnaryMathOperation* instr);
void DoMathSin(LUnaryMathOperation* instr);
// Support for recording safepoint and position information. // Support for recording safepoint and position information.
void RecordSafepoint(LPointerMap* pointers, int deoptimization_index); void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);

2
deps/v8/src/ia32/lithium-ia32.cc

@ -1361,7 +1361,7 @@ LInstruction* LChunkBuilder::DoCallConstantFunction(
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
BuiltinFunctionId op = instr->op(); BuiltinFunctionId op = instr->op();
if (op == kMathLog) { if (op == kMathLog || op == kMathSin || op == kMathCos) {
LOperand* input = UseFixedDouble(instr->value(), xmm1); LOperand* input = UseFixedDouble(instr->value(), xmm1);
LInstruction* result = new LUnaryMathOperation(input); LInstruction* result = new LUnaryMathOperation(input);
return MarkAsCall(DefineFixedDouble(result, xmm1), instr); return MarkAsCall(DefineFixedDouble(result, xmm1), instr);

826
deps/v8/src/objects-debug.cc

File diff suppressed because it is too large

131
deps/v8/src/objects.cc

@ -553,11 +553,11 @@ Object* Object::GetPrototype() {
} }
void Object::ShortPrint() { void Object::ShortPrint(FILE* out) {
HeapStringAllocator allocator; HeapStringAllocator allocator;
StringStream accumulator(&allocator); StringStream accumulator(&allocator);
ShortPrint(&accumulator); ShortPrint(&accumulator);
accumulator.OutputToStdOut(); accumulator.OutputToFile(out);
} }
@ -572,8 +572,8 @@ void Object::ShortPrint(StringStream* accumulator) {
} }
void Smi::SmiPrint() { void Smi::SmiPrint(FILE* out) {
PrintF("%d", value()); PrintF(out, "%d", value());
} }
@ -587,8 +587,8 @@ void Failure::FailurePrint(StringStream* accumulator) {
} }
void Failure::FailurePrint() { void Failure::FailurePrint(FILE* out) {
PrintF("Failure(%p)", reinterpret_cast<void*>(value())); PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
} }
@ -1141,8 +1141,8 @@ Object* HeapNumber::HeapNumberToBoolean() {
} }
void HeapNumber::HeapNumberPrint() { void HeapNumber::HeapNumberPrint(FILE* out) {
PrintF("%.16g", Number()); PrintF(out, "%.16g", Number());
} }
@ -5467,9 +5467,9 @@ Object* JSFunction::SetInstanceClassName(String* name) {
} }
void JSFunction::PrintName() { void JSFunction::PrintName(FILE* out) {
SmartPointer<char> name = shared()->DebugName()->ToCString(); SmartPointer<char> name = shared()->DebugName()->ToCString();
PrintF("%s", *name); PrintF(out, "%s", *name);
} }
@ -5999,18 +5999,18 @@ Map* Code::FindFirstMap() {
#ifdef ENABLE_DISASSEMBLER #ifdef ENABLE_DISASSEMBLER
#ifdef DEBUG #ifdef OBJECT_PRINT
void DeoptimizationInputData::DeoptimizationInputDataPrint() { void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
disasm::NameConverter converter; disasm::NameConverter converter;
int deopt_count = DeoptCount(); int deopt_count = DeoptCount();
PrintF("Deoptimization Input Data (deopt points = %d)\n", deopt_count); PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
if (0 == deopt_count) return; if (0 == deopt_count) return;
PrintF("%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands"); PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands");
for (int i = 0; i < deopt_count; i++) { for (int i = 0; i < deopt_count; i++) {
int command_count = 0; int command_count = 0;
PrintF("%6d %6d %6d", PrintF(out, "%6d %6d %6d",
i, AstId(i)->value(), ArgumentsStackHeight(i)->value()); i, AstId(i)->value(), ArgumentsStackHeight(i)->value());
int translation_index = TranslationIndex(i)->value(); int translation_index = TranslationIndex(i)->value();
TranslationIterator iterator(TranslationByteArray(), translation_index); TranslationIterator iterator(TranslationByteArray(), translation_index);
@ -6019,7 +6019,8 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() {
ASSERT(Translation::BEGIN == opcode); ASSERT(Translation::BEGIN == opcode);
int frame_count = iterator.Next(); int frame_count = iterator.Next();
if (FLAG_print_code_verbose) { if (FLAG_print_code_verbose) {
PrintF(" %s {count=%d}\n", Translation::StringFor(opcode), frame_count); PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
frame_count);
} }
for (int i = 0; i < frame_count; ++i) { for (int i = 0; i < frame_count; ++i) {
@ -6031,10 +6032,10 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() {
JSFunction::cast(LiteralArray()->get(function_id)); JSFunction::cast(LiteralArray()->get(function_id));
unsigned height = iterator.Next(); unsigned height = iterator.Next();
if (FLAG_print_code_verbose) { if (FLAG_print_code_verbose) {
PrintF("%24s %s {ast_id=%d, function=", PrintF(out, "%24s %s {ast_id=%d, function=",
"", Translation::StringFor(opcode), ast_id); "", Translation::StringFor(opcode), ast_id);
function->PrintName(); function->PrintName(out);
PrintF(", height=%u}\n", height); PrintF(out, ", height=%u}\n", height);
} }
// Size of translation is height plus all incoming arguments including // Size of translation is height plus all incoming arguments including
@ -6044,13 +6045,13 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() {
for (int j = 0; j < size; ++j) { for (int j = 0; j < size; ++j) {
opcode = static_cast<Translation::Opcode>(iterator.Next()); opcode = static_cast<Translation::Opcode>(iterator.Next());
if (FLAG_print_code_verbose) { if (FLAG_print_code_verbose) {
PrintF("%24s %s ", "", Translation::StringFor(opcode)); PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
} }
if (opcode == Translation::DUPLICATE) { if (opcode == Translation::DUPLICATE) {
opcode = static_cast<Translation::Opcode>(iterator.Next()); opcode = static_cast<Translation::Opcode>(iterator.Next());
if (FLAG_print_code_verbose) { if (FLAG_print_code_verbose) {
PrintF("%s ", Translation::StringFor(opcode)); PrintF(out, "%s ", Translation::StringFor(opcode));
} }
--j; // Two commands share the same frame index. --j; // Two commands share the same frame index.
} }
@ -6065,7 +6066,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() {
case Translation::REGISTER: { case Translation::REGISTER: {
int reg_code = iterator.Next(); int reg_code = iterator.Next();
if (FLAG_print_code_verbose) { if (FLAG_print_code_verbose) {
PrintF("{input=%s}", converter.NameOfCPURegister(reg_code)); PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
} }
break; break;
} }
@ -6073,7 +6074,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() {
case Translation::INT32_REGISTER: { case Translation::INT32_REGISTER: {
int reg_code = iterator.Next(); int reg_code = iterator.Next();
if (FLAG_print_code_verbose) { if (FLAG_print_code_verbose) {
PrintF("{input=%s}", converter.NameOfCPURegister(reg_code)); PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
} }
break; break;
} }
@ -6081,7 +6082,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() {
case Translation::DOUBLE_REGISTER: { case Translation::DOUBLE_REGISTER: {
int reg_code = iterator.Next(); int reg_code = iterator.Next();
if (FLAG_print_code_verbose) { if (FLAG_print_code_verbose) {
PrintF("{input=%s}", PrintF(out, "{input=%s}",
DoubleRegister::AllocationIndexToString(reg_code)); DoubleRegister::AllocationIndexToString(reg_code));
} }
break; break;
@ -6090,7 +6091,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() {
case Translation::STACK_SLOT: { case Translation::STACK_SLOT: {
int input_slot_index = iterator.Next(); int input_slot_index = iterator.Next();
if (FLAG_print_code_verbose) { if (FLAG_print_code_verbose) {
PrintF("{input=%d}", input_slot_index); PrintF(out, "{input=%d}", input_slot_index);
} }
break; break;
} }
@ -6098,7 +6099,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() {
case Translation::INT32_STACK_SLOT: { case Translation::INT32_STACK_SLOT: {
int input_slot_index = iterator.Next(); int input_slot_index = iterator.Next();
if (FLAG_print_code_verbose) { if (FLAG_print_code_verbose) {
PrintF("{input=%d}", input_slot_index); PrintF(out, "{input=%d}", input_slot_index);
} }
break; break;
} }
@ -6106,7 +6107,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() {
case Translation::DOUBLE_STACK_SLOT: { case Translation::DOUBLE_STACK_SLOT: {
int input_slot_index = iterator.Next(); int input_slot_index = iterator.Next();
if (FLAG_print_code_verbose) { if (FLAG_print_code_verbose) {
PrintF("{input=%d}", input_slot_index); PrintF(out, "{input=%d}", input_slot_index);
} }
break; break;
} }
@ -6114,7 +6115,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() {
case Translation::LITERAL: { case Translation::LITERAL: {
unsigned literal_index = iterator.Next(); unsigned literal_index = iterator.Next();
if (FLAG_print_code_verbose) { if (FLAG_print_code_verbose) {
PrintF("{literal_id=%u}", literal_index); PrintF(out, "{literal_id=%u}", literal_index);
} }
break; break;
} }
@ -6122,16 +6123,16 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() {
case Translation::ARGUMENTS_OBJECT: case Translation::ARGUMENTS_OBJECT:
break; break;
} }
if (FLAG_print_code_verbose) PrintF("\n"); if (FLAG_print_code_verbose) PrintF(out, "\n");
} }
} }
if (!FLAG_print_code_verbose) PrintF(" %12d\n", command_count); if (!FLAG_print_code_verbose) PrintF(out, " %12d\n", command_count);
} }
} }
void DeoptimizationOutputData::DeoptimizationOutputDataPrint() { void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
PrintF("Deoptimization Output Data (deopt points = %d)\n", PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
this->DeoptPoints()); this->DeoptPoints());
if (this->DeoptPoints() == 0) return; if (this->DeoptPoints() == 0) return;
@ -6202,56 +6203,56 @@ const char* Code::PropertyType2String(PropertyType type) {
} }
void Code::Disassemble(const char* name) { void Code::Disassemble(const char* name, FILE* out) {
PrintF("kind = %s\n", Kind2String(kind())); PrintF(out, "kind = %s\n", Kind2String(kind()));
if (is_inline_cache_stub()) { if (is_inline_cache_stub()) {
PrintF("ic_state = %s\n", ICState2String(ic_state())); PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
PrintF("ic_in_loop = %d\n", ic_in_loop() == IN_LOOP); PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
if (ic_state() == MONOMORPHIC) { if (ic_state() == MONOMORPHIC) {
PrintF("type = %s\n", PropertyType2String(type())); PrintF(out, "type = %s\n", PropertyType2String(type()));
} }
} }
if ((name != NULL) && (name[0] != '\0')) { if ((name != NULL) && (name[0] != '\0')) {
PrintF("name = %s\n", name); PrintF(out, "name = %s\n", name);
} }
if (kind() == OPTIMIZED_FUNCTION) { if (kind() == OPTIMIZED_FUNCTION) {
PrintF("stack_slots = %d\n", stack_slots()); PrintF(out, "stack_slots = %d\n", stack_slots());
} }
PrintF("Instructions (size = %d)\n", instruction_size()); PrintF(out, "Instructions (size = %d)\n", instruction_size());
Disassembler::Decode(NULL, this); Disassembler::Decode(out, this);
PrintF("\n"); PrintF(out, "\n");
#ifdef DEBUG #ifdef DEBUG
if (kind() == FUNCTION) { if (kind() == FUNCTION) {
DeoptimizationOutputData* data = DeoptimizationOutputData* data =
DeoptimizationOutputData::cast(this->deoptimization_data()); DeoptimizationOutputData::cast(this->deoptimization_data());
data->DeoptimizationOutputDataPrint(); data->DeoptimizationOutputDataPrint(out);
} else if (kind() == OPTIMIZED_FUNCTION) { } else if (kind() == OPTIMIZED_FUNCTION) {
DeoptimizationInputData* data = DeoptimizationInputData* data =
DeoptimizationInputData::cast(this->deoptimization_data()); DeoptimizationInputData::cast(this->deoptimization_data());
data->DeoptimizationInputDataPrint(); data->DeoptimizationInputDataPrint(out);
} }
PrintF("\n"); PrintF("\n");
#endif #endif
if (kind() == OPTIMIZED_FUNCTION) { if (kind() == OPTIMIZED_FUNCTION) {
SafepointTable table(this); SafepointTable table(this);
PrintF("Safepoints (size = %u)\n", table.size()); PrintF(out, "Safepoints (size = %u)\n", table.size());
for (unsigned i = 0; i < table.length(); i++) { for (unsigned i = 0; i < table.length(); i++) {
unsigned pc_offset = table.GetPcOffset(i); unsigned pc_offset = table.GetPcOffset(i);
PrintF("%p %4d ", (instruction_start() + pc_offset), pc_offset); PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
table.PrintEntry(i); table.PrintEntry(i);
PrintF(" (sp -> fp)"); PrintF(out, " (sp -> fp)");
int deoptimization_index = table.GetDeoptimizationIndex(i); int deoptimization_index = table.GetDeoptimizationIndex(i);
if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
PrintF(" %6d", deoptimization_index); PrintF(out, " %6d", deoptimization_index);
} else { } else {
PrintF(" <none>"); PrintF(out, " <none>");
} }
PrintF("\n"); PrintF(out, "\n");
} }
PrintF("\n"); PrintF(out, "\n");
} else if (kind() == FUNCTION) { } else if (kind() == FUNCTION) {
unsigned offset = stack_check_table_start(); unsigned offset = stack_check_table_start();
// If there is no stack check table, the "table start" will at or after // If there is no stack check table, the "table start" will at or after
@ -6260,19 +6261,19 @@ void Code::Disassemble(const char* name) {
unsigned* address = unsigned* address =
reinterpret_cast<unsigned*>(instruction_start() + offset); reinterpret_cast<unsigned*>(instruction_start() + offset);
unsigned length = address[0]; unsigned length = address[0];
PrintF("Stack checks (size = %u)\n", length); PrintF(out, "Stack checks (size = %u)\n", length);
PrintF("ast_id pc_offset\n"); PrintF(out, "ast_id pc_offset\n");
for (unsigned i = 0; i < length; ++i) { for (unsigned i = 0; i < length; ++i) {
unsigned index = (2 * i) + 1; unsigned index = (2 * i) + 1;
PrintF("%6u %9u\n", address[index], address[index + 1]); PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
} }
PrintF("\n"); PrintF(out, "\n");
} }
} }
PrintF("RelocInfo (size = %d)\n", relocation_size()); PrintF("RelocInfo (size = %d)\n", relocation_size());
for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(); for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
PrintF("\n"); PrintF(out, "\n");
} }
#endif // ENABLE_DISASSEMBLER #endif // ENABLE_DISASSEMBLER
@ -7421,22 +7422,22 @@ bool JSObject::ShouldConvertToFastElements() {
// class. This requires us to have the template functions put // class. This requires us to have the template functions put
// together, so even though this function belongs in objects-debug.cc, // together, so even though this function belongs in objects-debug.cc,
// we keep it here instead to satisfy certain compilers. // we keep it here instead to satisfy certain compilers.
#ifdef DEBUG #ifdef OBJECT_PRINT
template<typename Shape, typename Key> template<typename Shape, typename Key>
void Dictionary<Shape, Key>::Print() { void Dictionary<Shape, Key>::Print(FILE* out) {
int capacity = HashTable<Shape, Key>::Capacity(); int capacity = HashTable<Shape, Key>::Capacity();
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
Object* k = HashTable<Shape, Key>::KeyAt(i); Object* k = HashTable<Shape, Key>::KeyAt(i);
if (HashTable<Shape, Key>::IsKey(k)) { if (HashTable<Shape, Key>::IsKey(k)) {
PrintF(" "); PrintF(out, " ");
if (k->IsString()) { if (k->IsString()) {
String::cast(k)->StringPrint(); String::cast(k)->StringPrint(out);
} else { } else {
k->ShortPrint(); k->ShortPrint(out);
} }
PrintF(": "); PrintF(out, ": ");
ValueAt(i)->ShortPrint(); ValueAt(i)->ShortPrint(out);
PrintF("\n"); PrintF(out, "\n");
} }
} }
} }

343
deps/v8/src/objects.h

@ -607,10 +607,18 @@ class MaybeObject BASE_EMBEDDED {
return reinterpret_cast<Object*>(this); return reinterpret_cast<Object*>(this);
} }
#ifdef DEBUG #ifdef OBJECT_PRINT
// Prints this object with details. // Prints this object with details.
void Print(); inline void Print() {
void PrintLn(); Print(stdout);
};
inline void PrintLn() {
PrintLn(stdout);
}
void Print(FILE* out);
void PrintLn(FILE* out);
#endif
#ifdef DEBUG
// Verifies the object. // Verifies the object.
void Verify(); void Verify();
#endif #endif
@ -762,7 +770,10 @@ class Object : public MaybeObject {
#endif #endif
// Prints this object without details. // Prints this object without details.
void ShortPrint(); inline void ShortPrint() {
ShortPrint(stdout);
}
void ShortPrint(FILE* out);
// Prints this object without details to a message accumulator. // Prints this object without details to a message accumulator.
void ShortPrint(StringStream* accumulator); void ShortPrint(StringStream* accumulator);
@ -801,7 +812,10 @@ class Smi: public Object {
static inline Smi* cast(Object* object); static inline Smi* cast(Object* object);
// Dispatched behavior. // Dispatched behavior.
void SmiPrint(); inline void SmiPrint() {
SmiPrint(stdout);
}
void SmiPrint(FILE* out);
void SmiPrint(StringStream* accumulator); void SmiPrint(StringStream* accumulator);
#ifdef DEBUG #ifdef DEBUG
void SmiVerify(); void SmiVerify();
@ -870,7 +884,10 @@ class Failure: public MaybeObject {
static inline Failure* cast(MaybeObject* object); static inline Failure* cast(MaybeObject* object);
// Dispatched behavior. // Dispatched behavior.
void FailurePrint(); inline void FailurePrint() {
FailurePrint(stdout);
}
void FailurePrint(FILE* out);
void FailurePrint(StringStream* accumulator); void FailurePrint(StringStream* accumulator);
#ifdef DEBUG #ifdef DEBUG
void FailureVerify(); void FailureVerify();
@ -1099,14 +1116,23 @@ class HeapObject: public Object {
// Dispatched behavior. // Dispatched behavior.
void HeapObjectShortPrint(StringStream* accumulator); void HeapObjectShortPrint(StringStream* accumulator);
#ifdef OBJECT_PRINT
inline void HeapObjectPrint() {
HeapObjectPrint(stdout);
}
void HeapObjectPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void HeapObjectPrint();
void HeapObjectVerify(); void HeapObjectVerify();
inline void VerifyObjectField(int offset); inline void VerifyObjectField(int offset);
inline void VerifySmiField(int offset); inline void VerifySmiField(int offset);
#endif
void PrintHeader(const char* id); #ifdef OBJECT_PRINT
void PrintHeader(FILE* out, const char* id);
#endif
#ifdef DEBUG
// Verify a pointer is a valid HeapObject pointer that points to object // Verify a pointer is a valid HeapObject pointer that points to object
// areas in the heap. // areas in the heap.
static void VerifyHeapPointer(Object* p); static void VerifyHeapPointer(Object* p);
@ -1189,7 +1215,10 @@ class HeapNumber: public HeapObject {
// Dispatched behavior. // Dispatched behavior.
Object* HeapNumberToBoolean(); Object* HeapNumberToBoolean();
void HeapNumberPrint(); inline void HeapNumberPrint() {
HeapNumberPrint(stdout);
}
void HeapNumberPrint(FILE* out);
void HeapNumberPrint(StringStream* accumulator); void HeapNumberPrint(StringStream* accumulator);
#ifdef DEBUG #ifdef DEBUG
void HeapNumberVerify(); void HeapNumberVerify();
@ -1649,12 +1678,28 @@ class JSObject: public HeapObject {
// Dispatched behavior. // Dispatched behavior.
void JSObjectShortPrint(StringStream* accumulator); void JSObjectShortPrint(StringStream* accumulator);
#ifdef OBJECT_PRINT
inline void JSObjectPrint() {
JSObjectPrint(stdout);
}
void JSObjectPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void JSObjectPrint();
void JSObjectVerify(); void JSObjectVerify();
void PrintProperties(); #endif
void PrintElements(); #ifdef OBJECT_PRINT
inline void PrintProperties() {
PrintProperties(stdout);
}
void PrintProperties(FILE* out);
inline void PrintElements() {
PrintElements(stdout);
}
void PrintElements(FILE* out);
#endif
#ifdef DEBUG
// Structure for collecting spill information about JSObjects. // Structure for collecting spill information about JSObjects.
class SpillInformation { class SpillInformation {
public: public:
@ -1689,7 +1734,7 @@ class JSObject: public HeapObject {
static const uint32_t kMaxGap = 1024; static const uint32_t kMaxGap = 1024;
static const int kMaxFastElementsLength = 5000; static const int kMaxFastElementsLength = 5000;
static const int kInitialMaxFastElementArray = 100000; static const int kInitialMaxFastElementArray = 100000;
static const int kMaxFastProperties = 8; static const int kMaxFastProperties = 12;
static const int kMaxInstanceSize = 255 * kPointerSize; static const int kMaxInstanceSize = 255 * kPointerSize;
// When extending the backing storage for property values, we increase // When extending the backing storage for property values, we increase
// its size by more than the 1 entry necessary, so sequentially adding fields // its size by more than the 1 entry necessary, so sequentially adding fields
@ -1835,8 +1880,13 @@ class FixedArray: public HeapObject {
static const int kMaxLength = (kMaxSize - kHeaderSize) / kPointerSize; static const int kMaxLength = (kMaxSize - kHeaderSize) / kPointerSize;
// Dispatched behavior. // Dispatched behavior.
#ifdef OBJECT_PRINT
inline void FixedArrayPrint() {
FixedArrayPrint(stdout);
}
void FixedArrayPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void FixedArrayPrint();
void FixedArrayVerify(); void FixedArrayVerify();
// Checks if two FixedArrays have identical contents. // Checks if two FixedArrays have identical contents.
bool IsEqualTo(FixedArray* other); bool IsEqualTo(FixedArray* other);
@ -2012,10 +2062,15 @@ class DescriptorArray: public FixedArray {
static const int kEnumCacheBridgeCacheOffset = static const int kEnumCacheBridgeCacheOffset =
kEnumCacheBridgeEnumOffset + kPointerSize; kEnumCacheBridgeEnumOffset + kPointerSize;
#ifdef DEBUG #ifdef OBJECT_PRINT
// Print all the descriptors. // Print all the descriptors.
void PrintDescriptors(); inline void PrintDescriptors() {
PrintDescriptors(stdout);
}
void PrintDescriptors(FILE* out);
#endif
#ifdef DEBUG
// Is the descriptor array sorted and without duplicates? // Is the descriptor array sorted and without duplicates?
bool IsSortedNoDuplicates(); bool IsSortedNoDuplicates();
@ -2396,8 +2451,11 @@ class Dictionary: public HashTable<Shape, Key> {
// Ensure enough space for n additional elements. // Ensure enough space for n additional elements.
MUST_USE_RESULT MaybeObject* EnsureCapacity(int n, Key key); MUST_USE_RESULT MaybeObject* EnsureCapacity(int n, Key key);
#ifdef DEBUG #ifdef OBJECT_PRINT
void Print(); inline void Print() {
Print(stdout);
}
void Print(FILE* out);
#endif #endif
// Returns the key (slow). // Returns the key (slow).
Object* SlowReverseLookup(Object* value); Object* SlowReverseLookup(Object* value);
@ -2619,8 +2677,13 @@ class ByteArray: public HeapObject {
inline int ByteArraySize() { inline int ByteArraySize() {
return SizeFor(this->length()); return SizeFor(this->length());
} }
#ifdef OBJECT_PRINT
inline void ByteArrayPrint() {
ByteArrayPrint(stdout);
}
void ByteArrayPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void ByteArrayPrint();
void ByteArrayVerify(); void ByteArrayVerify();
#endif #endif
@ -2669,8 +2732,13 @@ class PixelArray: public HeapObject {
// Casting. // Casting.
static inline PixelArray* cast(Object* obj); static inline PixelArray* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void PixelArrayPrint() {
PixelArrayPrint(stdout);
}
void PixelArrayPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void PixelArrayPrint();
void PixelArrayVerify(); void PixelArrayVerify();
#endif // DEBUG #endif // DEBUG
@ -2741,8 +2809,13 @@ class ExternalByteArray: public ExternalArray {
// Casting. // Casting.
static inline ExternalByteArray* cast(Object* obj); static inline ExternalByteArray* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void ExternalByteArrayPrint() {
ExternalByteArrayPrint(stdout);
}
void ExternalByteArrayPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void ExternalByteArrayPrint();
void ExternalByteArrayVerify(); void ExternalByteArrayVerify();
#endif // DEBUG #endif // DEBUG
@ -2764,8 +2837,13 @@ class ExternalUnsignedByteArray: public ExternalArray {
// Casting. // Casting.
static inline ExternalUnsignedByteArray* cast(Object* obj); static inline ExternalUnsignedByteArray* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void ExternalUnsignedByteArrayPrint() {
ExternalUnsignedByteArrayPrint(stdout);
}
void ExternalUnsignedByteArrayPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void ExternalUnsignedByteArrayPrint();
void ExternalUnsignedByteArrayVerify(); void ExternalUnsignedByteArrayVerify();
#endif // DEBUG #endif // DEBUG
@ -2787,8 +2865,13 @@ class ExternalShortArray: public ExternalArray {
// Casting. // Casting.
static inline ExternalShortArray* cast(Object* obj); static inline ExternalShortArray* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void ExternalShortArrayPrint() {
ExternalShortArrayPrint(stdout);
}
void ExternalShortArrayPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void ExternalShortArrayPrint();
void ExternalShortArrayVerify(); void ExternalShortArrayVerify();
#endif // DEBUG #endif // DEBUG
@ -2810,8 +2893,13 @@ class ExternalUnsignedShortArray: public ExternalArray {
// Casting. // Casting.
static inline ExternalUnsignedShortArray* cast(Object* obj); static inline ExternalUnsignedShortArray* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void ExternalUnsignedShortArrayPrint() {
ExternalUnsignedShortArrayPrint(stdout);
}
void ExternalUnsignedShortArrayPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void ExternalUnsignedShortArrayPrint();
void ExternalUnsignedShortArrayVerify(); void ExternalUnsignedShortArrayVerify();
#endif // DEBUG #endif // DEBUG
@ -2833,8 +2921,13 @@ class ExternalIntArray: public ExternalArray {
// Casting. // Casting.
static inline ExternalIntArray* cast(Object* obj); static inline ExternalIntArray* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void ExternalIntArrayPrint() {
ExternalIntArrayPrint(stdout);
}
void ExternalIntArrayPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void ExternalIntArrayPrint();
void ExternalIntArrayVerify(); void ExternalIntArrayVerify();
#endif // DEBUG #endif // DEBUG
@ -2856,8 +2949,13 @@ class ExternalUnsignedIntArray: public ExternalArray {
// Casting. // Casting.
static inline ExternalUnsignedIntArray* cast(Object* obj); static inline ExternalUnsignedIntArray* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void ExternalUnsignedIntArrayPrint() {
ExternalUnsignedIntArrayPrint(stdout);
}
void ExternalUnsignedIntArrayPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void ExternalUnsignedIntArrayPrint();
void ExternalUnsignedIntArrayVerify(); void ExternalUnsignedIntArrayVerify();
#endif // DEBUG #endif // DEBUG
@ -2879,8 +2977,13 @@ class ExternalFloatArray: public ExternalArray {
// Casting. // Casting.
static inline ExternalFloatArray* cast(Object* obj); static inline ExternalFloatArray* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void ExternalFloatArrayPrint() {
ExternalFloatArrayPrint(stdout);
}
void ExternalFloatArrayPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void ExternalFloatArrayPrint();
void ExternalFloatArrayVerify(); void ExternalFloatArrayVerify();
#endif // DEBUG #endif // DEBUG
@ -2960,8 +3063,8 @@ class DeoptimizationInputData: public FixedArray {
// Casting. // Casting.
static inline DeoptimizationInputData* cast(Object* obj); static inline DeoptimizationInputData* cast(Object* obj);
#ifdef DEBUG #ifdef OBJECT_PRINT
void DeoptimizationInputDataPrint(); void DeoptimizationInputDataPrint(FILE* out);
#endif #endif
private: private:
@ -2999,8 +3102,8 @@ class DeoptimizationOutputData: public FixedArray {
// Casting. // Casting.
static inline DeoptimizationOutputData* cast(Object* obj); static inline DeoptimizationOutputData* cast(Object* obj);
#ifdef DEBUG #ifdef OBJECT_PRINT
void DeoptimizationOutputDataPrint(); void DeoptimizationOutputDataPrint(FILE* out);
#endif #endif
}; };
@ -3049,7 +3152,10 @@ class Code: public HeapObject {
static const char* Kind2String(Kind kind); static const char* Kind2String(Kind kind);
static const char* ICState2String(InlineCacheState state); static const char* ICState2String(InlineCacheState state);
static const char* PropertyType2String(PropertyType type); static const char* PropertyType2String(PropertyType type);
void Disassemble(const char* name); inline void Disassemble(const char* name) {
Disassemble(name, stdout);
}
void Disassemble(const char* name, FILE* out);
#endif // ENABLE_DISASSEMBLER #endif // ENABLE_DISASSEMBLER
// [instruction_size]: Size of the native instructions // [instruction_size]: Size of the native instructions
@ -3242,8 +3348,13 @@ class Code: public HeapObject {
template<typename StaticVisitor> template<typename StaticVisitor>
inline void CodeIterateBody(); inline void CodeIterateBody();
#ifdef OBJECT_PRINT
inline void CodePrint() {
CodePrint(stdout);
}
void CodePrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void CodePrint();
void CodeVerify(); void CodeVerify();
#endif #endif
@ -3531,8 +3642,13 @@ class Map: public HeapObject {
void ClearNonLiveTransitions(Object* real_prototype); void ClearNonLiveTransitions(Object* real_prototype);
// Dispatched behavior. // Dispatched behavior.
#ifdef OBJECT_PRINT
inline void MapPrint() {
MapPrint(stdout);
}
void MapPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void MapPrint();
void MapVerify(); void MapVerify();
void SharedMapVerify(); void SharedMapVerify();
#endif #endif
@ -3688,8 +3804,13 @@ class Script: public Struct {
// resource is accessible. Otherwise, always return true. // resource is accessible. Otherwise, always return true.
inline bool HasValidSource(); inline bool HasValidSource();
#ifdef OBJECT_PRINT
inline void ScriptPrint() {
ScriptPrint(stdout);
}
void ScriptPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void ScriptPrint();
void ScriptVerify(); void ScriptVerify();
#endif #endif
@ -4052,8 +4173,13 @@ class SharedFunctionInfo: public HeapObject {
// Dispatched behavior. // Dispatched behavior.
// Set max_length to -1 for unlimited length. // Set max_length to -1 for unlimited length.
void SourceCodePrint(StringStream* accumulator, int max_length); void SourceCodePrint(StringStream* accumulator, int max_length);
#ifdef OBJECT_PRINT
inline void SharedFunctionInfoPrint() {
SharedFunctionInfoPrint(stdout);
}
void SharedFunctionInfoPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void SharedFunctionInfoPrint();
void SharedFunctionInfoVerify(); void SharedFunctionInfoVerify();
#endif #endif
@ -4285,7 +4411,10 @@ class JSFunction: public JSObject {
DECL_ACCESSORS(next_function_link, Object) DECL_ACCESSORS(next_function_link, Object)
// Prints the name of the function using PrintF. // Prints the name of the function using PrintF.
void PrintName(); inline void PrintName() {
PrintName(stdout);
}
void PrintName(FILE* out);
// Casting. // Casting.
static inline JSFunction* cast(Object* obj); static inline JSFunction* cast(Object* obj);
@ -4295,8 +4424,13 @@ class JSFunction: public JSObject {
void JSFunctionIterateBody(int object_size, ObjectVisitor* v); void JSFunctionIterateBody(int object_size, ObjectVisitor* v);
// Dispatched behavior. // Dispatched behavior.
#ifdef OBJECT_PRINT
inline void JSFunctionPrint() {
JSFunctionPrint(stdout);
}
void JSFunctionPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void JSFunctionPrint();
void JSFunctionVerify(); void JSFunctionVerify();
#endif #endif
@ -4345,8 +4479,13 @@ class JSGlobalProxy : public JSObject {
static inline JSGlobalProxy* cast(Object* obj); static inline JSGlobalProxy* cast(Object* obj);
// Dispatched behavior. // Dispatched behavior.
#ifdef OBJECT_PRINT
inline void JSGlobalProxyPrint() {
JSGlobalProxyPrint(stdout);
}
void JSGlobalProxyPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void JSGlobalProxyPrint();
void JSGlobalProxyVerify(); void JSGlobalProxyVerify();
#endif #endif
@ -4416,8 +4555,13 @@ class JSGlobalObject: public GlobalObject {
static inline JSGlobalObject* cast(Object* obj); static inline JSGlobalObject* cast(Object* obj);
// Dispatched behavior. // Dispatched behavior.
#ifdef OBJECT_PRINT
inline void JSGlobalObjectPrint() {
JSGlobalObjectPrint(stdout);
}
void JSGlobalObjectPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void JSGlobalObjectPrint();
void JSGlobalObjectVerify(); void JSGlobalObjectVerify();
#endif #endif
@ -4445,8 +4589,13 @@ class JSBuiltinsObject: public GlobalObject {
static inline JSBuiltinsObject* cast(Object* obj); static inline JSBuiltinsObject* cast(Object* obj);
// Dispatched behavior. // Dispatched behavior.
#ifdef OBJECT_PRINT
inline void JSBuiltinsObjectPrint() {
JSBuiltinsObjectPrint(stdout);
}
void JSBuiltinsObjectPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void JSBuiltinsObjectPrint();
void JSBuiltinsObjectVerify(); void JSBuiltinsObjectVerify();
#endif #endif
@ -4483,8 +4632,13 @@ class JSValue: public JSObject {
static inline JSValue* cast(Object* obj); static inline JSValue* cast(Object* obj);
// Dispatched behavior. // Dispatched behavior.
#ifdef OBJECT_PRINT
inline void JSValuePrint() {
JSValuePrint(stdout);
}
void JSValuePrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void JSValuePrint();
void JSValueVerify(); void JSValueVerify();
#endif #endif
@ -4673,8 +4827,13 @@ class CodeCache: public Struct {
static inline CodeCache* cast(Object* obj); static inline CodeCache* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void CodeCachePrint() {
CodeCachePrint(stdout);
}
void CodeCachePrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void CodeCachePrint();
void CodeCacheVerify(); void CodeCacheVerify();
#endif #endif
@ -4975,8 +5134,13 @@ class String: public HeapObject {
// Dispatched behavior. // Dispatched behavior.
void StringShortPrint(StringStream* accumulator); void StringShortPrint(StringStream* accumulator);
#ifdef OBJECT_PRINT
inline void StringPrint() {
StringPrint(stdout);
}
void StringPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void StringPrint();
void StringVerify(); void StringVerify();
#endif #endif
inline bool IsFlat(); inline bool IsFlat();
@ -5531,7 +5695,12 @@ class JSGlobalPropertyCell: public HeapObject {
#ifdef DEBUG #ifdef DEBUG
void JSGlobalPropertyCellVerify(); void JSGlobalPropertyCellVerify();
void JSGlobalPropertyCellPrint(); #endif
#ifdef OBJECT_PRINT
inline void JSGlobalPropertyCellPrint() {
JSGlobalPropertyCellPrint(stdout);
}
void JSGlobalPropertyCellPrint(FILE* out);
#endif #endif
// Layout description. // Layout description.
@ -5566,8 +5735,13 @@ class Proxy: public HeapObject {
template<typename StaticVisitor> template<typename StaticVisitor>
inline void ProxyIterateBody(); inline void ProxyIterateBody();
#ifdef OBJECT_PRINT
inline void ProxyPrint() {
ProxyPrint(stdout);
}
void ProxyPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void ProxyPrint();
void ProxyVerify(); void ProxyVerify();
#endif #endif
@ -5616,8 +5790,13 @@ class JSArray: public JSObject {
inline void EnsureSize(int minimum_size_of_backing_fixed_array); inline void EnsureSize(int minimum_size_of_backing_fixed_array);
// Dispatched behavior. // Dispatched behavior.
#ifdef OBJECT_PRINT
inline void JSArrayPrint() {
JSArrayPrint(stdout);
}
void JSArrayPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void JSArrayPrint();
void JSArrayVerify(); void JSArrayVerify();
#endif #endif
@ -5688,8 +5867,13 @@ class AccessorInfo: public Struct {
static inline AccessorInfo* cast(Object* obj); static inline AccessorInfo* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void AccessorInfoPrint() {
AccessorInfoPrint(stdout);
}
void AccessorInfoPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void AccessorInfoPrint();
void AccessorInfoVerify(); void AccessorInfoVerify();
#endif #endif
@ -5719,8 +5903,13 @@ class AccessCheckInfo: public Struct {
static inline AccessCheckInfo* cast(Object* obj); static inline AccessCheckInfo* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void AccessCheckInfoPrint() {
AccessCheckInfoPrint(stdout);
}
void AccessCheckInfoPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void AccessCheckInfoPrint();
void AccessCheckInfoVerify(); void AccessCheckInfoVerify();
#endif #endif
@ -5745,8 +5934,13 @@ class InterceptorInfo: public Struct {
static inline InterceptorInfo* cast(Object* obj); static inline InterceptorInfo* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void InterceptorInfoPrint() {
InterceptorInfoPrint(stdout);
}
void InterceptorInfoPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void InterceptorInfoPrint();
void InterceptorInfoVerify(); void InterceptorInfoVerify();
#endif #endif
@ -5770,8 +5964,13 @@ class CallHandlerInfo: public Struct {
static inline CallHandlerInfo* cast(Object* obj); static inline CallHandlerInfo* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void CallHandlerInfoPrint() {
CallHandlerInfoPrint(stdout);
}
void CallHandlerInfoPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void CallHandlerInfoPrint();
void CallHandlerInfoVerify(); void CallHandlerInfoVerify();
#endif #endif
@ -5827,8 +6026,13 @@ class FunctionTemplateInfo: public TemplateInfo {
static inline FunctionTemplateInfo* cast(Object* obj); static inline FunctionTemplateInfo* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void FunctionTemplateInfoPrint() {
FunctionTemplateInfoPrint(stdout);
}
void FunctionTemplateInfoPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void FunctionTemplateInfoPrint();
void FunctionTemplateInfoVerify(); void FunctionTemplateInfoVerify();
#endif #endif
@ -5870,8 +6074,13 @@ class ObjectTemplateInfo: public TemplateInfo {
static inline ObjectTemplateInfo* cast(Object* obj); static inline ObjectTemplateInfo* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void ObjectTemplateInfoPrint() {
ObjectTemplateInfoPrint(stdout);
}
void ObjectTemplateInfoPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void ObjectTemplateInfoPrint();
void ObjectTemplateInfoVerify(); void ObjectTemplateInfoVerify();
#endif #endif
@ -5889,8 +6098,13 @@ class SignatureInfo: public Struct {
static inline SignatureInfo* cast(Object* obj); static inline SignatureInfo* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void SignatureInfoPrint() {
SignatureInfoPrint(stdout);
}
void SignatureInfoPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void SignatureInfoPrint();
void SignatureInfoVerify(); void SignatureInfoVerify();
#endif #endif
@ -5909,8 +6123,13 @@ class TypeSwitchInfo: public Struct {
static inline TypeSwitchInfo* cast(Object* obj); static inline TypeSwitchInfo* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void TypeSwitchInfoPrint() {
TypeSwitchInfoPrint(stdout);
}
void TypeSwitchInfoPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void TypeSwitchInfoPrint();
void TypeSwitchInfoVerify(); void TypeSwitchInfoVerify();
#endif #endif
@ -5956,8 +6175,13 @@ class DebugInfo: public Struct {
static inline DebugInfo* cast(Object* obj); static inline DebugInfo* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void DebugInfoPrint() {
DebugInfoPrint(stdout);
}
void DebugInfoPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void DebugInfoPrint();
void DebugInfoVerify(); void DebugInfoVerify();
#endif #endif
@ -6009,8 +6233,13 @@ class BreakPointInfo: public Struct {
static inline BreakPointInfo* cast(Object* obj); static inline BreakPointInfo* cast(Object* obj);
#ifdef OBJECT_PRINT
inline void BreakPointInfoPrint() {
BreakPointInfoPrint(stdout);
}
void BreakPointInfoPrint(FILE* out);
#endif
#ifdef DEBUG #ifdef DEBUG
void BreakPointInfoPrint();
void BreakPointInfoVerify(); void BreakPointInfoVerify();
#endif #endif

4
deps/v8/src/parser.cc

@ -3730,7 +3730,7 @@ RegExpParser::RegExpParser(FlatStringReader* in,
contains_anchor_(false), contains_anchor_(false),
is_scanned_for_captures_(false), is_scanned_for_captures_(false),
failed_(false) { failed_(false) {
Advance(1); Advance();
} }
@ -3768,7 +3768,7 @@ void RegExpParser::Reset(int pos) {
void RegExpParser::Advance(int dist) { void RegExpParser::Advance(int dist) {
for (int i = 0; i < dist; i++) next_pos_ += dist - 1;
Advance(); Advance();
} }

13
deps/v8/src/platform-nullos.cc

@ -128,6 +128,19 @@ void OS::VPrint(const char* format, va_list args) {
} }
void OS::FPrint(FILE* out, const char* format, ...) {
va_list args;
va_start(args, format);
VFPrint(out, format, args);
va_end(args);
}
void OS::VFPrint(FILE* out, const char* format, va_list args) {
vfprintf(out, format, args);
}
// Print error message to console. // Print error message to console.
void OS::PrintError(const char* format, ...) { void OS::PrintError(const char* format, ...) {
// Minimalistic implementation for bootstrapping. // Minimalistic implementation for bootstrapping.

27
deps/v8/src/platform-posix.cc

@ -142,6 +142,23 @@ void OS::VPrint(const char* format, va_list args) {
} }
void OS::FPrint(FILE* out, const char* format, ...) {
va_list args;
va_start(args, format);
VFPrint(out, format, args);
va_end(args);
}
void OS::VFPrint(FILE* out, const char* format, va_list args) {
#if defined(ANDROID)
LOG_PRI_VA(ANDROID_LOG_INFO, LOG_TAG, format, args);
#else
vfprintf(out, format, args);
#endif
}
void OS::PrintError(const char* format, ...) { void OS::PrintError(const char* format, ...) {
va_list args; va_list args;
va_start(args, format); va_start(args, format);
@ -173,6 +190,8 @@ int OS::VSNPrintF(Vector<char> str,
va_list args) { va_list args) {
int n = vsnprintf(str.start(), str.length(), format, args); int n = vsnprintf(str.start(), str.length(), format, args);
if (n < 0 || n >= str.length()) { if (n < 0 || n >= str.length()) {
// If the length is zero, the assignment fails.
if (str.length() > 0)
str[str.length() - 1] = '\0'; str[str.length() - 1] = '\0';
return -1; return -1;
} else { } else {
@ -204,6 +223,14 @@ class POSIXSocket : public Socket {
explicit POSIXSocket() { explicit POSIXSocket() {
// Create the socket. // Create the socket.
socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (IsValid()) {
// Allow rapid reuse.
static const int kOn = 1;
int ret = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
&kOn, sizeof(kOn));
ASSERT(ret == 0);
USE(ret);
}
} }
explicit POSIXSocket(int socket): socket_(socket) { } explicit POSIXSocket(int socket): socket_(socket) { }
virtual ~POSIXSocket() { Shutdown(); } virtual ~POSIXSocket() { Shutdown(); }

14
deps/v8/src/platform-win32.cc

@ -688,6 +688,19 @@ void OS::VPrint(const char* format, va_list args) {
} }
void OS::FPrint(FILE* out, const char* format, ...) {
va_list args;
va_start(args, format);
VFPrint(out, format, args);
va_end(args);
}
void OS::VFPrint(FILE* out, const char* format, va_list args) {
VPrintHelper(out, format, args);
}
// Print error message to console. // Print error message to console.
void OS::PrintError(const char* format, ...) { void OS::PrintError(const char* format, ...) {
va_list args; va_list args;
@ -716,6 +729,7 @@ int OS::VSNPrintF(Vector<char> str, const char* format, va_list args) {
// Make sure to zero-terminate the string if the output was // Make sure to zero-terminate the string if the output was
// truncated or if there was an error. // truncated or if there was an error.
if (n < 0 || n >= str.length()) { if (n < 0 || n >= str.length()) {
if (str.length() > 0)
str[str.length() - 1] = '\0'; str[str.length() - 1] = '\0';
return -1; return -1;
} else { } else {

4
deps/v8/src/platform.h

@ -184,6 +184,10 @@ class OS {
static void Print(const char* format, ...); static void Print(const char* format, ...);
static void VPrint(const char* format, va_list args); static void VPrint(const char* format, va_list args);
// Print output to a file. This is mostly used for debugging output.
static void FPrint(FILE* out, const char* format, ...);
static void VFPrint(FILE* out, const char* format, va_list args);
// Print error output to console. This is mostly used for error message // Print error output to console. This is mostly used for error message
// output. On platforms that has standard terminal output, the output // output. On platforms that has standard terminal output, the output
// should go to stderr. // should go to stderr.

8
deps/v8/src/profile-generator.cc

@ -2218,7 +2218,7 @@ void HeapSnapshotGenerator::SetGcRootsReference(Object* child_obj) {
void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) { void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) {
if (control_ == NULL) return; if (control_ == NULL) return;
HeapIterator iterator(HeapIterator::kPreciseFiltering); HeapIterator iterator(HeapIterator::kFilterUnreachable);
int objects_count = 0; int objects_count = 0;
for (HeapObject* obj = iterator.next(); for (HeapObject* obj = iterator.next();
obj != NULL; obj != NULL;
@ -2342,8 +2342,6 @@ bool HeapSnapshotGenerator::SetEntriesDominators() {
ASSERT(dominators[i] != NULL); ASSERT(dominators[i] != NULL);
ordered_entries[i]->set_dominator(dominators[i]); ordered_entries[i]->set_dominator(dominators[i]);
} }
// For nodes unreachable from root, set dominator to itself.
snapshot_->SetDominatorsToSelf();
return true; return true;
} }
@ -2373,9 +2371,9 @@ bool HeapSnapshotGenerator::ApproximateRetainedSizes() {
bool HeapSnapshotGenerator::IterateAndExtractReferences() { bool HeapSnapshotGenerator::IterateAndExtractReferences() {
HeapIterator iterator(HeapIterator::kPreciseFiltering); HeapIterator iterator(HeapIterator::kFilterUnreachable);
bool interrupted = false; bool interrupted = false;
// Heap iteration with precise filtering must be finished in any case. // Heap iteration with filtering must be finished in any case.
for (HeapObject* obj = iterator.next(); for (HeapObject* obj = iterator.next();
obj != NULL; obj != NULL;
obj = iterator.next(), IncProgressCounter()) { obj = iterator.next(), IncProgressCounter()) {

62
deps/v8/src/property.cc

@ -31,62 +31,62 @@ namespace v8 {
namespace internal { namespace internal {
#ifdef DEBUG #ifdef OBJECT_PRINT
void LookupResult::Print() { void LookupResult::Print(FILE* out) {
if (!IsFound()) { if (!IsFound()) {
PrintF("Not Found\n"); PrintF(out, "Not Found\n");
return; return;
} }
PrintF("LookupResult:\n"); PrintF(out, "LookupResult:\n");
PrintF(" -cacheable = %s\n", IsCacheable() ? "true" : "false"); PrintF(out, " -cacheable = %s\n", IsCacheable() ? "true" : "false");
PrintF(" -attributes = %x\n", GetAttributes()); PrintF(out, " -attributes = %x\n", GetAttributes());
switch (type()) { switch (type()) {
case NORMAL: case NORMAL:
PrintF(" -type = normal\n"); PrintF(out, " -type = normal\n");
PrintF(" -entry = %d", GetDictionaryEntry()); PrintF(out, " -entry = %d", GetDictionaryEntry());
break; break;
case MAP_TRANSITION: case MAP_TRANSITION:
PrintF(" -type = map transition\n"); PrintF(out, " -type = map transition\n");
PrintF(" -map:\n"); PrintF(out, " -map:\n");
GetTransitionMap()->Print(); GetTransitionMap()->Print(out);
PrintF("\n"); PrintF(out, "\n");
break; break;
case CONSTANT_FUNCTION: case CONSTANT_FUNCTION:
PrintF(" -type = constant function\n"); PrintF(out, " -type = constant function\n");
PrintF(" -function:\n"); PrintF(out, " -function:\n");
GetConstantFunction()->Print(); GetConstantFunction()->Print(out);
PrintF("\n"); PrintF(out, "\n");
break; break;
case FIELD: case FIELD:
PrintF(" -type = field\n"); PrintF(out, " -type = field\n");
PrintF(" -index = %d", GetFieldIndex()); PrintF(out, " -index = %d", GetFieldIndex());
PrintF("\n"); PrintF(out, "\n");
break; break;
case CALLBACKS: case CALLBACKS:
PrintF(" -type = call backs\n"); PrintF(out, " -type = call backs\n");
PrintF(" -callback object:\n"); PrintF(out, " -callback object:\n");
GetCallbackObject()->Print(); GetCallbackObject()->Print(out);
break; break;
case INTERCEPTOR: case INTERCEPTOR:
PrintF(" -type = lookup interceptor\n"); PrintF(out, " -type = lookup interceptor\n");
break; break;
case CONSTANT_TRANSITION: case CONSTANT_TRANSITION:
PrintF(" -type = constant property transition\n"); PrintF(out, " -type = constant property transition\n");
break; break;
case NULL_DESCRIPTOR: case NULL_DESCRIPTOR:
PrintF(" =type = null descriptor\n"); PrintF(out, " =type = null descriptor\n");
break; break;
} }
} }
void Descriptor::Print() { void Descriptor::Print(FILE* out) {
PrintF("Descriptor "); PrintF(out, "Descriptor ");
GetKey()->ShortPrint(); GetKey()->ShortPrint(out);
PrintF(" @ "); PrintF(out, " @ ");
GetValue()->ShortPrint(); GetValue()->ShortPrint(out);
PrintF(" %d\n", GetDetails().index()); PrintF(out, " %d\n", GetDetails().index());
} }

8
deps/v8/src/property.h

@ -60,8 +60,8 @@ class Descriptor BASE_EMBEDDED {
Object* GetValue() { return value_; } Object* GetValue() { return value_; }
PropertyDetails GetDetails() { return details_; } PropertyDetails GetDetails() { return details_; }
#ifdef DEBUG #ifdef OBJECT_PRINT
void Print(); void Print(FILE* out);
#endif #endif
void SetEnumerationIndex(int index) { void SetEnumerationIndex(int index) {
@ -310,8 +310,8 @@ class LookupResult BASE_EMBEDDED {
return GetValue(); return GetValue();
} }
#ifdef DEBUG #ifdef OBJECT_PRINT
void Print(); void Print(FILE* out);
#endif #endif
Object* GetValue() { Object* GetValue() {

27
deps/v8/src/regexp.js

@ -32,7 +32,7 @@ const $RegExp = global.RegExp;
// A recursive descent parser for Patterns according to the grammar of // A recursive descent parser for Patterns according to the grammar of
// ECMA-262 15.10.1, with deviations noted below. // ECMA-262 15.10.1, with deviations noted below.
function DoConstructRegExp(object, pattern, flags, isConstructorCall) { function DoConstructRegExp(object, pattern, flags) {
// RegExp : Called as constructor; see ECMA-262, section 15.10.4. // RegExp : Called as constructor; see ECMA-262, section 15.10.4.
if (IS_REGEXP(pattern)) { if (IS_REGEXP(pattern)) {
if (!IS_UNDEFINED(flags)) { if (!IS_UNDEFINED(flags)) {
@ -80,7 +80,7 @@ function DoConstructRegExp(object, pattern, flags, isConstructorCall) {
function RegExpConstructor(pattern, flags) { function RegExpConstructor(pattern, flags) {
if (%_IsConstructCall()) { if (%_IsConstructCall()) {
DoConstructRegExp(this, pattern, flags, true); DoConstructRegExp(this, pattern, flags);
} else { } else {
// RegExp : Called as function; see ECMA-262, section 15.10.3.1. // RegExp : Called as function; see ECMA-262, section 15.10.3.1.
if (IS_REGEXP(pattern) && IS_UNDEFINED(flags)) { if (IS_REGEXP(pattern) && IS_UNDEFINED(flags)) {
@ -104,9 +104,9 @@ function CompileRegExp(pattern, flags) {
// the empty string. For compatibility with JSC, we match their // the empty string. For compatibility with JSC, we match their
// behavior. // behavior.
if (IS_UNDEFINED(pattern) && %_ArgumentsLength() != 0) { if (IS_UNDEFINED(pattern) && %_ArgumentsLength() != 0) {
DoConstructRegExp(this, 'undefined', flags, false); DoConstructRegExp(this, 'undefined', flags);
} else { } else {
DoConstructRegExp(this, pattern, flags, false); DoConstructRegExp(this, pattern, flags);
} }
} }
@ -150,12 +150,12 @@ function BuildResultFromMatchInfo(lastMatchInfo, s) {
function RegExpExecNoTests(regexp, string, start) { function RegExpExecNoTests(regexp, string, start) {
// Must be called with RegExp, string and positive integer as arguments. // Must be called with RegExp, string and positive integer as arguments.
var matchInfo = DoRegExpExec(regexp, string, start); var matchInfo = %_RegExpExec(regexp, string, start, lastMatchInfo);
var result = null;
if (matchInfo !== null) { if (matchInfo !== null) {
result = BuildResultFromMatchInfo(matchInfo, string); lastMatchInfoOverride = null;
return BuildResultFromMatchInfo(matchInfo, string);
} }
return result; return null;
} }
@ -261,11 +261,14 @@ function RegExpTest(string) {
%_StringCharCodeAt(this.source, 2) != 63) { // '?' %_StringCharCodeAt(this.source, 2) != 63) { // '?'
if (!%_ObjectEquals(regexp_key, this)) { if (!%_ObjectEquals(regexp_key, this)) {
regexp_key = this; regexp_key = this;
regexp_val = new $RegExp(this.source.substring(2, this.source.length), regexp_val = new $RegExp(SubString(this.source, 2, this.source.length),
(this.ignoreCase ? 'i' : '') (!this.ignoreCase
+ (this.multiline ? 'm' : '')); ? !this.multiline ? "" : "m"
: !this.multiline ? "i" : "im"));
}
if (%_RegExpExec(regexp_val, string, 0, lastMatchInfo) === null) {
return false;
} }
if (!regexp_val.test(string)) return false;
} }
%_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, string, lastIndex]); %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, string, lastIndex]);
// matchIndices is either null or the lastMatchInfo array. // matchIndices is either null or the lastMatchInfo array.

2
deps/v8/src/runtime.cc

@ -7204,7 +7204,7 @@ static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
// extension object itself. // extension object itself.
if ((attributes & READ_ONLY) == 0 || if ((attributes & READ_ONLY) == 0 ||
(context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) { (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
Handle<Object> set = SetProperty(context_ext, name, value, attributes); Handle<Object> set = SetProperty(context_ext, name, value, NONE);
if (set.is_null()) { if (set.is_null()) {
// Failure::Exception is converted to a null handle in the // Failure::Exception is converted to a null handle in the
// handle-based methods such as SetProperty. We therefore need // handle-based methods such as SetProperty. We therefore need

53
deps/v8/src/spaces.cc

@ -364,15 +364,15 @@ void MemoryAllocator::TearDown() {
} }
void MemoryAllocator::FreeChunkTables(AtomicWord* array, int len, int level) { void MemoryAllocator::FreeChunkTables(uintptr_t* array, int len, int level) {
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
if (array[i] != kUnusedChunkTableEntry) { if (array[i] != kUnusedChunkTableEntry) {
AtomicWord* subarray = reinterpret_cast<AtomicWord*>(array[i]); uintptr_t* subarray = reinterpret_cast<uintptr_t*>(array[i]);
if (level > 1) { if (level > 1) {
Release_Store(&array[i], kUnusedChunkTableEntry); array[i] = kUnusedChunkTableEntry;
FreeChunkTables(subarray, 1 << kChunkTableBitsPerLevel, level - 1); FreeChunkTables(subarray, 1 << kChunkTableBitsPerLevel, level - 1);
} else { } else {
Release_Store(&array[i], kUnusedChunkTableEntry); array[i] = kUnusedChunkTableEntry;
} }
delete[] subarray; delete[] subarray;
} }
@ -822,7 +822,7 @@ void MemoryAllocator::AddToAllocatedChunks(Address addr, intptr_t size) {
void MemoryAllocator::AddChunkUsingAddress(uintptr_t chunk_start, void MemoryAllocator::AddChunkUsingAddress(uintptr_t chunk_start,
uintptr_t chunk_index_base) { uintptr_t chunk_index_base) {
AtomicWord* fine_grained = AllocatedChunksFinder( uintptr_t* fine_grained = AllocatedChunksFinder(
chunk_table_, chunk_table_,
chunk_index_base, chunk_index_base,
kChunkSizeLog2 + (kChunkTableLevels - 1) * kChunkTableBitsPerLevel, kChunkSizeLog2 + (kChunkTableLevels - 1) * kChunkTableBitsPerLevel,
@ -830,7 +830,7 @@ void MemoryAllocator::AddChunkUsingAddress(uintptr_t chunk_start,
int index = FineGrainedIndexForAddress(chunk_index_base); int index = FineGrainedIndexForAddress(chunk_index_base);
if (fine_grained[index] != kUnusedChunkTableEntry) index++; if (fine_grained[index] != kUnusedChunkTableEntry) index++;
ASSERT(fine_grained[index] == kUnusedChunkTableEntry); ASSERT(fine_grained[index] == kUnusedChunkTableEntry);
Release_Store(&fine_grained[index], chunk_start); fine_grained[index] = chunk_start;
} }
@ -845,7 +845,7 @@ void MemoryAllocator::RemoveFromAllocatedChunks(Address addr, intptr_t size) {
void MemoryAllocator::RemoveChunkFoundUsingAddress( void MemoryAllocator::RemoveChunkFoundUsingAddress(
uintptr_t chunk_start, uintptr_t chunk_start,
uintptr_t chunk_index_base) { uintptr_t chunk_index_base) {
AtomicWord* fine_grained = AllocatedChunksFinder( uintptr_t* fine_grained = AllocatedChunksFinder(
chunk_table_, chunk_table_,
chunk_index_base, chunk_index_base,
kChunkSizeLog2 + (kChunkTableLevels - 1) * kChunkTableBitsPerLevel, kChunkSizeLog2 + (kChunkTableLevels - 1) * kChunkTableBitsPerLevel,
@ -854,22 +854,23 @@ void MemoryAllocator::RemoveChunkFoundUsingAddress(
ASSERT(fine_grained != kUnusedChunkTableEntry); ASSERT(fine_grained != kUnusedChunkTableEntry);
int index = FineGrainedIndexForAddress(chunk_index_base); int index = FineGrainedIndexForAddress(chunk_index_base);
ASSERT(fine_grained[index] != kUnusedChunkTableEntry); ASSERT(fine_grained[index] != kUnusedChunkTableEntry);
if (fine_grained[index] != static_cast<AtomicWord>(chunk_start)) { if (fine_grained[index] != chunk_start) {
index++; index++;
ASSERT(fine_grained[index] == static_cast<AtomicWord>(chunk_start)); ASSERT(fine_grained[index] == chunk_start);
Release_Store(&fine_grained[index], kUnusedChunkTableEntry); fine_grained[index] = kUnusedChunkTableEntry;
} else { } else {
Release_Store(&fine_grained[index], fine_grained[index + 1]); // If only one of the entries is used it must be the first, since
// Here for a moment the two entries are duplicates, but the reader can // InAllocatedChunks relies on that. Move things around so that this is
// handle that. // the case.
NoBarrier_Store(&fine_grained[index + 1], kUnusedChunkTableEntry); fine_grained[index] = fine_grained[index + 1];
fine_grained[index + 1] = kUnusedChunkTableEntry;
} }
} }
bool MemoryAllocator::InAllocatedChunks(Address addr) { bool MemoryAllocator::InAllocatedChunks(Address addr) {
uintptr_t int_address = reinterpret_cast<uintptr_t>(addr); uintptr_t int_address = reinterpret_cast<uintptr_t>(addr);
AtomicWord* fine_grained = AllocatedChunksFinder( uintptr_t* fine_grained = AllocatedChunksFinder(
chunk_table_, chunk_table_,
int_address, int_address,
kChunkSizeLog2 + (kChunkTableLevels - 1) * kChunkTableBitsPerLevel, kChunkSizeLog2 + (kChunkTableLevels - 1) * kChunkTableBitsPerLevel,
@ -877,21 +878,18 @@ bool MemoryAllocator::InAllocatedChunks(Address addr) {
if (fine_grained == NULL) return false; if (fine_grained == NULL) return false;
int index = FineGrainedIndexForAddress(int_address); int index = FineGrainedIndexForAddress(int_address);
if (fine_grained[index] == kUnusedChunkTableEntry) return false; if (fine_grained[index] == kUnusedChunkTableEntry) return false;
uintptr_t entry = static_cast<uintptr_t>(fine_grained[index]); uintptr_t entry = fine_grained[index];
if (entry <= int_address && entry + kChunkSize > int_address) return true; if (entry <= int_address && entry + kChunkSize > int_address) return true;
index++; index++;
if (fine_grained[index] == kUnusedChunkTableEntry) return false; if (fine_grained[index] == kUnusedChunkTableEntry) return false;
entry = static_cast<uintptr_t>(fine_grained[index]); entry = fine_grained[index];
// At this point it would seem that we must have a hit, but there is a small
// window during RemoveChunkFoundUsingAddress where the two entries are
// duplicates and we have to handle that.
if (entry <= int_address && entry + kChunkSize > int_address) return true; if (entry <= int_address && entry + kChunkSize > int_address) return true;
return false; return false;
} }
AtomicWord* MemoryAllocator::AllocatedChunksFinder( uintptr_t* MemoryAllocator::AllocatedChunksFinder(
AtomicWord* table, uintptr_t* table,
uintptr_t address, uintptr_t address,
int bit_position, int bit_position,
CreateTables create_as_needed) { CreateTables create_as_needed) {
@ -906,8 +904,8 @@ AtomicWord* MemoryAllocator::AllocatedChunksFinder(
address & ((V8_INTPTR_C(1) << bit_position) - 1); address & ((V8_INTPTR_C(1) << bit_position) - 1);
ASSERT((table == chunk_table_ && index < kChunkTableTopLevelEntries) || ASSERT((table == chunk_table_ && index < kChunkTableTopLevelEntries) ||
(table != chunk_table_ && index < 1 << kChunkTableBitsPerLevel)); (table != chunk_table_ && index < 1 << kChunkTableBitsPerLevel));
AtomicWord* more_fine_grained_table = uintptr_t* more_fine_grained_table =
reinterpret_cast<AtomicWord*>(table[index]); reinterpret_cast<uintptr_t*>(table[index]);
if (more_fine_grained_table == kUnusedChunkTableEntry) { if (more_fine_grained_table == kUnusedChunkTableEntry) {
if (create_as_needed == kDontCreateTables) return NULL; if (create_as_needed == kDontCreateTables) return NULL;
int words_needed = 1 << kChunkTableBitsPerLevel; int words_needed = 1 << kChunkTableBitsPerLevel;
@ -915,12 +913,11 @@ AtomicWord* MemoryAllocator::AllocatedChunksFinder(
words_needed = words_needed =
(1 << kChunkTableBitsPerLevel) * kChunkTableFineGrainedWordsPerEntry; (1 << kChunkTableBitsPerLevel) * kChunkTableFineGrainedWordsPerEntry;
} }
more_fine_grained_table = new AtomicWord[words_needed]; more_fine_grained_table = new uintptr_t[words_needed];
for (int i = 0; i < words_needed; i++) { for (int i = 0; i < words_needed; i++) {
more_fine_grained_table[i] = kUnusedChunkTableEntry; more_fine_grained_table[i] = kUnusedChunkTableEntry;
} }
Release_Store(&table[index], table[index] = reinterpret_cast<uintptr_t>(more_fine_grained_table);
reinterpret_cast<AtomicWord>(more_fine_grained_table));
} }
return AllocatedChunksFinder( return AllocatedChunksFinder(
more_fine_grained_table, more_fine_grained_table,
@ -930,7 +927,7 @@ AtomicWord* MemoryAllocator::AllocatedChunksFinder(
} }
AtomicWord MemoryAllocator::chunk_table_[kChunkTableTopLevelEntries]; uintptr_t MemoryAllocator::chunk_table_[kChunkTableTopLevelEntries];
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

9
deps/v8/src/spaces.h

@ -28,7 +28,6 @@
#ifndef V8_SPACES_H_ #ifndef V8_SPACES_H_
#define V8_SPACES_H_ #define V8_SPACES_H_
#include "atomicops.h"
#include "list-inl.h" #include "list-inl.h"
#include "log.h" #include "log.h"
@ -688,7 +687,7 @@ class MemoryAllocator : public AllStatic {
// The chunks are not chunk-size aligned so for a given chunk-sized area of // The chunks are not chunk-size aligned so for a given chunk-sized area of
// memory there can be two chunks that cover it. // memory there can be two chunks that cover it.
static const int kChunkTableFineGrainedWordsPerEntry = 2; static const int kChunkTableFineGrainedWordsPerEntry = 2;
static const AtomicWord kUnusedChunkTableEntry = 0; static const uintptr_t kUnusedChunkTableEntry = 0;
// Maximum space size in bytes. // Maximum space size in bytes.
static intptr_t capacity_; static intptr_t capacity_;
@ -696,7 +695,7 @@ class MemoryAllocator : public AllStatic {
static intptr_t capacity_executable_; static intptr_t capacity_executable_;
// Top level table to track whether memory is part of a chunk or not. // Top level table to track whether memory is part of a chunk or not.
static AtomicWord chunk_table_[kChunkTableTopLevelEntries]; static uintptr_t chunk_table_[kChunkTableTopLevelEntries];
// Allocated space size in bytes. // Allocated space size in bytes.
static intptr_t size_; static intptr_t size_;
@ -766,11 +765,11 @@ class MemoryAllocator : public AllStatic {
// Controls whether the lookup creates intermediate levels of tables as // Controls whether the lookup creates intermediate levels of tables as
// needed. // needed.
enum CreateTables { kDontCreateTables, kCreateTablesAsNeeded }; enum CreateTables { kDontCreateTables, kCreateTablesAsNeeded };
static AtomicWord* AllocatedChunksFinder(AtomicWord* table, static uintptr_t* AllocatedChunksFinder(uintptr_t* table,
uintptr_t address, uintptr_t address,
int bit_position, int bit_position,
CreateTables create_as_needed); CreateTables create_as_needed);
static void FreeChunkTables(AtomicWord* array, int length, int level); static void FreeChunkTables(uintptr_t* array, int length, int level);
static int FineGrainedIndexForAddress(uintptr_t address) { static int FineGrainedIndexForAddress(uintptr_t address) {
int index = ((address >> kChunkSizeLog2) & int index = ((address >> kChunkSizeLog2) &
((1 << kChunkTableBitsPerLevel) - 1)); ((1 << kChunkTableBitsPerLevel) - 1));

6
deps/v8/src/string-stream.cc

@ -264,7 +264,7 @@ void StringStream::Log() {
} }
void StringStream::OutputToStdOut() { void StringStream::OutputToFile(FILE* out) {
// Dump the output to stdout, but make sure to break it up into // Dump the output to stdout, but make sure to break it up into
// manageable chunks to avoid losing parts of the output in the OS // manageable chunks to avoid losing parts of the output in the OS
// printing code. This is a problem on Windows in particular; see // printing code. This is a problem on Windows in particular; see
@ -273,10 +273,10 @@ void StringStream::OutputToStdOut() {
for (unsigned next; (next = position + 2048) < length_; position = next) { for (unsigned next; (next = position + 2048) < length_; position = next) {
char save = buffer_[next]; char save = buffer_[next];
buffer_[next] = '\0'; buffer_[next] = '\0';
internal::PrintF("%s", &buffer_[position]); internal::PrintF(out, "%s", &buffer_[position]);
buffer_[next] = save; buffer_[next] = save;
} }
internal::PrintF("%s", &buffer_[position]); internal::PrintF(out, "%s", &buffer_[position]);
} }

3
deps/v8/src/string-stream.h

@ -138,7 +138,8 @@ class StringStream {
FmtElm arg3); FmtElm arg3);
// Getting the message out. // Getting the message out.
void OutputToStdOut(); void OutputToFile(FILE* out);
void OutputToStdOut() { OutputToFile(stdout); }
void Log(); void Log();
Handle<String> ToString(); Handle<String> ToString();
SmartPointer<const char> ToCString() const; SmartPointer<const char> ToCString() const;

67
deps/v8/src/string.js

@ -159,7 +159,7 @@ function StringLocaleCompare(other) {
function StringMatch(regexp) { function StringMatch(regexp) {
var subject = TO_STRING_INLINE(this); var subject = TO_STRING_INLINE(this);
if (IS_REGEXP(regexp)) { if (IS_REGEXP(regexp)) {
if (!regexp.global) return regexp.exec(subject); if (!regexp.global) return RegExpExecNoTests(regexp, subject, 0);
%_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]); %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
// lastMatchInfo is defined in regexp.js. // lastMatchInfo is defined in regexp.js.
return %StringMatch(subject, regexp, lastMatchInfo); return %StringMatch(subject, regexp, lastMatchInfo);
@ -245,17 +245,18 @@ function StringReplace(search, replace) {
// Expand the $-expressions in the string and return a new string with // Expand the $-expressions in the string and return a new string with
// the result. // the result.
function ExpandReplacement(string, subject, matchInfo, builder) { function ExpandReplacement(string, subject, matchInfo, builder) {
var length = string.length;
var builder_elements = builder.elements;
var next = %StringIndexOf(string, '$', 0); var next = %StringIndexOf(string, '$', 0);
if (next < 0) { if (next < 0) {
builder.add(string); if (length > 0) builder_elements.push(string);
return; return;
} }
// Compute the number of captures; see ECMA-262, 15.5.4.11, p. 102. // Compute the number of captures; see ECMA-262, 15.5.4.11, p. 102.
var m = NUMBER_OF_CAPTURES(matchInfo) >> 1; // Includes the match. var m = NUMBER_OF_CAPTURES(matchInfo) >> 1; // Includes the match.
if (next > 0) builder.add(SubString(string, 0, next)); if (next > 0) builder_elements.push(SubString(string, 0, next));
var length = string.length;
while (true) { while (true) {
var expansion = '$'; var expansion = '$';
@ -264,7 +265,7 @@ function ExpandReplacement(string, subject, matchInfo, builder) {
var peek = %_StringCharCodeAt(string, position); var peek = %_StringCharCodeAt(string, position);
if (peek == 36) { // $$ if (peek == 36) { // $$
++position; ++position;
builder.add('$'); builder_elements.push('$');
} else if (peek == 38) { // $& - match } else if (peek == 38) { // $& - match
++position; ++position;
builder.addSpecialSlice(matchInfo[CAPTURE0], builder.addSpecialSlice(matchInfo[CAPTURE0],
@ -301,14 +302,14 @@ function ExpandReplacement(string, subject, matchInfo, builder) {
// digit capture references, we can only enter here when a // digit capture references, we can only enter here when a
// single digit capture reference is outside the range of // single digit capture reference is outside the range of
// captures. // captures.
builder.add('$'); builder_elements.push('$');
--position; --position;
} }
} else { } else {
builder.add('$'); builder_elements.push('$');
} }
} else { } else {
builder.add('$'); builder_elements.push('$');
} }
// Go the the next $ in the string. // Go the the next $ in the string.
@ -318,13 +319,15 @@ function ExpandReplacement(string, subject, matchInfo, builder) {
// haven't reached the end, we need to append the suffix. // haven't reached the end, we need to append the suffix.
if (next < 0) { if (next < 0) {
if (position < length) { if (position < length) {
builder.add(SubString(string, position, length)); builder_elements.push(SubString(string, position, length));
} }
return; return;
} }
// Append substring between the previous and the next $ character. // Append substring between the previous and the next $ character.
builder.add(SubString(string, position, next)); if (next > position) {
builder_elements.push(SubString(string, position, next));
}
} }
}; };
@ -559,23 +562,22 @@ function StringSplit(separator, limit) {
var currentIndex = 0; var currentIndex = 0;
var startIndex = 0; var startIndex = 0;
var startMatch = 0;
var result = []; var result = [];
outer_loop: outer_loop:
while (true) { while (true) {
if (startIndex === length) { if (startIndex === length) {
result.push(subject.slice(currentIndex, length)); result.push(SubString(subject, currentIndex, length));
break; break;
} }
var matchInfo = splitMatch(separator, subject, currentIndex, startIndex); var matchInfo = DoRegExpExec(separator, subject, startIndex);
if (matchInfo == null || length === (startMatch = matchInfo[CAPTURE0])) {
if (IS_NULL(matchInfo)) { result.push(SubString(subject, currentIndex, length));
result.push(subject.slice(currentIndex, length));
break; break;
} }
var endIndex = matchInfo[CAPTURE1]; var endIndex = matchInfo[CAPTURE1];
// We ignore a zero-length match at the currentIndex. // We ignore a zero-length match at the currentIndex.
@ -584,7 +586,12 @@ function StringSplit(separator, limit) {
continue; continue;
} }
result.push(SubString(subject, currentIndex, matchInfo[CAPTURE0])); if (currentIndex + 1 == startMatch) {
result.push(%_StringCharAt(subject, currentIndex));
} else {
result.push(%_SubString(subject, currentIndex, startMatch));
}
if (result.length === limit) break; if (result.length === limit) break;
var matchinfo_len = NUMBER_OF_CAPTURES(matchInfo) + REGEXP_FIRST_CAPTURE; var matchinfo_len = NUMBER_OF_CAPTURES(matchInfo) + REGEXP_FIRST_CAPTURE;
@ -609,19 +616,6 @@ function StringSplit(separator, limit) {
} }
// ECMA-262 section 15.5.4.14
// Helper function used by split. This version returns the matchInfo
// instead of allocating a new array with basically the same information.
function splitMatch(separator, subject, current_index, start_index) {
var matchInfo = DoRegExpExec(separator, subject, start_index);
if (matchInfo == null) return null;
// Section 15.5.4.14 paragraph two says that we do not allow zero length
// matches at the end of the string.
if (matchInfo[CAPTURE0] === subject.length) return null;
return matchInfo;
}
// ECMA-262 section 15.5.4.15 // ECMA-262 section 15.5.4.15
function StringSubstring(start, end) { function StringSubstring(start, end) {
var s = TO_STRING_INLINE(this); var s = TO_STRING_INLINE(this);
@ -844,24 +838,21 @@ function ReplaceResultBuilder(str) {
ReplaceResultBuilder.prototype.add = function(str) { ReplaceResultBuilder.prototype.add = function(str) {
str = TO_STRING_INLINE(str); str = TO_STRING_INLINE(str);
if (str.length > 0) { if (str.length > 0) this.elements.push(str);
var elements = this.elements;
elements[elements.length] = str;
}
} }
ReplaceResultBuilder.prototype.addSpecialSlice = function(start, end) { ReplaceResultBuilder.prototype.addSpecialSlice = function(start, end) {
var len = end - start; var len = end - start;
if (start < 0 || len <= 0) return; if (start < 0 || len <= 0) return;
var elements = this.elements;
if (start < 0x80000 && len < 0x800) { if (start < 0x80000 && len < 0x800) {
elements[elements.length] = (start << 11) | len; this.elements.push((start << 11) | len);
} else { } else {
// 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength, // 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength,
// so -len is a smi. // so -len is a smi.
elements[elements.length] = -len; var elements = this.elements;
elements[elements.length] = start; elements.push(-len);
elements.push(start);
} }
} }

12
deps/v8/src/utils.cc

@ -45,8 +45,16 @@ void PrintF(const char* format, ...) {
} }
void Flush() { void PrintF(FILE* out, const char* format, ...) {
fflush(stdout); va_list arguments;
va_start(arguments, format);
OS::VFPrint(out, format, arguments);
va_end(arguments);
}
void Flush(FILE* out) {
fflush(out);
} }

2
deps/v8/src/v8-counters.h

@ -28,7 +28,9 @@
#ifndef V8_V8_COUNTERS_H_ #ifndef V8_V8_COUNTERS_H_
#define V8_V8_COUNTERS_H_ #define V8_V8_COUNTERS_H_
#include "allocation.h"
#include "counters.h" #include "counters.h"
#include "v8globals.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {

10
deps/v8/src/v8utils.h

@ -43,18 +43,26 @@ namespace internal {
// so it works on MacOSX. // so it works on MacOSX.
#if defined(__MACH__) && defined(__APPLE__) #if defined(__MACH__) && defined(__APPLE__)
#define PRINTF_CHECKING #define PRINTF_CHECKING
#define FPRINTF_CHECKING
#else // MacOsX. #else // MacOsX.
#define PRINTF_CHECKING __attribute__ ((format (printf, 1, 2))) #define PRINTF_CHECKING __attribute__ ((format (printf, 1, 2)))
#define FPRINTF_CHECKING __attribute__ ((format (printf, 2, 3)))
#endif #endif
#else #else
#define PRINTF_CHECKING #define PRINTF_CHECKING
#define FPRINTF_CHECKING
#endif #endif
// Our version of printf(). // Our version of printf().
void PRINTF_CHECKING PrintF(const char* format, ...); void PRINTF_CHECKING PrintF(const char* format, ...);
void FPRINTF_CHECKING PrintF(FILE* out, const char* format, ...);
// Our version of fflush. // Our version of fflush.
void Flush(); void Flush(FILE* out);
inline void Flush() {
Flush(stdout);
}
// Read a line of characters after printing the prompt to stdout. The resulting // Read a line of characters after printing the prompt to stdout. The resulting

4
deps/v8/src/version.cc

@ -34,8 +34,8 @@
// cannot be changed without changing the SCons build script. // cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3 #define MAJOR_VERSION 3
#define MINOR_VERSION 0 #define MINOR_VERSION 0
#define BUILD_NUMBER 3 #define BUILD_NUMBER 4
#define PATCH_LEVEL 0 #define PATCH_LEVEL 1
#define CANDIDATE_VERSION false #define CANDIDATE_VERSION false
// Define SONAME to have the SCons build the put a specific SONAME into the // Define SONAME to have the SCons build the put a specific SONAME into the

4
deps/v8/src/x64/codegen-x64.cc

@ -6784,9 +6784,9 @@ void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) {
// Check that both indices are valid. // Check that both indices are valid.
__ movq(tmp2.reg(), FieldOperand(object.reg(), JSArray::kLengthOffset)); __ movq(tmp2.reg(), FieldOperand(object.reg(), JSArray::kLengthOffset));
__ cmpl(tmp2.reg(), index1.reg()); __ SmiCompare(tmp2.reg(), index1.reg());
deferred->Branch(below_equal); deferred->Branch(below_equal);
__ cmpl(tmp2.reg(), index2.reg()); __ SmiCompare(tmp2.reg(), index2.reg());
deferred->Branch(below_equal); deferred->Branch(below_equal);
// Bring addresses into index1 and index2. // Bring addresses into index1 and index2.

64
deps/v8/test/cctest/test-heap.cc

@ -1216,7 +1216,7 @@ TEST(TestInternalWeakListsTraverseWithGC) {
TEST(TestSizeOfObjectsVsHeapIteratorPrecision) { TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
InitializeVM(); InitializeVM();
intptr_t size_of_objects_1 = Heap::SizeOfObjects(); intptr_t size_of_objects_1 = Heap::SizeOfObjects();
HeapIterator iterator(HeapIterator::kPreciseFiltering); HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
intptr_t size_of_objects_2 = 0; intptr_t size_of_objects_2 = 0;
for (HeapObject* obj = iterator.next(); for (HeapObject* obj = iterator.next();
obj != NULL; obj != NULL;
@ -1240,3 +1240,65 @@ TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
CHECK_GT(size_of_objects_2 / 100, delta); CHECK_GT(size_of_objects_2 / 100, delta);
} }
} }
class HeapIteratorTestHelper {
public:
HeapIteratorTestHelper(Object* a, Object* b)
: a_(a), b_(b), a_found_(false), b_found_(false) {}
bool a_found() { return a_found_; }
bool b_found() { return b_found_; }
void IterateHeap(HeapIterator::HeapObjectsFiltering mode) {
HeapIterator iterator(mode);
for (HeapObject* obj = iterator.next();
obj != NULL;
obj = iterator.next()) {
if (obj == a_)
a_found_ = true;
else if (obj == b_)
b_found_ = true;
}
}
private:
Object* a_;
Object* b_;
bool a_found_;
bool b_found_;
};
TEST(HeapIteratorFilterUnreachable) {
InitializeVM();
v8::HandleScope scope;
CompileRun("a = {}; b = {};");
v8::Handle<Object> a(Top::context()->global()->GetProperty(
*Factory::LookupAsciiSymbol("a"))->ToObjectChecked());
v8::Handle<Object> b(Top::context()->global()->GetProperty(
*Factory::LookupAsciiSymbol("b"))->ToObjectChecked());
CHECK_NE(*a, *b);
{
HeapIteratorTestHelper helper(*a, *b);
helper.IterateHeap(HeapIterator::kFilterUnreachable);
CHECK(helper.a_found());
CHECK(helper.b_found());
}
CHECK(Top::context()->global()->DeleteProperty(
*Factory::LookupAsciiSymbol("a"), JSObject::FORCE_DELETION));
// We ensure that GC will not happen, so our raw pointer stays valid.
AssertNoAllocation no_alloc;
Object* a_saved = *a;
a.Clear();
// Verify that "a" object still resides in the heap...
{
HeapIteratorTestHelper helper(a_saved, *b);
helper.IterateHeap(HeapIterator::kNoFiltering);
CHECK(helper.a_found());
CHECK(helper.b_found());
}
// ...but is now unreachable.
{
HeapIteratorTestHelper helper(a_saved, *b);
helper.IterateHeap(HeapIterator::kFilterUnreachable);
CHECK(!helper.a_found());
CHECK(helper.b_found());
}
}

13
deps/v8/test/mjsunit/array-slice.js

@ -218,3 +218,16 @@
assertTrue(delete Array.prototype[5]); assertTrue(delete Array.prototype[5]);
} }
})(); })();
// Check slicing on arguments object.
(function() {
function func(expected, a0, a1, a2) {
assertEquals(expected, Array.prototype.slice.call(arguments, 1));
}
func([]);
func(['a'], 'a');
func(['a', 1], 'a', 1);
func(['a', 1, undefined], 'a', 1, undefined);
func(['a', 1, undefined, void(0)], 'a', 1, undefined, void(0));
})();

17
deps/v8/test/mjsunit/array-sort.js

@ -1,4 +1,4 @@
// Copyright 2008 the V8 project authors. All rights reserved. // Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
@ -360,3 +360,18 @@ function TestSpecialCasesInheritedElementSort() {
} }
TestSpecialCasesInheritedElementSort(); TestSpecialCasesInheritedElementSort();
// Test that sort calls compare function with global object as receiver,
// and with only elements of the array as arguments.
function o(v) {
return {__proto__: o.prototype, val: v};
}
var arr = [o(1), o(2), o(4), o(8), o(16), o(32), o(64), o(128), o(256), o(-0)];
var global = this;
function cmpTest(a, b) {
assertEquals(global, this);
assertTrue(a instanceof o);
assertTrue(b instanceof o);
return a.val - b.val;
}
arr.sort(cmpTest);

43
deps/v8/test/mjsunit/with-readonly.js

@ -0,0 +1,43 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
// OWNER OR 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.
// Test that readonly variables are treated correctly.
// Create an object with a read-only length property in the prototype
// chain by putting the string split function in the prototype chain.
var o = {};
o.__proto__ = String.prototype.split;
function f() {
with (o) {
length = 23;
length = 24;
assertEquals(24, length);
}
}
f();

3
deps/v8/tools/gyp/v8.gyp

@ -70,7 +70,8 @@
'DEBUG', 'DEBUG',
'_DEBUG', '_DEBUG',
'ENABLE_DISASSEMBLER', 'ENABLE_DISASSEMBLER',
'V8_ENABLE_CHECKS' 'V8_ENABLE_CHECKS',
'OBJECT_PRINT',
], ],
'msvs_settings': { 'msvs_settings': {
'VCCLCompilerTool': { 'VCCLCompilerTool': {

3
deps/v8/tools/v8.xcodeproj/project.pbxproj

@ -1850,6 +1850,7 @@
DEBUG, DEBUG,
ENABLE_LOGGING_AND_PROFILING, ENABLE_LOGGING_AND_PROFILING,
V8_ENABLE_CHECKS, V8_ENABLE_CHECKS,
OBJECT_PRINT,
ENABLE_VMSTATE_TRACKING, ENABLE_VMSTATE_TRACKING,
); );
GCC_SYMBOLS_PRIVATE_EXTERN = YES; GCC_SYMBOLS_PRIVATE_EXTERN = YES;
@ -1914,6 +1915,7 @@
V8_TARGET_ARCH_IA32, V8_TARGET_ARCH_IA32,
DEBUG, DEBUG,
V8_ENABLE_CHECKS, V8_ENABLE_CHECKS,
OBJECT_PRINT,
ENABLE_DEBUGGER_SUPPORT, ENABLE_DEBUGGER_SUPPORT,
); );
HEADER_SEARCH_PATHS = ../src; HEADER_SEARCH_PATHS = ../src;
@ -1976,6 +1978,7 @@
V8_TARGET_ARCH_IA32, V8_TARGET_ARCH_IA32,
DEBUG, DEBUG,
V8_ENABLE_CHECKS, V8_ENABLE_CHECKS,
OBJECT_PRINT,
ENABLE_DEBUGGER_SUPPORT, ENABLE_DEBUGGER_SUPPORT,
); );
HEADER_SEARCH_PATHS = ../src; HEADER_SEARCH_PATHS = ../src;

2
deps/v8/tools/visual_studio/debug.vsprops

@ -7,7 +7,7 @@
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="0" Optimization="0"
PreprocessorDefinitions="DEBUG;_DEBUG;ENABLE_DISASSEMBLER;V8_ENABLE_CHECKS" PreprocessorDefinitions="DEBUG;_DEBUG;ENABLE_DISASSEMBLER;V8_ENABLE_CHECKS,OBJECT_PRINT"
RuntimeLibrary="1" RuntimeLibrary="1"
/> />
<Tool <Tool

4
doc/api/addons.markdown

@ -12,7 +12,7 @@ knowledge of several libraries:
descriptor to become readable, wait for a timer, or wait for a signal to descriptor to become readable, wait for a timer, or wait for a signal to
received one will need to interface with libev. That is, if you perform received one will need to interface with libev. That is, if you perform
any I/O, libev will need to be used. Node uses the `EV_DEFAULT` event any I/O, libev will need to be used. Node uses the `EV_DEFAULT` event
loop. Documentation can be found http:/cvs.schmorp.de/libev/ev.html[here]. loop. Documentation can be found [here](http://cvs.schmorp.de/libev/ev.html).
- libeio, C thread pool library. Used to execute blocking POSIX system - libeio, C thread pool library. Used to execute blocking POSIX system
calls asynchronously. Mostly wrappers already exist for such calls, in calls asynchronously. Mostly wrappers already exist for such calls, in
@ -69,7 +69,7 @@ like this:
Running `node-waf configure build` will create a file Running `node-waf configure build` will create a file
`build/default/hello.node` which is our Addon. `build/default/hello.node` which is our Addon.
`node-waf` is just [WAF](http://code.google.com/p/waf/), the python-based build system. `node-waf` is `node-waf` is just [WAF](http://code.google.com/p/waf), the python-based build system. `node-waf` is
provided for the ease of users. provided for the ease of users.
All Node addons must export a function called `init` with this signature: All Node addons must export a function called `init` with this signature:

2
doc/api/appendix_1.markdown

@ -2,7 +2,7 @@
There are many third party modules for Node. At the time of writing, August There are many third party modules for Node. At the time of writing, August
2010, the master repository of modules is 2010, the master repository of modules is
http://github.com/ry/node/wiki/modules[the wiki page]. [the wiki page](http://github.com/ry/node/wiki/modules).
This appendix is intended as a SMALL guide to new-comers to help them This appendix is intended as a SMALL guide to new-comers to help them
quickly find what are considered to be quality modules. It is not intended quickly find what are considered to be quality modules. It is not intended

4
doc/api/assert.markdown

@ -65,8 +65,8 @@ Custom error validation:
throw new Error("Wrong value"); throw new Error("Wrong value");
}, },
function(err) { function(err) {
if ( !(err instanceof Error) || !/value/.test(err) ) { if ( (err instanceof Error) && /value/.test(err) ) {
return false; return true;
} }
}, },
"unexpected error" "unexpected error"

97
doc/api/os.markdown

@ -2,6 +2,101 @@
Use `require('os')` to access this module. Use `require('os')` to access this module.
### os.getHostname() ### os.hostname()
Returns the hostname of the operating system. Returns the hostname of the operating system.
### os.type()
Returns the operating system name.
### os.release()
Returns the operating system release.
### os.uptime()
Returns the system uptime in seconds.
### os.loadavg()
Returns an array containing the 1, 5, and 15 minute load averages.
### os.totalmem()
Returns the total amount of system memory in bytes.
### os.freemem()
Returns the amount of free system memory in bytes.
### os.cpus()
Returns an array of objects containing information about each CPU/core installed: model, speed (in MHz), and times (an object containing the number of CPU ticks spent in: user, nice, sys, idle, and irq).
Example inspection of os.cpus:
[ { model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz',
speed: 2926,
times:
{ user: 252020,
nice: 0,
sys: 30340,
idle: 1070356870,
irq: 0 } },
{ model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz',
speed: 2926,
times:
{ user: 306960,
nice: 0,
sys: 26980,
idle: 1071569080,
irq: 0 } },
{ model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz',
speed: 2926,
times:
{ user: 248450,
nice: 0,
sys: 21750,
idle: 1070919370,
irq: 0 } },
{ model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz',
speed: 2926,
times:
{ user: 256880,
nice: 0,
sys: 19430,
idle: 1070905480,
irq: 20 } },
{ model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz',
speed: 2926,
times:
{ user: 511580,
nice: 20,
sys: 40900,
idle: 1070842510,
irq: 0 } },
{ model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz',
speed: 2926,
times:
{ user: 291660,
nice: 0,
sys: 34360,
idle: 1070888000,
irq: 10 } },
{ model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz',
speed: 2926,
times:
{ user: 308260,
nice: 0,
sys: 55410,
idle: 1071129970,
irq: 880 } },
{ model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz',
speed: 2926,
times:
{ user: 266450,
nice: 1480,
sys: 34920,
idle: 1072572010,
irq: 30 } } ]

17
doc/api/process.markdown

@ -59,7 +59,8 @@ standard POSIX signal names such as SIGINT, SIGUSR1, etc.
Example of listening for `SIGINT`: Example of listening for `SIGINT`:
var stdin = process.openStdin(); // Start reading from stdin so we don't exit.
process.stdin.resume();
process.on('SIGINT', function () { process.on('SIGINT', function () {
console.log('Got SIGINT. Press Control-D to exit.'); console.log('Got SIGINT. Press Control-D to exit.');
@ -80,21 +81,21 @@ Example: the definition of `console.log`
}; };
### process.openStdin() ### process.stdin
Opens the standard input stream, returns a `Readable Stream`. A `Readable Stream` for stdin. The stdin stream is paused by default, so one
must call `process.stdin.resume()` to read from it.
Example of opening standard input and listening for both events: Example of opening standard input and listening for both events:
var stdin = process.openStdin(); process.stdin.resume();
process.stdin.setEncoding('utf8');
stdin.setEncoding('utf8'); process.stdin.on('data', function (chunk) {
stdin.on('data', function (chunk) {
process.stdout.write('data: ' + chunk); process.stdout.write('data: ' + chunk);
}); });
stdin.on('end', function () { process.stdin.on('end', function () {
process.stdout.write('end'); process.stdout.write('end');
}); });

4
doc/api/repl.markdown

@ -27,11 +27,11 @@ For example, you could add this to your bashrc file:
alias node="env NODE_NO_READLINE=1 rlwrap node" alias node="env NODE_NO_READLINE=1 rlwrap node"
### repl.start(prompt='> ', stream=process.openStdin()) ### repl.start(prompt='> ', stream=process.stdin)
Starts a REPL with `prompt` as the prompt and `stream` for all I/O. `prompt` Starts a REPL with `prompt` as the prompt and `stream` for all I/O. `prompt`
is optional and defaults to `> `. `stream` is optional and defaults to is optional and defaults to `> `. `stream` is optional and defaults to
`process.openStdin()`. `process.stdin`.
Multiple REPLs may be started against the same running instance of node. Each Multiple REPLs may be started against the same running instance of node. Each
will share the same global object but will have unique I/O. will share the same global object but will have unique I/O.

57
doc/api/streams.markdown

@ -65,7 +65,7 @@ Resumes the incoming `'data'` events after a `pause()`.
Closes the underlying file descriptor. Stream will not emit any more events. Closes the underlying file descriptor. Stream will not emit any more events.
### stream.pipe(destination, [options], [filter]) ### stream.pipe(destination, [options])
This is a `Stream.prototype` method available on all `Stream`s. This is a `Stream.prototype` method available on all `Stream`s.
@ -75,7 +75,8 @@ streams are kept in sync by pausing and resuming as necessary.
Emulating the Unix `cat` command: Emulating the Unix `cat` command:
process.openStdin().pipe(process.stdout); process.stdin.resume();
process.stdin.pipe(process.stdout);
By default `end()` is called on the destination when the source stream emits By default `end()` is called on the destination when the source stream emits
@ -84,55 +85,17 @@ By default `end()` is called on the destination when the source stream emits
This keeps `process.stdout` open so that "Goodbye" can be written at the end. This keeps `process.stdout` open so that "Goodbye" can be written at the end.
var stdin = process.openStdin(); process.stdin.resume();
stdin.pipe(process.stdout, { end: false });
stdin.on("end", function() { process.stdout.write("Goodbye\n"); });
NOTE: If the source stream does not support `pause()` and `resume()`, this function process.stdin.pipe(process.stdout, { end: false });
adds simple definitions which simply emit `'pause'` and `'resume'` events on
the source stream.
The `filter` argument is an optional callback which can be used to filter all
data passing through the pipe. This makes it easy to do arbitrary transforms
(like gzip) while still maintaining the proper throttling. `filter` gets
three arguments: a buffer, a write function, and a done function. Here is an
example of a chat which uses a `filter` to append each message with the
address of the sender.
var net = require('net'); process.stdin.on("end", function() {
var people = []; process.stdout.write("Goodbye\n");
function address(socket) {
return '<' + socket.remoteAddress + ':' + socket.remotePort + '> ';
}
net.Server(function (socket) {
socket.write("hello!\r\n");
people.forEach(function (p) {
socket.pipe(p, { end: false }, function (d, write, done) {
write(address(socket));
write(d);
done();
}); });
p.pipe(socket, { end: false }, function (d, write, done) { NOTE: If the source stream does not support `pause()` and `resume()`, this function
write(address(p)); adds simple definitions which simply emit `'pause'` and `'resume'` events on
write(d); the source stream.
done();
});
});
people.push(socket);
socket.on('end', function () {
people.splice(people.indexOf(socket), 1);
});
}).listen(8000);
## Writable Stream ## Writable Stream

8
doc/index.html

@ -24,7 +24,7 @@
<li><a href="#links">Links</a></li> <li><a href="#links">Links</a></li>
<li><a href="#contributing">Contributing</a></li> <li><a href="#contributing">Contributing</a></li>
<li><a href="http://nodejs.org/docs/v0.3.2/api">v0.3.2 docs</a></li> <li><a href="http://nodejs.org/docs/v0.3.2/api">v0.3.2 docs</a></li>
<li><a href="http://nodejs.org/docs/v0.2.5/api.html">v0.2.5 docs</a></li> <li><a href="http://nodejs.org/docs/v0.2.6/api.html">v0.2.6 docs</a></li>
</ol> </ol>
</div> </div>
<div id="content"> <div id="content">
@ -86,9 +86,9 @@ net.createServer(function (socket) {
<a href="http://github.com/ry/node/tree/master">git repo</a> <a href="http://github.com/ry/node/tree/master">git repo</a>
</p> </p>
<p> <p>
Stable: 2010.11.16 Stable: 2010.12.30
<a href="http://nodejs.org/dist/node-v0.2.5.tar.gz">node-v0.2.5.tar.gz</a> <a href="http://nodejs.org/dist/node-v0.2.6.tar.gz">node-v0.2.6.tar.gz</a>
(<a href="http://nodejs.org/docs/v0.2.5/api.html">Documentation</a>) (<a href="http://nodejs.org/docs/v0.2.6/api.html">Documentation</a>)
</p> </p>
<p> <p>

9
lib/assert.js

@ -246,13 +246,14 @@ function expectedException(actual, expected) {
} }
if (expected instanceof RegExp) { if (expected instanceof RegExp) {
if (expected.test(actual)) { return expected.test(actual);
} else if (actual instanceof expected) {
return true; return true;
} } else if ( expected.call({}, actual) === true ) {
} else if (actual instanceof expected ||
expected.call({}, actual) !== false) {
return true; return true;
} }
return false;
} }
function _throws(shouldThrow, block, expected, message) { function _throws(shouldThrow, block, expected, message) {

16
lib/console.js

@ -3,8 +3,10 @@ var writeError = process.binding('stdio').writeError;
// console object // console object
var formatRegExp = /%[sdj]/g; var formatRegExp = /%[sdj]/g;
function format(f) { function format(f) {
var util = require('util');
if (typeof f !== 'string') { if (typeof f !== 'string') {
var objects = [], util = require('util'); var objects = [];
for (var i = 0; i < arguments.length; i++) { for (var i = 0; i < arguments.length; i++) {
objects.push(util.inspect(arguments[i])); objects.push(util.inspect(arguments[i]));
} }
@ -16,15 +18,19 @@ function format(f) {
var args = arguments; var args = arguments;
var str = String(f).replace(formatRegExp, function(x) { var str = String(f).replace(formatRegExp, function(x) {
switch (x) { switch (x) {
case '%s': return args[i++]; case '%s': return String(args[i++]);
case '%d': return +args[i++]; case '%d': return Number(args[i++]);
case '%j': return JSON.stringify(args[i++]); case '%j': return JSON.stringify(args[i++]);
default: default:
return x; return x;
} }
}); });
for (var len = args.length; i < len; ++i) { for (var len = args.length, x = args[i]; i < len; x = args[++i]) {
str += ' ' + args[i]; if (x === null || typeof x !== 'object') {
str += ' ' + x;
} else {
str += ' ' + util.inspect(x);
}
} }
return str; return str;
} }

2
lib/events.js

@ -89,6 +89,8 @@ EventEmitter.prototype.once = function(type, listener) {
self.removeListener(type, g); self.removeListener(type, g);
listener.apply(this, arguments); listener.apply(this, arguments);
}); });
return this;
}; };
EventEmitter.prototype.removeListener = function(type, listener) { EventEmitter.prototype.removeListener = function(type, listener) {

9
lib/os.js

@ -1,3 +1,10 @@
var binding = process.binding('os'); var binding = process.binding('os');
exports.getHostname = binding.getHostname; exports.hostname = binding.getHostname;
exports.loadavg = binding.getLoadAvg;
exports.uptime = binding.getUptime;
exports.freemem = binding.getFreeMem;
exports.totalmem = binding.getTotalMem;
exports.cpus = binding.getCPUs;
exports.type = binding.getOSType;
exports.release = binding.getOSRelease;

34
lib/readline.js

@ -83,7 +83,13 @@ Interface.prototype.__defineGetter__('columns', function() {
Interface.prototype.setPrompt = function(prompt, length) { Interface.prototype.setPrompt = function(prompt, length) {
this._prompt = prompt; this._prompt = prompt;
this._promptLength = length ? length : Buffer.byteLength(prompt); if (length) {
this._promptLength = length;
} else {
var lines = prompt.split(/[\r\n]/);
var lastLine = lines[lines.length - 1];
this._promptLength = Buffer.byteLength(lastLine);
}
}; };
@ -97,6 +103,28 @@ Interface.prototype.prompt = function() {
}; };
Interface.prototype.question = function(query, cb) {
if (cb) {
this._oldPrompt = this._prompt;
this.setPrompt(query);
this._questionCallback = cb;
this.prompt();
}
};
Interface.prototype._onLine = function(line) {
if (this._questionCallback) {
var cb = this._questionCallback;
this._questionCallback = null;
this.setPrompt(this._oldPrompt);
cb(line)
} else {
this.emit('line', line);
}
};
Interface.prototype._addHistory = function() { Interface.prototype._addHistory = function() {
if (this.line.length === 0) return ''; if (this.line.length === 0) return '';
@ -149,7 +177,7 @@ Interface.prototype.write = function(d) {
Interface.prototype._normalWrite = function(b) { Interface.prototype._normalWrite = function(b) {
// Very simple implementation right now. Should try to break on // Very simple implementation right now. Should try to break on
// new lines. // new lines.
this.emit('line', b.toString()); this._onLine(b.toString());
}; };
Interface.prototype._insertString = function(c) { Interface.prototype._insertString = function(c) {
@ -304,7 +332,7 @@ Interface.prototype._ttyWrite = function(b) {
case 13: /* enter */ case 13: /* enter */
var line = this._addHistory(); var line = this._addHistory();
this.output.write('\r\n'); this.output.write('\r\n');
this.emit('line', line); this._onLine(line);
break; break;
case 127: /* backspace */ case 127: /* backspace */

83
lib/repl.js

@ -20,20 +20,21 @@
*/ */
var util = require('util'); var util = require('util');
var Script = process.binding('evals').Script; var vm = require('vm');
var evalcx = Script.runInContext;
var path = require('path'); var path = require('path');
var fs = require('fs'); var fs = require('fs');
var rl = require('readline'); var rl = require('readline');
var context;
var context;
var disableColors = process.env.NODE_DISABLE_COLORS ? true : false; var disableColors = process.env.NODE_DISABLE_COLORS ? true : false;
// hack for require.resolve("./relative") to work properly. // hack for require.resolve("./relative") to work properly.
module.filename = process.cwd() + '/repl'; module.filename = process.cwd() + '/repl';
function resetContext() { function resetContext() {
context = Script.createContext(); context = vm.createContext();
for (var i in global) context[i] = global[i]; for (var i in global) context[i] = global[i];
context.module = module; context.module = module;
context.require = require; context.require = require;
@ -43,12 +44,13 @@ function resetContext() {
// Can overridden with custom print functions, such as `probe` or `eyes.js` // Can overridden with custom print functions, such as `probe` or `eyes.js`
exports.writer = util.inspect; exports.writer = util.inspect;
function REPLServer(prompt, stream) { function REPLServer(prompt, stream) {
var self = this; var self = this;
if (!context) resetContext(); if (!context) resetContext();
if (!exports.repl) exports.repl = this; if (!exports.repl) exports.repl = this;
self.context = context; self.context = context;
self.buffered_cmd = ''; self.bufferedCommand = '';
self.stream = stream || process.openStdin(); self.stream = stream || process.openStdin();
self.prompt = prompt || '> '; self.prompt = prompt || '> ';
@ -70,9 +72,9 @@ function REPLServer(prompt, stream) {
rli.setPrompt(self.prompt); rli.setPrompt(self.prompt);
rli.on('SIGINT', function() { rli.on('SIGINT', function() {
if (self.buffered_cmd && self.buffered_cmd.length > 0) { if (self.bufferedCommand && self.bufferedCommand.length > 0) {
rli.write('\n'); rli.write('\n');
self.buffered_cmd = ''; self.bufferedCommand = '';
self.displayPrompt(); self.displayPrompt();
} else { } else {
rli.close(); rli.close();
@ -104,18 +106,31 @@ function REPLServer(prompt, stream) {
if (!skipCatchall) { if (!skipCatchall) {
// The catchall for errors // The catchall for errors
try { try {
self.buffered_cmd += cmd; self.bufferedCommand += cmd + '\n';
// This try is for determining if the command is complete, or should // This try is for determining if the command is complete, or should
// continue onto the next line. // continue onto the next line.
try { try {
// Use evalcx to supply the global context // We try to evaluate both expressions e.g.
var ret = evalcx(self.buffered_cmd, context, 'repl'); // '{ a : 1 }'
// and statements e.g.
// 'for (var i = 0; i < 10; i++) console.log(i);'
var ret;
try {
// First we attempt to eval as expression with parens.
// This catches '{a : 1}' properly.
ret = vm.runInContext('(' + self.bufferedCommand + ')', context, 'repl');
} catch (e) {
// Now as statement without parens.
ret = vm.runInContext(self.bufferedCommand, context, 'repl');
}
if (ret !== undefined) { if (ret !== undefined) {
context._ = ret; context._ = ret;
self.stream.write(exports.writer(ret) + '\n'); self.stream.write(exports.writer(ret) + '\n');
} }
self.buffered_cmd = ''; self.bufferedCommand = '';
} catch (e) { } catch (e) {
// instanceof doesn't work across context switches. // instanceof doesn't work across context switches.
if (!(e && e.constructor && e.constructor.name === 'SyntaxError')) { if (!(e && e.constructor && e.constructor.name === 'SyntaxError')) {
@ -135,7 +150,7 @@ function REPLServer(prompt, stream) {
} else { } else {
self.stream.write(e.toString() + '\n'); self.stream.write(e.toString() + '\n');
} }
self.buffered_cmd = ''; self.bufferedCommand = '';
} }
} }
@ -150,21 +165,30 @@ function REPLServer(prompt, stream) {
} }
exports.REPLServer = REPLServer; exports.REPLServer = REPLServer;
// prompt is a string to print on each line for the prompt, // prompt is a string to print on each line for the prompt,
// source is a stream to use for I/O, defaulting to stdin/stdout. // source is a stream to use for I/O, defaulting to stdin/stdout.
exports.start = function(prompt, source) { exports.start = function(prompt, source) {
return new REPLServer(prompt, source); return new REPLServer(prompt, source);
}; };
REPLServer.prototype.displayPrompt = function() { REPLServer.prototype.displayPrompt = function() {
this.rli.setPrompt(this.buffered_cmd.length ? '... ' : this.prompt); this.rli.setPrompt(this.bufferedCommand.length ? '... ' : this.prompt);
this.rli.prompt(); this.rli.prompt();
}; };
// read a line from the stream, then eval it // read a line from the stream, then eval it
REPLServer.prototype.readline = function(cmd) { REPLServer.prototype.readline = function(cmd) {
}; };
var requireRE = /\brequire\s*\(['"](([\w\.\/-]+\/)?([\w\.\/-]*))/;
var simpleExpressionRE =
/(([a-zA-Z_$](?:\w|\$)*)\.)*([a-zA-Z_$](?:\w|\$)*)\.?$/;
// Provide a list of completions for the given leading text. This is // Provide a list of completions for the given leading text. This is
// given to the readline interface for handling tab completion. // given to the readline interface for handling tab completion.
// //
@ -192,8 +216,8 @@ REPLServer.prototype.complete = function(line) {
if (match[1].length > 1) { if (match[1].length > 1) {
filter = match[1]; filter = match[1];
} }
} else if (match =
line.match(/\brequire\s*\(['"](([\w\.\/-]+\/)?([\w\.\/-]*))/)) { } else if (match = line.match(requireRE)) {
// require('...<Tab>') // require('...<Tab>')
//TODO: suggest require.exts be exposed to be introspec registered //TODO: suggest require.exts be exposed to be introspec registered
//extensions? //extensions?
@ -261,7 +285,6 @@ REPLServer.prototype.complete = function(line) {
'url']; 'url'];
completionGroups.push(builtinLibs); completionGroups.push(builtinLibs);
} }
}
// Handle variable member lookup. // Handle variable member lookup.
// We support simple chained expressions like the following (no function // We support simple chained expressions like the following (no function
@ -273,10 +296,8 @@ REPLServer.prototype.complete = function(line) {
// spam.eggs.<|> # completions for 'spam.eggs' with filter '' // spam.eggs.<|> # completions for 'spam.eggs' with filter ''
// foo<|> # all scope vars with filter 'foo' // foo<|> # all scope vars with filter 'foo'
// foo.<|> # completions for 'foo' with filter '' // foo.<|> # completions for 'foo' with filter ''
else if (line.length === 0 || line[line.length - 1].match(/\w|\.|\$/)) { } else if (line.length === 0 || line[line.length - 1].match(/\w|\.|\$/)) {
var simpleExpressionPat = match = simpleExpressionRE.exec(line);
/(([a-zA-Z_$](?:\w|\$)*)\.)*([a-zA-Z_$](?:\w|\$)*)\.?$/;
match = simpleExpressionPat.exec(line);
if (line.length === 0 || match) { if (line.length === 0 || match) {
var expr; var expr;
completeOn = (match ? match[0] : ''); completeOn = (match ? match[0] : '');
@ -320,7 +341,7 @@ REPLServer.prototype.complete = function(line) {
} }
} else { } else {
try { try {
obj = evalcx(expr, this.context, 'repl'); obj = vm.runInContext(expr, this.context, 'repl');
} catch (e) { } catch (e) {
//console.log("completion eval error, expr='"+expr+"': "+e); //console.log("completion eval error, expr='"+expr+"': "+e);
} }
@ -373,6 +394,7 @@ REPLServer.prototype.complete = function(line) {
} }
completionGroups = newCompletionGroups; completionGroups = newCompletionGroups;
} }
if (completionGroups.length) { if (completionGroups.length) {
var uniq = {}; // unique completions across all groups var uniq = {}; // unique completions across all groups
completions = []; completions = [];
@ -398,13 +420,13 @@ REPLServer.prototype.complete = function(line) {
return [completions || [], completeOn]; return [completions || [], completeOn];
}; };
/** /**
* Used to parse and execute the Node REPL commands. * Used to parse and execute the Node REPL commands.
* *
* @param {keyword} keyword The command entered to check. * @param {keyword} keyword The command entered to check.
* @return {Boolean} If true it means don't continue parsing the command. * @return {Boolean} If true it means don't continue parsing the command.
*/ */
REPLServer.prototype.parseREPLKeyword = function(keyword, rest) { REPLServer.prototype.parseREPLKeyword = function(keyword, rest) {
var cmd = this.commands[keyword]; var cmd = this.commands[keyword];
if (cmd) { if (cmd) {
@ -414,20 +436,23 @@ REPLServer.prototype.parseREPLKeyword = function(keyword, rest) {
return false; return false;
}; };
REPLServer.prototype.defineCommand = function(keyword, cmd) { REPLServer.prototype.defineCommand = function(keyword, cmd) {
if (typeof cmd === 'function') cmd = {action: cmd}; if (typeof cmd === 'function') {
else if (typeof cmd.action !== 'function') { cmd = {action: cmd};
} else if (typeof cmd.action !== 'function') {
throw new Error('bad argument, action must be a function'); throw new Error('bad argument, action must be a function');
} }
this.commands['.' + keyword] = cmd; this.commands['.' + keyword] = cmd;
}; };
function defineDefaultCommands(repl) { function defineDefaultCommands(repl) {
// TODO remove me after 0.3.x // TODO remove me after 0.3.x
repl.defineCommand('break', { repl.defineCommand('break', {
help: 'Sometimes you get stuck, this gets you out', help: 'Sometimes you get stuck, this gets you out',
action: function() { action: function() {
this.buffered_cmd = ''; this.bufferedCommand = '';
this.displayPrompt(); this.displayPrompt();
} }
}); });
@ -436,7 +461,7 @@ function defineDefaultCommands(repl) {
help: 'Break, and also clear the local context', help: 'Break, and also clear the local context',
action: function() { action: function() {
this.stream.write('Clearing context...\n'); this.stream.write('Clearing context...\n');
this.buffered_cmd = ''; this.bufferedCommand = '';
resetContext(); resetContext();
this.displayPrompt(); this.displayPrompt();
} }
@ -462,6 +487,7 @@ function defineDefaultCommands(repl) {
}); });
} }
function trimWhitespace(cmd) { function trimWhitespace(cmd) {
var trimmer = /^\s*(.+)\s*$/m, var trimmer = /^\s*(.+)\s*$/m,
matches = trimmer.exec(cmd); matches = trimmer.exec(cmd);
@ -471,6 +497,7 @@ function trimWhitespace(cmd) {
} }
} }
function regexpEscape(s) { function regexpEscape(s) {
return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
} }
@ -496,9 +523,9 @@ REPLServer.prototype.convertToContext = function(cmd) {
} }
// Replaces: function foo() {}; with: foo = function foo() {}; // Replaces: function foo() {}; with: foo = function foo() {};
matches = scopeFunc.exec(self.buffered_cmd); matches = scopeFunc.exec(self.bufferedCommand);
if (matches && matches.length === 2) { if (matches && matches.length === 2) {
return matches[1] + ' = ' + self.buffered_cmd; return matches[1] + ' = ' + self.bufferedCommand;
} }
return cmd; return cmd;

41
lib/stream.js

@ -7,55 +7,16 @@ function Stream() {
util.inherits(Stream, events.EventEmitter); util.inherits(Stream, events.EventEmitter);
exports.Stream = Stream; exports.Stream = Stream;
Stream.prototype.pipe = function(dest /* options, filter */) { Stream.prototype.pipe = function(dest, options) {
var source = this; var source = this;
// parse arguments
var options, filter;
if (typeof arguments[1] == 'object') {
options = arguments[1];
filter = arguments[2];
} else {
filter = arguments[1];
}
function ondata(chunk) { function ondata(chunk) {
// FIXME shouldn't need to test writable - this is working around bug.
// .writable should not change before a 'end' event is fired.
if (dest.writable) { if (dest.writable) {
if (false === dest.write(chunk)) source.pause(); if (false === dest.write(chunk)) source.pause();
} }
} }
if (!filter) {
source.on('data', ondata); source.on('data', ondata);
} else {
//
// TODO: needs tests
//
var wait = false;
var waitQueue = [];
function done () {
wait = false;
// Drain the waitQueue
if (dest.writable && waitQueue.length) {
wait = true;
filter(waitQueue.shift(), ondata, done);
}
}
source.on('data', function (d) {
if (wait) {
waitQueue.push(d);
source.pause();
} else {
wait = true;
filter(d, ondata, done);
}
});
}
function ondrain() { function ondrain() {
if (source.readable) source.resume(); if (source.readable) source.resume();

33
src/node.cc

@ -1200,7 +1200,7 @@ static void CheckStatus(EV_P_ ev_timer *watcher, int revents) {
// check memory // check memory
size_t rss, vsize; size_t rss, vsize;
if (!ev_is_active(&gc_idle) && OS::GetMemory(&rss, &vsize) == 0) { if (!ev_is_active(&gc_idle) && Platform::GetMemory(&rss, &vsize) == 0) {
if (rss > 1024*1024*128) { if (rss > 1024*1024*128) {
// larger than 128 megs, just start the idle watcher // larger than 128 megs, just start the idle watcher
ev_idle_start(EV_A_ &gc_idle); ev_idle_start(EV_A_ &gc_idle);
@ -1225,7 +1225,7 @@ v8::Handle<v8::Value> MemoryUsage(const v8::Arguments& args) {
size_t rss, vsize; size_t rss, vsize;
int r = OS::GetMemory(&rss, &vsize); int r = Platform::GetMemory(&rss, &vsize);
if (r != 0) { if (r != 0) {
return ThrowException(Exception::Error(String::New(strerror(errno)))); return ThrowException(Exception::Error(String::New(strerror(errno))));
@ -1260,7 +1260,7 @@ v8::Handle<v8::Value> MemoryUsage(const v8::Arguments& args) {
Handle<Value> Kill(const Arguments& args) { Handle<Value> Kill(const Arguments& args) {
HandleScope scope; HandleScope scope;
if (args.Length() != 2 || !args[0]->IsNumber() || !args[1]->IsNumber()) { if (args.Length() != 2) {
return ThrowException(Exception::Error(String::New("Bad argument."))); return ThrowException(Exception::Error(String::New("Bad argument.")));
} }
@ -1537,7 +1537,7 @@ static Handle<Value> ProcessTitleGetter(Local<String> property,
const AccessorInfo& info) { const AccessorInfo& info) {
HandleScope scope; HandleScope scope;
int len; int len;
const char *s = OS::GetProcessTitle(&len); const char *s = Platform::GetProcessTitle(&len);
return scope.Close(s ? String::New(s, len) : String::Empty()); return scope.Close(s ? String::New(s, len) : String::Empty());
} }
@ -1547,7 +1547,7 @@ static void ProcessTitleSetter(Local<String> property,
const AccessorInfo& info) { const AccessorInfo& info) {
HandleScope scope; HandleScope scope;
String::Utf8Value title(value->ToString()); String::Utf8Value title(value->ToString());
OS::SetProcessTitle(*title); Platform::SetProcessTitle(*title);
} }
@ -1636,6 +1636,8 @@ static Handle<Array> EnvEnumerator(const AccessorInfo& info) {
static void Load(int argc, char *argv[]) { static void Load(int argc, char *argv[]) {
HandleScope scope; HandleScope scope;
int i, j;
Local<FunctionTemplate> process_template = FunctionTemplate::New(); Local<FunctionTemplate> process_template = FunctionTemplate::New();
node::EventEmitter::Initialize(process_template); node::EventEmitter::Initialize(process_template);
@ -1661,6 +1663,22 @@ static void Load(int argc, char *argv[]) {
versions->Set(String::NewSymbol("ares"), String::New(ARES_VERSION_STR)); versions->Set(String::NewSymbol("ares"), String::New(ARES_VERSION_STR));
snprintf(buf, 20, "%d.%d", ev_version_major(), ev_version_minor()); snprintf(buf, 20, "%d.%d", ev_version_major(), ev_version_minor());
versions->Set(String::NewSymbol("ev"), String::New(buf)); versions->Set(String::NewSymbol("ev"), String::New(buf));
#ifdef HAVE_OPENSSL
// Stupid code to slice out the version string.
int c, l = strlen(OPENSSL_VERSION_TEXT);
for (i = 0; i < l; i++) {
c = OPENSSL_VERSION_TEXT[i];
if ('0' <= c && c <= '9') {
for (j = i + 1; j < l; j++) {
c = OPENSSL_VERSION_TEXT[j];
if (c == ' ') break;
}
break;
}
}
versions->Set(String::NewSymbol("openssl"),
String::New(OPENSSL_VERSION_TEXT + i, j - i));
#endif
@ -1668,7 +1686,6 @@ static void Load(int argc, char *argv[]) {
process->Set(String::NewSymbol("platform"), String::New("PLATFORM")); process->Set(String::NewSymbol("platform"), String::New("PLATFORM"));
// process.argv // process.argv
int i, j;
Local<Array> arguments = Array::New(argc - option_end_index + 1); Local<Array> arguments = Array::New(argc - option_end_index + 1);
arguments->Set(Integer::New(0), String::New(argv[0])); arguments->Set(Integer::New(0), String::New(argv[0]));
for (j = 1, i = option_end_index; i < argc; j++, i++) { for (j = 1, i = option_end_index; i < argc; j++, i++) {
@ -1711,7 +1728,7 @@ static void Load(int argc, char *argv[]) {
size_t size = 2*PATH_MAX; size_t size = 2*PATH_MAX;
char execPath[size]; char execPath[size];
if (OS::GetExecutablePath(execPath, &size) != 0) { if (Platform::GetExecutablePath(execPath, &size) != 0) {
// as a last ditch effort, fallback on argv[0] ? // as a last ditch effort, fallback on argv[0] ?
process->Set(String::NewSymbol("execPath"), String::New(argv[0])); process->Set(String::NewSymbol("execPath"), String::New(argv[0]));
} else { } else {
@ -1906,7 +1923,7 @@ static int RegisterSignalHandler(int signal, void (*handler)(int)) {
int Start(int argc, char *argv[]) { int Start(int argc, char *argv[]) {
// Hack aroung with the argv pointer. Used for process.title = "blah". // Hack aroung with the argv pointer. Used for process.title = "blah".
argv = node::OS::SetupArgs(argc, argv); argv = node::Platform::SetupArgs(argc, argv);
// Parse a few arguments which are specific to Node. // Parse a few arguments which are specific to Node.
node::ParseArgs(&argc, argv); node::ParseArgs(&argc, argv);

31
src/node.js

@ -35,7 +35,9 @@
if (!x) throw new Error(msg || 'assertion error'); if (!x) throw new Error(msg || 'assertion error');
}; };
var evals = process.binding('evals'); var Script = process.binding('evals').Script;
var runInThisContext = Script.runInThisContext;
var runInNewContext = Script.runInNewContext;
// lazy loaded. // lazy loaded.
var constants; var constants;
@ -86,9 +88,10 @@
if (internalModuleCache[id]) return internalModuleCache[id].exports; if (internalModuleCache[id]) return internalModuleCache[id].exports;
if (!natives[id]) throw new Error('No such native module ' + id); if (!natives[id]) throw new Error('No such native module ' + id);
var fn = evals.Script.runInThisContext( var fn = runInThisContext(
'(function (module, exports, require) {' + natives[id] + '\n})', '(function (module, exports, require) {' + natives[id] + '\n})',
id + '.js'); id + '.js',
true);
var m = {id: id, exports: {}}; var m = {id: id, exports: {}};
fn(m, m.exports, requireNative); fn(m, m.exports, requireNative);
m.loaded = true; m.loaded = true;
@ -332,7 +335,7 @@
sandbox.global = sandbox; sandbox.global = sandbox;
sandbox.root = root; sandbox.root = root;
return evals.Script.runInNewContext(content, sandbox, filename); return runInNewContext(content, sandbox, filename, true);
} else { } else {
debug('load root module'); debug('load root module');
// root module // root module
@ -342,7 +345,7 @@
global.__dirname = dirname; global.__dirname = dirname;
global.module = self; global.module = self;
return evals.Script.runInThisContext(content, filename); return runInThisContext(content, filename, true);
} }
} else { } else {
@ -352,7 +355,7 @@
content + content +
'\n});'; '\n});';
var compiledWrapper = evals.Script.runInThisContext(wrapper, filename); var compiledWrapper = runInThisContext(wrapper, filename, true);
if (filename === process.argv[1] && global.v8debug) { if (filename === process.argv[1] && global.v8debug) {
global.v8debug.Debug.setBreakPoint(compiledWrapper, 0, 0); global.v8debug.Debug.setBreakPoint(compiledWrapper, 0, 0);
} }
@ -461,7 +464,9 @@
}; };
var stdout; var stdout, stdin;
process.__defineGetter__('stdout', function() { process.__defineGetter__('stdout', function() {
if (stdout) return stdout; if (stdout) return stdout;
@ -484,8 +489,8 @@
return stdout; return stdout;
}); });
var stdin;
process.openStdin = function() { process.__defineGetter__('stdin', function() {
if (stdin) return stdin; if (stdin) return stdin;
var binding = process.binding('stdio'), var binding = process.binding('stdio'),
@ -500,9 +505,13 @@
stdin.readable = true; stdin.readable = true;
} }
stdin.resume();
return stdin; return stdin;
});
process.openStdin = function() {
process.stdin.resume();
return process.stdin;
}; };

6
src/node_crypto.cc

@ -177,8 +177,8 @@ Handle<Value> SecureContext::SetKey(const Arguments& args) {
} }
SSL_CTX_use_PrivateKey(sc->ctx_, key); SSL_CTX_use_PrivateKey(sc->ctx_, key);
EVP_PKEY_free(key);
BIO_free(bio); BIO_free(bio);
// XXX Free key?
return True(); return True();
} }
@ -1719,19 +1719,19 @@ class Decipher : public ObjectWrap {
if (alloc_buf) { if (alloc_buf) {
delete [] buf; delete [] buf;
alloc_buf = false;
} }
buf = ciphertext; buf = ciphertext;
len = ciphertext_len; len = ciphertext_len;
alloc_buf = true;
} else if (strcasecmp(*encoding, "base64") == 0) { } else if (strcasecmp(*encoding, "base64") == 0) {
unbase64((unsigned char*)buf, len, (char **)&ciphertext, &ciphertext_len); unbase64((unsigned char*)buf, len, (char **)&ciphertext, &ciphertext_len);
if (alloc_buf) { if (alloc_buf) {
delete [] buf; delete [] buf;
alloc_buf = false;
} }
buf = ciphertext; buf = ciphertext;
len = ciphertext_len; len = ciphertext_len;
alloc_buf = true;
} else if (strcasecmp(*encoding, "binary") == 0) { } else if (strcasecmp(*encoding, "binary") == 0) {
// Binary - do nothing // Binary - do nothing

35
src/node_net.cc

@ -462,13 +462,16 @@ static Handle<Value> Connect(const Arguments& args) {
#ifdef __POSIX__ #ifdef __POSIX__
#define ADDRESS_TO_JS(info, address_storage) \ #define ADDRESS_TO_JS(info, address_storage, addrlen) \
do { \ do { \
char ip[INET6_ADDRSTRLEN]; \ char ip[INET6_ADDRSTRLEN]; \
int port; \ int port; \
struct sockaddr_in *a4; \ struct sockaddr_in *a4; \
struct sockaddr_in6 *a6; \ struct sockaddr_in6 *a6; \
struct sockaddr_un *au; \ struct sockaddr_un *au; \
if (addrlen == 0) { \
(info)->Set(address_symbol, String::Empty()); \
} else { \
switch ((address_storage).ss_family) { \ switch ((address_storage).ss_family) { \
case AF_INET6: \ case AF_INET6: \
a6 = (struct sockaddr_in6*)&(address_storage); \ a6 = (struct sockaddr_in6*)&(address_storage); \
@ -485,22 +488,40 @@ do { \
(info)->Set(port_symbol, Integer::New(port)); \ (info)->Set(port_symbol, Integer::New(port)); \
break; \ break; \
case AF_UNIX: \ case AF_UNIX: \
/*
* Three types of addresses (see man 7 unix):
* * unnamed: sizeof(sa_family_t) (sun_path should not be used)
* * abstract (Linux extension): sizeof(struct sockaddr_un)
* * pathname: sizeof(sa_family_t) + strlen(sun_path) + 1
*/ \
au = (struct sockaddr_un*)&(address_storage); \ au = (struct sockaddr_un*)&(address_storage); \
if (addrlen == sizeof(sa_family_t)) { \
(info)->Set(address_symbol, String::Empty()); \
} else if (addrlen == sizeof(struct sockaddr_un)) { \
/* first byte is '\0' and all remaining bytes are name;
* it is not NUL-terminated and may contain embedded NULs */ \
(info)->Set(address_symbol, String::New(au->sun_path + 1, sizeof(au->sun_path - 1))); \
} else { \
(info)->Set(address_symbol, String::New(au->sun_path)); \ (info)->Set(address_symbol, String::New(au->sun_path)); \
} \
break; \ break; \
default: \ default: \
(info)->Set(address_symbol, String::Empty()); \ (info)->Set(address_symbol, String::Empty()); \
} \ } \
} \
} while (0) } while (0)
#else // __MINGW32__ #else // __MINGW32__
#define ADDRESS_TO_JS(info, address_storage) \ #define ADDRESS_TO_JS(info, address_storage, addrlen) \
do { \ do { \
char ip[INET6_ADDRSTRLEN]; \ char ip[INET6_ADDRSTRLEN]; \
int port; \ int port; \
struct sockaddr_in *a4; \ struct sockaddr_in *a4; \
struct sockaddr_in6 *a6; \ struct sockaddr_in6 *a6; \
if (addrlen == 0) { \
(info)->Set(address_symbol, String::Empty()); \
} else { \
switch ((address_storage).ss_family) { \ switch ((address_storage).ss_family) { \
case AF_INET6: \ case AF_INET6: \
a6 = (struct sockaddr_in6*)&(address_storage); \ a6 = (struct sockaddr_in6*)&(address_storage); \
@ -519,6 +540,7 @@ do { \
default: \ default: \
(info)->Set(address_symbol, String::Empty()); \ (info)->Set(address_symbol, String::Empty()); \
} \ } \
} \
} while (0) } while (0)
#endif // __MINGW32__ #endif // __MINGW32__
@ -542,7 +564,7 @@ static Handle<Value> GetSockName(const Arguments& args) {
Local<Object> info = Object::New(); Local<Object> info = Object::New();
ADDRESS_TO_JS(info, address_storage); ADDRESS_TO_JS(info, address_storage, len);
return scope.Close(info); return scope.Close(info);
} }
@ -564,7 +586,7 @@ static Handle<Value> GetPeerName(const Arguments& args) {
Local<Object> info = Object::New(); Local<Object> info = Object::New();
ADDRESS_TO_JS(info, address_storage); ADDRESS_TO_JS(info, address_storage, len);
return scope.Close(info); return scope.Close(info);
} }
@ -614,6 +636,7 @@ static Handle<Value> Accept(const Arguments& args) {
if (peer_fd < 0) { if (peer_fd < 0) {
if (errno == EAGAIN) return scope.Close(Null()); if (errno == EAGAIN) return scope.Close(Null());
if (errno == ECONNABORTED) return scope.Close(Null());
return ThrowException(ErrnoException(errno, "accept")); return ThrowException(ErrnoException(errno, "accept"));
} }
#else // __MINGW32__ #else // __MINGW32__
@ -642,7 +665,7 @@ static Handle<Value> Accept(const Arguments& args) {
peer_info->Set(fd_symbol, Integer::New(peer_fd)); peer_info->Set(fd_symbol, Integer::New(peer_fd));
ADDRESS_TO_JS(peer_info, address_storage); ADDRESS_TO_JS(peer_info, address_storage, len);
return scope.Close(peer_info); return scope.Close(peer_info);
} }
@ -787,7 +810,7 @@ static Handle<Value> RecvFrom(const Arguments& args) {
info->Set(size_symbol, Integer::New(bytes_read)); info->Set(size_symbol, Integer::New(bytes_read));
ADDRESS_TO_JS(info, address_storage); ADDRESS_TO_JS(info, address_storage, addrlen);
return scope.Close(info); return scope.Close(info);
} }

94
src/node_os.cc

@ -3,10 +3,14 @@
#include <node.h> #include <node.h>
#include <v8.h> #include <v8.h>
#include "platform.h"
#include <errno.h> #include <errno.h>
#include <string.h>
#ifdef __POSIX__ #ifdef __POSIX__
# include <unistd.h> // gethostname # include <unistd.h> // gethostname, sysconf
# include <sys/utsname.h>
#else // __MINGW32__ #else // __MINGW32__
# include <winsock2.h> // gethostname # include <winsock2.h> // gethostname
#endif // __MINGW32__ #endif // __MINGW32__
@ -30,10 +34,98 @@ static Handle<Value> GetHostname(const Arguments& args) {
return scope.Close(String::New(s)); return scope.Close(String::New(s));
} }
static Handle<Value> GetOSType(const Arguments& args) {
HandleScope scope;
char type[256];
struct utsname info;
uname(&info);
strncpy(type, info.sysname, strlen(info.sysname));
type[strlen(info.sysname)] = 0;
return scope.Close(String::New(type));
}
static Handle<Value> GetOSRelease(const Arguments& args) {
HandleScope scope;
char release[256];
struct utsname info;
uname(&info);
strncpy(release, info.release, strlen(info.release));
release[strlen(info.release)] = 0;
return scope.Close(String::New(release));
}
static Handle<Value> GetCPUInfo(const Arguments& args) {
HandleScope scope;
Local<Array> cpus;
int r = Platform::GetCPUInfo(&cpus);
if (r < 0) {
return Undefined();
}
return scope.Close(cpus);
}
static Handle<Value> GetFreeMemory(const Arguments& args) {
HandleScope scope;
double amount = Platform::GetFreeMemory();
if (amount < 0) {
return Undefined();
}
return scope.Close(Number::New(amount));
}
static Handle<Value> GetTotalMemory(const Arguments& args) {
HandleScope scope;
double amount = Platform::GetTotalMemory();
if (amount < 0) {
return Undefined();
}
return scope.Close(Number::New(amount));
}
static Handle<Value> GetUptime(const Arguments& args) {
HandleScope scope;
double uptime = Platform::GetUptime();
if (uptime < 0) {
return Undefined();
}
return scope.Close(Number::New(uptime));
}
static Handle<Value> GetLoadAvg(const Arguments& args) {
HandleScope scope;
Local<Array> loads = Array::New(3);
int r = Platform::GetLoadAvg(&loads);
if (r < 0) {
return Undefined();
}
return scope.Close(loads);
}
void OS::Initialize(v8::Handle<v8::Object> target) { void OS::Initialize(v8::Handle<v8::Object> target) {
HandleScope scope; HandleScope scope;
NODE_SET_METHOD(target, "getHostname", GetHostname); NODE_SET_METHOD(target, "getHostname", GetHostname);
NODE_SET_METHOD(target, "getLoadAvg", GetLoadAvg);
NODE_SET_METHOD(target, "getUptime", GetUptime);
NODE_SET_METHOD(target, "getTotalMem", GetTotalMemory);
NODE_SET_METHOD(target, "getFreeMem", GetFreeMemory);
NODE_SET_METHOD(target, "getCPUs", GetCPUInfo);
NODE_SET_METHOD(target, "getOSType", GetOSType);
NODE_SET_METHOD(target, "getOSRelease", GetOSRelease);
} }

281
src/node_script.cc

@ -2,109 +2,198 @@
#include <node_script.h> #include <node_script.h>
#include <assert.h> #include <assert.h>
namespace node {
using v8::Context;
using v8::Script;
using v8::Value;
using v8::Handle;
using v8::HandleScope;
using v8::Object;
using v8::Arguments;
using v8::ThrowException;
using v8::TryCatch;
using v8::String;
using v8::Exception;
using v8::Local;
using v8::Array;
using v8::Persistent;
using v8::Integer;
using v8::FunctionTemplate;
using namespace v8;
using namespace node;
class WrappedContext : ObjectWrap {
public:
static void Initialize(Handle<Object> target);
static Handle<Value> New(const Arguments& args);
Persistent<FunctionTemplate> node::Context::constructor_template; Persistent<Context> GetV8Context();
static Local<Object> NewInstance();
protected:
void node::Context::Initialize (Handle<Object> target) { static Persistent<FunctionTemplate> constructor_template;
WrappedContext();
~WrappedContext();
Persistent<Context> context_;
};
Persistent<FunctionTemplate> WrappedContext::constructor_template;
class WrappedScript : ObjectWrap {
public:
static void Initialize(Handle<Object> target);
enum EvalInputFlags { compileCode, unwrapExternal };
enum EvalContextFlags { thisContext, newContext, userContext };
enum EvalOutputFlags { returnResult, wrapExternal };
template <EvalInputFlags input_flag,
EvalContextFlags context_flag,
EvalOutputFlags output_flag>
static Handle<Value> EvalMachine(const Arguments& args);
protected:
static Persistent<FunctionTemplate> constructor_template;
WrappedScript() : ObjectWrap() {}
~WrappedScript();
static Handle<Value> New(const Arguments& args);
static Handle<Value> CreateContext(const Arguments& arg);
static Handle<Value> RunInContext(const Arguments& args);
static Handle<Value> RunInThisContext(const Arguments& args);
static Handle<Value> RunInNewContext(const Arguments& args);
static Handle<Value> CompileRunInContext(const Arguments& args);
static Handle<Value> CompileRunInThisContext(const Arguments& args);
static Handle<Value> CompileRunInNewContext(const Arguments& args);
Persistent<Script> script_;
};
void WrappedContext::Initialize(Handle<Object> target) {
HandleScope scope; HandleScope scope;
Local<FunctionTemplate> t = FunctionTemplate::New(node::Context::New); Local<FunctionTemplate> t = FunctionTemplate::New(WrappedContext::New);
constructor_template = Persistent<FunctionTemplate>::New(t); constructor_template = Persistent<FunctionTemplate>::New(t);
constructor_template->InstanceTemplate()->SetInternalFieldCount(1); constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
constructor_template->SetClassName(String::NewSymbol("Context")); constructor_template->SetClassName(String::NewSymbol("Context"));
target->Set(String::NewSymbol("Context"), constructor_template->GetFunction()); target->Set(String::NewSymbol("Context"),
constructor_template->GetFunction());
} }
Handle<Value> node::Context::New (const Arguments& args) { Handle<Value> WrappedContext::New(const Arguments& args) {
HandleScope scope; HandleScope scope;
node::Context *t = new node::Context(); WrappedContext *t = new WrappedContext();
t->Wrap(args.This()); t->Wrap(args.This());
return args.This(); return args.This();
} }
node::Context::Context() : ObjectWrap() { WrappedContext::WrappedContext() : ObjectWrap() {
context_ = v8::Context::New(); context_ = Context::New();
} }
node::Context::~Context() { WrappedContext::~WrappedContext() {
context_.Dispose(); context_.Dispose();
} }
Local<Object> node::Context::NewInstance() { Local<Object> WrappedContext::NewInstance() {
Local<Object> context = constructor_template->GetFunction()->NewInstance(); Local<Object> context = constructor_template->GetFunction()->NewInstance();
return context; return context;
} }
v8::Persistent<v8::Context> node::Context::GetV8Context() { Persistent<Context> WrappedContext::GetV8Context() {
return context_; return context_;
} }
Persistent<FunctionTemplate> node::Script::constructor_template; Persistent<FunctionTemplate> WrappedScript::constructor_template;
void node::Script::Initialize (Handle<Object> target) { void WrappedScript::Initialize(Handle<Object> target) {
HandleScope scope; HandleScope scope;
Local<FunctionTemplate> t = FunctionTemplate::New(node::Script::New); Local<FunctionTemplate> t = FunctionTemplate::New(WrappedScript::New);
constructor_template = Persistent<FunctionTemplate>::New(t); constructor_template = Persistent<FunctionTemplate>::New(t);
constructor_template->InstanceTemplate()->SetInternalFieldCount(1); constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
constructor_template->SetClassName(String::NewSymbol("Script")); constructor_template->SetClassName(String::NewSymbol("Script"));
NODE_SET_PROTOTYPE_METHOD(constructor_template, "createContext", node::Script::CreateContext); NODE_SET_PROTOTYPE_METHOD(constructor_template,
NODE_SET_PROTOTYPE_METHOD(constructor_template, "runInContext", node::Script::RunInContext); "createContext",
NODE_SET_PROTOTYPE_METHOD(constructor_template, "runInThisContext", node::Script::RunInThisContext); WrappedScript::CreateContext);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "runInNewContext", node::Script::RunInNewContext);
NODE_SET_METHOD(constructor_template, "createContext", node::Script::CreateContext); NODE_SET_PROTOTYPE_METHOD(constructor_template,
NODE_SET_METHOD(constructor_template, "runInContext", node::Script::CompileRunInContext); "runInContext",
NODE_SET_METHOD(constructor_template, "runInThisContext", node::Script::CompileRunInThisContext); WrappedScript::RunInContext);
NODE_SET_METHOD(constructor_template, "runInNewContext", node::Script::CompileRunInNewContext);
target->Set(String::NewSymbol("Script"), constructor_template->GetFunction()); NODE_SET_PROTOTYPE_METHOD(constructor_template,
"runInThisContext",
WrappedScript::RunInThisContext);
NODE_SET_PROTOTYPE_METHOD(constructor_template,
"runInNewContext",
WrappedScript::RunInNewContext);
NODE_SET_METHOD(constructor_template,
"createContext",
WrappedScript::CreateContext);
NODE_SET_METHOD(constructor_template,
"runInContext",
WrappedScript::CompileRunInContext);
NODE_SET_METHOD(constructor_template,
"runInThisContext",
WrappedScript::CompileRunInThisContext);
NODE_SET_METHOD(constructor_template,
"runInNewContext",
WrappedScript::CompileRunInNewContext);
target->Set(String::NewSymbol("Script"),
constructor_template->GetFunction());
} }
Handle<Value> node::Script::New (const Arguments& args) { Handle<Value> WrappedScript::New(const Arguments& args) {
if (!args.IsConstructCall()) { if (!args.IsConstructCall()) {
return FromConstructorTemplate(constructor_template, args); return FromConstructorTemplate(constructor_template, args);
} }
HandleScope scope; HandleScope scope;
node::Script *t = new node::Script(); WrappedScript *t = new WrappedScript();
t->Wrap(args.Holder()); t->Wrap(args.Holder());
return return
node::Script::EvalMachine<compileCode, thisContext, wrapExternal>(args); WrappedScript::EvalMachine<compileCode, thisContext, wrapExternal>(args);
} }
node::Script::~Script() { WrappedScript::~WrappedScript() {
script_.Dispose(); script_.Dispose();
} }
Handle<Value> node::Script::CreateContext (const Arguments& args) { Handle<Value> WrappedScript::CreateContext(const Arguments& args) {
HandleScope scope; HandleScope scope;
Local<v8::Object> context = node::Context::NewInstance(); Local<Object> context = WrappedContext::NewInstance();
if (args.Length() > 0) { if (args.Length() > 0) {
Local<Object> sandbox = args[0]->ToObject(); Local<Object> sandbox = args[0]->ToObject();
Local<Array> keys = sandbox->GetPropertyNames(); Local<Array> keys = sandbox->GetPropertyNames();
@ -120,93 +209,102 @@ Handle<Value> node::Script::CreateContext (const Arguments& args) {
} }
Handle<Value> node::Script::RunInContext (const Arguments& args) { Handle<Value> WrappedScript::RunInContext(const Arguments& args) {
return return
node::Script::EvalMachine<unwrapExternal, userContext, returnResult>(args); WrappedScript::EvalMachine<unwrapExternal, userContext, returnResult>(args);
} }
Handle<Value> node::Script::RunInThisContext (const Arguments& args) { Handle<Value> WrappedScript::RunInThisContext(const Arguments& args) {
return return
node::Script::EvalMachine<unwrapExternal, thisContext, returnResult>(args); WrappedScript::EvalMachine<unwrapExternal, thisContext, returnResult>(args);
} }
Handle<Value> node::Script::RunInNewContext(const Arguments& args) { Handle<Value> WrappedScript::RunInNewContext(const Arguments& args) {
return return
node::Script::EvalMachine<unwrapExternal, newContext, returnResult>(args); WrappedScript::EvalMachine<unwrapExternal, newContext, returnResult>(args);
} }
Handle<Value> node::Script::CompileRunInContext (const Arguments& args) { Handle<Value> WrappedScript::CompileRunInContext(const Arguments& args) {
return return
node::Script::EvalMachine<compileCode, userContext, returnResult>(args); WrappedScript::EvalMachine<compileCode, userContext, returnResult>(args);
} }
Handle<Value> node::Script::CompileRunInThisContext (const Arguments& args) { Handle<Value> WrappedScript::CompileRunInThisContext(const Arguments& args) {
return return
node::Script::EvalMachine<compileCode, thisContext, returnResult>(args); WrappedScript::EvalMachine<compileCode, thisContext, returnResult>(args);
} }
Handle<Value> node::Script::CompileRunInNewContext(const Arguments& args) { Handle<Value> WrappedScript::CompileRunInNewContext(const Arguments& args) {
return return
node::Script::EvalMachine<compileCode, newContext, returnResult>(args); WrappedScript::EvalMachine<compileCode, newContext, returnResult>(args);
} }
template <node::Script::EvalInputFlags iFlag, template <WrappedScript::EvalInputFlags input_flag,
node::Script::EvalContextFlags cFlag, WrappedScript::EvalContextFlags context_flag,
node::Script::EvalOutputFlags oFlag> WrappedScript::EvalOutputFlags output_flag>
Handle<Value> node::Script::EvalMachine(const Arguments& args) { Handle<Value> WrappedScript::EvalMachine(const Arguments& args) {
HandleScope scope; HandleScope scope;
if (iFlag == compileCode && args.Length() < 1) { if (input_flag == compileCode && args.Length() < 1) {
return ThrowException(Exception::TypeError( return ThrowException(Exception::TypeError(
String::New("needs at least 'code' argument."))); String::New("needs at least 'code' argument.")));
} }
const int sbIndex = iFlag == compileCode ? 1 : 0; const int sandbox_index = input_flag == compileCode ? 1 : 0;
if (cFlag == userContext && args.Length() < (sbIndex + 1)) { if (context_flag == userContext && args.Length() < (sandbox_index + 1)) {
return ThrowException(Exception::TypeError( return ThrowException(Exception::TypeError(
String::New("needs a 'context' argument."))); String::New("needs a 'context' argument.")));
} }
Local<String> code; Local<String> code;
if (iFlag == compileCode) code = args[0]->ToString(); if (input_flag == compileCode) code = args[0]->ToString();
Local<Object> sandbox; Local<Object> sandbox;
if (cFlag == newContext) { if (context_flag == newContext) {
sandbox = args[sbIndex]->IsObject() ? args[sbIndex]->ToObject() : Object::New(); sandbox = args[sandbox_index]->IsObject() ? args[sandbox_index]->ToObject()
} else if (cFlag == userContext) { : Object::New();
sandbox = args[sbIndex]->ToObject(); } else if (context_flag == userContext) {
sandbox = args[sandbox_index]->ToObject();
} }
const int fnIndex = sbIndex + (cFlag == newContext ? 1 : 0); const int filename_index = sandbox_index +
Local<String> filename = args.Length() > fnIndex (context_flag == newContext ? 1 : 0);
? args[fnIndex]->ToString() Local<String> filename = args.Length() > filename_index
? args[filename_index]->ToString()
: String::New("evalmachine.<anonymous>"); : String::New("evalmachine.<anonymous>");
Persistent<v8::Context> context; const int display_error_index = args.Length() - 1;
bool display_error = false;
if (args.Length() > display_error_index &&
args[display_error_index]->IsBoolean() &&
args[display_error_index]->BooleanValue() == true) {
display_error = true;
}
Persistent<Context> context;
Local<Array> keys; Local<Array> keys;
unsigned int i; unsigned int i;
if (cFlag == newContext) { if (context_flag == newContext) {
// Create the new context // Create the new context
context = v8::Context::New(); context = Context::New();
} else if (cFlag == userContext) { } else if (context_flag == userContext) {
// Use the passed in context // Use the passed in context
Local<Object> contextArg = args[sbIndex]->ToObject(); Local<Object> contextArg = args[sandbox_index]->ToObject();
node::Context *nContext = ObjectWrap::Unwrap<node::Context>(sandbox); WrappedContext *nContext = ObjectWrap::Unwrap<WrappedContext>(sandbox);
context = nContext->GetV8Context(); context = nContext->GetV8Context();
} }
// New and user context share code. DRY it up. // New and user context share code. DRY it up.
if (cFlag == userContext || cFlag == newContext) { if (context_flag == userContext || context_flag == newContext) {
// Enter the context // Enter the context
context->Enter(); context->Enter();
@ -226,48 +324,49 @@ template <node::Script::EvalInputFlags iFlag,
TryCatch try_catch; TryCatch try_catch;
Handle<Value> result; Handle<Value> result;
Handle<v8::Script> script; Handle<Script> script;
if (iFlag == compileCode) { if (input_flag == compileCode) {
// well, here node::Script::New would suffice in all cases, but maybe // well, here WrappedScript::New would suffice in all cases, but maybe
// Compile has a little better performance where possible // Compile has a little better performance where possible
script = oFlag == returnResult ? v8::Script::Compile(code, filename) script = output_flag == returnResult ? Script::Compile(code, filename)
: v8::Script::New(code, filename); : Script::New(code, filename);
if (script.IsEmpty()) { if (script.IsEmpty()) {
// FIXME UGLY HACK TO DISPLAY SYNTAX ERRORS. // FIXME UGLY HACK TO DISPLAY SYNTAX ERRORS.
DisplayExceptionLine(try_catch); if (display_error) DisplayExceptionLine(try_catch);
// Hack because I can't get a proper stacktrace on SyntaxError // Hack because I can't get a proper stacktrace on SyntaxError
return try_catch.ReThrow(); return try_catch.ReThrow();
} }
} else { } else {
node::Script *nScript = ObjectWrap::Unwrap<node::Script>(args.Holder()); WrappedScript *n_script = ObjectWrap::Unwrap<WrappedScript>(args.Holder());
if (!nScript) { if (!n_script) {
return ThrowException(Exception::Error( return ThrowException(Exception::Error(
String::New("Must be called as a method of Script."))); String::New("Must be called as a method of Script.")));
} else if (nScript->script_.IsEmpty()) { } else if (n_script->script_.IsEmpty()) {
return ThrowException(Exception::Error( return ThrowException(Exception::Error(
String::New("'this' must be a result of previous new Script(code) call."))); String::New("'this' must be a result of previous "
"new Script(code) call.")));
} }
script = nScript->script_; script = n_script->script_;
} }
if (oFlag == returnResult) { if (output_flag == returnResult) {
result = script->Run(); result = script->Run();
if (result.IsEmpty()) return try_catch.ReThrow(); if (result.IsEmpty()) return try_catch.ReThrow();
} else { } else {
node::Script *nScript = ObjectWrap::Unwrap<node::Script>(args.Holder()); WrappedScript *n_script = ObjectWrap::Unwrap<WrappedScript>(args.Holder());
if (!nScript) { if (!n_script) {
return ThrowException(Exception::Error( return ThrowException(Exception::Error(
String::New("Must be called as a method of Script."))); String::New("Must be called as a method of Script.")));
} }
nScript->script_ = Persistent<v8::Script>::New(script); n_script->script_ = Persistent<Script>::New(script);
result = args.This(); result = args.This();
} }
if (cFlag == userContext || cFlag == newContext) { if (context_flag == userContext || context_flag == newContext) {
// success! copy changes back onto the sandbox object. // success! copy changes back onto the sandbox object.
keys = context->Global()->GetPropertyNames(); keys = context->Global()->GetPropertyNames();
for (i = 0; i < keys->Length(); i++) { for (i = 0; i < keys->Length(); i++) {
@ -278,12 +377,12 @@ template <node::Script::EvalInputFlags iFlag,
} }
} }
if (cFlag == newContext) { if (context_flag == newContext) {
// Clean up, clean up, everybody everywhere! // Clean up, clean up, everybody everywhere!
context->DetachGlobal(); context->DetachGlobal();
context->Exit(); context->Exit();
context.Dispose(); context.Dispose();
} else if (cFlag == userContext) { } else if (context_flag == userContext) {
// Exit the passed in context. // Exit the passed in context.
context->Exit(); context->Exit();
} }
@ -291,11 +390,17 @@ template <node::Script::EvalInputFlags iFlag,
return result == args.This() ? result : scope.Close(result); return result == args.This() ? result : scope.Close(result);
} }
void node::InitEvals(Handle<Object> target) {
void InitEvals(Handle<Object> target) {
HandleScope scope; HandleScope scope;
node::Context::Initialize(target); WrappedContext::Initialize(target);
node::Script::Initialize(target); WrappedScript::Initialize(target);
} }
} // namespace node
NODE_MODULE(node_evals, node::InitEvals); NODE_MODULE(node_evals, node::InitEvals);

48
src/node_script.h

@ -8,54 +8,6 @@
namespace node { namespace node {
class Context : ObjectWrap {
public:
static void Initialize (v8::Handle<v8::Object> target);
static v8::Handle<v8::Value> New (const v8::Arguments& args);
v8::Persistent<v8::Context> GetV8Context();
static v8::Local<v8::Object> NewInstance();
protected:
static v8::Persistent<v8::FunctionTemplate> constructor_template;
Context ();
~Context();
v8::Persistent<v8::Context> context_;
};
class Script : ObjectWrap {
public:
static void Initialize (v8::Handle<v8::Object> target);
enum EvalInputFlags { compileCode, unwrapExternal };
enum EvalContextFlags { thisContext, newContext, userContext };
enum EvalOutputFlags { returnResult, wrapExternal };
template <EvalInputFlags iFlag, EvalContextFlags cFlag, EvalOutputFlags oFlag>
static v8::Handle<v8::Value> EvalMachine(const v8::Arguments& args);
protected:
static v8::Persistent<v8::FunctionTemplate> constructor_template;
Script () : ObjectWrap () {}
~Script();
static v8::Handle<v8::Value> New (const v8::Arguments& args);
static v8::Handle<v8::Value> CreateContext (const v8::Arguments& arg);
static v8::Handle<v8::Value> RunInContext (const v8::Arguments& args);
static v8::Handle<v8::Value> RunInThisContext (const v8::Arguments& args);
static v8::Handle<v8::Value> RunInNewContext (const v8::Arguments& args);
static v8::Handle<v8::Value> CompileRunInContext (const v8::Arguments& args);
static v8::Handle<v8::Value> CompileRunInThisContext (const v8::Arguments& args);
static v8::Handle<v8::Value> CompileRunInNewContext (const v8::Arguments& args);
v8::Persistent<v8::Script> script_;
};
void InitEvals(v8::Handle<v8::Object> target); void InitEvals(v8::Handle<v8::Object> target);

9
src/platform.h

@ -1,9 +1,11 @@
#ifndef NODE_PLATFORM_H_ #ifndef NODE_PLATFORM_H_
#define NODE_PLATFORM_H_ #define NODE_PLATFORM_H_
#include <v8.h>
namespace node { namespace node {
class OS { class Platform {
public: public:
static char** SetupArgs(int argc, char *argv[]); static char** SetupArgs(int argc, char *argv[]);
static void SetProcessTitle(char *title); static void SetProcessTitle(char *title);
@ -11,6 +13,11 @@ class OS {
static int GetMemory(size_t *rss, size_t *vsize); static int GetMemory(size_t *rss, size_t *vsize);
static int GetExecutablePath(char* buffer, size_t* size); static int GetExecutablePath(char* buffer, size_t* size);
static int GetCPUInfo(v8::Local<v8::Array> *cpus);
static double GetFreeMemory();
static double GetTotalMemory();
static double GetUptime();
static int GetLoadAvg(v8::Local<v8::Array> *loads);
}; };

124
src/platform_cygwin.cc

@ -1,13 +1,21 @@
#include "node.h" #include "node.h"
#include "platform.h" #include "platform.h"
#include <v8.h>
#include <sys/param.h> // for MAXPATHLEN #include <sys/param.h> // for MAXPATHLEN
#include <unistd.h> // getpagesize #include <sys/sysinfo.h>
#include <unistd.h> // getpagesize, sysconf
#include <stdio.h> // sscanf, snprintf
#include <string.h>
#include <windows.h> #include <windows.h>
namespace node { namespace node {
using namespace v8;
static char buf[MAXPATHLEN + 1]; static char buf[MAXPATHLEN + 1];
static char *process_title = NULL; static char *process_title = NULL;
@ -30,12 +38,12 @@ static void _winapi_perror(const char* prefix = NULL) {
} }
char** OS::SetupArgs(int argc, char *argv[]) { char** Platform::SetupArgs(int argc, char *argv[]) {
return argv; return argv;
} }
void OS::SetProcessTitle(char *title) { void Platform::SetProcessTitle(char *title) {
// We need to convert _title_ to UTF-16 first, because that's what windows uses internally. // We need to convert _title_ to UTF-16 first, because that's what windows uses internally.
// It would be more efficient to use the UTF-16 value that we can obtain from v8, // It would be more efficient to use the UTF-16 value that we can obtain from v8,
// but it's not accessible from here. // but it's not accessible from here.
@ -139,7 +147,7 @@ static inline char* _getProcessTitle() {
} }
const char* OS::GetProcessTitle(int *len) { const char* Platform::GetProcessTitle(int *len) {
// If the process_title was never read before nor explicitly set, // If the process_title was never read before nor explicitly set,
// we must query it with getConsoleTitleW // we must query it with getConsoleTitleW
if (!process_title) { if (!process_title) {
@ -156,7 +164,7 @@ const char* OS::GetProcessTitle(int *len) {
} }
int OS::GetMemory(size_t *rss, size_t *vsize) { int Platform::GetMemory(size_t *rss, size_t *vsize) {
FILE *f = fopen("/proc/self/stat", "r"); FILE *f = fopen("/proc/self/stat", "r");
if (!f) return -1; if (!f) return -1;
@ -236,11 +244,115 @@ error:
} }
int OS::GetExecutablePath(char* buffer, size_t* size) { int Platform::GetExecutablePath(char* buffer, size_t* size) {
*size = readlink("/proc/self/exe", buffer, *size - 1); *size = readlink("/proc/self/exe", buffer, *size - 1);
if (*size <= 0) return -1; if (*size <= 0) return -1;
buffer[*size] = '\0'; buffer[*size] = '\0';
return 0; return 0;
} }
int Platform::GetCPUInfo(Local<Array> *cpus) {
Local<Object> cpuinfo;
Local<Object> cputimes;
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
multiplier = ((uint64_t)1000L / ticks), cpuspeed;
int numcpus = 0, i = 0;
unsigned long long ticks_user, ticks_sys, ticks_idle, ticks_nice, ticks_intr;
char line[512], speedPath[256], model[512];
FILE *fpStat = fopen("/proc/stat", "r");
FILE *fpModel = fopen("/proc/cpuinfo", "r");
FILE *fpSpeed;
if (fpModel) {
while (fgets(line, 511, fpModel) != NULL) {
if (strncmp(line, "model name", 10) == 0) {
numcpus++;
if (numcpus == 1) {
char *p = strchr(line, ':') + 2;
strcpy(model, p);
model[strlen(model)-1] = 0;
}
} else if (strncmp(line, "cpu MHz", 7) == 0) {
if (numcpus == 1) {
sscanf(line, "%*s %*s : %u", &cpuspeed);
}
}
}
fclose(fpModel);
}
*cpus = Array::New(numcpus);
if (fpStat) {
while (fgets(line, 511, fpStat) != NULL) {
if (strncmp(line, "cpu ", 4) == 0)
continue;
else if (strncmp(line, "intr ", 5) == 0)
break;
sscanf(line, "%*s %llu %llu %llu %llu",
&ticks_user, &ticks_nice, &ticks_sys, &ticks_idle);
snprintf(speedPath, sizeof(speedPath),
"/sys/devices/system/cpu/cpu%u/cpufreq/cpuinfo_max_freq", i);
fpSpeed = fopen(speedPath, "r");
if (fpSpeed) {
if (fgets(line, 511, fpSpeed) != NULL) {
sscanf(line, "%u", &cpuspeed);
cpuspeed /= 1000;
}
fclose(fpSpeed);
}
cpuinfo = Object::New();
cputimes = Object::New();
cputimes->Set(String::New("user"), Number::New(ticks_user * multiplier));
cputimes->Set(String::New("nice"), Number::New(ticks_nice * multiplier));
cputimes->Set(String::New("sys"), Number::New(ticks_sys * multiplier));
cputimes->Set(String::New("idle"), Number::New(ticks_idle * multiplier));
cputimes->Set(String::New("irq"), Number::New(0));
cpuinfo->Set(String::New("model"), String::New(model));
cpuinfo->Set(String::New("speed"), Number::New(cpuspeed));
cpuinfo->Set(String::New("times"), cputimes);
(*cpus)->Set(i++, cpuinfo);
}
fclose(fpStat);
}
return 0;
}
double Platform::GetFreeMemory() {
double pagesize = static_cast<double>(sysconf(_SC_PAGESIZE));
double pages = static_cast<double>(sysconf(_SC_AVPHYS_PAGES));
return static_cast<double>(pages * pagesize);
}
double Platform::GetTotalMemory() {
double pagesize = static_cast<double>(sysconf(_SC_PAGESIZE));
double pages = static_cast<double>(sysconf(_SC_PHYS_PAGES));
return pages * pagesize;
}
double Platform::GetUptime() {
double amount;
char line[512];
FILE *fpUptime = fopen("/proc/uptime", "r");
if (fpUptime) {
if (fgets(line, 511, fpUptime) != NULL) {
sscanf(line, "%lf %*lf", &amount);
}
fclose(fpUptime);
}
return amount;
}
int Platform::GetLoadAvg(Local<Array> *loads) {
// Unsupported as of cygwin 1.7.7
return -1;
}
} // namespace node } // namespace node

131
src/platform_darwin.cc

@ -1,27 +1,38 @@
#include "node.h" #include "node.h"
#include "platform.h" #include "platform.h"
#include <v8.h>
#include <mach/task.h> #include <mach/task.h>
#include <mach/mach_init.h> #include <mach/mach.h>
#include <mach/mach_host.h>
#include <mach-o/dyld.h> /* _NSGetExecutablePath */ #include <mach-o/dyld.h> /* _NSGetExecutablePath */
#include <limits.h> /* PATH_MAX */ #include <limits.h> /* PATH_MAX */
#include <unistd.h> // sysconf
#include <sys/param.h>
#include <sys/sysctl.h>
#include <time.h>
namespace node { namespace node {
using namespace v8;
static char *process_title; static char *process_title;
char** OS::SetupArgs(int argc, char *argv[]) { char** Platform::SetupArgs(int argc, char *argv[]) {
process_title = argc ? strdup(argv[0]) : NULL; process_title = argc ? strdup(argv[0]) : NULL;
return argv; return argv;
} }
// OS::SetProcessTitle implemented in platform_darwin_proctitle.cc // Platform::SetProcessTitle implemented in platform_darwin_proctitle.cc
} // namespace node } // namespace node
#include "platform_darwin_proctitle.cc" #include "platform_darwin_proctitle.cc"
namespace node { namespace node {
const char* OS::GetProcessTitle(int *len) { const char* Platform::GetProcessTitle(int *len) {
if (process_title) { if (process_title) {
*len = strlen(process_title); *len = strlen(process_title);
return process_title; return process_title;
@ -32,7 +43,7 @@ const char* OS::GetProcessTitle(int *len) {
// Researched by Tim Becker and Michael Knight // Researched by Tim Becker and Michael Knight
// http://blog.kuriositaet.de/?p=257 // http://blog.kuriositaet.de/?p=257
int OS::GetMemory(size_t *rss, size_t *vsize) { int Platform::GetMemory(size_t *rss, size_t *vsize) {
struct task_basic_info t_info; struct task_basic_info t_info;
mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
@ -50,7 +61,7 @@ int OS::GetMemory(size_t *rss, size_t *vsize) {
} }
int OS::GetExecutablePath(char* buffer, size_t* size) { int Platform::GetExecutablePath(char* buffer, size_t* size) {
uint32_t usize = *size; uint32_t usize = *size;
int result = _NSGetExecutablePath(buffer, &usize); int result = _NSGetExecutablePath(buffer, &usize);
if (result) return result; if (result) return result;
@ -68,4 +79,112 @@ int OS::GetExecutablePath(char* buffer, size_t* size) {
return 0; return 0;
} }
int Platform::GetCPUInfo(Local<Array> *cpus) {
Local<Object> cpuinfo;
Local<Object> cputimes;
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
multiplier = ((uint64_t)1000L / ticks);
char model[512];
uint64_t cpuspeed;
size_t size;
size = sizeof(model);
if (sysctlbyname("hw.model", &model, &size, NULL, 0) < 0) {
return -1;
}
size = sizeof(cpuspeed);
if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0) < 0) {
return -1;
}
natural_t numcpus;
mach_msg_type_number_t count;
processor_cpu_load_info_data_t *info;
if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus,
reinterpret_cast<processor_info_array_t*>(&info),
&count) != KERN_SUCCESS) {
return -1;
}
*cpus = Array::New(numcpus);
for (int i = 0; i < numcpus; i++) {
cpuinfo = Object::New();
cputimes = Object::New();
cputimes->Set(String::New("user"),
Number::New((uint64_t)(info[i].cpu_ticks[0]) * multiplier));
cputimes->Set(String::New("nice"),
Number::New((uint64_t)(info[i].cpu_ticks[3]) * multiplier));
cputimes->Set(String::New("sys"),
Number::New((uint64_t)(info[i].cpu_ticks[1]) * multiplier));
cputimes->Set(String::New("idle"),
Number::New((uint64_t)(info[i].cpu_ticks[2]) * multiplier));
cputimes->Set(String::New("irq"), Number::New(0));
cpuinfo->Set(String::New("model"), String::New(model));
cpuinfo->Set(String::New("speed"), Number::New(cpuspeed/1000000));
cpuinfo->Set(String::New("times"), cputimes);
(*cpus)->Set(i, cpuinfo);
}
vm_deallocate(mach_task_self(), (vm_address_t)info, count);
return 0;
}
double Platform::GetFreeMemory() {
double pagesize = static_cast<double>(sysconf(_SC_PAGESIZE));
vm_statistics_data_t info;
mach_msg_type_number_t count = sizeof(info) / sizeof(integer_t);
if (host_statistics(mach_host_self(), HOST_VM_INFO,
(host_info_t)&info, &count) != KERN_SUCCESS) {
return -1;
}
return (static_cast<double>(info.free_count)) * pagesize;
}
double Platform::GetTotalMemory() {
uint64_t info;
static int which[] = {CTL_HW, HW_MEMSIZE};
size_t size = sizeof(info);
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return -1;
}
return static_cast<double>(info);
}
double Platform::GetUptime() {
time_t now;
struct timeval info;
size_t size = sizeof(info);
static int which[] = {CTL_KERN, KERN_BOOTTIME};
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return -1;
}
now = time(NULL);
return static_cast<double>(now - info.tv_sec);
}
int Platform::GetLoadAvg(Local<Array> *loads) {
struct loadavg info;
size_t size = sizeof(info);
static int which[] = {CTL_VM, VM_LOADAVG};
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return -1;
}
(*loads)->Set(0, Number::New(static_cast<double>(info.ldavg[0])
/ static_cast<double>(info.fscale)));
(*loads)->Set(1, Number::New(static_cast<double>(info.ldavg[1])
/ static_cast<double>(info.fscale)));
(*loads)->Set(2, Number::New(static_cast<double>(info.ldavg[2])
/ static_cast<double>(info.fscale)));
return 0;
}
} // namespace node } // namespace node

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

Loading…
Cancel
Save