diff options
author | Bert Belder <bertbelder@gmail.com> | 2011-01-03 00:57:32 +0300 |
---|---|---|
committer | Bert Belder <bertbelder@gmail.com> | 2011-01-03 00:57:32 +0300 |
commit | 33118df8f98f7c81c36653563b2b58e44bcc4c6f (patch) | |
tree | 4e3e8c6165a40ed2abe726aaea3b0531ac873bf9 | |
parent | 86518c3b1101a20fafb8d213d0d68988cb4407fe (diff) | |
parent | b5637170b17d4ad7d47362a394e360c44af60e46 (diff) |
Merge remote branch 'origin/master'
Conflicts:
src/node_net.cc
src/node_os.cc
116 files changed, 3374 insertions, 1382 deletions
@@ -25,9 +25,15 @@ uninstall: test: all python tools/test.py --mode=release simple message +test-valgrind: all + python tools/test.py --mode=release --valgrind simple message + test-all: all python tools/test.py --mode=debug,release +test-all-valgrind: all + python tools/test.py --mode=debug,release --valgrind + test-release: all python tools/test.py --mode=release diff --git a/Makefile.cmake b/Makefile.cmake index aaa3f6f258c..0281b413e7c 100644 --- a/Makefile.cmake +++ b/Makefile.cmake @@ -2,12 +2,13 @@ BUILD?=build VERBOSE?=0 PARALLEL_JOBS?=1 CMAKE?=cmake +TOOLCHAIN_FILE=#./cmake/codesourcery-arm-toolchain.cmake -all: doc package +all: package $(BUILD)/Makefile: 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 cd $(BUILD) && make -j $(PARALLEL_JOBS) diff --git a/README.cmake b/README.cmake index 88cd99c8692..925249c8ae5 100644 --- a/README.cmake +++ b/README.cmake @@ -38,6 +38,18 @@ To submit valgrind test results: 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: cd ~/your-node-source-dir mkdir name-of-build-dir (can be anything) diff --git a/cmake/codesourcery-arm-toolchain.cmake b/cmake/codesourcery-arm-toolchain.cmake new file mode 100644 index 00000000000..c45bce50675 --- /dev/null +++ b/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 "") diff --git a/cmake/configure.cmake b/cmake/configure.cmake index eef89c5fdcf..79b6369d590 100644 --- a/cmake/configure.cmake +++ b/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}) 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() diff --git a/cmake/libs.cmake b/cmake/libs.cmake index 2844d86ac0d..aeeb01d8115 100644 --- a/cmake/libs.cmake +++ b/cmake/libs.cmake @@ -13,6 +13,7 @@ find_library(RT rt) find_library(DL dl) check_library_exists(socket socket "" HAVE_SOCKET_LIB) check_library_exists(nsl gethostbyname "" HAVE_NSL_LIB) +check_library_exists(util openpty "" HAVE_UTIL_LIB) if(RT) set(extra_libs ${extra_libs} ${RT}) @@ -35,7 +36,11 @@ if(${HAVE_NSL_LIB}) set(extra_libs ${extra_libs} nsl) 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) set(HAVE_OPENSSL True) set(node_extra_src ${node_extra_src} src/node_crypto.cc) diff --git a/cmake/node_build.cmake b/cmake/node_build.cmake index ec9010dd3f9..240bdc6f9cc 100644 --- a/cmake/node_build.cmake +++ b/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} 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}) - set(node_extra_src "src/platform_none.cc") +if(NOT EXISTS ${CMAKE_SOURCE_DIR}/${node_platform_src}) + set(node_extra_src ${node_extra_src} "src/platform_none.cc") +else() + set(node_extra_src ${node_extra_src} ${node_platform_src}) endif() set(node_sources @@ -36,6 +38,18 @@ set(node_sources src/node_natives.h ${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(config.h.cmake ${PROJECT_BINARY_DIR}/config.h) diff --git a/cmake/v8_build.cmake b/cmake/v8_build.cmake index ea27e5fd083..b35caef2e66 100644 --- a/cmake/v8_build.cmake +++ b/cmake/v8_build.cmake @@ -38,6 +38,7 @@ if(NOT SHARED_V8) set_property(TARGET v8 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) # use ExternalProject for CMake >2.8 @@ -47,7 +48,7 @@ if(NOT SHARED_V8) URL ${PROJECT_SOURCE_DIR}/deps/v8 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 # ignore this stuff, it's not needed for building v8 but ExternalProject @@ -78,7 +79,7 @@ if(NOT SHARED_V8) add_custom_command( 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/ DEPENDS ${v8_sources_dest} ) diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index f1b47b06c39..c81d7a7376e 100644 --- a/deps/v8/ChangeLog +++ b/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 Reapplied all changes for version 3.0.1. diff --git a/deps/v8/SConstruct b/deps/v8/SConstruct index 41c9faeb63a..5908be1525c 100644 --- a/deps/v8/SConstruct +++ b/deps/v8/SConstruct @@ -108,11 +108,14 @@ LIBRARY_FLAGS = { 'CPPDEFINES': ['V8_INTERPRETED_REGEXP'] }, 'mode:debug': { - 'CPPDEFINES': ['V8_ENABLE_CHECKS'] + 'CPPDEFINES': ['V8_ENABLE_CHECKS', 'OBJECT_PRINT'] }, 'vmstate:on': { 'CPPDEFINES': ['ENABLE_VMSTATE_TRACKING'], }, + 'objectprint:on': { + 'CPPDEFINES': ['OBJECT_PRINT'], + }, 'protectheap:on': { 'CPPDEFINES': ['ENABLE_VMSTATE_TRACKING', 'ENABLE_HEAP_PROTECTION'], }, @@ -225,8 +228,7 @@ LIBRARY_FLAGS = { 'LINKFLAGS': ['-m64'], }, 'prof:oprofile': { - 'CPPDEFINES': ['ENABLE_OPROFILE_AGENT'], - 'LIBS': ['opagent', 'bfd'] + 'CPPDEFINES': ['ENABLE_OPROFILE_AGENT'] } }, 'msvc': { @@ -711,6 +713,11 @@ SIMPLE_OPTIONS = { 'default': 'off', 'help': 'enable VM state tracking' }, + 'objectprint': { + 'values': ['on', 'off'], + 'default': 'off', + 'help': 'enable object printing' + }, 'protectheap': { 'values': ['on', 'off'], 'default': 'off', diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index 82de6b8b5e8..2c0f35080d3 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -1355,6 +1355,21 @@ class Date : public Value { V8EXPORT double NumberValue() const; 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: V8EXPORT static void CheckCast(v8::Value* obj); }; diff --git a/deps/v8/src/SConscript b/deps/v8/src/SConscript index 5d7907251f6..8ccc6f2d8bb 100755 --- a/deps/v8/src/SConscript +++ b/deps/v8/src/SConscript @@ -231,7 +231,8 @@ SOURCES = { 'mode:release': [], 'mode:debug': [ 'objects-debug.cc', 'prettyprinter.cc', 'regexp-macro-assembler-tracer.cc' - ] + ], + 'objectprint:on': ['objects-debug.cc'] } diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index b85d658dc38..110468e2313 100644 --- a/deps/v8/src/api.cc +++ b/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) { char flags_buf[3]; int num_flags = 0; diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index 3670765a612..5ec8584f9ed 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/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 -// necessary. Uses r1 for the object, r0 for the function that it may -// be an instance of (these are fetched from the stack). +// Uses registers r0 to r4. Expected input is +// function in r0 (or at sp+1*ptrsz) and object in +// r1 (or at sp), depending on whether or not +// args_in_registers() is true. void InstanceofStub::Generate(MacroAssembler* masm) { - // Get the object - slow case for smis (we may need to throw an exception - // depending on the rhs). - Label slow, loop, is_instance, is_not_instance; - __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); - __ BranchOnSmi(r0, &slow); + // Fixed register usage throughout the stub: + const Register object = r1; // Object (lhs). + const Register map = r3; // Map of the object. + const Register function = r0; // Function (rhs). + const Register prototype = r4; // Prototype of the function. + const Register scratch = r2; + Label slow, loop, is_instance, is_not_instance, not_js_object; + if (!args_in_registers()) { + __ ldr(function, MemOperand(sp, 1 * kPointerSize)); + __ ldr(object, MemOperand(sp, 0)); + } - // Check that the left hand is a JS object and put map in r3. - __ CompareObjectType(r0, r3, r2, FIRST_JS_OBJECT_TYPE); - __ b(lt, &slow); - __ cmp(r2, Operand(LAST_JS_OBJECT_TYPE)); - __ b(gt, &slow); - - // Get the prototype of the function (r4 is result, r2 is scratch). - __ ldr(r1, MemOperand(sp, 0)); - // r1 is function, r3 is map. + // Check that the left hand is a JS object and load map. + __ BranchOnSmi(object, &slow); + __ IsObjectJSObjectType(object, map, scratch, &slow); // Look up the function and the map in the instanceof cache. Label miss; __ LoadRoot(ip, Heap::kInstanceofCacheFunctionRootIndex); - __ cmp(r1, ip); + __ cmp(object, ip); __ b(ne, &miss); __ LoadRoot(ip, Heap::kInstanceofCacheMapRootIndex); - __ cmp(r3, ip); + __ cmp(map, ip); __ b(ne, &miss); - __ LoadRoot(r0, Heap::kInstanceofCacheAnswerRootIndex); - __ pop(); - __ pop(); - __ mov(pc, Operand(lr)); + __ LoadRoot(function, Heap::kInstanceofCacheAnswerRootIndex); + __ Ret(args_in_registers() ? 0 : 2); __ bind(&miss); - __ TryGetFunctionPrototype(r1, r4, r2, &slow); + __ TryGetFunctionPrototype(object, prototype, scratch, &slow); // Check that the function prototype is a JS object. - __ BranchOnSmi(r4, &slow); - __ CompareObjectType(r4, r5, r5, FIRST_JS_OBJECT_TYPE); - __ b(lt, &slow); - __ cmp(r5, Operand(LAST_JS_OBJECT_TYPE)); - __ b(gt, &slow); + __ BranchOnSmi(prototype, &slow); + __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); - __ StoreRoot(r1, Heap::kInstanceofCacheFunctionRootIndex); - __ StoreRoot(r3, Heap::kInstanceofCacheMapRootIndex); + __ StoreRoot(object, Heap::kInstanceofCacheFunctionRootIndex); + __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex); // Register mapping: r3 is object map and r4 is function prototype. // 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. __ bind(&loop); - __ cmp(r2, Operand(r4)); + __ cmp(scratch, Operand(prototype)); __ b(eq, &is_instance); __ LoadRoot(ip, Heap::kNullValueRootIndex); - __ cmp(r2, ip); + __ cmp(scratch, ip); __ b(eq, &is_not_instance); - __ ldr(r2, FieldMemOperand(r2, HeapObject::kMapOffset)); - __ ldr(r2, FieldMemOperand(r2, Map::kPrototypeOffset)); + __ ldr(scratch, FieldMemOperand(scratch, HeapObject::kMapOffset)); + __ ldr(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset)); __ jmp(&loop); __ bind(&is_instance); __ mov(r0, Operand(Smi::FromInt(0))); __ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex); - __ pop(); - __ pop(); - __ mov(pc, Operand(lr)); // Return. + __ Ret(args_in_registers() ? 0 : 2); __ bind(&is_not_instance); __ mov(r0, Operand(Smi::FromInt(1))); - __ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex); - __ pop(); - __ pop(); - __ mov(pc, Operand(lr)); // Return. + __ Ret(args_in_registers() ? 0 : 2); + + Label object_not_null, object_not_null_or_smi; + __ bind(¬_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. __ bind(&slow); diff --git a/deps/v8/src/arm/lithium-arm.cc b/deps/v8/src/arm/lithium-arm.cc index 9c792316f5e..e31d2e1d8a8 100644 --- a/deps/v8/src/arm/lithium-arm.cc +++ b/deps/v8/src/arm/lithium-arm.cc @@ -1316,7 +1316,8 @@ LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) { LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) { 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); } @@ -1375,6 +1376,12 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { case kMathLog: Abort("MathLog LUnaryMathOperation not implemented"); return NULL; + case kMathCos: + Abort("MathCos LUnaryMathOperation not implemented"); + return NULL; + case kMathSin: + Abort("MathSin LUnaryMathOperation not implemented"); + return NULL; default: UNREACHABLE(); return NULL; diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index 533d32c7474..dfc48917da6 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/arm/lithium-codegen-arm.cc @@ -1337,7 +1337,14 @@ void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* 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) { - Abort("LUnaryMathOperation unimplemented."); + Abort("DoMathAbs unimplemented."); } @@ -1562,9 +1569,6 @@ void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { - ASSERT(instr->op() == kMathFloor || - instr->op() == kMathAbs); - switch (instr->op()) { case kMathAbs: DoMathAbs(instr); @@ -1576,6 +1580,7 @@ void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { DoMathSqrt(instr); break; default: + Abort("Unimplemented type of LUnaryMathOperation."); UNREACHABLE(); } } diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index 6effec1e319..4a131465902 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/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, Register reg2, 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 void MacroAssembler::DebugBreak() { ASSERT(allow_stub_calls()); diff --git a/deps/v8/src/arm/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h index 3da8726777b..97bbb2fb678 100644 --- a/deps/v8/src/arm/macro-assembler-arm.h +++ b/deps/v8/src/arm/macro-assembler-arm.h @@ -96,6 +96,7 @@ class MacroAssembler: public Assembler { // from the stack, clobbering only the sp register. 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 // less efficient form using xor instead of mov is emitted. @@ -298,6 +299,18 @@ class MacroAssembler: public Assembler { const ParameterCount& actual, 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 // --------------------------------------------------------------------------- diff --git a/deps/v8/src/array.js b/deps/v8/src/array.js index a805157b13b..0f1e969f987 100644 --- a/deps/v8/src/array.js +++ b/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 // modification, are permitted provided that the following conditions are // met: @@ -677,39 +677,76 @@ function ArraySort(comparefn) { function QuickSort(a, from, to) { // Insertion sort is faster for short arrays. - if (to - from <= 22) { + if (to - from <= 10) { InsertionSort(a, from, to); return; } - var pivot_index = $floor($random() * (to - from)) + from; - var pivot = a[pivot_index]; - // Issue 95: Keep the pivot element out of the comparisons to avoid - // infinite recursion if comparefn(pivot, pivot) != 0. - %_SwapElements(a, from, pivot_index); - var low_end = from; // Upper bound of the elements lower than pivot. - var high_start = to; // Lower bound of the elements greater than pivot. + // Find a pivot as the median of first, last and middle element. + var v0 = a[from]; + var v1 = a[to - 1]; + var middle_index = from + ((to - from) >> 1); + var v2 = a[middle_index]; + var c01 = %_CallFunction(global_receiver, v0, v1, comparefn); + 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 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 order = %_CallFunction(global_receiver, element, pivot, comparefn); if (order < 0) { %_SwapElements(a, i, low_end); - i++; low_end++; } else if (order > 0) { - high_start--; + do { + 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); - } else { // order == 0 - i++; + if (order < 0) { + %_SwapElements(a, i, low_end); + low_end++; + } } } QuickSort(a, from, low_end); QuickSort(a, high_start, to); } - // Copies 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 + // Copy elements in the range 0..length from obj's prototype chain + // to obj itself, if obj has holes. Return one more than the maximal index // of a prototype property. function CopyFromPrototype(obj, length) { var max = 0; diff --git a/deps/v8/src/assembler.cc b/deps/v8/src/assembler.cc index 3b44efa9c02..eeb84128d76 100644 --- a/deps/v8/src/assembler.cc +++ b/deps/v8/src/assembler.cc @@ -467,34 +467,35 @@ const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) { } -void RelocInfo::Print() { - PrintF("%p %s", pc_, RelocModeName(rmode_)); +void RelocInfo::Print(FILE* out) { + PrintF(out, "%p %s", pc_, RelocModeName(rmode_)); if (IsComment(rmode_)) { - PrintF(" (%s)", reinterpret_cast<char*>(data_)); + PrintF(out, " (%s)", reinterpret_cast<char*>(data_)); } else if (rmode_ == EMBEDDED_OBJECT) { - PrintF(" ("); - target_object()->ShortPrint(); - PrintF(")"); + PrintF(out, " ("); + target_object()->ShortPrint(out); + PrintF(out, ")"); } else if (rmode_ == EXTERNAL_REFERENCE) { ExternalReferenceEncoder ref_encoder; - PrintF(" (%s) (%p)", + PrintF(out, " (%s) (%p)", ref_encoder.NameOfAddress(*target_reference_address()), *target_reference_address()); } else if (IsCodeTarget(rmode_)) { 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_)) { - PrintF(" (%" V8_PTR_PREFIX "d)", data()); + PrintF(out, " (%" V8_PTR_PREFIX "d)", data()); } else if (rmode_ == RelocInfo::RUNTIME_ENTRY) { // Depotimization bailouts are stored as runtime entries. int id = Deoptimizer::GetDeoptimizationId( target_address(), Deoptimizer::EAGER); if (id != Deoptimizer::kNotDeoptimizationEntry) { - PrintF(" (deoptimization bailout %d)", id); + PrintF(out, " (deoptimization bailout %d)", id); } } - PrintF("\n"); + PrintF(out, "\n"); } #endif // ENABLE_DISASSEMBLER diff --git a/deps/v8/src/assembler.h b/deps/v8/src/assembler.h index 72a9b15380b..b68ad389708 100644 --- a/deps/v8/src/assembler.h +++ b/deps/v8/src/assembler.h @@ -322,7 +322,7 @@ class RelocInfo BASE_EMBEDDED { #ifdef ENABLE_DISASSEMBLER // Printing static const char* RelocModeName(Mode rmode); - void Print(); + void Print(FILE* out); #endif // ENABLE_DISASSEMBLER #ifdef DEBUG // Debugging diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index a833119e853..21381f15d5c 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -515,10 +515,10 @@ BUILTIN(ArrayShift) { Object* elms_obj; { MaybeObject* maybe_elms_obj = EnsureJSArrayWithWritableFastElements(receiver); + if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayShift", args); if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; } - if (elms_obj == NULL || - !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) { + if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) { return CallJsBuiltin("ArrayShift", args); } FixedArray* elms = FixedArray::cast(elms_obj); @@ -557,10 +557,10 @@ BUILTIN(ArrayUnshift) { Object* elms_obj; { MaybeObject* maybe_elms_obj = EnsureJSArrayWithWritableFastElements(receiver); + if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayUnshift", args); if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; } - if (elms_obj == NULL || - !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) { + if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) { return CallJsBuiltin("ArrayUnshift", args); } FixedArray* elms = FixedArray::cast(elms_obj); @@ -611,21 +611,46 @@ BUILTIN(ArrayUnshift) { BUILTIN(ArraySlice) { Object* receiver = *args.receiver(); - Object* elms_obj; + FixedArray* elms; + int len = -1; { MaybeObject* maybe_elms_obj = EnsureJSArrayWithWritableFastElements(receiver); - if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; - } - if (elms_obj == NULL || - !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) { - return CallJsBuiltin("ArraySlice", args); - } - FixedArray* elms = FixedArray::cast(elms_obj); - JSArray* array = JSArray::cast(receiver); - ASSERT(array->HasFastElements()); - - int len = Smi::cast(array->length())->value(); + Object* elms_obj; + if (maybe_elms_obj != NULL && maybe_elms_obj->ToObject(&elms_obj)) { + if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) { + return CallJsBuiltin("ArraySlice", args); + } + elms = FixedArray::cast(elms_obj); + JSArray* array = JSArray::cast(receiver); + ASSERT(array->HasFastElements()); + 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; // Note carefully choosen defaults---if argument is missing, @@ -693,10 +718,10 @@ BUILTIN(ArraySplice) { Object* elms_obj; { MaybeObject* maybe_elms_obj = EnsureJSArrayWithWritableFastElements(receiver); + if (maybe_elms_obj == NULL) return CallJsBuiltin("ArraySplice", args); if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; } - if (elms_obj == NULL || - !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) { + if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) { return CallJsBuiltin("ArraySplice", args); } FixedArray* elms = FixedArray::cast(elms_obj); diff --git a/deps/v8/src/code-stubs.h b/deps/v8/src/code-stubs.h index 8ba9971751b..b7804b77f28 100644 --- a/deps/v8/src/code-stubs.h +++ b/deps/v8/src/code-stubs.h @@ -47,7 +47,7 @@ namespace internal { V(Compare) \ V(CompareIC) \ V(MathPow) \ - V(TranscendentalCacheSSE2) \ + V(TranscendentalCache) \ V(RecordWrite) \ V(ConvertToDouble) \ V(WriteInt32ToHeapNumber) \ @@ -56,7 +56,6 @@ namespace internal { V(FastNewClosure) \ V(FastNewContext) \ V(FastCloneShallowArray) \ - V(TranscendentalCache) \ V(GenericUnaryOp) \ V(RevertToNumber) \ V(ToBoolean) \ diff --git a/deps/v8/src/codegen.cc b/deps/v8/src/codegen.cc index 8a64d77b709..da479e8fc1e 100644 --- a/deps/v8/src/codegen.cc +++ b/deps/v8/src/codegen.cc @@ -215,8 +215,17 @@ void CodeGenerator::PrintCode(Handle<Code> code, CompilationInfo* info) { } PrintF("\n\n"); } - PrintF("--- Code ---\n"); - code->Disassemble(*function->name()->ToCString()); + 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"); + } + code->Disassemble(*function->debug_name()->ToCString()); } #endif // ENABLE_DISASSEMBLER } diff --git a/deps/v8/src/counters.h b/deps/v8/src/counters.h index aed46cfb36e..048fdaabf29 100644 --- a/deps/v8/src/counters.h +++ b/deps/v8/src/counters.h @@ -28,6 +28,9 @@ #ifndef V8_COUNTERS_H_ #define V8_COUNTERS_H_ +#include "../include/v8.h" +#include "allocation.h" + namespace v8 { namespace internal { diff --git a/deps/v8/src/date.js b/deps/v8/src/date.js index 38bb8eb2544..bc70327c41c 100644 --- a/deps/v8/src/date.js +++ b/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() { diff --git a/deps/v8/src/debug.cc b/deps/v8/src/debug.cc index 7709eb0e93d..ca3c1db790b 100644 --- a/deps/v8/src/debug.cc +++ b/deps/v8/src/debug.cc @@ -858,7 +858,7 @@ bool Debug::Load() { if (caught_exception) return false; // Debugger loaded. - debug_context_ = Handle<Context>::cast(GlobalHandles::Create(*context)); + debug_context_ = context; return true; } diff --git a/deps/v8/src/deoptimizer.cc b/deps/v8/src/deoptimizer.cc index 93839a49a80..dd70baaa165 100644 --- a/deps/v8/src/deoptimizer.cc +++ b/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) { switch (opcode) { diff --git a/deps/v8/src/deoptimizer.h b/deps/v8/src/deoptimizer.h index 32edd1009f5..2d7dfc895c3 100644 --- a/deps/v8/src/deoptimizer.h +++ b/deps/v8/src/deoptimizer.h @@ -476,7 +476,7 @@ class Translation BASE_EMBEDDED { static int NumberOfOperandsFor(Opcode opcode); -#ifdef DEBUG +#ifdef OBJECT_PRINT static const char* StringFor(Opcode opcode); #endif diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h index facbec273b1..f160a85afc7 100644 --- a/deps/v8/src/flag-definitions.h +++ b/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(new_snapshot, true, "use new snapshot implementation") +// objects.cc +DEFINE_bool(use_verbose_printer, true, "allows verbose printing") + // parser.cc 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 DEFINE_bool(print_code, false, "print generated 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_builtin_code, false, "print generated code for builtins") diff --git a/deps/v8/src/full-codegen.cc b/deps/v8/src/full-codegen.cc index 96307a302d5..58540f07bc6 100644 --- a/deps/v8/src/full-codegen.cc +++ b/deps/v8/src/full-codegen.cc @@ -671,8 +671,12 @@ const FullCodeGenerator::InlineFunctionGenerator FullCodeGenerator::InlineFunctionGenerator FullCodeGenerator::FindInlineFunctionGenerator(Runtime::FunctionId id) { - return kInlineFunctionGenerators[ - static_cast<int>(id) - static_cast<int>(Runtime::kFirstInlineFunction)]; + int lookup_index = + 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); InlineFunctionGenerator generator = FindInlineFunctionGenerator(function->function_id); - ASSERT(generator != NULL); ((*this).*(generator))(args); } diff --git a/deps/v8/src/heap-profiler.cc b/deps/v8/src/heap-profiler.cc index 002950031bd..dfda7c6fec5 100644 --- a/deps/v8/src/heap-profiler.cc +++ b/deps/v8/src/heap-profiler.cc @@ -367,7 +367,6 @@ HeapSnapshot* HeapProfiler::TakeSnapshot(String* name, HeapSnapshot* HeapProfiler::TakeSnapshotImpl(const char* name, int type, v8::ActivityControl* control) { - Heap::CollectAllGarbage(true); HeapSnapshot::Type s_type = static_cast<HeapSnapshot::Type>(type); HeapSnapshot* result = snapshots_->NewSnapshot(s_type, name, next_snapshot_uid_++); @@ -379,6 +378,7 @@ HeapSnapshot* HeapProfiler::TakeSnapshotImpl(const char* name, break; } case HeapSnapshot::kAggregated: { + Heap::CollectAllGarbage(true); AggregatedHeapSnapshot agg_snapshot; AggregatedHeapSnapshotGenerator generator(&agg_snapshot); generator.GenerateSnapshot(); @@ -808,7 +808,7 @@ void AggregatedHeapSnapshotGenerator::CollectStats(HeapObject* obj) { void AggregatedHeapSnapshotGenerator::GenerateSnapshot() { - HeapIterator iterator(HeapIterator::kPreciseFiltering); + HeapIterator iterator(HeapIterator::kFilterFreeListNodes); for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { CollectStats(obj); agg_snapshot_->js_cons_profile()->CollectStats(obj); diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index ccf9b47a35c..1e9999164cc 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -4483,7 +4483,7 @@ void Heap::RecordStats(HeapStats* stats, bool take_snapshot) { MemoryAllocator::Size() + MemoryAllocator::Available(); *stats->os_error = OS::GetLastError(); if (take_snapshot) { - HeapIterator iterator(HeapIterator::kPreciseFiltering); + HeapIterator iterator(HeapIterator::kFilterFreeListNodes); for (HeapObject* obj = iterator.next(); obj != NULL; 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: FreeListNodesFilter() { MarkFreeListNodes(); } - inline bool IsFreeListNode(HeapObject* object) { + bool SkipObject(HeapObject* object) { if (object->IsMarked()) { object->ClearMark(); 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() : filtering_(HeapIterator::kNoFiltering), filter_(NULL) { @@ -4962,7 +5028,7 @@ HeapIterator::HeapIterator() } -HeapIterator::HeapIterator(HeapIterator::FreeListNodesFiltering filtering) +HeapIterator::HeapIterator(HeapIterator::HeapObjectsFiltering filtering) : filtering_(filtering), filter_(NULL) { Init(); @@ -4976,12 +5042,17 @@ HeapIterator::~HeapIterator() { void HeapIterator::Init() { // Start the iteration. - if (filtering_ == kPreciseFiltering) { - filter_ = new FreeListNodesFilter; - space_iterator_ = - new SpaceIterator(MarkCompactCollector::SizeOfMarkedObject); - } else { - space_iterator_ = new SpaceIterator; + space_iterator_ = filtering_ == kNoFiltering ? new SpaceIterator : + new SpaceIterator(MarkCompactCollector::SizeOfMarkedObject); + switch (filtering_) { + case kFilterFreeListNodes: + filter_ = new FreeListNodesFilter; + break; + case kFilterUnreachable: + filter_ = new UnreachableObjectsFilter; + break; + default: + break; } object_iterator_ = space_iterator_->next(); } @@ -4989,9 +5060,9 @@ void HeapIterator::Init() { void HeapIterator::Shutdown() { #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. - if (filtering_ == kPreciseFiltering) { + if (filtering_ != kNoFiltering) { ASSERT(object_iterator_ == NULL); } #endif @@ -5008,7 +5079,7 @@ HeapObject* HeapIterator::next() { if (filter_ == NULL) return NextObject(); HeapObject* obj = NextObject(); - while (obj != NULL && filter_->IsFreeListNode(obj)) obj = NextObject(); + while (obj != NULL && filter_->SkipObject(obj)) obj = NextObject(); return obj; } diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h index fbcc70df531..18a4afbe46a 100644 --- a/deps/v8/src/heap.h +++ b/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 // phases. Also, it is forbidden to interrupt iteration in this mode, // as this will leave heap objects marked (and thus, unusable). -class FreeListNodesFilter; +class HeapObjectsFilter; class HeapIterator BASE_EMBEDDED { public: - enum FreeListNodesFiltering { + enum HeapObjectsFiltering { kNoFiltering, - kPreciseFiltering + kFilterFreeListNodes, + kFilterUnreachable }; HeapIterator(); - explicit HeapIterator(FreeListNodesFiltering filtering); + explicit HeapIterator(HeapObjectsFiltering filtering); ~HeapIterator(); HeapObject* next(); @@ -1608,8 +1609,8 @@ class HeapIterator BASE_EMBEDDED { void Shutdown(); HeapObject* NextObject(); - FreeListNodesFiltering filtering_; - FreeListNodesFilter* filter_; + HeapObjectsFiltering filtering_; + HeapObjectsFilter* filter_; // Space iterator for iterating all the spaces. SpaceIterator* space_iterator_; // Object iterator for the space currently being iterated. @@ -1968,6 +1969,8 @@ class GCTracer BASE_EMBEDDED { class TranscendentalCache { public: 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); @@ -2056,7 +2059,6 @@ class TranscendentalCache { friend class ExternalReference; // Inline implementation of the cache. friend class TranscendentalCacheStub; - friend class TranscendentalCacheSSE2Stub; static TranscendentalCache* caches_[kNumberOfCaches]; Element elements_[kCacheSize]; diff --git a/deps/v8/src/hydrogen-instructions.cc b/deps/v8/src/hydrogen-instructions.cc index a96ee406ff5..3f39888e9bf 100644 --- a/deps/v8/src/hydrogen-instructions.cc +++ b/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 { stream->Add("B%d", FirstSuccessor()->block_id()); } diff --git a/deps/v8/src/hydrogen-instructions.h b/deps/v8/src/hydrogen-instructions.h index aafa7a8830c..cbbe8fcc88a 100644 --- a/deps/v8/src/hydrogen-instructions.h +++ b/deps/v8/src/hydrogen-instructions.h @@ -905,6 +905,8 @@ class HCompareMapAndBranch: public HUnaryControlInstruction { virtual HBasicBlock* FirstSuccessor() const { return true_destination_; } virtual HBasicBlock* SecondSuccessor() const { return false_destination_; } + virtual void PrintDataTo(StringStream* stream) const; + Handle<Map> map() const { return map_; } DECLARE_CONCRETE_INSTRUCTION(CompareMapAndBranch, "compare_map_and_branch") @@ -1387,6 +1389,8 @@ class HUnaryMathOperation: public HUnaryOperation { case kMathSqrt: case kMathPowHalf: case kMathLog: + case kMathSin: + case kMathCos: set_representation(Representation::Double()); break; default: @@ -1409,6 +1413,8 @@ class HUnaryMathOperation: public HUnaryOperation { case kMathSqrt: case kMathPowHalf: case kMathLog: + case kMathSin: + case kMathCos: return Representation::Double(); break; case kMathAbs: diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index 32108dc1cde..e34acd67d44 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -3165,6 +3165,9 @@ HInstruction* HGraphBuilder::BuildStoreNamedField(HValue* object, if (lookup->type() == MAP_TRANSITION) { Handle<Map> transition(lookup->GetTransitionMapFromMap(*type)); 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; } @@ -3529,9 +3532,10 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, maps.Add(map); HSubgraph* subgraph = CreateBranchSubgraph(environment()); SubgraphScope scope(this, subgraph); - HInstruction* instr = + HLoadNamedField* instr = BuildLoadNamedField(object, expr, map, &lookup, false); instr->set_position(expr->position()); + instr->ClearFlag(HValue::kUseGVN); // Don't do GVN on polymorphic loads. PushAndAdd(instr); subgraphs.Add(subgraph); } else { @@ -3570,11 +3574,11 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, } -HInstruction* HGraphBuilder::BuildLoadNamedField(HValue* object, - Property* expr, - Handle<Map> type, - LookupResult* lookup, - bool smi_and_map_check) { +HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, + Property* expr, + Handle<Map> type, + LookupResult* lookup, + bool smi_and_map_check) { if (smi_and_map_check) { AddInstruction(new HCheckNonSmi(object)); AddInstruction(new HCheckMap(object, type)); @@ -4093,6 +4097,8 @@ bool HGraphBuilder::TryMathFunctionInline(Call* expr) { case kMathAbs: case kMathSqrt: case kMathLog: + case kMathSin: + case kMathCos: if (argument_count == 2) { HValue* argument = Pop(); Drop(1); // Receiver. @@ -4169,7 +4175,7 @@ bool HGraphBuilder::TryCallApply(Call* expr) { if (args->length() != 2) return false; 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()); if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; diff --git a/deps/v8/src/hydrogen.h b/deps/v8/src/hydrogen.h index 2c9aeac75c2..ebabf3d2923 100644 --- a/deps/v8/src/hydrogen.h +++ b/deps/v8/src/hydrogen.h @@ -786,11 +786,11 @@ class HGraphBuilder: public AstVisitor { HValue* left, HValue* right); HInstruction* BuildIncrement(HValue* value, bool increment); - HInstruction* BuildLoadNamedField(HValue* object, - Property* expr, - Handle<Map> type, - LookupResult* result, - bool smi_and_map_check); + HLoadNamedField* BuildLoadNamedField(HValue* object, + Property* expr, + Handle<Map> type, + LookupResult* result, + bool smi_and_map_check); HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr); HInstruction* BuildLoadKeyedFastElement(HValue* object, HValue* key, diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc index d75acab0826..a371c963931 100644 --- a/deps/v8/src/ia32/code-stubs-ia32.cc +++ b/deps/v8/src/ia32/code-stubs-ia32.cc @@ -2472,41 +2472,65 @@ void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { void TranscendentalCacheStub::Generate(MacroAssembler* masm) { - // Input on stack: - // esp[4]: argument (should be number). - // esp[0]: return address. - // Test that eax is a number. + // TAGGED case: + // Input: + // esp[4]: tagged number input argument (should be number). + // esp[0]: return address. + // 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_clear_stack; - NearLabel input_not_smi; - NearLabel loaded; - __ mov(eax, Operand(esp, kPointerSize)); - __ test(eax, Immediate(kSmiTagMask)); - __ j(not_zero, &input_not_smi); - // Input is a smi. Untag and load it onto the FPU stack. - // Then load the low and high words of the double into ebx, edx. - STATIC_ASSERT(kSmiTagSize == 1); - __ sar(eax, 1); - __ sub(Operand(esp), Immediate(2 * kPointerSize)); - __ mov(Operand(esp, 0), eax); - __ fild_s(Operand(esp, 0)); - __ fst_d(Operand(esp, 0)); - __ pop(edx); - __ pop(ebx); - __ jmp(&loaded); - __ bind(&input_not_smi); - // Check if input is a HeapNumber. - __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); - __ cmp(Operand(ebx), Immediate(Factory::heap_number_map())); - __ j(not_equal, &runtime_call); - // Input is a HeapNumber. Push it on the FPU stack and load its - // low and high words into ebx, edx. - __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); - __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset)); - __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset)); + Label skip_cache; + const bool tagged = (argument_type_ == TAGGED); + if (tagged) { + // Test that eax is a number. + NearLabel input_not_smi; + NearLabel loaded; + __ mov(eax, Operand(esp, kPointerSize)); + __ test(eax, Immediate(kSmiTagMask)); + __ j(not_zero, &input_not_smi); + // Input is a smi. Untag and load it onto the FPU stack. + // Then load the low and high words of the double into ebx, edx. + STATIC_ASSERT(kSmiTagSize == 1); + __ sar(eax, 1); + __ sub(Operand(esp), Immediate(2 * kPointerSize)); + __ mov(Operand(esp, 0), eax); + __ fild_s(Operand(esp, 0)); + __ fst_d(Operand(esp, 0)); + __ pop(edx); + __ pop(ebx); + __ jmp(&loaded); + __ bind(&input_not_smi); + // Check if input is a HeapNumber. + __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); + __ cmp(Operand(ebx), Immediate(Factory::heap_number_map())); + __ j(not_equal, &runtime_call); + // Input is a HeapNumber. Push it on the FPU stack and load its + // low and high words into ebx, edx. + __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); + __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset)); + __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset)); + + __ bind(&loaded); + } 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); + } - __ bind(&loaded); - // ST[0] == double value + // ST[0] or xmm1 == double value // ebx = low 32 bits of double value // edx = high 32 bits of double value // Compute hash (the shifts are arithmetic): @@ -2522,7 +2546,7 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) { ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize)); __ and_(Operand(ecx), Immediate(TranscendentalCache::kCacheSize - 1)); - // ST[0] == double value. + // ST[0] or xmm1 == double value. // ebx = low 32 bits of double value. // edx = high 32 bits of double value. // ecx = TranscendentalCache::hash(double value). @@ -2559,31 +2583,80 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) { __ j(not_equal, &cache_miss); // Cache hit! __ mov(eax, Operand(ecx, 2 * kIntSize)); - __ fstp(0); - __ ret(kPointerSize); + if (tagged) { + __ fstp(0); + __ ret(kPointerSize); + } else { // UNTAGGED. + __ 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, &runtime_call_clear_stack); + if (tagged) { + __ 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); __ mov(Operand(ecx, 0), ebx); __ mov(Operand(ecx, kIntSize), edx); __ mov(Operand(ecx, 2 * kIntSize), eax); __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); - __ ret(kPointerSize); + if (tagged) { + __ 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(); + } - __ bind(&runtime_call_clear_stack); - __ fstp(0); - __ bind(&runtime_call); - __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); + // Call runtime, doing whatever allocation and cleanup is necessary. + if (tagged) { + __ bind(&runtime_call_clear_stack); + __ fstp(0); + __ bind(&runtime_call); + __ 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() { switch (type_) { - // Add more cases when necessary. case TranscendentalCache::SIN: return Runtime::kMath_sin; case TranscendentalCache::COS: return Runtime::kMath_cos; case TranscendentalCache::LOG: return Runtime::kMath_log; @@ -2596,14 +2669,14 @@ Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) { // Only free register is edi. - // Input value is on FP stack, and also in ebx/edx. Address of result - // (a newly allocated HeapNumber) is in eax. - NearLabel done; + // Input value is on FP stack, and also in ebx/edx. + // Input value is possibly in xmm1. + // Address of result (a newly allocated HeapNumber) may be in eax. if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) { // Both fsin and fcos require arguments in the range +/-2^63 and // return NaN for infinities and NaN. They can share all code except // 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 // work. We must reduce it to the appropriate range. __ 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 // 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 diff --git a/deps/v8/src/ia32/code-stubs-ia32.h b/deps/v8/src/ia32/code-stubs-ia32.h index 04f23ace9b4..f66a8c7e45a 100644 --- a/deps/v8/src/ia32/code-stubs-ia32.h +++ b/deps/v8/src/ia32/code-stubs-ia32.h @@ -40,32 +40,21 @@ namespace internal { // TranscendentalCache runtime function. class TranscendentalCacheStub: public CodeStub { public: - explicit TranscendentalCacheStub(TranscendentalCache::Type type) - : type_(type) {} - void Generate(MacroAssembler* masm); - private: - TranscendentalCache::Type type_; - - Major MajorKey() { return TranscendentalCache; } - int MinorKey() { return type_; } - Runtime::FunctionId RuntimeFunction(); - void GenerateOperation(MacroAssembler* masm); -}; - + enum ArgumentType { + TAGGED = 0, + UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits + }; -// Check the transcendental cache, or generate the result, using SSE2. -// The argument and result will be in xmm1. -// Only supports TranscendentalCache::LOG at this point. -class TranscendentalCacheSSE2Stub: public CodeStub { - public: - explicit TranscendentalCacheSSE2Stub(TranscendentalCache::Type type) - : type_(type) {} + explicit TranscendentalCacheStub(TranscendentalCache::Type type, + ArgumentType argument_type) + : type_(type), argument_type_(argument_type) {} void Generate(MacroAssembler* masm); private: TranscendentalCache::Type type_; + ArgumentType argument_type_; - Major MajorKey() { return TranscendentalCacheSSE2; } - int MinorKey() { return type_; } + Major MajorKey() { return TranscendentalCache; } + int MinorKey() { return type_ | argument_type_; } Runtime::FunctionId RuntimeFunction(); void GenerateOperation(MacroAssembler* masm); }; diff --git a/deps/v8/src/ia32/codegen-ia32.cc b/deps/v8/src/ia32/codegen-ia32.cc index 4c9d05558bd..2f14e82e14a 100644 --- a/deps/v8/src/ia32/codegen-ia32.cc +++ b/deps/v8/src/ia32/codegen-ia32.cc @@ -7912,7 +7912,8 @@ void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) { void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) { ASSERT_EQ(args->length(), 1); Load(args->at(0)); - TranscendentalCacheStub stub(TranscendentalCache::SIN); + TranscendentalCacheStub stub(TranscendentalCache::SIN, + TranscendentalCacheStub::TAGGED); Result result = frame_->CallStub(&stub, 1); frame_->Push(&result); } @@ -7921,7 +7922,8 @@ void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) { void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) { ASSERT_EQ(args->length(), 1); Load(args->at(0)); - TranscendentalCacheStub stub(TranscendentalCache::COS); + TranscendentalCacheStub stub(TranscendentalCache::COS, + TranscendentalCacheStub::TAGGED); Result result = frame_->CallStub(&stub, 1); frame_->Push(&result); } @@ -7930,7 +7932,8 @@ void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) { void CodeGenerator::GenerateMathLog(ZoneList<Expression*>* args) { ASSERT_EQ(args->length(), 1); Load(args->at(0)); - TranscendentalCacheStub stub(TranscendentalCache::LOG); + TranscendentalCacheStub stub(TranscendentalCache::LOG, + TranscendentalCacheStub::TAGGED); Result result = frame_->CallStub(&stub, 1); frame_->Push(&result); } diff --git a/deps/v8/src/ia32/full-codegen-ia32.cc b/deps/v8/src/ia32/full-codegen-ia32.cc index be059cdfe3a..13a11777ab6 100644 --- a/deps/v8/src/ia32/full-codegen-ia32.cc +++ b/deps/v8/src/ia32/full-codegen-ia32.cc @@ -3067,7 +3067,8 @@ void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) { void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) { // Load the argument on the stack and call the stub. - TranscendentalCacheStub stub(TranscendentalCache::SIN); + TranscendentalCacheStub stub(TranscendentalCache::SIN, + TranscendentalCacheStub::TAGGED); ASSERT(args->length() == 1); VisitForStackValue(args->at(0)); __ CallStub(&stub); @@ -3077,7 +3078,8 @@ void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) { void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) { // Load the argument on the stack and call the stub. - TranscendentalCacheStub stub(TranscendentalCache::COS); + TranscendentalCacheStub stub(TranscendentalCache::COS, + TranscendentalCacheStub::TAGGED); ASSERT(args->length() == 1); VisitForStackValue(args->at(0)); __ CallStub(&stub); @@ -3087,7 +3089,8 @@ void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) { void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) { // Load the argument on the stack and call the stub. - TranscendentalCacheStub stub(TranscendentalCache::LOG); + TranscendentalCacheStub stub(TranscendentalCache::LOG, + TranscendentalCacheStub::TAGGED); ASSERT(args->length() == 1); VisitForStackValue(args->at(0)); __ CallStub(&stub); diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.cc b/deps/v8/src/ia32/lithium-codegen-ia32.cc index 0e9773748e0..d64f528e71c 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.cc +++ b/deps/v8/src/ia32/lithium-codegen-ia32.cc @@ -686,7 +686,8 @@ void LCodeGen::DoCallStub(LCallStub* instr) { break; } case CodeStub::TranscendentalCache: { - TranscendentalCacheStub stub(instr->transcendental_type()); + TranscendentalCacheStub stub(instr->transcendental_type(), + TranscendentalCacheStub::TAGGED); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); break; } @@ -2314,7 +2315,24 @@ void LCodeGen::DoPower(LPower* instr) { void LCodeGen::DoMathLog(LUnaryMathOperation* instr) { 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); } @@ -2336,6 +2354,12 @@ void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { case kMathPowHalf: DoMathPowHalf(instr); break; + case kMathCos: + DoMathCos(instr); + break; + case kMathSin: + DoMathSin(instr); + break; case kMathLog: DoMathLog(instr); break; diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.h b/deps/v8/src/ia32/lithium-codegen-ia32.h index 5ac7b1edb24..6d8173a1cf2 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.h +++ b/deps/v8/src/ia32/lithium-codegen-ia32.h @@ -177,6 +177,8 @@ class LCodeGen BASE_EMBEDDED { void DoMathSqrt(LUnaryMathOperation* instr); void DoMathPowHalf(LUnaryMathOperation* instr); void DoMathLog(LUnaryMathOperation* instr); + void DoMathCos(LUnaryMathOperation* instr); + void DoMathSin(LUnaryMathOperation* instr); // Support for recording safepoint and position information. void RecordSafepoint(LPointerMap* pointers, int deoptimization_index); diff --git a/deps/v8/src/ia32/lithium-ia32.cc b/deps/v8/src/ia32/lithium-ia32.cc index e1148fc186f..3b272d0b022 100644 --- a/deps/v8/src/ia32/lithium-ia32.cc +++ b/deps/v8/src/ia32/lithium-ia32.cc @@ -1361,7 +1361,7 @@ LInstruction* LChunkBuilder::DoCallConstantFunction( LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { BuiltinFunctionId op = instr->op(); - if (op == kMathLog) { + if (op == kMathLog || op == kMathSin || op == kMathCos) { LOperand* input = UseFixedDouble(instr->value(), xmm1); LInstruction* result = new LUnaryMathOperation(input); return MarkAsCall(DefineFixedDouble(result, xmm1), instr); diff --git a/deps/v8/src/objects-debug.cc b/deps/v8/src/objects-debug.cc index cb7b35ec433..53296d9272f 100644 --- a/deps/v8/src/objects-debug.cc +++ b/deps/v8/src/objects-debug.cc @@ -35,32 +35,34 @@ namespace v8 { namespace internal { -#ifdef DEBUG +#ifdef OBJECT_PRINT static const char* TypeToString(InstanceType type); -void MaybeObject::Print() { +void MaybeObject::Print(FILE* out) { Object* this_as_object; if (ToObject(&this_as_object)) { if (this_as_object->IsSmi()) { - Smi::cast(this_as_object)->SmiPrint(); + Smi::cast(this_as_object)->SmiPrint(out); } else { - HeapObject::cast(this_as_object)->HeapObjectPrint(); + HeapObject::cast(this_as_object)->HeapObjectPrint(out); } } else { - Failure::cast(this)->FailurePrint(); + Failure::cast(this)->FailurePrint(out); } - Flush(); + Flush(out); } -void MaybeObject::PrintLn() { - Print(); - PrintF("\n"); +void MaybeObject::PrintLn(FILE* out) { + Print(out); + PrintF(out, "\n"); } +#endif // OBJECT_PRINT +#ifdef DEBUG void MaybeObject::Verify() { Object* this_as_object; if (ToObject(&this_as_object)) { @@ -92,114 +94,120 @@ void Smi::SmiVerify() { void Failure::FailureVerify() { ASSERT(IsFailure()); } +#endif // DEBUG -void HeapObject::PrintHeader(const char* id) { - PrintF("%p: [%s]\n", reinterpret_cast<void*>(this), id); +#ifdef OBJECT_PRINT +void HeapObject::PrintHeader(FILE* out, const char* id) { + PrintF(out, "%p: [%s]\n", reinterpret_cast<void*>(this), id); } -void HeapObject::HeapObjectPrint() { +void HeapObject::HeapObjectPrint(FILE* out) { InstanceType instance_type = map()->instance_type(); HandleScope scope; if (instance_type < FIRST_NONSTRING_TYPE) { - String::cast(this)->StringPrint(); + String::cast(this)->StringPrint(out); return; } switch (instance_type) { case MAP_TYPE: - Map::cast(this)->MapPrint(); + Map::cast(this)->MapPrint(out); break; case HEAP_NUMBER_TYPE: - HeapNumber::cast(this)->HeapNumberPrint(); + HeapNumber::cast(this)->HeapNumberPrint(out); break; case FIXED_ARRAY_TYPE: - FixedArray::cast(this)->FixedArrayPrint(); + FixedArray::cast(this)->FixedArrayPrint(out); break; case BYTE_ARRAY_TYPE: - ByteArray::cast(this)->ByteArrayPrint(); + ByteArray::cast(this)->ByteArrayPrint(out); break; case PIXEL_ARRAY_TYPE: - PixelArray::cast(this)->PixelArrayPrint(); + PixelArray::cast(this)->PixelArrayPrint(out); break; case EXTERNAL_BYTE_ARRAY_TYPE: - ExternalByteArray::cast(this)->ExternalByteArrayPrint(); + ExternalByteArray::cast(this)->ExternalByteArrayPrint(out); break; case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: - ExternalUnsignedByteArray::cast(this)->ExternalUnsignedByteArrayPrint(); + ExternalUnsignedByteArray::cast(this) + ->ExternalUnsignedByteArrayPrint(out); break; case EXTERNAL_SHORT_ARRAY_TYPE: - ExternalShortArray::cast(this)->ExternalShortArrayPrint(); + ExternalShortArray::cast(this)->ExternalShortArrayPrint(out); break; case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: - ExternalUnsignedShortArray::cast(this)->ExternalUnsignedShortArrayPrint(); + ExternalUnsignedShortArray::cast(this) + ->ExternalUnsignedShortArrayPrint(out); break; case EXTERNAL_INT_ARRAY_TYPE: - ExternalIntArray::cast(this)->ExternalIntArrayPrint(); + ExternalIntArray::cast(this)->ExternalIntArrayPrint(out); break; case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: - ExternalUnsignedIntArray::cast(this)->ExternalUnsignedIntArrayPrint(); + ExternalUnsignedIntArray::cast(this)->ExternalUnsignedIntArrayPrint(out); break; case EXTERNAL_FLOAT_ARRAY_TYPE: - ExternalFloatArray::cast(this)->ExternalFloatArrayPrint(); + ExternalFloatArray::cast(this)->ExternalFloatArrayPrint(out); break; case FILLER_TYPE: - PrintF("filler"); + PrintF(out, "filler"); break; case JS_OBJECT_TYPE: // fall through case JS_CONTEXT_EXTENSION_OBJECT_TYPE: case JS_ARRAY_TYPE: case JS_REGEXP_TYPE: - JSObject::cast(this)->JSObjectPrint(); + JSObject::cast(this)->JSObjectPrint(out); break; case ODDBALL_TYPE: - Oddball::cast(this)->to_string()->Print(); + Oddball::cast(this)->to_string()->Print(out); break; case JS_FUNCTION_TYPE: - JSFunction::cast(this)->JSFunctionPrint(); + JSFunction::cast(this)->JSFunctionPrint(out); break; case JS_GLOBAL_PROXY_TYPE: - JSGlobalProxy::cast(this)->JSGlobalProxyPrint(); + JSGlobalProxy::cast(this)->JSGlobalProxyPrint(out); break; case JS_GLOBAL_OBJECT_TYPE: - JSGlobalObject::cast(this)->JSGlobalObjectPrint(); + JSGlobalObject::cast(this)->JSGlobalObjectPrint(out); break; case JS_BUILTINS_OBJECT_TYPE: - JSBuiltinsObject::cast(this)->JSBuiltinsObjectPrint(); + JSBuiltinsObject::cast(this)->JSBuiltinsObjectPrint(out); break; case JS_VALUE_TYPE: - PrintF("Value wrapper around:"); - JSValue::cast(this)->value()->Print(); + PrintF(out, "Value wrapper around:"); + JSValue::cast(this)->value()->Print(out); break; case CODE_TYPE: - Code::cast(this)->CodePrint(); + Code::cast(this)->CodePrint(out); break; case PROXY_TYPE: - Proxy::cast(this)->ProxyPrint(); + Proxy::cast(this)->ProxyPrint(out); break; case SHARED_FUNCTION_INFO_TYPE: - SharedFunctionInfo::cast(this)->SharedFunctionInfoPrint(); + SharedFunctionInfo::cast(this)->SharedFunctionInfoPrint(out); break; case JS_GLOBAL_PROPERTY_CELL_TYPE: - JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellPrint(); + JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellPrint(out); break; #define MAKE_STRUCT_CASE(NAME, Name, name) \ case NAME##_TYPE: \ - Name::cast(this)->Name##Print(); \ + Name::cast(this)->Name##Print(out); \ break; STRUCT_LIST(MAKE_STRUCT_CASE) #undef MAKE_STRUCT_CASE default: - PrintF("UNKNOWN TYPE %d", map()->instance_type()); + PrintF(out, "UNKNOWN TYPE %d", map()->instance_type()); UNREACHABLE(); break; } } +#endif // OBJECT_PRINT +#ifdef DEBUG void HeapObject::HeapObjectVerify() { InstanceType instance_type = map()->instance_type(); @@ -312,53 +320,57 @@ void HeapObject::VerifyHeapPointer(Object* p) { void HeapNumber::HeapNumberVerify() { ASSERT(IsHeapNumber()); } +#endif // DEBUG -void ByteArray::ByteArrayPrint() { - PrintF("byte array, data starts at %p", GetDataStartAddress()); +#ifdef OBJECT_PRINT +void ByteArray::ByteArrayPrint(FILE* out) { + PrintF(out, "byte array, data starts at %p", GetDataStartAddress()); } -void PixelArray::PixelArrayPrint() { - PrintF("pixel array"); +void PixelArray::PixelArrayPrint(FILE* out) { + PrintF(out, "pixel array"); } -void ExternalByteArray::ExternalByteArrayPrint() { - PrintF("external byte array"); +void ExternalByteArray::ExternalByteArrayPrint(FILE* out) { + PrintF(out, "external byte array"); } -void ExternalUnsignedByteArray::ExternalUnsignedByteArrayPrint() { - PrintF("external unsigned byte array"); +void ExternalUnsignedByteArray::ExternalUnsignedByteArrayPrint(FILE* out) { + PrintF(out, "external unsigned byte array"); } -void ExternalShortArray::ExternalShortArrayPrint() { - PrintF("external short array"); +void ExternalShortArray::ExternalShortArrayPrint(FILE* out) { + PrintF(out, "external short array"); } -void ExternalUnsignedShortArray::ExternalUnsignedShortArrayPrint() { - PrintF("external unsigned short array"); +void ExternalUnsignedShortArray::ExternalUnsignedShortArrayPrint(FILE* out) { + PrintF(out, "external unsigned short array"); } -void ExternalIntArray::ExternalIntArrayPrint() { - PrintF("external int array"); +void ExternalIntArray::ExternalIntArrayPrint(FILE* out) { + PrintF(out, "external int array"); } -void ExternalUnsignedIntArray::ExternalUnsignedIntArrayPrint() { - PrintF("external unsigned int array"); +void ExternalUnsignedIntArray::ExternalUnsignedIntArrayPrint(FILE* out) { + PrintF(out, "external unsigned int array"); } -void ExternalFloatArray::ExternalFloatArrayPrint() { - PrintF("external float array"); +void ExternalFloatArray::ExternalFloatArrayPrint(FILE* out) { + PrintF(out, "external float array"); } +#endif // OBJECT_PRINT +#ifdef DEBUG void ByteArray::ByteArrayVerify() { ASSERT(IsByteArray()); } @@ -402,38 +414,40 @@ void ExternalUnsignedIntArray::ExternalUnsignedIntArrayVerify() { void ExternalFloatArray::ExternalFloatArrayVerify() { ASSERT(IsExternalFloatArray()); } +#endif // DEBUG -void JSObject::PrintProperties() { +#ifdef OBJECT_PRINT +void JSObject::PrintProperties(FILE* out) { if (HasFastProperties()) { DescriptorArray* descs = map()->instance_descriptors(); for (int i = 0; i < descs->number_of_descriptors(); i++) { - PrintF(" "); - descs->GetKey(i)->StringPrint(); - PrintF(": "); + PrintF(out, " "); + descs->GetKey(i)->StringPrint(out); + PrintF(out, ": "); switch (descs->GetType(i)) { case FIELD: { int index = descs->GetFieldIndex(i); - FastPropertyAt(index)->ShortPrint(); - PrintF(" (field at offset %d)\n", index); + FastPropertyAt(index)->ShortPrint(out); + PrintF(out, " (field at offset %d)\n", index); break; } case CONSTANT_FUNCTION: - descs->GetConstantFunction(i)->ShortPrint(); - PrintF(" (constant function)\n"); + descs->GetConstantFunction(i)->ShortPrint(out); + PrintF(out, " (constant function)\n"); break; case CALLBACKS: - descs->GetCallbacksObject(i)->ShortPrint(); - PrintF(" (callback)\n"); + descs->GetCallbacksObject(i)->ShortPrint(out); + PrintF(out, " (callback)\n"); break; case MAP_TRANSITION: - PrintF(" (map transition)\n"); + PrintF(out, " (map transition)\n"); break; case CONSTANT_TRANSITION: - PrintF(" (constant transition)\n"); + PrintF(out, " (constant transition)\n"); break; case NULL_DESCRIPTOR: - PrintF(" (null descriptor)\n"); + PrintF(out, " (null descriptor)\n"); break; default: UNREACHABLE(); @@ -441,34 +455,34 @@ void JSObject::PrintProperties() { } } } else { - property_dictionary()->Print(); + property_dictionary()->Print(out); } } -void JSObject::PrintElements() { +void JSObject::PrintElements(FILE* out) { switch (GetElementsKind()) { case FAST_ELEMENTS: { // Print in array notation for non-sparse arrays. FixedArray* p = FixedArray::cast(elements()); for (int i = 0; i < p->length(); i++) { - PrintF(" %d: ", i); - p->get(i)->ShortPrint(); - PrintF("\n"); + PrintF(out, " %d: ", i); + p->get(i)->ShortPrint(out); + PrintF(out, "\n"); } break; } case PIXEL_ELEMENTS: { PixelArray* p = PixelArray::cast(elements()); for (int i = 0; i < p->length(); i++) { - PrintF(" %d: %d\n", i, p->get(i)); + PrintF(out, " %d: %d\n", i, p->get(i)); } break; } case EXTERNAL_BYTE_ELEMENTS: { ExternalByteArray* p = ExternalByteArray::cast(elements()); for (int i = 0; i < p->length(); i++) { - PrintF(" %d: %d\n", i, static_cast<int>(p->get(i))); + PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i))); } break; } @@ -476,14 +490,14 @@ void JSObject::PrintElements() { ExternalUnsignedByteArray* p = ExternalUnsignedByteArray::cast(elements()); for (int i = 0; i < p->length(); i++) { - PrintF(" %d: %d\n", i, static_cast<int>(p->get(i))); + PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i))); } break; } case EXTERNAL_SHORT_ELEMENTS: { ExternalShortArray* p = ExternalShortArray::cast(elements()); for (int i = 0; i < p->length(); i++) { - PrintF(" %d: %d\n", i, static_cast<int>(p->get(i))); + PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i))); } break; } @@ -491,14 +505,14 @@ void JSObject::PrintElements() { ExternalUnsignedShortArray* p = ExternalUnsignedShortArray::cast(elements()); for (int i = 0; i < p->length(); i++) { - PrintF(" %d: %d\n", i, static_cast<int>(p->get(i))); + PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i))); } break; } case EXTERNAL_INT_ELEMENTS: { ExternalIntArray* p = ExternalIntArray::cast(elements()); for (int i = 0; i < p->length(); i++) { - PrintF(" %d: %d\n", i, static_cast<int>(p->get(i))); + PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i))); } break; } @@ -506,19 +520,19 @@ void JSObject::PrintElements() { ExternalUnsignedIntArray* p = ExternalUnsignedIntArray::cast(elements()); for (int i = 0; i < p->length(); i++) { - PrintF(" %d: %d\n", i, static_cast<int>(p->get(i))); + PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i))); } break; } case EXTERNAL_FLOAT_ELEMENTS: { ExternalFloatArray* p = ExternalFloatArray::cast(elements()); for (int i = 0; i < p->length(); i++) { - PrintF(" %d: %f\n", i, p->get(i)); + PrintF(out, " %d: %f\n", i, p->get(i)); } break; } case DICTIONARY_ELEMENTS: - elements()->Print(); + elements()->Print(out); break; default: UNREACHABLE(); @@ -527,17 +541,19 @@ void JSObject::PrintElements() { } -void JSObject::JSObjectPrint() { - PrintF("%p: [JSObject]\n", reinterpret_cast<void*>(this)); - PrintF(" - map = %p\n", reinterpret_cast<void*>(map())); - PrintF(" - prototype = %p\n", reinterpret_cast<void*>(GetPrototype())); - PrintF(" {\n"); - PrintProperties(); - PrintElements(); - PrintF(" }\n"); +void JSObject::JSObjectPrint(FILE* out) { + PrintF(out, "%p: [JSObject]\n", reinterpret_cast<void*>(this)); + PrintF(out, " - map = %p\n", reinterpret_cast<void*>(map())); + PrintF(out, " - prototype = %p\n", reinterpret_cast<void*>(GetPrototype())); + PrintF(out, " {\n"); + PrintProperties(out); + PrintElements(out); + PrintF(out, " }\n"); } +#endif // OBJECT_PRINT +#ifdef DEBUG void JSObject::JSObjectVerify() { VerifyHeapPointer(properties()); VerifyHeapPointer(elements()); @@ -551,8 +567,10 @@ void JSObject::JSObjectVerify() { elements()->map() == Heap::fixed_cow_array_map())); ASSERT(map()->has_fast_elements() == HasFastElements()); } +#endif // DEBUG +#ifdef OBJECT_PRINT static const char* TypeToString(InstanceType type) { switch (type) { case INVALID_TYPE: return "INVALID"; @@ -608,42 +626,44 @@ static const char* TypeToString(InstanceType type) { } -void Map::MapPrint() { - HeapObject::PrintHeader("Map"); - PrintF(" - type: %s\n", TypeToString(instance_type())); - PrintF(" - instance size: %d\n", instance_size()); - PrintF(" - inobject properties: %d\n", inobject_properties()); - PrintF(" - pre-allocated property fields: %d\n", +void Map::MapPrint(FILE* out) { + HeapObject::PrintHeader(out, "Map"); + PrintF(out, " - type: %s\n", TypeToString(instance_type())); + PrintF(out, " - instance size: %d\n", instance_size()); + PrintF(out, " - inobject properties: %d\n", inobject_properties()); + PrintF(out, " - pre-allocated property fields: %d\n", pre_allocated_property_fields()); - PrintF(" - unused property fields: %d\n", unused_property_fields()); + PrintF(out, " - unused property fields: %d\n", unused_property_fields()); if (is_hidden_prototype()) { - PrintF(" - hidden_prototype\n"); + PrintF(out, " - hidden_prototype\n"); } if (has_named_interceptor()) { - PrintF(" - named_interceptor\n"); + PrintF(out, " - named_interceptor\n"); } if (has_indexed_interceptor()) { - PrintF(" - indexed_interceptor\n"); + PrintF(out, " - indexed_interceptor\n"); } if (is_undetectable()) { - PrintF(" - undetectable\n"); + PrintF(out, " - undetectable\n"); } if (has_instance_call_handler()) { - PrintF(" - instance_call_handler\n"); + PrintF(out, " - instance_call_handler\n"); } if (is_access_check_needed()) { - PrintF(" - access_check_needed\n"); + PrintF(out, " - access_check_needed\n"); } - PrintF(" - instance descriptors: "); - instance_descriptors()->ShortPrint(); - PrintF("\n - prototype: "); - prototype()->ShortPrint(); - PrintF("\n - constructor: "); - constructor()->ShortPrint(); - PrintF("\n"); + PrintF(out, " - instance descriptors: "); + instance_descriptors()->ShortPrint(out); + PrintF(out, "\n - prototype: "); + prototype()->ShortPrint(out); + PrintF(out, "\n - constructor: "); + constructor()->ShortPrint(out); + PrintF(out, "\n"); } +#endif // OBJECT_PRINT +#ifdef DEBUG void Map::MapVerify() { ASSERT(!Heap::InNewSpace(this)); ASSERT(FIRST_TYPE <= instance_type() && instance_type() <= LAST_TYPE); @@ -665,17 +685,21 @@ void Map::SharedMapVerify() { ASSERT_EQ(StaticVisitorBase::GetVisitorId(instance_type(), instance_size()), visitor_id()); } +#endif // DEBUG -void CodeCache::CodeCachePrint() { - HeapObject::PrintHeader("CodeCache"); - PrintF("\n - default_cache: "); - default_cache()->ShortPrint(); - PrintF("\n - normal_type_cache: "); - normal_type_cache()->ShortPrint(); +#ifdef OBJECT_PRINT +void CodeCache::CodeCachePrint(FILE* out) { + HeapObject::PrintHeader(out, "CodeCache"); + PrintF(out, "\n - default_cache: "); + default_cache()->ShortPrint(out); + PrintF(out, "\n - normal_type_cache: "); + normal_type_cache()->ShortPrint(out); } +#endif // OBJECT_PRINT +#ifdef DEBUG void CodeCache::CodeCacheVerify() { VerifyHeapPointer(default_cache()); VerifyHeapPointer(normal_type_cache()); @@ -683,19 +707,23 @@ void CodeCache::CodeCacheVerify() { ASSERT(normal_type_cache()->IsUndefined() || normal_type_cache()->IsCodeCacheHashTable()); } +#endif // DEBUG -void FixedArray::FixedArrayPrint() { - HeapObject::PrintHeader("FixedArray"); - PrintF(" - length: %d", length()); +#ifdef OBJECT_PRINT +void FixedArray::FixedArrayPrint(FILE* out) { + HeapObject::PrintHeader(out, "FixedArray"); + PrintF(out, " - length: %d", length()); for (int i = 0; i < length(); i++) { - PrintF("\n [%d]: ", i); - get(i)->ShortPrint(); + PrintF(out, "\n [%d]: ", i); + get(i)->ShortPrint(out); } - PrintF("\n"); + PrintF(out, "\n"); } +#endif // OBJECT_PRINT +#ifdef DEBUG void FixedArray::FixedArrayVerify() { for (int i = 0; i < length(); i++) { Object* e = get(i); @@ -706,39 +734,57 @@ void FixedArray::FixedArrayVerify() { } } } +#endif // DEBUG -void JSValue::JSValuePrint() { - HeapObject::PrintHeader("ValueObject"); - value()->Print(); +#ifdef OBJECT_PRINT +void JSValue::JSValuePrint(FILE* out) { + HeapObject::PrintHeader(out, "ValueObject"); + value()->Print(out); } +#endif // OBJECT_PRINT +#ifdef DEBUG void JSValue::JSValueVerify() { Object* v = value(); if (v->IsHeapObject()) { VerifyHeapPointer(v); } } +#endif // DEBUG -void String::StringPrint() { +#ifdef OBJECT_PRINT +void String::StringPrint(FILE* out) { if (StringShape(this).IsSymbol()) { - PrintF("#"); + PrintF(out, "#"); } else if (StringShape(this).IsCons()) { - PrintF("c\""); + PrintF(out, "c\""); } else { - PrintF("\""); + PrintF(out, "\""); } - for (int i = 0; i < length(); i++) { - PrintF("%c", Get(i)); + const char truncated_epilogue[] = "...<truncated>"; + int len = length(); + if (!FLAG_use_verbose_printer) { + if (len > 100) { + len = 100 - sizeof(truncated_epilogue); + } + } + for (int i = 0; i < len; i++) { + PrintF(out, "%c", Get(i)); + } + if (len != length()) { + PrintF(out, "%s", truncated_epilogue); } - if (!StringShape(this).IsSymbol()) PrintF("\""); + if (!StringShape(this).IsSymbol()) PrintF(out, "\""); } +#endif // OBJECT_PRINT +#ifdef DEBUG void String::StringVerify() { CHECK(IsString()); CHECK(length() >= 0 && length() <= Smi::kMaxValue); @@ -746,32 +792,36 @@ void String::StringVerify() { CHECK(!Heap::InNewSpace(this)); } } +#endif // DEBUG -void JSFunction::JSFunctionPrint() { - HeapObject::PrintHeader("Function"); - PrintF(" - map = 0x%p\n", reinterpret_cast<void*>(map())); - PrintF(" - initial_map = "); +#ifdef OBJECT_PRINT +void JSFunction::JSFunctionPrint(FILE* out) { + HeapObject::PrintHeader(out, "Function"); + PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map())); + PrintF(out, " - initial_map = "); if (has_initial_map()) { - initial_map()->ShortPrint(); + initial_map()->ShortPrint(out); } - PrintF("\n - shared_info = "); - shared()->ShortPrint(); - PrintF("\n - name = "); - shared()->name()->Print(); - PrintF("\n - context = "); - unchecked_context()->ShortPrint(); - PrintF("\n - code = "); - code()->ShortPrint(); - PrintF("\n"); + PrintF(out, "\n - shared_info = "); + shared()->ShortPrint(out); + PrintF(out, "\n - name = "); + shared()->name()->Print(out); + PrintF(out, "\n - context = "); + unchecked_context()->ShortPrint(out); + PrintF(out, "\n - code = "); + code()->ShortPrint(out); + PrintF(out, "\n"); - PrintProperties(); - PrintElements(); + PrintProperties(out); + PrintElements(out); - PrintF("\n"); + PrintF(out, "\n"); } +#endif // OBJECT_PRINT +#ifdef DEBUG void JSFunction::JSFunctionVerify() { CHECK(IsJSFunction()); VerifyObjectField(kPrototypeOrInitialMapOffset); @@ -779,36 +829,41 @@ void JSFunction::JSFunctionVerify() { CHECK(next_function_link()->IsUndefined() || next_function_link()->IsJSFunction()); } +#endif // DEBUG -void SharedFunctionInfo::SharedFunctionInfoPrint() { - HeapObject::PrintHeader("SharedFunctionInfo"); - PrintF(" - name: "); - name()->ShortPrint(); - PrintF("\n - expected_nof_properties: %d", expected_nof_properties()); - PrintF("\n - instance class name = "); - instance_class_name()->Print(); - PrintF("\n - code = "); - code()->ShortPrint(); - PrintF("\n - source code = "); - GetSourceCode()->ShortPrint(); +#ifdef OBJECT_PRINT +void SharedFunctionInfo::SharedFunctionInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "SharedFunctionInfo"); + PrintF(out, " - name: "); + name()->ShortPrint(out); + PrintF(out, "\n - expected_nof_properties: %d", expected_nof_properties()); + PrintF(out, "\n - instance class name = "); + instance_class_name()->Print(out); + PrintF(out, "\n - code = "); + code()->ShortPrint(out); + PrintF(out, "\n - source code = "); + GetSourceCode()->ShortPrint(out); // Script files are often large, hard to read. - // PrintF("\n - script ="); - // script()->Print(); - PrintF("\n - function token position = %d", function_token_position()); - PrintF("\n - start position = %d", start_position()); - PrintF("\n - end position = %d", end_position()); - PrintF("\n - is expression = %d", is_expression()); - PrintF("\n - debug info = "); - debug_info()->ShortPrint(); - PrintF("\n - length = %d", length()); - PrintF("\n - has_only_simple_this_property_assignments = %d", + // PrintF(out, "\n - script ="); + // script()->Print(out); + PrintF(out, "\n - function token position = %d", function_token_position()); + PrintF(out, "\n - start position = %d", start_position()); + PrintF(out, "\n - end position = %d", end_position()); + PrintF(out, "\n - is expression = %d", is_expression()); + PrintF(out, "\n - debug info = "); + debug_info()->ShortPrint(out); + PrintF(out, "\n - length = %d", length()); + PrintF(out, "\n - has_only_simple_this_property_assignments = %d", has_only_simple_this_property_assignments()); - PrintF("\n - this_property_assignments = "); - this_property_assignments()->ShortPrint(); - PrintF("\n"); + PrintF(out, "\n - this_property_assignments = "); + this_property_assignments()->ShortPrint(out); + PrintF(out, "\n"); } +#endif // OBJECT_PRINT + +#ifdef DEBUG void SharedFunctionInfo::SharedFunctionInfoVerify() { CHECK(IsSharedFunctionInfo()); VerifyObjectField(kNameOffset); @@ -819,17 +874,21 @@ void SharedFunctionInfo::SharedFunctionInfoVerify() { VerifyObjectField(kScriptOffset); VerifyObjectField(kDebugInfoOffset); } +#endif // DEBUG -void JSGlobalProxy::JSGlobalProxyPrint() { - PrintF("global_proxy"); - JSObjectPrint(); - PrintF("context : "); - context()->ShortPrint(); - PrintF("\n"); +#ifdef OBJECT_PRINT +void JSGlobalProxy::JSGlobalProxyPrint(FILE* out) { + PrintF(out, "global_proxy"); + JSObjectPrint(out); + PrintF(out, "context : "); + context()->ShortPrint(out); + PrintF(out, "\n"); } +#endif // OBJECT_PRINT +#ifdef DEBUG void JSGlobalProxy::JSGlobalProxyVerify() { CHECK(IsJSGlobalProxy()); JSObjectVerify(); @@ -839,17 +898,21 @@ void JSGlobalProxy::JSGlobalProxyVerify() { CHECK(HasFastElements()); CHECK_EQ(0, FixedArray::cast(elements())->length()); } +#endif // DEBUG -void JSGlobalObject::JSGlobalObjectPrint() { - PrintF("global "); - JSObjectPrint(); - PrintF("global context : "); - global_context()->ShortPrint(); - PrintF("\n"); +#ifdef OBJECT_PRINT +void JSGlobalObject::JSGlobalObjectPrint(FILE* out) { + PrintF(out, "global "); + JSObjectPrint(out); + PrintF(out, "global context : "); + global_context()->ShortPrint(out); + PrintF(out, "\n"); } +#endif // OBJECT_PRINT +#ifdef DEBUG void JSGlobalObject::JSGlobalObjectVerify() { CHECK(IsJSGlobalObject()); JSObjectVerify(); @@ -859,14 +922,18 @@ void JSGlobalObject::JSGlobalObjectVerify() { VerifyObjectField(i); } } +#endif // DEBUG -void JSBuiltinsObject::JSBuiltinsObjectPrint() { - PrintF("builtins "); - JSObjectPrint(); +#ifdef OBJECT_PRINT +void JSBuiltinsObject::JSBuiltinsObjectPrint(FILE* out) { + PrintF(out, "builtins "); + JSObjectPrint(out); } +#endif // OBJECT_PRINT +#ifdef DEBUG void JSBuiltinsObject::JSBuiltinsObjectVerify() { CHECK(IsJSBuiltinsObject()); JSObjectVerify(); @@ -897,21 +964,27 @@ void JSGlobalPropertyCell::JSGlobalPropertyCellVerify() { CHECK(IsJSGlobalPropertyCell()); VerifyObjectField(kValueOffset); } +#endif // DEBUG -void JSGlobalPropertyCell::JSGlobalPropertyCellPrint() { - HeapObject::PrintHeader("JSGlobalPropertyCell"); +#ifdef OBJECT_PRINT +void JSGlobalPropertyCell::JSGlobalPropertyCellPrint(FILE* out) { + HeapObject::PrintHeader(out, "JSGlobalPropertyCell"); } -void Code::CodePrint() { - HeapObject::PrintHeader("Code"); +void Code::CodePrint(FILE* out) { + HeapObject::PrintHeader(out, "Code"); #ifdef ENABLE_DISASSEMBLER - Disassemble(NULL); + if (FLAG_use_verbose_printer) { + Disassemble(NULL, out); + } #endif } +#endif // OBJECT_PRINT +#ifdef DEBUG void Code::CodeVerify() { CHECK(IsAligned(reinterpret_cast<intptr_t>(instruction_start()), kCodeAlignment)); @@ -966,13 +1039,17 @@ void JSRegExp::JSRegExpVerify() { break; } } +#endif // DEBUG -void Proxy::ProxyPrint() { - PrintF("proxy to %p", proxy()); +#ifdef OBJECT_PRINT +void Proxy::ProxyPrint(FILE* out) { + PrintF(out, "proxy to %p", proxy()); } +#endif // OBJECT_PRINT +#ifdef DEBUG void Proxy::ProxyVerify() { ASSERT(IsProxy()); } @@ -986,38 +1063,50 @@ void AccessorInfo::AccessorInfoVerify() { VerifyPointer(data()); VerifyPointer(flag()); } +#endif // DEBUG + -void AccessorInfo::AccessorInfoPrint() { - HeapObject::PrintHeader("AccessorInfo"); - PrintF("\n - getter: "); - getter()->ShortPrint(); - PrintF("\n - setter: "); - setter()->ShortPrint(); - PrintF("\n - name: "); - name()->ShortPrint(); - PrintF("\n - data: "); - data()->ShortPrint(); - PrintF("\n - flag: "); - flag()->ShortPrint(); +#ifdef OBJECT_PRINT +void AccessorInfo::AccessorInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "AccessorInfo"); + PrintF(out, "\n - getter: "); + getter()->ShortPrint(out); + PrintF(out, "\n - setter: "); + setter()->ShortPrint(out); + PrintF(out, "\n - name: "); + name()->ShortPrint(out); + PrintF(out, "\n - data: "); + data()->ShortPrint(out); + PrintF(out, "\n - flag: "); + flag()->ShortPrint(out); } +#endif // OBJECT_PRINT + +#ifdef DEBUG void AccessCheckInfo::AccessCheckInfoVerify() { CHECK(IsAccessCheckInfo()); VerifyPointer(named_callback()); VerifyPointer(indexed_callback()); VerifyPointer(data()); } +#endif // DEBUG -void AccessCheckInfo::AccessCheckInfoPrint() { - HeapObject::PrintHeader("AccessCheckInfo"); - PrintF("\n - named_callback: "); - named_callback()->ShortPrint(); - PrintF("\n - indexed_callback: "); - indexed_callback()->ShortPrint(); - PrintF("\n - data: "); - data()->ShortPrint(); + +#ifdef OBJECT_PRINT +void AccessCheckInfo::AccessCheckInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "AccessCheckInfo"); + PrintF(out, "\n - named_callback: "); + named_callback()->ShortPrint(out); + PrintF(out, "\n - indexed_callback: "); + indexed_callback()->ShortPrint(out); + PrintF(out, "\n - data: "); + data()->ShortPrint(out); } +#endif // OBJECT_PRINT + +#ifdef DEBUG void InterceptorInfo::InterceptorInfoVerify() { CHECK(IsInterceptorInfo()); VerifyPointer(getter()); @@ -1027,38 +1116,50 @@ void InterceptorInfo::InterceptorInfoVerify() { VerifyPointer(enumerator()); VerifyPointer(data()); } +#endif // DEBUG + -void InterceptorInfo::InterceptorInfoPrint() { - HeapObject::PrintHeader("InterceptorInfo"); - PrintF("\n - getter: "); - getter()->ShortPrint(); - PrintF("\n - setter: "); - setter()->ShortPrint(); - PrintF("\n - query: "); - query()->ShortPrint(); - PrintF("\n - deleter: "); - deleter()->ShortPrint(); - PrintF("\n - enumerator: "); - enumerator()->ShortPrint(); - PrintF("\n - data: "); - data()->ShortPrint(); +#ifdef OBJECT_PRINT +void InterceptorInfo::InterceptorInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "InterceptorInfo"); + PrintF(out, "\n - getter: "); + getter()->ShortPrint(out); + PrintF(out, "\n - setter: "); + setter()->ShortPrint(out); + PrintF(out, "\n - query: "); + query()->ShortPrint(out); + PrintF(out, "\n - deleter: "); + deleter()->ShortPrint(out); + PrintF(out, "\n - enumerator: "); + enumerator()->ShortPrint(out); + PrintF(out, "\n - data: "); + data()->ShortPrint(out); } +#endif // OBJECT_PRINT + +#ifdef DEBUG void CallHandlerInfo::CallHandlerInfoVerify() { CHECK(IsCallHandlerInfo()); VerifyPointer(callback()); VerifyPointer(data()); } +#endif // DEBUG + -void CallHandlerInfo::CallHandlerInfoPrint() { - HeapObject::PrintHeader("CallHandlerInfo"); - PrintF("\n - callback: "); - callback()->ShortPrint(); - PrintF("\n - data: "); - data()->ShortPrint(); - PrintF("\n - call_stub_cache: "); +#ifdef OBJECT_PRINT +void CallHandlerInfo::CallHandlerInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "CallHandlerInfo"); + PrintF(out, "\n - callback: "); + callback()->ShortPrint(out); + PrintF(out, "\n - data: "); + data()->ShortPrint(out); + PrintF(out, "\n - call_stub_cache: "); } +#endif // OBJECT_PRINT + +#ifdef DEBUG void TemplateInfo::TemplateInfoVerify() { VerifyPointer(tag()); VerifyPointer(property_list()); @@ -1078,81 +1179,106 @@ void FunctionTemplateInfo::FunctionTemplateInfoVerify() { VerifyPointer(signature()); VerifyPointer(access_check_info()); } +#endif // DEBUG + + +#ifdef OBJECT_PRINT +void FunctionTemplateInfo::FunctionTemplateInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "FunctionTemplateInfo"); + PrintF(out, "\n - class name: "); + class_name()->ShortPrint(out); + PrintF(out, "\n - tag: "); + tag()->ShortPrint(out); + PrintF(out, "\n - property_list: "); + property_list()->ShortPrint(out); + PrintF(out, "\n - serial_number: "); + serial_number()->ShortPrint(out); + PrintF(out, "\n - call_code: "); + call_code()->ShortPrint(out); + PrintF(out, "\n - property_accessors: "); + property_accessors()->ShortPrint(out); + PrintF(out, "\n - prototype_template: "); + prototype_template()->ShortPrint(out); + PrintF(out, "\n - parent_template: "); + parent_template()->ShortPrint(out); + PrintF(out, "\n - named_property_handler: "); + named_property_handler()->ShortPrint(out); + PrintF(out, "\n - indexed_property_handler: "); + indexed_property_handler()->ShortPrint(out); + PrintF(out, "\n - instance_template: "); + instance_template()->ShortPrint(out); + PrintF(out, "\n - signature: "); + signature()->ShortPrint(out); + PrintF(out, "\n - access_check_info: "); + access_check_info()->ShortPrint(out); + PrintF(out, "\n - hidden_prototype: %s", + hidden_prototype() ? "true" : "false"); + PrintF(out, "\n - undetectable: %s", undetectable() ? "true" : "false"); + PrintF(out, "\n - need_access_check: %s", + needs_access_check() ? "true" : "false"); +} +#endif // OBJECT_PRINT -void FunctionTemplateInfo::FunctionTemplateInfoPrint() { - HeapObject::PrintHeader("FunctionTemplateInfo"); - PrintF("\n - class name: "); - class_name()->ShortPrint(); - PrintF("\n - tag: "); - tag()->ShortPrint(); - PrintF("\n - property_list: "); - property_list()->ShortPrint(); - PrintF("\n - serial_number: "); - serial_number()->ShortPrint(); - PrintF("\n - call_code: "); - call_code()->ShortPrint(); - PrintF("\n - property_accessors: "); - property_accessors()->ShortPrint(); - PrintF("\n - prototype_template: "); - prototype_template()->ShortPrint(); - PrintF("\n - parent_template: "); - parent_template()->ShortPrint(); - PrintF("\n - named_property_handler: "); - named_property_handler()->ShortPrint(); - PrintF("\n - indexed_property_handler: "); - indexed_property_handler()->ShortPrint(); - PrintF("\n - instance_template: "); - instance_template()->ShortPrint(); - PrintF("\n - signature: "); - signature()->ShortPrint(); - PrintF("\n - access_check_info: "); - access_check_info()->ShortPrint(); - PrintF("\n - hidden_prototype: %s", hidden_prototype() ? "true" : "false"); - PrintF("\n - undetectable: %s", undetectable() ? "true" : "false"); - PrintF("\n - need_access_check: %s", needs_access_check() ? "true" : "false"); -} +#ifdef DEBUG void ObjectTemplateInfo::ObjectTemplateInfoVerify() { CHECK(IsObjectTemplateInfo()); TemplateInfoVerify(); VerifyPointer(constructor()); VerifyPointer(internal_field_count()); } +#endif // DEBUG -void ObjectTemplateInfo::ObjectTemplateInfoPrint() { - HeapObject::PrintHeader("ObjectTemplateInfo"); - PrintF("\n - constructor: "); - constructor()->ShortPrint(); - PrintF("\n - internal_field_count: "); - internal_field_count()->ShortPrint(); + +#ifdef OBJECT_PRINT +void ObjectTemplateInfo::ObjectTemplateInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "ObjectTemplateInfo"); + PrintF(out, "\n - constructor: "); + constructor()->ShortPrint(out); + PrintF(out, "\n - internal_field_count: "); + internal_field_count()->ShortPrint(out); } +#endif // OBJECT_PRINT + +#ifdef DEBUG void SignatureInfo::SignatureInfoVerify() { CHECK(IsSignatureInfo()); VerifyPointer(receiver()); VerifyPointer(args()); } +#endif // DEBUG + -void SignatureInfo::SignatureInfoPrint() { - HeapObject::PrintHeader("SignatureInfo"); - PrintF("\n - receiver: "); - receiver()->ShortPrint(); - PrintF("\n - args: "); - args()->ShortPrint(); +#ifdef OBJECT_PRINT +void SignatureInfo::SignatureInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "SignatureInfo"); + PrintF(out, "\n - receiver: "); + receiver()->ShortPrint(out); + PrintF(out, "\n - args: "); + args()->ShortPrint(out); } +#endif // OBJECT_PRINT + +#ifdef DEBUG void TypeSwitchInfo::TypeSwitchInfoVerify() { CHECK(IsTypeSwitchInfo()); VerifyPointer(types()); } +#endif // DEBUG + -void TypeSwitchInfo::TypeSwitchInfoPrint() { - HeapObject::PrintHeader("TypeSwitchInfo"); - PrintF("\n - types: "); - types()->ShortPrint(); +#ifdef OBJECT_PRINT +void TypeSwitchInfo::TypeSwitchInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "TypeSwitchInfo"); + PrintF(out, "\n - types: "); + types()->ShortPrint(out); } +#endif // OBJECT_PRINT +#ifdef DEBUG void Script::ScriptVerify() { CHECK(IsScript()); VerifyPointer(source()); @@ -1165,41 +1291,45 @@ void Script::ScriptVerify() { VerifyPointer(line_ends()); VerifyPointer(id()); } +#endif // DEBUG -void Script::ScriptPrint() { - HeapObject::PrintHeader("Script"); - PrintF("\n - source: "); - source()->ShortPrint(); - PrintF("\n - name: "); - name()->ShortPrint(); - PrintF("\n - line_offset: "); - line_offset()->ShortPrint(); - PrintF("\n - column_offset: "); - column_offset()->ShortPrint(); - PrintF("\n - type: "); - type()->ShortPrint(); - PrintF("\n - id: "); - id()->ShortPrint(); - PrintF("\n - data: "); - data()->ShortPrint(); - PrintF("\n - context data: "); - context_data()->ShortPrint(); - PrintF("\n - wrapper: "); - wrapper()->ShortPrint(); - PrintF("\n - compilation type: "); - compilation_type()->ShortPrint(); - PrintF("\n - line ends: "); - line_ends()->ShortPrint(); - PrintF("\n - eval from shared: "); - eval_from_shared()->ShortPrint(); - PrintF("\n - eval from instructions offset: "); - eval_from_instructions_offset()->ShortPrint(); - PrintF("\n"); -} +#ifdef OBJECT_PRINT +void Script::ScriptPrint(FILE* out) { + HeapObject::PrintHeader(out, "Script"); + PrintF(out, "\n - source: "); + source()->ShortPrint(out); + PrintF(out, "\n - name: "); + name()->ShortPrint(out); + PrintF(out, "\n - line_offset: "); + line_offset()->ShortPrint(out); + PrintF(out, "\n - column_offset: "); + column_offset()->ShortPrint(out); + PrintF(out, "\n - type: "); + type()->ShortPrint(out); + PrintF(out, "\n - id: "); + id()->ShortPrint(out); + PrintF(out, "\n - data: "); + data()->ShortPrint(out); + PrintF(out, "\n - context data: "); + context_data()->ShortPrint(out); + PrintF(out, "\n - wrapper: "); + wrapper()->ShortPrint(out); + PrintF(out, "\n - compilation type: "); + compilation_type()->ShortPrint(out); + PrintF(out, "\n - line ends: "); + line_ends()->ShortPrint(out); + PrintF(out, "\n - eval from shared: "); + eval_from_shared()->ShortPrint(out); + PrintF(out, "\n - eval from instructions offset: "); + eval_from_instructions_offset()->ShortPrint(out); + PrintF(out, "\n"); +} +#endif // OBJECT_PRINT #ifdef ENABLE_DEBUGGER_SUPPORT +#ifdef DEBUG void DebugInfo::DebugInfoVerify() { CHECK(IsDebugInfo()); VerifyPointer(shared()); @@ -1207,21 +1337,25 @@ void DebugInfo::DebugInfoVerify() { VerifyPointer(code()); VerifyPointer(break_points()); } +#endif // DEBUG -void DebugInfo::DebugInfoPrint() { - HeapObject::PrintHeader("DebugInfo"); - PrintF("\n - shared: "); - shared()->ShortPrint(); - PrintF("\n - original_code: "); - original_code()->ShortPrint(); - PrintF("\n - code: "); - code()->ShortPrint(); - PrintF("\n - break_points: "); - break_points()->Print(); +#ifdef OBJECT_PRINT +void DebugInfo::DebugInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "DebugInfo"); + PrintF(out, "\n - shared: "); + shared()->ShortPrint(out); + PrintF(out, "\n - original_code: "); + original_code()->ShortPrint(out); + PrintF(out, "\n - code: "); + code()->ShortPrint(out); + PrintF(out, "\n - break_points: "); + break_points()->Print(out); } +#endif // OBJECT_PRINT +#ifdef DEBUG void BreakPointInfo::BreakPointInfoVerify() { CHECK(IsBreakPointInfo()); code_position()->SmiVerify(); @@ -1229,19 +1363,23 @@ void BreakPointInfo::BreakPointInfoVerify() { statement_position()->SmiVerify(); VerifyPointer(break_point_objects()); } +#endif // DEBUG -void BreakPointInfo::BreakPointInfoPrint() { - HeapObject::PrintHeader("BreakPointInfo"); - PrintF("\n - code_position: %d", code_position()->value()); - PrintF("\n - source_position: %d", source_position()->value()); - PrintF("\n - statement_position: %d", statement_position()->value()); - PrintF("\n - break_point_objects: "); - break_point_objects()->ShortPrint(); +#ifdef OBJECT_PRINT +void BreakPointInfo::BreakPointInfoPrint(FILE* out) { + HeapObject::PrintHeader(out, "BreakPointInfo"); + PrintF(out, "\n - code_position: %d", code_position()->value()); + PrintF(out, "\n - source_position: %d", source_position()->value()); + PrintF(out, "\n - statement_position: %d", statement_position()->value()); + PrintF(out, "\n - break_point_objects: "); + break_point_objects()->ShortPrint(out); } -#endif +#endif // OBJECT_PRINT +#endif // ENABLE_DEBUGGER_SUPPORT +#ifdef DEBUG void JSObject::IncrementSpillStatistics(SpillInformation* info) { info->number_of_objects_++; // Named properties @@ -1324,20 +1462,24 @@ void JSObject::SpillInformation::Print() { PrintF("\n"); } +#endif // DEBUG -void DescriptorArray::PrintDescriptors() { - PrintF("Descriptor array %d\n", number_of_descriptors()); +#ifdef OBJECT_PRINT +void DescriptorArray::PrintDescriptors(FILE* out) { + PrintF(out, "Descriptor array %d\n", number_of_descriptors()); for (int i = 0; i < number_of_descriptors(); i++) { - PrintF(" %d: ", i); + PrintF(out, " %d: ", i); Descriptor desc; Get(i, &desc); - desc.Print(); + desc.Print(out); } - PrintF("\n"); + PrintF(out, "\n"); } +#endif // OBJECT_PRINT +#ifdef DEBUG bool DescriptorArray::IsSortedNoDuplicates() { String* current_key = NULL; uint32_t current = 0; diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index 96f5c4b2470..ab2f9644705 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -553,11 +553,11 @@ Object* Object::GetPrototype() { } -void Object::ShortPrint() { +void Object::ShortPrint(FILE* out) { HeapStringAllocator allocator; StringStream accumulator(&allocator); ShortPrint(&accumulator); - accumulator.OutputToStdOut(); + accumulator.OutputToFile(out); } @@ -572,8 +572,8 @@ void Object::ShortPrint(StringStream* accumulator) { } -void Smi::SmiPrint() { - PrintF("%d", value()); +void Smi::SmiPrint(FILE* out) { + PrintF(out, "%d", value()); } @@ -587,8 +587,8 @@ void Failure::FailurePrint(StringStream* accumulator) { } -void Failure::FailurePrint() { - PrintF("Failure(%p)", reinterpret_cast<void*>(value())); +void Failure::FailurePrint(FILE* out) { + PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value())); } @@ -1141,8 +1141,8 @@ Object* HeapNumber::HeapNumberToBoolean() { } -void HeapNumber::HeapNumberPrint() { - PrintF("%.16g", Number()); +void HeapNumber::HeapNumberPrint(FILE* out) { + 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(); - PrintF("%s", *name); + PrintF(out, "%s", *name); } @@ -5999,18 +5999,18 @@ Map* Code::FindFirstMap() { #ifdef ENABLE_DISASSEMBLER -#ifdef DEBUG +#ifdef OBJECT_PRINT -void DeoptimizationInputData::DeoptimizationInputDataPrint() { +void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) { disasm::NameConverter converter; 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; - 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++) { int command_count = 0; - PrintF("%6d %6d %6d", + PrintF(out, "%6d %6d %6d", i, AstId(i)->value(), ArgumentsStackHeight(i)->value()); int translation_index = TranslationIndex(i)->value(); TranslationIterator iterator(TranslationByteArray(), translation_index); @@ -6019,7 +6019,8 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() { ASSERT(Translation::BEGIN == opcode); int frame_count = iterator.Next(); 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) { @@ -6031,10 +6032,10 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() { JSFunction::cast(LiteralArray()->get(function_id)); unsigned height = iterator.Next(); 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); - function->PrintName(); - PrintF(", height=%u}\n", height); + function->PrintName(out); + PrintF(out, ", height=%u}\n", height); } // Size of translation is height plus all incoming arguments including @@ -6044,13 +6045,13 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() { for (int j = 0; j < size; ++j) { opcode = static_cast<Translation::Opcode>(iterator.Next()); if (FLAG_print_code_verbose) { - PrintF("%24s %s ", "", Translation::StringFor(opcode)); + PrintF(out, "%24s %s ", "", Translation::StringFor(opcode)); } if (opcode == Translation::DUPLICATE) { opcode = static_cast<Translation::Opcode>(iterator.Next()); if (FLAG_print_code_verbose) { - PrintF("%s ", Translation::StringFor(opcode)); + PrintF(out, "%s ", Translation::StringFor(opcode)); } --j; // Two commands share the same frame index. } @@ -6065,7 +6066,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() { case Translation::REGISTER: { int reg_code = iterator.Next(); if (FLAG_print_code_verbose) { - PrintF("{input=%s}", converter.NameOfCPURegister(reg_code)); + PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code)); } break; } @@ -6073,7 +6074,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() { case Translation::INT32_REGISTER: { int reg_code = iterator.Next(); if (FLAG_print_code_verbose) { - PrintF("{input=%s}", converter.NameOfCPURegister(reg_code)); + PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code)); } break; } @@ -6081,7 +6082,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() { case Translation::DOUBLE_REGISTER: { int reg_code = iterator.Next(); if (FLAG_print_code_verbose) { - PrintF("{input=%s}", + PrintF(out, "{input=%s}", DoubleRegister::AllocationIndexToString(reg_code)); } break; @@ -6090,7 +6091,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() { case Translation::STACK_SLOT: { int input_slot_index = iterator.Next(); if (FLAG_print_code_verbose) { - PrintF("{input=%d}", input_slot_index); + PrintF(out, "{input=%d}", input_slot_index); } break; } @@ -6098,7 +6099,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() { case Translation::INT32_STACK_SLOT: { int input_slot_index = iterator.Next(); if (FLAG_print_code_verbose) { - PrintF("{input=%d}", input_slot_index); + PrintF(out, "{input=%d}", input_slot_index); } break; } @@ -6106,7 +6107,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() { case Translation::DOUBLE_STACK_SLOT: { int input_slot_index = iterator.Next(); if (FLAG_print_code_verbose) { - PrintF("{input=%d}", input_slot_index); + PrintF(out, "{input=%d}", input_slot_index); } break; } @@ -6114,7 +6115,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() { case Translation::LITERAL: { unsigned literal_index = iterator.Next(); if (FLAG_print_code_verbose) { - PrintF("{literal_id=%u}", literal_index); + PrintF(out, "{literal_id=%u}", literal_index); } break; } @@ -6122,16 +6123,16 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint() { case Translation::ARGUMENTS_OBJECT: 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() { - PrintF("Deoptimization Output Data (deopt points = %d)\n", +void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) { + PrintF(out, "Deoptimization Output Data (deopt points = %d)\n", this->DeoptPoints()); if (this->DeoptPoints() == 0) return; @@ -6202,56 +6203,56 @@ const char* Code::PropertyType2String(PropertyType type) { } -void Code::Disassemble(const char* name) { - PrintF("kind = %s\n", Kind2String(kind())); +void Code::Disassemble(const char* name, FILE* out) { + PrintF(out, "kind = %s\n", Kind2String(kind())); if (is_inline_cache_stub()) { - PrintF("ic_state = %s\n", ICState2String(ic_state())); - PrintF("ic_in_loop = %d\n", ic_in_loop() == IN_LOOP); + PrintF(out, "ic_state = %s\n", ICState2String(ic_state())); + PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP); if (ic_state() == MONOMORPHIC) { - PrintF("type = %s\n", PropertyType2String(type())); + PrintF(out, "type = %s\n", PropertyType2String(type())); } } if ((name != NULL) && (name[0] != '\0')) { - PrintF("name = %s\n", name); + PrintF(out, "name = %s\n", name); } 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()); - Disassembler::Decode(NULL, this); - PrintF("\n"); + PrintF(out, "Instructions (size = %d)\n", instruction_size()); + Disassembler::Decode(out, this); + PrintF(out, "\n"); #ifdef DEBUG if (kind() == FUNCTION) { DeoptimizationOutputData* data = DeoptimizationOutputData::cast(this->deoptimization_data()); - data->DeoptimizationOutputDataPrint(); + data->DeoptimizationOutputDataPrint(out); } else if (kind() == OPTIMIZED_FUNCTION) { DeoptimizationInputData* data = DeoptimizationInputData::cast(this->deoptimization_data()); - data->DeoptimizationInputDataPrint(); + data->DeoptimizationInputDataPrint(out); } PrintF("\n"); #endif if (kind() == OPTIMIZED_FUNCTION) { 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++) { 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); - PrintF(" (sp -> fp)"); + PrintF(out, " (sp -> fp)"); int deoptimization_index = table.GetDeoptimizationIndex(i); if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { - PrintF(" %6d", deoptimization_index); + PrintF(out, " %6d", deoptimization_index); } else { - PrintF(" <none>"); + PrintF(out, " <none>"); } - PrintF("\n"); + PrintF(out, "\n"); } - PrintF("\n"); + PrintF(out, "\n"); } else if (kind() == FUNCTION) { unsigned offset = stack_check_table_start(); // 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 = reinterpret_cast<unsigned*>(instruction_start() + offset); unsigned length = address[0]; - PrintF("Stack checks (size = %u)\n", length); - PrintF("ast_id pc_offset\n"); + PrintF(out, "Stack checks (size = %u)\n", length); + PrintF(out, "ast_id pc_offset\n"); for (unsigned i = 0; i < length; ++i) { 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()); - for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(); - PrintF("\n"); + for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out); + PrintF(out, "\n"); } #endif // ENABLE_DISASSEMBLER @@ -7421,22 +7422,22 @@ bool JSObject::ShouldConvertToFastElements() { // class. This requires us to have the template functions put // together, so even though this function belongs in objects-debug.cc, // we keep it here instead to satisfy certain compilers. -#ifdef DEBUG +#ifdef OBJECT_PRINT template<typename Shape, typename Key> -void Dictionary<Shape, Key>::Print() { +void Dictionary<Shape, Key>::Print(FILE* out) { int capacity = HashTable<Shape, Key>::Capacity(); for (int i = 0; i < capacity; i++) { Object* k = HashTable<Shape, Key>::KeyAt(i); if (HashTable<Shape, Key>::IsKey(k)) { - PrintF(" "); + PrintF(out, " "); if (k->IsString()) { - String::cast(k)->StringPrint(); + String::cast(k)->StringPrint(out); } else { - k->ShortPrint(); + k->ShortPrint(out); } - PrintF(": "); - ValueAt(i)->ShortPrint(); - PrintF("\n"); + PrintF(out, ": "); + ValueAt(i)->ShortPrint(out); + PrintF(out, "\n"); } } } diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 498ee451bca..c5fda7d0385 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -607,10 +607,18 @@ class MaybeObject BASE_EMBEDDED { return reinterpret_cast<Object*>(this); } -#ifdef DEBUG +#ifdef OBJECT_PRINT // Prints this object with details. - void Print(); - void PrintLn(); + inline void Print() { + Print(stdout); + }; + inline void PrintLn() { + PrintLn(stdout); + } + void Print(FILE* out); + void PrintLn(FILE* out); +#endif +#ifdef DEBUG // Verifies the object. void Verify(); #endif @@ -762,7 +770,10 @@ class Object : public MaybeObject { #endif // 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. void ShortPrint(StringStream* accumulator); @@ -801,7 +812,10 @@ class Smi: public Object { static inline Smi* cast(Object* object); // Dispatched behavior. - void SmiPrint(); + inline void SmiPrint() { + SmiPrint(stdout); + } + void SmiPrint(FILE* out); void SmiPrint(StringStream* accumulator); #ifdef DEBUG void SmiVerify(); @@ -870,7 +884,10 @@ class Failure: public MaybeObject { static inline Failure* cast(MaybeObject* object); // Dispatched behavior. - void FailurePrint(); + inline void FailurePrint() { + FailurePrint(stdout); + } + void FailurePrint(FILE* out); void FailurePrint(StringStream* accumulator); #ifdef DEBUG void FailureVerify(); @@ -1099,14 +1116,23 @@ class HeapObject: public Object { // Dispatched behavior. void HeapObjectShortPrint(StringStream* accumulator); +#ifdef OBJECT_PRINT + inline void HeapObjectPrint() { + HeapObjectPrint(stdout); + } + void HeapObjectPrint(FILE* out); +#endif #ifdef DEBUG - void HeapObjectPrint(); void HeapObjectVerify(); inline void VerifyObjectField(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 // areas in the heap. static void VerifyHeapPointer(Object* p); @@ -1189,7 +1215,10 @@ class HeapNumber: public HeapObject { // Dispatched behavior. Object* HeapNumberToBoolean(); - void HeapNumberPrint(); + inline void HeapNumberPrint() { + HeapNumberPrint(stdout); + } + void HeapNumberPrint(FILE* out); void HeapNumberPrint(StringStream* accumulator); #ifdef DEBUG void HeapNumberVerify(); @@ -1649,12 +1678,28 @@ class JSObject: public HeapObject { // Dispatched behavior. void JSObjectShortPrint(StringStream* accumulator); +#ifdef OBJECT_PRINT + inline void JSObjectPrint() { + JSObjectPrint(stdout); + } + void JSObjectPrint(FILE* out); +#endif #ifdef DEBUG - void JSObjectPrint(); void JSObjectVerify(); - void PrintProperties(); - void PrintElements(); +#endif +#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. class SpillInformation { public: @@ -1689,7 +1734,7 @@ class JSObject: public HeapObject { static const uint32_t kMaxGap = 1024; static const int kMaxFastElementsLength = 5000; static const int kInitialMaxFastElementArray = 100000; - static const int kMaxFastProperties = 8; + static const int kMaxFastProperties = 12; static const int kMaxInstanceSize = 255 * kPointerSize; // When extending the backing storage for property values, we increase // 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; // Dispatched behavior. +#ifdef OBJECT_PRINT + inline void FixedArrayPrint() { + FixedArrayPrint(stdout); + } + void FixedArrayPrint(FILE* out); +#endif #ifdef DEBUG - void FixedArrayPrint(); void FixedArrayVerify(); // Checks if two FixedArrays have identical contents. bool IsEqualTo(FixedArray* other); @@ -2012,10 +2062,15 @@ class DescriptorArray: public FixedArray { static const int kEnumCacheBridgeCacheOffset = kEnumCacheBridgeEnumOffset + kPointerSize; -#ifdef DEBUG +#ifdef OBJECT_PRINT // 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? bool IsSortedNoDuplicates(); @@ -2396,8 +2451,11 @@ class Dictionary: public HashTable<Shape, Key> { // Ensure enough space for n additional elements. MUST_USE_RESULT MaybeObject* EnsureCapacity(int n, Key key); -#ifdef DEBUG - void Print(); +#ifdef OBJECT_PRINT + inline void Print() { + Print(stdout); + } + void Print(FILE* out); #endif // Returns the key (slow). Object* SlowReverseLookup(Object* value); @@ -2619,8 +2677,13 @@ class ByteArray: public HeapObject { inline int ByteArraySize() { return SizeFor(this->length()); } +#ifdef OBJECT_PRINT + inline void ByteArrayPrint() { + ByteArrayPrint(stdout); + } + void ByteArrayPrint(FILE* out); +#endif #ifdef DEBUG - void ByteArrayPrint(); void ByteArrayVerify(); #endif @@ -2669,8 +2732,13 @@ class PixelArray: public HeapObject { // Casting. static inline PixelArray* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void PixelArrayPrint() { + PixelArrayPrint(stdout); + } + void PixelArrayPrint(FILE* out); +#endif #ifdef DEBUG - void PixelArrayPrint(); void PixelArrayVerify(); #endif // DEBUG @@ -2741,8 +2809,13 @@ class ExternalByteArray: public ExternalArray { // Casting. static inline ExternalByteArray* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void ExternalByteArrayPrint() { + ExternalByteArrayPrint(stdout); + } + void ExternalByteArrayPrint(FILE* out); +#endif #ifdef DEBUG - void ExternalByteArrayPrint(); void ExternalByteArrayVerify(); #endif // DEBUG @@ -2764,8 +2837,13 @@ class ExternalUnsignedByteArray: public ExternalArray { // Casting. static inline ExternalUnsignedByteArray* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void ExternalUnsignedByteArrayPrint() { + ExternalUnsignedByteArrayPrint(stdout); + } + void ExternalUnsignedByteArrayPrint(FILE* out); +#endif #ifdef DEBUG - void ExternalUnsignedByteArrayPrint(); void ExternalUnsignedByteArrayVerify(); #endif // DEBUG @@ -2787,8 +2865,13 @@ class ExternalShortArray: public ExternalArray { // Casting. static inline ExternalShortArray* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void ExternalShortArrayPrint() { + ExternalShortArrayPrint(stdout); + } + void ExternalShortArrayPrint(FILE* out); +#endif #ifdef DEBUG - void ExternalShortArrayPrint(); void ExternalShortArrayVerify(); #endif // DEBUG @@ -2810,8 +2893,13 @@ class ExternalUnsignedShortArray: public ExternalArray { // Casting. static inline ExternalUnsignedShortArray* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void ExternalUnsignedShortArrayPrint() { + ExternalUnsignedShortArrayPrint(stdout); + } + void ExternalUnsignedShortArrayPrint(FILE* out); +#endif #ifdef DEBUG - void ExternalUnsignedShortArrayPrint(); void ExternalUnsignedShortArrayVerify(); #endif // DEBUG @@ -2833,8 +2921,13 @@ class ExternalIntArray: public ExternalArray { // Casting. static inline ExternalIntArray* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void ExternalIntArrayPrint() { + ExternalIntArrayPrint(stdout); + } + void ExternalIntArrayPrint(FILE* out); +#endif #ifdef DEBUG - void ExternalIntArrayPrint(); void ExternalIntArrayVerify(); #endif // DEBUG @@ -2856,8 +2949,13 @@ class ExternalUnsignedIntArray: public ExternalArray { // Casting. static inline ExternalUnsignedIntArray* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void ExternalUnsignedIntArrayPrint() { + ExternalUnsignedIntArrayPrint(stdout); + } + void ExternalUnsignedIntArrayPrint(FILE* out); +#endif #ifdef DEBUG - void ExternalUnsignedIntArrayPrint(); void ExternalUnsignedIntArrayVerify(); #endif // DEBUG @@ -2879,8 +2977,13 @@ class ExternalFloatArray: public ExternalArray { // Casting. static inline ExternalFloatArray* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void ExternalFloatArrayPrint() { + ExternalFloatArrayPrint(stdout); + } + void ExternalFloatArrayPrint(FILE* out); +#endif #ifdef DEBUG - void ExternalFloatArrayPrint(); void ExternalFloatArrayVerify(); #endif // DEBUG @@ -2960,8 +3063,8 @@ class DeoptimizationInputData: public FixedArray { // Casting. static inline DeoptimizationInputData* cast(Object* obj); -#ifdef DEBUG - void DeoptimizationInputDataPrint(); +#ifdef OBJECT_PRINT + void DeoptimizationInputDataPrint(FILE* out); #endif private: @@ -2999,8 +3102,8 @@ class DeoptimizationOutputData: public FixedArray { // Casting. static inline DeoptimizationOutputData* cast(Object* obj); -#ifdef DEBUG - void DeoptimizationOutputDataPrint(); +#ifdef OBJECT_PRINT + void DeoptimizationOutputDataPrint(FILE* out); #endif }; @@ -3049,7 +3152,10 @@ class Code: public HeapObject { static const char* Kind2String(Kind kind); static const char* ICState2String(InlineCacheState state); 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 // [instruction_size]: Size of the native instructions @@ -3242,8 +3348,13 @@ class Code: public HeapObject { template<typename StaticVisitor> inline void CodeIterateBody(); +#ifdef OBJECT_PRINT + inline void CodePrint() { + CodePrint(stdout); + } + void CodePrint(FILE* out); +#endif #ifdef DEBUG - void CodePrint(); void CodeVerify(); #endif @@ -3531,8 +3642,13 @@ class Map: public HeapObject { void ClearNonLiveTransitions(Object* real_prototype); // Dispatched behavior. +#ifdef OBJECT_PRINT + inline void MapPrint() { + MapPrint(stdout); + } + void MapPrint(FILE* out); +#endif #ifdef DEBUG - void MapPrint(); void MapVerify(); void SharedMapVerify(); #endif @@ -3688,8 +3804,13 @@ class Script: public Struct { // resource is accessible. Otherwise, always return true. inline bool HasValidSource(); +#ifdef OBJECT_PRINT + inline void ScriptPrint() { + ScriptPrint(stdout); + } + void ScriptPrint(FILE* out); +#endif #ifdef DEBUG - void ScriptPrint(); void ScriptVerify(); #endif @@ -4052,8 +4173,13 @@ class SharedFunctionInfo: public HeapObject { // Dispatched behavior. // Set max_length to -1 for unlimited length. void SourceCodePrint(StringStream* accumulator, int max_length); +#ifdef OBJECT_PRINT + inline void SharedFunctionInfoPrint() { + SharedFunctionInfoPrint(stdout); + } + void SharedFunctionInfoPrint(FILE* out); +#endif #ifdef DEBUG - void SharedFunctionInfoPrint(); void SharedFunctionInfoVerify(); #endif @@ -4285,7 +4411,10 @@ class JSFunction: public JSObject { DECL_ACCESSORS(next_function_link, Object) // Prints the name of the function using PrintF. - void PrintName(); + inline void PrintName() { + PrintName(stdout); + } + void PrintName(FILE* out); // Casting. static inline JSFunction* cast(Object* obj); @@ -4295,8 +4424,13 @@ class JSFunction: public JSObject { void JSFunctionIterateBody(int object_size, ObjectVisitor* v); // Dispatched behavior. +#ifdef OBJECT_PRINT + inline void JSFunctionPrint() { + JSFunctionPrint(stdout); + } + void JSFunctionPrint(FILE* out); +#endif #ifdef DEBUG - void JSFunctionPrint(); void JSFunctionVerify(); #endif @@ -4345,8 +4479,13 @@ class JSGlobalProxy : public JSObject { static inline JSGlobalProxy* cast(Object* obj); // Dispatched behavior. +#ifdef OBJECT_PRINT + inline void JSGlobalProxyPrint() { + JSGlobalProxyPrint(stdout); + } + void JSGlobalProxyPrint(FILE* out); +#endif #ifdef DEBUG - void JSGlobalProxyPrint(); void JSGlobalProxyVerify(); #endif @@ -4416,8 +4555,13 @@ class JSGlobalObject: public GlobalObject { static inline JSGlobalObject* cast(Object* obj); // Dispatched behavior. +#ifdef OBJECT_PRINT + inline void JSGlobalObjectPrint() { + JSGlobalObjectPrint(stdout); + } + void JSGlobalObjectPrint(FILE* out); +#endif #ifdef DEBUG - void JSGlobalObjectPrint(); void JSGlobalObjectVerify(); #endif @@ -4445,8 +4589,13 @@ class JSBuiltinsObject: public GlobalObject { static inline JSBuiltinsObject* cast(Object* obj); // Dispatched behavior. +#ifdef OBJECT_PRINT + inline void JSBuiltinsObjectPrint() { + JSBuiltinsObjectPrint(stdout); + } + void JSBuiltinsObjectPrint(FILE* out); +#endif #ifdef DEBUG - void JSBuiltinsObjectPrint(); void JSBuiltinsObjectVerify(); #endif @@ -4483,8 +4632,13 @@ class JSValue: public JSObject { static inline JSValue* cast(Object* obj); // Dispatched behavior. +#ifdef OBJECT_PRINT + inline void JSValuePrint() { + JSValuePrint(stdout); + } + void JSValuePrint(FILE* out); +#endif #ifdef DEBUG - void JSValuePrint(); void JSValueVerify(); #endif @@ -4673,8 +4827,13 @@ class CodeCache: public Struct { static inline CodeCache* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void CodeCachePrint() { + CodeCachePrint(stdout); + } + void CodeCachePrint(FILE* out); +#endif #ifdef DEBUG - void CodeCachePrint(); void CodeCacheVerify(); #endif @@ -4975,8 +5134,13 @@ class String: public HeapObject { // Dispatched behavior. void StringShortPrint(StringStream* accumulator); +#ifdef OBJECT_PRINT + inline void StringPrint() { + StringPrint(stdout); + } + void StringPrint(FILE* out); +#endif #ifdef DEBUG - void StringPrint(); void StringVerify(); #endif inline bool IsFlat(); @@ -5531,7 +5695,12 @@ class JSGlobalPropertyCell: public HeapObject { #ifdef DEBUG void JSGlobalPropertyCellVerify(); - void JSGlobalPropertyCellPrint(); +#endif +#ifdef OBJECT_PRINT + inline void JSGlobalPropertyCellPrint() { + JSGlobalPropertyCellPrint(stdout); + } + void JSGlobalPropertyCellPrint(FILE* out); #endif // Layout description. @@ -5566,8 +5735,13 @@ class Proxy: public HeapObject { template<typename StaticVisitor> inline void ProxyIterateBody(); +#ifdef OBJECT_PRINT + inline void ProxyPrint() { + ProxyPrint(stdout); + } + void ProxyPrint(FILE* out); +#endif #ifdef DEBUG - void ProxyPrint(); void ProxyVerify(); #endif @@ -5616,8 +5790,13 @@ class JSArray: public JSObject { inline void EnsureSize(int minimum_size_of_backing_fixed_array); // Dispatched behavior. +#ifdef OBJECT_PRINT + inline void JSArrayPrint() { + JSArrayPrint(stdout); + } + void JSArrayPrint(FILE* out); +#endif #ifdef DEBUG - void JSArrayPrint(); void JSArrayVerify(); #endif @@ -5688,8 +5867,13 @@ class AccessorInfo: public Struct { static inline AccessorInfo* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void AccessorInfoPrint() { + AccessorInfoPrint(stdout); + } + void AccessorInfoPrint(FILE* out); +#endif #ifdef DEBUG - void AccessorInfoPrint(); void AccessorInfoVerify(); #endif @@ -5719,8 +5903,13 @@ class AccessCheckInfo: public Struct { static inline AccessCheckInfo* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void AccessCheckInfoPrint() { + AccessCheckInfoPrint(stdout); + } + void AccessCheckInfoPrint(FILE* out); +#endif #ifdef DEBUG - void AccessCheckInfoPrint(); void AccessCheckInfoVerify(); #endif @@ -5745,8 +5934,13 @@ class InterceptorInfo: public Struct { static inline InterceptorInfo* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void InterceptorInfoPrint() { + InterceptorInfoPrint(stdout); + } + void InterceptorInfoPrint(FILE* out); +#endif #ifdef DEBUG - void InterceptorInfoPrint(); void InterceptorInfoVerify(); #endif @@ -5770,8 +5964,13 @@ class CallHandlerInfo: public Struct { static inline CallHandlerInfo* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void CallHandlerInfoPrint() { + CallHandlerInfoPrint(stdout); + } + void CallHandlerInfoPrint(FILE* out); +#endif #ifdef DEBUG - void CallHandlerInfoPrint(); void CallHandlerInfoVerify(); #endif @@ -5827,8 +6026,13 @@ class FunctionTemplateInfo: public TemplateInfo { static inline FunctionTemplateInfo* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void FunctionTemplateInfoPrint() { + FunctionTemplateInfoPrint(stdout); + } + void FunctionTemplateInfoPrint(FILE* out); +#endif #ifdef DEBUG - void FunctionTemplateInfoPrint(); void FunctionTemplateInfoVerify(); #endif @@ -5870,8 +6074,13 @@ class ObjectTemplateInfo: public TemplateInfo { static inline ObjectTemplateInfo* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void ObjectTemplateInfoPrint() { + ObjectTemplateInfoPrint(stdout); + } + void ObjectTemplateInfoPrint(FILE* out); +#endif #ifdef DEBUG - void ObjectTemplateInfoPrint(); void ObjectTemplateInfoVerify(); #endif @@ -5889,8 +6098,13 @@ class SignatureInfo: public Struct { static inline SignatureInfo* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void SignatureInfoPrint() { + SignatureInfoPrint(stdout); + } + void SignatureInfoPrint(FILE* out); +#endif #ifdef DEBUG - void SignatureInfoPrint(); void SignatureInfoVerify(); #endif @@ -5909,8 +6123,13 @@ class TypeSwitchInfo: public Struct { static inline TypeSwitchInfo* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void TypeSwitchInfoPrint() { + TypeSwitchInfoPrint(stdout); + } + void TypeSwitchInfoPrint(FILE* out); +#endif #ifdef DEBUG - void TypeSwitchInfoPrint(); void TypeSwitchInfoVerify(); #endif @@ -5956,8 +6175,13 @@ class DebugInfo: public Struct { static inline DebugInfo* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void DebugInfoPrint() { + DebugInfoPrint(stdout); + } + void DebugInfoPrint(FILE* out); +#endif #ifdef DEBUG - void DebugInfoPrint(); void DebugInfoVerify(); #endif @@ -6009,8 +6233,13 @@ class BreakPointInfo: public Struct { static inline BreakPointInfo* cast(Object* obj); +#ifdef OBJECT_PRINT + inline void BreakPointInfoPrint() { + BreakPointInfoPrint(stdout); + } + void BreakPointInfoPrint(FILE* out); +#endif #ifdef DEBUG - void BreakPointInfoPrint(); void BreakPointInfoVerify(); #endif diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc index 94ad57c9c28..08f77b8f304 100644 --- a/deps/v8/src/parser.cc +++ b/deps/v8/src/parser.cc @@ -3730,7 +3730,7 @@ RegExpParser::RegExpParser(FlatStringReader* in, contains_anchor_(false), is_scanned_for_captures_(false), failed_(false) { - Advance(1); + Advance(); } @@ -3768,8 +3768,8 @@ void RegExpParser::Reset(int pos) { void RegExpParser::Advance(int dist) { - for (int i = 0; i < dist; i++) - Advance(); + next_pos_ += dist - 1; + Advance(); } diff --git a/deps/v8/src/platform-nullos.cc b/deps/v8/src/platform-nullos.cc index f34483dbc4d..72ea0e57673 100644 --- a/deps/v8/src/platform-nullos.cc +++ b/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. void OS::PrintError(const char* format, ...) { // Minimalistic implementation for bootstrapping. diff --git a/deps/v8/src/platform-posix.cc b/deps/v8/src/platform-posix.cc index c50d396ad38..ab5c0a37687 100644 --- a/deps/v8/src/platform-posix.cc +++ b/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, ...) { va_list args; va_start(args, format); @@ -173,7 +190,9 @@ int OS::VSNPrintF(Vector<char> str, va_list args) { int n = vsnprintf(str.start(), str.length(), format, args); if (n < 0 || n >= str.length()) { - str[str.length() - 1] = '\0'; + // If the length is zero, the assignment fails. + if (str.length() > 0) + str[str.length() - 1] = '\0'; return -1; } else { return n; @@ -204,6 +223,14 @@ class POSIXSocket : public Socket { explicit POSIXSocket() { // Create the socket. 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) { } virtual ~POSIXSocket() { Shutdown(); } diff --git a/deps/v8/src/platform-win32.cc b/deps/v8/src/platform-win32.cc index badc31beb3d..4438045eaf5 100644 --- a/deps/v8/src/platform-win32.cc +++ b/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. void OS::PrintError(const char* format, ...) { va_list args; @@ -716,7 +729,8 @@ int OS::VSNPrintF(Vector<char> str, const char* format, va_list args) { // Make sure to zero-terminate the string if the output was // truncated or if there was an error. if (n < 0 || n >= str.length()) { - str[str.length() - 1] = '\0'; + if (str.length() > 0) + str[str.length() - 1] = '\0'; return -1; } else { return n; diff --git a/deps/v8/src/platform.h b/deps/v8/src/platform.h index 690f83c7fbb..bdfbbab6981 100644 --- a/deps/v8/src/platform.h +++ b/deps/v8/src/platform.h @@ -184,6 +184,10 @@ class OS { static void Print(const char* format, ...); 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 // output. On platforms that has standard terminal output, the output // should go to stderr. diff --git a/deps/v8/src/profile-generator.cc b/deps/v8/src/profile-generator.cc index 364f51d4f1c..34d18771cf1 100644 --- a/deps/v8/src/profile-generator.cc +++ b/deps/v8/src/profile-generator.cc @@ -2218,7 +2218,7 @@ void HeapSnapshotGenerator::SetGcRootsReference(Object* child_obj) { void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) { if (control_ == NULL) return; - HeapIterator iterator(HeapIterator::kPreciseFiltering); + HeapIterator iterator(HeapIterator::kFilterUnreachable); int objects_count = 0; for (HeapObject* obj = iterator.next(); obj != NULL; @@ -2342,8 +2342,6 @@ bool HeapSnapshotGenerator::SetEntriesDominators() { ASSERT(dominators[i] != NULL); ordered_entries[i]->set_dominator(dominators[i]); } - // For nodes unreachable from root, set dominator to itself. - snapshot_->SetDominatorsToSelf(); return true; } @@ -2373,9 +2371,9 @@ bool HeapSnapshotGenerator::ApproximateRetainedSizes() { bool HeapSnapshotGenerator::IterateAndExtractReferences() { - HeapIterator iterator(HeapIterator::kPreciseFiltering); + HeapIterator iterator(HeapIterator::kFilterUnreachable); 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(); obj != NULL; obj = iterator.next(), IncProgressCounter()) { diff --git a/deps/v8/src/property.cc b/deps/v8/src/property.cc index b579b687b66..96774333e81 100644 --- a/deps/v8/src/property.cc +++ b/deps/v8/src/property.cc @@ -31,62 +31,62 @@ namespace v8 { namespace internal { -#ifdef DEBUG -void LookupResult::Print() { +#ifdef OBJECT_PRINT +void LookupResult::Print(FILE* out) { if (!IsFound()) { - PrintF("Not Found\n"); + PrintF(out, "Not Found\n"); return; } - PrintF("LookupResult:\n"); - PrintF(" -cacheable = %s\n", IsCacheable() ? "true" : "false"); - PrintF(" -attributes = %x\n", GetAttributes()); + PrintF(out, "LookupResult:\n"); + PrintF(out, " -cacheable = %s\n", IsCacheable() ? "true" : "false"); + PrintF(out, " -attributes = %x\n", GetAttributes()); switch (type()) { case NORMAL: - PrintF(" -type = normal\n"); - PrintF(" -entry = %d", GetDictionaryEntry()); + PrintF(out, " -type = normal\n"); + PrintF(out, " -entry = %d", GetDictionaryEntry()); break; case MAP_TRANSITION: - PrintF(" -type = map transition\n"); - PrintF(" -map:\n"); - GetTransitionMap()->Print(); - PrintF("\n"); + PrintF(out, " -type = map transition\n"); + PrintF(out, " -map:\n"); + GetTransitionMap()->Print(out); + PrintF(out, "\n"); break; case CONSTANT_FUNCTION: - PrintF(" -type = constant function\n"); - PrintF(" -function:\n"); - GetConstantFunction()->Print(); - PrintF("\n"); + PrintF(out, " -type = constant function\n"); + PrintF(out, " -function:\n"); + GetConstantFunction()->Print(out); + PrintF(out, "\n"); break; case FIELD: - PrintF(" -type = field\n"); - PrintF(" -index = %d", GetFieldIndex()); - PrintF("\n"); + PrintF(out, " -type = field\n"); + PrintF(out, " -index = %d", GetFieldIndex()); + PrintF(out, "\n"); break; case CALLBACKS: - PrintF(" -type = call backs\n"); - PrintF(" -callback object:\n"); - GetCallbackObject()->Print(); + PrintF(out, " -type = call backs\n"); + PrintF(out, " -callback object:\n"); + GetCallbackObject()->Print(out); break; case INTERCEPTOR: - PrintF(" -type = lookup interceptor\n"); + PrintF(out, " -type = lookup interceptor\n"); break; case CONSTANT_TRANSITION: - PrintF(" -type = constant property transition\n"); + PrintF(out, " -type = constant property transition\n"); break; case NULL_DESCRIPTOR: - PrintF(" =type = null descriptor\n"); + PrintF(out, " =type = null descriptor\n"); break; } } -void Descriptor::Print() { - PrintF("Descriptor "); - GetKey()->ShortPrint(); - PrintF(" @ "); - GetValue()->ShortPrint(); - PrintF(" %d\n", GetDetails().index()); +void Descriptor::Print(FILE* out) { + PrintF(out, "Descriptor "); + GetKey()->ShortPrint(out); + PrintF(out, " @ "); + GetValue()->ShortPrint(out); + PrintF(out, " %d\n", GetDetails().index()); } diff --git a/deps/v8/src/property.h b/deps/v8/src/property.h index 537b4e6e269..c39fe41e75d 100644 --- a/deps/v8/src/property.h +++ b/deps/v8/src/property.h @@ -60,8 +60,8 @@ class Descriptor BASE_EMBEDDED { Object* GetValue() { return value_; } PropertyDetails GetDetails() { return details_; } -#ifdef DEBUG - void Print(); +#ifdef OBJECT_PRINT + void Print(FILE* out); #endif void SetEnumerationIndex(int index) { @@ -310,8 +310,8 @@ class LookupResult BASE_EMBEDDED { return GetValue(); } -#ifdef DEBUG - void Print(); +#ifdef OBJECT_PRINT + void Print(FILE* out); #endif Object* GetValue() { diff --git a/deps/v8/src/regexp.js b/deps/v8/src/regexp.js index dd27266a947..0de66c644ed 100644 --- a/deps/v8/src/regexp.js +++ b/deps/v8/src/regexp.js @@ -32,7 +32,7 @@ const $RegExp = global.RegExp; // A recursive descent parser for Patterns according to the grammar of // 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. if (IS_REGEXP(pattern)) { if (!IS_UNDEFINED(flags)) { @@ -80,7 +80,7 @@ function DoConstructRegExp(object, pattern, flags, isConstructorCall) { function RegExpConstructor(pattern, flags) { if (%_IsConstructCall()) { - DoConstructRegExp(this, pattern, flags, true); + DoConstructRegExp(this, pattern, flags); } else { // RegExp : Called as function; see ECMA-262, section 15.10.3.1. 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 // behavior. if (IS_UNDEFINED(pattern) && %_ArgumentsLength() != 0) { - DoConstructRegExp(this, 'undefined', flags, false); + DoConstructRegExp(this, 'undefined', flags); } else { - DoConstructRegExp(this, pattern, flags, false); + DoConstructRegExp(this, pattern, flags); } } @@ -150,12 +150,12 @@ function BuildResultFromMatchInfo(lastMatchInfo, s) { function RegExpExecNoTests(regexp, string, start) { // Must be called with RegExp, string and positive integer as arguments. - var matchInfo = DoRegExpExec(regexp, string, start); - var result = null; + var matchInfo = %_RegExpExec(regexp, string, start, lastMatchInfo); 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) { // '?' if (!%_ObjectEquals(regexp_key, this)) { regexp_key = this; - regexp_val = new $RegExp(this.source.substring(2, this.source.length), - (this.ignoreCase ? 'i' : '') - + (this.multiline ? 'm' : '')); + regexp_val = new $RegExp(SubString(this.source, 2, this.source.length), + (!this.ignoreCase + ? !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]); // matchIndices is either null or the lastMatchInfo array. diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index 0fd2f8b4bfc..724a4363483 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -7204,7 +7204,7 @@ static MaybeObject* Runtime_StoreContextSlot(Arguments args) { // extension object itself. if ((attributes & READ_ONLY) == 0 || (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()) { // Failure::Exception is converted to a null handle in the // handle-based methods such as SetProperty. We therefore need diff --git a/deps/v8/src/spaces.cc b/deps/v8/src/spaces.cc index 8e9d889607f..fca10329696 100644 --- a/deps/v8/src/spaces.cc +++ b/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++) { if (array[i] != kUnusedChunkTableEntry) { - AtomicWord* subarray = reinterpret_cast<AtomicWord*>(array[i]); + uintptr_t* subarray = reinterpret_cast<uintptr_t*>(array[i]); if (level > 1) { - Release_Store(&array[i], kUnusedChunkTableEntry); + array[i] = kUnusedChunkTableEntry; FreeChunkTables(subarray, 1 << kChunkTableBitsPerLevel, level - 1); } else { - Release_Store(&array[i], kUnusedChunkTableEntry); + array[i] = kUnusedChunkTableEntry; } delete[] subarray; } @@ -822,7 +822,7 @@ void MemoryAllocator::AddToAllocatedChunks(Address addr, intptr_t size) { void MemoryAllocator::AddChunkUsingAddress(uintptr_t chunk_start, uintptr_t chunk_index_base) { - AtomicWord* fine_grained = AllocatedChunksFinder( + uintptr_t* fine_grained = AllocatedChunksFinder( chunk_table_, chunk_index_base, kChunkSizeLog2 + (kChunkTableLevels - 1) * kChunkTableBitsPerLevel, @@ -830,7 +830,7 @@ void MemoryAllocator::AddChunkUsingAddress(uintptr_t chunk_start, int index = FineGrainedIndexForAddress(chunk_index_base); if (fine_grained[index] != kUnusedChunkTableEntry) index++; 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( uintptr_t chunk_start, uintptr_t chunk_index_base) { - AtomicWord* fine_grained = AllocatedChunksFinder( + uintptr_t* fine_grained = AllocatedChunksFinder( chunk_table_, chunk_index_base, kChunkSizeLog2 + (kChunkTableLevels - 1) * kChunkTableBitsPerLevel, @@ -854,22 +854,23 @@ void MemoryAllocator::RemoveChunkFoundUsingAddress( ASSERT(fine_grained != kUnusedChunkTableEntry); int index = FineGrainedIndexForAddress(chunk_index_base); ASSERT(fine_grained[index] != kUnusedChunkTableEntry); - if (fine_grained[index] != static_cast<AtomicWord>(chunk_start)) { + if (fine_grained[index] != chunk_start) { index++; - ASSERT(fine_grained[index] == static_cast<AtomicWord>(chunk_start)); - Release_Store(&fine_grained[index], kUnusedChunkTableEntry); + ASSERT(fine_grained[index] == chunk_start); + fine_grained[index] = kUnusedChunkTableEntry; } else { - Release_Store(&fine_grained[index], fine_grained[index + 1]); - // Here for a moment the two entries are duplicates, but the reader can - // handle that. - NoBarrier_Store(&fine_grained[index + 1], kUnusedChunkTableEntry); + // If only one of the entries is used it must be the first, since + // InAllocatedChunks relies on that. Move things around so that this is + // the case. + fine_grained[index] = fine_grained[index + 1]; + fine_grained[index + 1] = kUnusedChunkTableEntry; } } bool MemoryAllocator::InAllocatedChunks(Address addr) { uintptr_t int_address = reinterpret_cast<uintptr_t>(addr); - AtomicWord* fine_grained = AllocatedChunksFinder( + uintptr_t* fine_grained = AllocatedChunksFinder( chunk_table_, int_address, kChunkSizeLog2 + (kChunkTableLevels - 1) * kChunkTableBitsPerLevel, @@ -877,21 +878,18 @@ bool MemoryAllocator::InAllocatedChunks(Address addr) { if (fine_grained == NULL) return false; int index = FineGrainedIndexForAddress(int_address); 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; index++; if (fine_grained[index] == kUnusedChunkTableEntry) return false; - entry = static_cast<uintptr_t>(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. + entry = fine_grained[index]; if (entry <= int_address && entry + kChunkSize > int_address) return true; return false; } -AtomicWord* MemoryAllocator::AllocatedChunksFinder( - AtomicWord* table, +uintptr_t* MemoryAllocator::AllocatedChunksFinder( + uintptr_t* table, uintptr_t address, int bit_position, CreateTables create_as_needed) { @@ -906,8 +904,8 @@ AtomicWord* MemoryAllocator::AllocatedChunksFinder( address & ((V8_INTPTR_C(1) << bit_position) - 1); ASSERT((table == chunk_table_ && index < kChunkTableTopLevelEntries) || (table != chunk_table_ && index < 1 << kChunkTableBitsPerLevel)); - AtomicWord* more_fine_grained_table = - reinterpret_cast<AtomicWord*>(table[index]); + uintptr_t* more_fine_grained_table = + reinterpret_cast<uintptr_t*>(table[index]); if (more_fine_grained_table == kUnusedChunkTableEntry) { if (create_as_needed == kDontCreateTables) return NULL; int words_needed = 1 << kChunkTableBitsPerLevel; @@ -915,12 +913,11 @@ AtomicWord* MemoryAllocator::AllocatedChunksFinder( words_needed = (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++) { more_fine_grained_table[i] = kUnusedChunkTableEntry; } - Release_Store(&table[index], - reinterpret_cast<AtomicWord>(more_fine_grained_table)); + table[index] = reinterpret_cast<uintptr_t>(more_fine_grained_table); } return AllocatedChunksFinder( more_fine_grained_table, @@ -930,7 +927,7 @@ AtomicWord* MemoryAllocator::AllocatedChunksFinder( } -AtomicWord MemoryAllocator::chunk_table_[kChunkTableTopLevelEntries]; +uintptr_t MemoryAllocator::chunk_table_[kChunkTableTopLevelEntries]; // ----------------------------------------------------------------------------- diff --git a/deps/v8/src/spaces.h b/deps/v8/src/spaces.h index 2c17ef00887..4f2d07b0c81 100644 --- a/deps/v8/src/spaces.h +++ b/deps/v8/src/spaces.h @@ -28,7 +28,6 @@ #ifndef V8_SPACES_H_ #define V8_SPACES_H_ -#include "atomicops.h" #include "list-inl.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 // memory there can be two chunks that cover it. static const int kChunkTableFineGrainedWordsPerEntry = 2; - static const AtomicWord kUnusedChunkTableEntry = 0; + static const uintptr_t kUnusedChunkTableEntry = 0; // Maximum space size in bytes. static intptr_t capacity_; @@ -696,7 +695,7 @@ class MemoryAllocator : public AllStatic { static intptr_t capacity_executable_; // 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. static intptr_t size_; @@ -766,11 +765,11 @@ class MemoryAllocator : public AllStatic { // Controls whether the lookup creates intermediate levels of tables as // needed. enum CreateTables { kDontCreateTables, kCreateTablesAsNeeded }; - static AtomicWord* AllocatedChunksFinder(AtomicWord* table, - uintptr_t address, - int bit_position, - CreateTables create_as_needed); - static void FreeChunkTables(AtomicWord* array, int length, int level); + static uintptr_t* AllocatedChunksFinder(uintptr_t* table, + uintptr_t address, + int bit_position, + CreateTables create_as_needed); + static void FreeChunkTables(uintptr_t* array, int length, int level); static int FineGrainedIndexForAddress(uintptr_t address) { int index = ((address >> kChunkSizeLog2) & ((1 << kChunkTableBitsPerLevel) - 1)); diff --git a/deps/v8/src/string-stream.cc b/deps/v8/src/string-stream.cc index d1859a20fa9..7abd1bbe858 100644 --- a/deps/v8/src/string-stream.cc +++ b/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 // manageable chunks to avoid losing parts of the output in the OS // 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) { char save = buffer_[next]; buffer_[next] = '\0'; - internal::PrintF("%s", &buffer_[position]); + internal::PrintF(out, "%s", &buffer_[position]); buffer_[next] = save; } - internal::PrintF("%s", &buffer_[position]); + internal::PrintF(out, "%s", &buffer_[position]); } diff --git a/deps/v8/src/string-stream.h b/deps/v8/src/string-stream.h index b74c7939588..b3f2e0d76e8 100644 --- a/deps/v8/src/string-stream.h +++ b/deps/v8/src/string-stream.h @@ -138,7 +138,8 @@ class StringStream { FmtElm arg3); // Getting the message out. - void OutputToStdOut(); + void OutputToFile(FILE* out); + void OutputToStdOut() { OutputToFile(stdout); } void Log(); Handle<String> ToString(); SmartPointer<const char> ToCString() const; diff --git a/deps/v8/src/string.js b/deps/v8/src/string.js index 6d4e0c18f7d..95275995e13 100644 --- a/deps/v8/src/string.js +++ b/deps/v8/src/string.js @@ -159,7 +159,7 @@ function StringLocaleCompare(other) { function StringMatch(regexp) { var subject = TO_STRING_INLINE(this); 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]); // lastMatchInfo is defined in regexp.js. 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 // the result. function ExpandReplacement(string, subject, matchInfo, builder) { + var length = string.length; + var builder_elements = builder.elements; var next = %StringIndexOf(string, '$', 0); if (next < 0) { - builder.add(string); + if (length > 0) builder_elements.push(string); return; } // Compute the number of captures; see ECMA-262, 15.5.4.11, p. 102. var m = NUMBER_OF_CAPTURES(matchInfo) >> 1; // Includes the match. - if (next > 0) builder.add(SubString(string, 0, next)); - var length = string.length; + if (next > 0) builder_elements.push(SubString(string, 0, next)); while (true) { var expansion = '$'; @@ -264,7 +265,7 @@ function ExpandReplacement(string, subject, matchInfo, builder) { var peek = %_StringCharCodeAt(string, position); if (peek == 36) { // $$ ++position; - builder.add('$'); + builder_elements.push('$'); } else if (peek == 38) { // $& - match ++position; builder.addSpecialSlice(matchInfo[CAPTURE0], @@ -301,14 +302,14 @@ function ExpandReplacement(string, subject, matchInfo, builder) { // digit capture references, we can only enter here when a // single digit capture reference is outside the range of // captures. - builder.add('$'); + builder_elements.push('$'); --position; } } else { - builder.add('$'); + builder_elements.push('$'); } } else { - builder.add('$'); + builder_elements.push('$'); } // 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. if (next < 0) { if (position < length) { - builder.add(SubString(string, position, length)); + builder_elements.push(SubString(string, position, length)); } return; } // 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 startIndex = 0; + var startMatch = 0; var result = []; outer_loop: while (true) { if (startIndex === length) { - result.push(subject.slice(currentIndex, length)); + result.push(SubString(subject, currentIndex, length)); break; } - var matchInfo = splitMatch(separator, subject, currentIndex, startIndex); - - if (IS_NULL(matchInfo)) { - result.push(subject.slice(currentIndex, length)); + var matchInfo = DoRegExpExec(separator, subject, startIndex); + if (matchInfo == null || length === (startMatch = matchInfo[CAPTURE0])) { + result.push(SubString(subject, currentIndex, length)); break; } - var endIndex = matchInfo[CAPTURE1]; // We ignore a zero-length match at the currentIndex. @@ -584,7 +586,12 @@ function StringSplit(separator, limit) { 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; 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 function StringSubstring(start, end) { var s = TO_STRING_INLINE(this); @@ -844,24 +838,21 @@ function ReplaceResultBuilder(str) { ReplaceResultBuilder.prototype.add = function(str) { str = TO_STRING_INLINE(str); - if (str.length > 0) { - var elements = this.elements; - elements[elements.length] = str; - } + if (str.length > 0) this.elements.push(str); } ReplaceResultBuilder.prototype.addSpecialSlice = function(start, end) { var len = end - start; if (start < 0 || len <= 0) return; - var elements = this.elements; if (start < 0x80000 && len < 0x800) { - elements[elements.length] = (start << 11) | len; + this.elements.push((start << 11) | len); } else { // 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength, // so -len is a smi. - elements[elements.length] = -len; - elements[elements.length] = start; + var elements = this.elements; + elements.push(-len); + elements.push(start); } } diff --git a/deps/v8/src/utils.cc b/deps/v8/src/utils.cc index 2c234bb7622..d0ec4ef5286 100644 --- a/deps/v8/src/utils.cc +++ b/deps/v8/src/utils.cc @@ -45,8 +45,16 @@ void PrintF(const char* format, ...) { } -void Flush() { - fflush(stdout); +void PrintF(FILE* out, const char* format, ...) { + va_list arguments; + va_start(arguments, format); + OS::VFPrint(out, format, arguments); + va_end(arguments); +} + + +void Flush(FILE* out) { + fflush(out); } diff --git a/deps/v8/src/v8-counters.h b/deps/v8/src/v8-counters.h index a5cf42e9057..fa5d581eab0 100644 --- a/deps/v8/src/v8-counters.h +++ b/deps/v8/src/v8-counters.h @@ -28,7 +28,9 @@ #ifndef V8_V8_COUNTERS_H_ #define V8_V8_COUNTERS_H_ +#include "allocation.h" #include "counters.h" +#include "v8globals.h" namespace v8 { namespace internal { diff --git a/deps/v8/src/v8utils.h b/deps/v8/src/v8utils.h index 59b3898bda1..b000d144099 100644 --- a/deps/v8/src/v8utils.h +++ b/deps/v8/src/v8utils.h @@ -43,18 +43,26 @@ namespace internal { // so it works on MacOSX. #if defined(__MACH__) && defined(__APPLE__) #define PRINTF_CHECKING +#define FPRINTF_CHECKING #else // MacOsX. #define PRINTF_CHECKING __attribute__ ((format (printf, 1, 2))) +#define FPRINTF_CHECKING __attribute__ ((format (printf, 2, 3))) #endif #else #define PRINTF_CHECKING +#define FPRINTF_CHECKING #endif // Our version of printf(). void PRINTF_CHECKING PrintF(const char* format, ...); +void FPRINTF_CHECKING PrintF(FILE* out, const char* format, ...); // 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 diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index 60e61b1164c..d2c0960508d 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -34,8 +34,8 @@ // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 3 #define MINOR_VERSION 0 -#define BUILD_NUMBER 3 -#define PATCH_LEVEL 0 +#define BUILD_NUMBER 4 +#define PATCH_LEVEL 1 #define CANDIDATE_VERSION false // Define SONAME to have the SCons build the put a specific SONAME into the diff --git a/deps/v8/src/x64/codegen-x64.cc b/deps/v8/src/x64/codegen-x64.cc index 6c8b3339846..9a255722981 100644 --- a/deps/v8/src/x64/codegen-x64.cc +++ b/deps/v8/src/x64/codegen-x64.cc @@ -6784,9 +6784,9 @@ void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) { // Check that both indices are valid. __ movq(tmp2.reg(), FieldOperand(object.reg(), JSArray::kLengthOffset)); - __ cmpl(tmp2.reg(), index1.reg()); + __ SmiCompare(tmp2.reg(), index1.reg()); deferred->Branch(below_equal); - __ cmpl(tmp2.reg(), index2.reg()); + __ SmiCompare(tmp2.reg(), index2.reg()); deferred->Branch(below_equal); // Bring addresses into index1 and index2. diff --git a/deps/v8/test/cctest/test-heap.cc b/deps/v8/test/cctest/test-heap.cc index aa5fe59bd99..a23ee171f2a 100644 --- a/deps/v8/test/cctest/test-heap.cc +++ b/deps/v8/test/cctest/test-heap.cc @@ -1216,7 +1216,7 @@ TEST(TestInternalWeakListsTraverseWithGC) { TEST(TestSizeOfObjectsVsHeapIteratorPrecision) { InitializeVM(); intptr_t size_of_objects_1 = Heap::SizeOfObjects(); - HeapIterator iterator(HeapIterator::kPreciseFiltering); + HeapIterator iterator(HeapIterator::kFilterFreeListNodes); intptr_t size_of_objects_2 = 0; for (HeapObject* obj = iterator.next(); obj != NULL; @@ -1240,3 +1240,65 @@ TEST(TestSizeOfObjectsVsHeapIteratorPrecision) { 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()); + } +} diff --git a/deps/v8/test/mjsunit/array-slice.js b/deps/v8/test/mjsunit/array-slice.js index 8f9ce535862..50b5b273064 100644 --- a/deps/v8/test/mjsunit/array-slice.js +++ b/deps/v8/test/mjsunit/array-slice.js @@ -218,3 +218,16 @@ 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)); +})(); diff --git a/deps/v8/test/mjsunit/array-sort.js b/deps/v8/test/mjsunit/array-sort.js index a082abcb174..7060c5f366a 100644 --- a/deps/v8/test/mjsunit/array-sort.js +++ b/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 // modification, are permitted provided that the following conditions are // met: @@ -360,3 +360,18 @@ function 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);
\ No newline at end of file diff --git a/deps/v8/test/mjsunit/with-readonly.js b/deps/v8/test/mjsunit/with-readonly.js new file mode 100644 index 00000000000..e29520a4dcc --- /dev/null +++ b/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(); + diff --git a/deps/v8/tools/gyp/v8.gyp b/deps/v8/tools/gyp/v8.gyp index 91cbd6ab3be..6af6611d1be 100644 --- a/deps/v8/tools/gyp/v8.gyp +++ b/deps/v8/tools/gyp/v8.gyp @@ -70,7 +70,8 @@ 'DEBUG', '_DEBUG', 'ENABLE_DISASSEMBLER', - 'V8_ENABLE_CHECKS' + 'V8_ENABLE_CHECKS', + 'OBJECT_PRINT', ], 'msvs_settings': { 'VCCLCompilerTool': { diff --git a/deps/v8/tools/v8.xcodeproj/project.pbxproj b/deps/v8/tools/v8.xcodeproj/project.pbxproj index 51f1cfbf076..5254c6e665a 100644 --- a/deps/v8/tools/v8.xcodeproj/project.pbxproj +++ b/deps/v8/tools/v8.xcodeproj/project.pbxproj @@ -1850,6 +1850,7 @@ DEBUG, ENABLE_LOGGING_AND_PROFILING, V8_ENABLE_CHECKS, + OBJECT_PRINT, ENABLE_VMSTATE_TRACKING, ); GCC_SYMBOLS_PRIVATE_EXTERN = YES; @@ -1914,6 +1915,7 @@ V8_TARGET_ARCH_IA32, DEBUG, V8_ENABLE_CHECKS, + OBJECT_PRINT, ENABLE_DEBUGGER_SUPPORT, ); HEADER_SEARCH_PATHS = ../src; @@ -1976,6 +1978,7 @@ V8_TARGET_ARCH_IA32, DEBUG, V8_ENABLE_CHECKS, + OBJECT_PRINT, ENABLE_DEBUGGER_SUPPORT, ); HEADER_SEARCH_PATHS = ../src; diff --git a/deps/v8/tools/visual_studio/debug.vsprops b/deps/v8/tools/visual_studio/debug.vsprops index 5e3555a9d7f..60b79fe07c0 100644 --- a/deps/v8/tools/visual_studio/debug.vsprops +++ b/deps/v8/tools/visual_studio/debug.vsprops @@ -7,7 +7,7 @@ <Tool Name="VCCLCompilerTool" Optimization="0" - PreprocessorDefinitions="DEBUG;_DEBUG;ENABLE_DISASSEMBLER;V8_ENABLE_CHECKS" + PreprocessorDefinitions="DEBUG;_DEBUG;ENABLE_DISASSEMBLER;V8_ENABLE_CHECKS,OBJECT_PRINT" RuntimeLibrary="1" /> <Tool diff --git a/doc/api/addons.markdown b/doc/api/addons.markdown index 115bd078d75..315015f571e 100644 --- a/doc/api/addons.markdown +++ b/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 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 - 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 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 `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. All Node addons must export a function called `init` with this signature: diff --git a/doc/api/appendix_1.markdown b/doc/api/appendix_1.markdown index 3274fdacd38..395a9414f47 100644 --- a/doc/api/appendix_1.markdown +++ b/doc/api/appendix_1.markdown @@ -2,7 +2,7 @@ There are many third party modules for Node. At the time of writing, August 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 quickly find what are considered to be quality modules. It is not intended diff --git a/doc/api/assert.markdown b/doc/api/assert.markdown index 24685ebf38a..a0607e2d3dc 100644 --- a/doc/api/assert.markdown +++ b/doc/api/assert.markdown @@ -65,8 +65,8 @@ Custom error validation: throw new Error("Wrong value"); }, function(err) { - if ( !(err instanceof Error) || !/value/.test(err) ) { - return false; + if ( (err instanceof Error) && /value/.test(err) ) { + return true; } }, "unexpected error" diff --git a/doc/api/os.markdown b/doc/api/os.markdown index 4429bddbfb6..3c4e1b44fdc 100644 --- a/doc/api/os.markdown +++ b/doc/api/os.markdown @@ -2,6 +2,101 @@ Use `require('os')` to access this module. -### os.getHostname() +### os.hostname() 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 } } ]
\ No newline at end of file diff --git a/doc/api/process.markdown b/doc/api/process.markdown index 5fee9a16da1..3383d59a9f5 100644 --- a/doc/api/process.markdown +++ b/doc/api/process.markdown @@ -59,7 +59,8 @@ standard POSIX signal names such as SIGINT, SIGUSR1, etc. 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 () { 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: - var stdin = process.openStdin(); + process.stdin.resume(); + process.stdin.setEncoding('utf8'); - stdin.setEncoding('utf8'); - - stdin.on('data', function (chunk) { + process.stdin.on('data', function (chunk) { process.stdout.write('data: ' + chunk); }); - stdin.on('end', function () { + process.stdin.on('end', function () { process.stdout.write('end'); }); diff --git a/doc/api/repl.markdown b/doc/api/repl.markdown index 8ae3623a48c..1bdb4f2fcb5 100644 --- a/doc/api/repl.markdown +++ b/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" -### 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` 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 will share the same global object but will have unique I/O. diff --git a/doc/api/streams.markdown b/doc/api/streams.markdown index 88ae04f5c03..51540cc1c03 100644 --- a/doc/api/streams.markdown +++ b/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. -### stream.pipe(destination, [options], [filter]) +### stream.pipe(destination, [options]) 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: - 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 @@ -84,56 +85,18 @@ 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. - var stdin = process.openStdin(); - stdin.pipe(process.stdout, { end: false }); - stdin.on("end", function() { process.stdout.write("Goodbye\n"); }); + process.stdin.resume(); + + process.stdin.pipe(process.stdout, { end: false }); + + process.stdin.on("end", function() { + process.stdout.write("Goodbye\n"); + }); NOTE: If the source stream does not support `pause()` and `resume()`, this function 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'); - var people = []; - - 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) { - write(address(p)); - write(d); - done(); - }); - }); - - people.push(socket); - - socket.on('end', function () { - people.splice(people.indexOf(socket), 1); - }); - }).listen(8000); - - - - ## Writable Stream A `Writable Stream` has the following methods, members, and events. diff --git a/doc/index.html b/doc/index.html index 24db2721111..da1c96296d9 100644 --- a/doc/index.html +++ b/doc/index.html @@ -24,7 +24,7 @@ <li><a href="#links">Links</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.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> </div> <div id="content"> @@ -86,9 +86,9 @@ net.createServer(function (socket) { <a href="http://github.com/ry/node/tree/master">git repo</a> </p> <p> - Stable: 2010.11.16 - <a href="http://nodejs.org/dist/node-v0.2.5.tar.gz">node-v0.2.5.tar.gz</a> - (<a href="http://nodejs.org/docs/v0.2.5/api.html">Documentation</a>) + Stable: 2010.12.30 + <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.6/api.html">Documentation</a>) </p> <p> diff --git a/lib/assert.js b/lib/assert.js index 3b18f05cb4b..b46f28b8625 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -246,13 +246,14 @@ function expectedException(actual, expected) { } if (expected instanceof RegExp) { - if (expected.test(actual)) { - return true; - } - } else if (actual instanceof expected || - expected.call({}, actual) !== false) { + return expected.test(actual); + } else if (actual instanceof expected) { + return true; + } else if ( expected.call({}, actual) === true ) { return true; } + + return false; } function _throws(shouldThrow, block, expected, message) { diff --git a/lib/console.js b/lib/console.js index 857199cf5c9..8f09c5aab6a 100644 --- a/lib/console.js +++ b/lib/console.js @@ -3,8 +3,10 @@ var writeError = process.binding('stdio').writeError; // console object var formatRegExp = /%[sdj]/g; function format(f) { + var util = require('util'); + if (typeof f !== 'string') { - var objects = [], util = require('util'); + var objects = []; for (var i = 0; i < arguments.length; i++) { objects.push(util.inspect(arguments[i])); } @@ -16,15 +18,19 @@ function format(f) { var args = arguments; var str = String(f).replace(formatRegExp, function(x) { switch (x) { - case '%s': return args[i++]; - case '%d': return +args[i++]; + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); case '%j': return JSON.stringify(args[i++]); default: return x; } }); - for (var len = args.length; i < len; ++i) { - str += ' ' + args[i]; + for (var len = args.length, x = args[i]; i < len; x = args[++i]) { + if (x === null || typeof x !== 'object') { + str += ' ' + x; + } else { + str += ' ' + util.inspect(x); + } } return str; } diff --git a/lib/events.js b/lib/events.js index 26e0f061933..ad3ce726c74 100644 --- a/lib/events.js +++ b/lib/events.js @@ -89,6 +89,8 @@ EventEmitter.prototype.once = function(type, listener) { self.removeListener(type, g); listener.apply(this, arguments); }); + + return this; }; EventEmitter.prototype.removeListener = function(type, listener) { diff --git a/lib/os.js b/lib/os.js index 14a582c2e21..5b1bb22d18c 100644 --- a/lib/os.js +++ b/lib/os.js @@ -1,3 +1,10 @@ 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;
\ No newline at end of file diff --git a/lib/readline.js b/lib/readline.js index cc62922623b..341b20b4795 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -83,7 +83,13 @@ Interface.prototype.__defineGetter__('columns', function() { Interface.prototype.setPrompt = function(prompt, length) { 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() { if (this.line.length === 0) return ''; @@ -149,7 +177,7 @@ Interface.prototype.write = function(d) { Interface.prototype._normalWrite = function(b) { // Very simple implementation right now. Should try to break on // new lines. - this.emit('line', b.toString()); + this._onLine(b.toString()); }; Interface.prototype._insertString = function(c) { @@ -304,7 +332,7 @@ Interface.prototype._ttyWrite = function(b) { case 13: /* enter */ var line = this._addHistory(); this.output.write('\r\n'); - this.emit('line', line); + this._onLine(line); break; case 127: /* backspace */ diff --git a/lib/repl.js b/lib/repl.js index 4d144f17cdf..aef0e9e2d3b 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -20,20 +20,21 @@ */ var util = require('util'); -var Script = process.binding('evals').Script; -var evalcx = Script.runInContext; +var vm = require('vm'); var path = require('path'); var fs = require('fs'); var rl = require('readline'); -var context; +var context; var disableColors = process.env.NODE_DISABLE_COLORS ? true : false; + // hack for require.resolve("./relative") to work properly. module.filename = process.cwd() + '/repl'; + function resetContext() { - context = Script.createContext(); + context = vm.createContext(); for (var i in global) context[i] = global[i]; context.module = module; context.require = require; @@ -43,12 +44,13 @@ function resetContext() { // Can overridden with custom print functions, such as `probe` or `eyes.js` exports.writer = util.inspect; + function REPLServer(prompt, stream) { var self = this; if (!context) resetContext(); if (!exports.repl) exports.repl = this; self.context = context; - self.buffered_cmd = ''; + self.bufferedCommand = ''; self.stream = stream || process.openStdin(); self.prompt = prompt || '> '; @@ -70,9 +72,9 @@ function REPLServer(prompt, stream) { rli.setPrompt(self.prompt); rli.on('SIGINT', function() { - if (self.buffered_cmd && self.buffered_cmd.length > 0) { + if (self.bufferedCommand && self.bufferedCommand.length > 0) { rli.write('\n'); - self.buffered_cmd = ''; + self.bufferedCommand = ''; self.displayPrompt(); } else { rli.close(); @@ -104,18 +106,31 @@ function REPLServer(prompt, stream) { if (!skipCatchall) { // The catchall for errors try { - self.buffered_cmd += cmd; + self.bufferedCommand += cmd + '\n'; // This try is for determining if the command is complete, or should // continue onto the next line. try { - // Use evalcx to supply the global context - var ret = evalcx(self.buffered_cmd, context, 'repl'); + // We try to evaluate both expressions e.g. + // '{ 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) { context._ = ret; self.stream.write(exports.writer(ret) + '\n'); } - self.buffered_cmd = ''; + self.bufferedCommand = ''; } catch (e) { // instanceof doesn't work across context switches. if (!(e && e.constructor && e.constructor.name === 'SyntaxError')) { @@ -135,7 +150,7 @@ function REPLServer(prompt, stream) { } else { self.stream.write(e.toString() + '\n'); } - self.buffered_cmd = ''; + self.bufferedCommand = ''; } } @@ -150,21 +165,30 @@ function REPLServer(prompt, stream) { } exports.REPLServer = REPLServer; + // 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. exports.start = function(prompt, source) { return new REPLServer(prompt, source); }; + REPLServer.prototype.displayPrompt = function() { - this.rli.setPrompt(this.buffered_cmd.length ? '... ' : this.prompt); + this.rli.setPrompt(this.bufferedCommand.length ? '... ' : this.prompt); this.rli.prompt(); }; + // read a line from the stream, then eval it 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 // given to the readline interface for handling tab completion. // @@ -192,8 +216,8 @@ REPLServer.prototype.complete = function(line) { if (match[1].length > 1) { filter = match[1]; } - } else if (match = - line.match(/\brequire\s*\(['"](([\w\.\/-]+\/)?([\w\.\/-]*))/)) { + + } else if (match = line.match(requireRE)) { // require('...<Tab>') //TODO: suggest require.exts be exposed to be introspec registered //extensions? @@ -261,7 +285,6 @@ REPLServer.prototype.complete = function(line) { 'url']; completionGroups.push(builtinLibs); } - } // Handle variable member lookup. // 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 '' // foo<|> # all scope vars with filter 'foo' // foo.<|> # completions for 'foo' with filter '' - else if (line.length === 0 || line[line.length - 1].match(/\w|\.|\$/)) { - var simpleExpressionPat = - /(([a-zA-Z_$](?:\w|\$)*)\.)*([a-zA-Z_$](?:\w|\$)*)\.?$/; - match = simpleExpressionPat.exec(line); + } else if (line.length === 0 || line[line.length - 1].match(/\w|\.|\$/)) { + match = simpleExpressionRE.exec(line); if (line.length === 0 || match) { var expr; completeOn = (match ? match[0] : ''); @@ -320,7 +341,7 @@ REPLServer.prototype.complete = function(line) { } } else { try { - obj = evalcx(expr, this.context, 'repl'); + obj = vm.runInContext(expr, this.context, 'repl'); } catch (e) { //console.log("completion eval error, expr='"+expr+"': "+e); } @@ -373,6 +394,7 @@ REPLServer.prototype.complete = function(line) { } completionGroups = newCompletionGroups; } + if (completionGroups.length) { var uniq = {}; // unique completions across all groups completions = []; @@ -398,13 +420,13 @@ REPLServer.prototype.complete = function(line) { return [completions || [], completeOn]; }; + /** * Used to parse and execute the Node REPL commands. * * @param {keyword} keyword The command entered to check. * @return {Boolean} If true it means don't continue parsing the command. */ - REPLServer.prototype.parseREPLKeyword = function(keyword, rest) { var cmd = this.commands[keyword]; if (cmd) { @@ -414,20 +436,23 @@ REPLServer.prototype.parseREPLKeyword = function(keyword, rest) { return false; }; + REPLServer.prototype.defineCommand = function(keyword, cmd) { - if (typeof cmd === 'function') cmd = {action: cmd}; - else if (typeof cmd.action !== 'function') { + if (typeof cmd === 'function') { + cmd = {action: cmd}; + } else if (typeof cmd.action !== 'function') { throw new Error('bad argument, action must be a function'); } this.commands['.' + keyword] = cmd; }; + function defineDefaultCommands(repl) { // TODO remove me after 0.3.x repl.defineCommand('break', { help: 'Sometimes you get stuck, this gets you out', action: function() { - this.buffered_cmd = ''; + this.bufferedCommand = ''; this.displayPrompt(); } }); @@ -436,7 +461,7 @@ function defineDefaultCommands(repl) { help: 'Break, and also clear the local context', action: function() { this.stream.write('Clearing context...\n'); - this.buffered_cmd = ''; + this.bufferedCommand = ''; resetContext(); this.displayPrompt(); } @@ -462,6 +487,7 @@ function defineDefaultCommands(repl) { }); } + function trimWhitespace(cmd) { var trimmer = /^\s*(.+)\s*$/m, matches = trimmer.exec(cmd); @@ -471,6 +497,7 @@ function trimWhitespace(cmd) { } } + function regexpEscape(s) { return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); } @@ -496,9 +523,9 @@ REPLServer.prototype.convertToContext = function(cmd) { } // Replaces: function foo() {}; with: foo = function foo() {}; - matches = scopeFunc.exec(self.buffered_cmd); + matches = scopeFunc.exec(self.bufferedCommand); if (matches && matches.length === 2) { - return matches[1] + ' = ' + self.buffered_cmd; + return matches[1] + ' = ' + self.bufferedCommand; } return cmd; diff --git a/lib/stream.js b/lib/stream.js index e92c1bc5dbe..98f0c37fcbc 100644 --- a/lib/stream.js +++ b/lib/stream.js @@ -7,55 +7,16 @@ function Stream() { util.inherits(Stream, events.EventEmitter); exports.Stream = Stream; -Stream.prototype.pipe = function(dest /* options, filter */) { +Stream.prototype.pipe = function(dest, options) { 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) { - // 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 (false === dest.write(chunk)) source.pause(); } } - if (!filter) { - 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); - } - }); - } - + source.on('data', ondata); function ondrain() { if (source.readable) source.resume(); diff --git a/src/node.cc b/src/node.cc index d6a17450360..f42c82481e9 100644 --- a/src/node.cc +++ b/src/node.cc @@ -1200,7 +1200,7 @@ static void CheckStatus(EV_P_ ev_timer *watcher, int revents) { // check memory 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) { // larger than 128 megs, just start the idle watcher ev_idle_start(EV_A_ &gc_idle); @@ -1225,7 +1225,7 @@ v8::Handle<v8::Value> MemoryUsage(const v8::Arguments& args) { size_t rss, vsize; - int r = OS::GetMemory(&rss, &vsize); + int r = Platform::GetMemory(&rss, &vsize); if (r != 0) { 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) { HandleScope scope; - if (args.Length() != 2 || !args[0]->IsNumber() || !args[1]->IsNumber()) { + if (args.Length() != 2) { return ThrowException(Exception::Error(String::New("Bad argument."))); } @@ -1537,7 +1537,7 @@ static Handle<Value> ProcessTitleGetter(Local<String> property, const AccessorInfo& info) { HandleScope scope; int len; - const char *s = OS::GetProcessTitle(&len); + const char *s = Platform::GetProcessTitle(&len); return scope.Close(s ? String::New(s, len) : String::Empty()); } @@ -1547,7 +1547,7 @@ static void ProcessTitleSetter(Local<String> property, const AccessorInfo& info) { HandleScope scope; 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[]) { HandleScope scope; + int i, j; + Local<FunctionTemplate> process_template = FunctionTemplate::New(); 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)); snprintf(buf, 20, "%d.%d", ev_version_major(), ev_version_minor()); 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.argv - int i, j; Local<Array> arguments = Array::New(argc - option_end_index + 1); arguments->Set(Integer::New(0), String::New(argv[0])); 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; char execPath[size]; - if (OS::GetExecutablePath(execPath, &size) != 0) { + if (Platform::GetExecutablePath(execPath, &size) != 0) { // as a last ditch effort, fallback on argv[0] ? process->Set(String::NewSymbol("execPath"), String::New(argv[0])); } else { @@ -1906,7 +1923,7 @@ static int RegisterSignalHandler(int signal, void (*handler)(int)) { int Start(int argc, char *argv[]) { // 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. node::ParseArgs(&argc, argv); diff --git a/src/node.js b/src/node.js index 2bb46a60f5e..f017d3ab80a 100644 --- a/src/node.js +++ b/src/node.js @@ -35,7 +35,9 @@ 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. var constants; @@ -86,9 +88,10 @@ if (internalModuleCache[id]) return internalModuleCache[id].exports; 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})', - id + '.js'); + id + '.js', + true); var m = {id: id, exports: {}}; fn(m, m.exports, requireNative); m.loaded = true; @@ -332,7 +335,7 @@ sandbox.global = sandbox; sandbox.root = root; - return evals.Script.runInNewContext(content, sandbox, filename); + return runInNewContext(content, sandbox, filename, true); } else { debug('load root module'); // root module @@ -342,7 +345,7 @@ global.__dirname = dirname; global.module = self; - return evals.Script.runInThisContext(content, filename); + return runInThisContext(content, filename, true); } } else { @@ -352,7 +355,7 @@ content + '\n});'; - var compiledWrapper = evals.Script.runInThisContext(wrapper, filename); + var compiledWrapper = runInThisContext(wrapper, filename, true); if (filename === process.argv[1] && global.v8debug) { global.v8debug.Debug.setBreakPoint(compiledWrapper, 0, 0); } @@ -461,7 +464,9 @@ }; - var stdout; + var stdout, stdin; + + process.__defineGetter__('stdout', function() { if (stdout) return stdout; @@ -484,8 +489,8 @@ return stdout; }); - var stdin; - process.openStdin = function() { + + process.__defineGetter__('stdin', function() { if (stdin) return stdin; var binding = process.binding('stdio'), @@ -500,9 +505,13 @@ stdin.readable = true; } - stdin.resume(); - return stdin; + }); + + + process.openStdin = function() { + process.stdin.resume(); + return process.stdin; }; diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 3970a2a514f..ae9e32d2c83 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -177,8 +177,8 @@ Handle<Value> SecureContext::SetKey(const Arguments& args) { } SSL_CTX_use_PrivateKey(sc->ctx_, key); + EVP_PKEY_free(key); BIO_free(bio); - // XXX Free key? return True(); } @@ -1719,19 +1719,19 @@ class Decipher : public ObjectWrap { if (alloc_buf) { delete [] buf; - alloc_buf = false; } buf = ciphertext; len = ciphertext_len; + alloc_buf = true; } else if (strcasecmp(*encoding, "base64") == 0) { unbase64((unsigned char*)buf, len, (char **)&ciphertext, &ciphertext_len); if (alloc_buf) { delete [] buf; - alloc_buf = false; } buf = ciphertext; len = ciphertext_len; + alloc_buf = true; } else if (strcasecmp(*encoding, "binary") == 0) { // Binary - do nothing diff --git a/src/node_net.cc b/src/node_net.cc index 8b9b061bfe8..b711c396921 100644 --- a/src/node_net.cc +++ b/src/node_net.cc @@ -462,62 +462,84 @@ static Handle<Value> Connect(const Arguments& args) { #ifdef __POSIX__ -#define ADDRESS_TO_JS(info, address_storage) \ +#define ADDRESS_TO_JS(info, address_storage, addrlen) \ do { \ char ip[INET6_ADDRSTRLEN]; \ int port; \ struct sockaddr_in *a4; \ struct sockaddr_in6 *a6; \ struct sockaddr_un *au; \ - switch ((address_storage).ss_family) { \ - case AF_INET6: \ - a6 = (struct sockaddr_in6*)&(address_storage); \ - inet_ntop(AF_INET6, &(a6->sin6_addr), ip, INET6_ADDRSTRLEN); \ - port = ntohs(a6->sin6_port); \ - (info)->Set(address_symbol, String::New(ip)); \ - (info)->Set(port_symbol, Integer::New(port)); \ - break; \ - case AF_INET: \ - a4 = (struct sockaddr_in*)&(address_storage); \ - inet_ntop(AF_INET, &(a4->sin_addr), ip, INET6_ADDRSTRLEN); \ - port = ntohs(a4->sin_port); \ - (info)->Set(address_symbol, String::New(ip)); \ - (info)->Set(port_symbol, Integer::New(port)); \ - break; \ - case AF_UNIX: \ - au = (struct sockaddr_un*)&(address_storage); \ - (info)->Set(address_symbol, String::New(au->sun_path)); \ - break; \ - default: \ - (info)->Set(address_symbol, String::Empty()); \ + if (addrlen == 0) { \ + (info)->Set(address_symbol, String::Empty()); \ + } else { \ + switch ((address_storage).ss_family) { \ + case AF_INET6: \ + a6 = (struct sockaddr_in6*)&(address_storage); \ + inet_ntop(AF_INET6, &(a6->sin6_addr), ip, INET6_ADDRSTRLEN); \ + port = ntohs(a6->sin6_port); \ + (info)->Set(address_symbol, String::New(ip)); \ + (info)->Set(port_symbol, Integer::New(port)); \ + break; \ + case AF_INET: \ + a4 = (struct sockaddr_in*)&(address_storage); \ + inet_ntop(AF_INET, &(a4->sin_addr), ip, INET6_ADDRSTRLEN); \ + port = ntohs(a4->sin_port); \ + (info)->Set(address_symbol, String::New(ip)); \ + (info)->Set(port_symbol, Integer::New(port)); \ + break; \ + 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); \ + 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)); \ + } \ + break; \ + default: \ + (info)->Set(address_symbol, String::Empty()); \ + } \ } \ } while (0) #else // __MINGW32__ -#define ADDRESS_TO_JS(info, address_storage) \ +#define ADDRESS_TO_JS(info, address_storage, addrlen) \ do { \ char ip[INET6_ADDRSTRLEN]; \ int port; \ struct sockaddr_in *a4; \ struct sockaddr_in6 *a6; \ - switch ((address_storage).ss_family) { \ - case AF_INET6: \ - a6 = (struct sockaddr_in6*)&(address_storage); \ - inet_ntop(AF_INET6, &(a6->sin6_addr), ip, INET6_ADDRSTRLEN); \ - port = ntohs(a6->sin6_port); \ - (info)->Set(address_symbol, String::New(ip)); \ - (info)->Set(port_symbol, Integer::New(port)); \ - break; \ - case AF_INET: \ - a4 = (struct sockaddr_in*)&(address_storage); \ - inet_ntop(AF_INET, &(a4->sin_addr), ip, INET6_ADDRSTRLEN); \ - port = ntohs(a4->sin_port); \ - (info)->Set(address_symbol, String::New(ip)); \ - (info)->Set(port_symbol, Integer::New(port)); \ - break; \ - default: \ - (info)->Set(address_symbol, String::Empty()); \ + if (addrlen == 0) { \ + (info)->Set(address_symbol, String::Empty()); \ + } else { \ + switch ((address_storage).ss_family) { \ + case AF_INET6: \ + a6 = (struct sockaddr_in6*)&(address_storage); \ + inet_ntop(AF_INET6, &(a6->sin6_addr), ip, INET6_ADDRSTRLEN); \ + port = ntohs(a6->sin6_port); \ + (info)->Set(address_symbol, String::New(ip)); \ + (info)->Set(port_symbol, Integer::New(port)); \ + break; \ + case AF_INET: \ + a4 = (struct sockaddr_in*)&(address_storage); \ + inet_ntop(AF_INET, &(a4->sin_addr), ip, INET6_ADDRSTRLEN); \ + port = ntohs(a4->sin_port); \ + (info)->Set(address_symbol, String::New(ip)); \ + (info)->Set(port_symbol, Integer::New(port)); \ + break; \ + default: \ + (info)->Set(address_symbol, String::Empty()); \ + } \ } \ } while (0) @@ -542,7 +564,7 @@ static Handle<Value> GetSockName(const Arguments& args) { Local<Object> info = Object::New(); - ADDRESS_TO_JS(info, address_storage); + ADDRESS_TO_JS(info, address_storage, len); return scope.Close(info); } @@ -564,7 +586,7 @@ static Handle<Value> GetPeerName(const Arguments& args) { Local<Object> info = Object::New(); - ADDRESS_TO_JS(info, address_storage); + ADDRESS_TO_JS(info, address_storage, len); return scope.Close(info); } @@ -614,6 +636,7 @@ static Handle<Value> Accept(const Arguments& args) { if (peer_fd < 0) { if (errno == EAGAIN) return scope.Close(Null()); + if (errno == ECONNABORTED) return scope.Close(Null()); return ThrowException(ErrnoException(errno, "accept")); } #else // __MINGW32__ @@ -642,7 +665,7 @@ static Handle<Value> Accept(const Arguments& args) { 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); } @@ -787,7 +810,7 @@ static Handle<Value> RecvFrom(const Arguments& args) { 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); } diff --git a/src/node_os.cc b/src/node_os.cc index 2c17d33c81a..9765955d864 100644 --- a/src/node_os.cc +++ b/src/node_os.cc @@ -3,10 +3,14 @@ #include <node.h> #include <v8.h> +#include "platform.h" + #include <errno.h> +#include <string.h> #ifdef __POSIX__ -# include <unistd.h> // gethostname +# include <unistd.h> // gethostname, sysconf +# include <sys/utsname.h> #else // __MINGW32__ # include <winsock2.h> // gethostname #endif // __MINGW32__ @@ -30,13 +34,101 @@ static Handle<Value> GetHostname(const Arguments& args) { 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) { HandleScope scope; 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); } } // namespace node -NODE_MODULE(node_os, node::OS::Initialize); +NODE_MODULE(node_os, node::OS::Initialize);
\ No newline at end of file diff --git a/src/node_script.cc b/src/node_script.cc index 5c4223d10e4..609b6166227 100644 --- a/src/node_script.cc +++ b/src/node_script.cc @@ -2,109 +2,198 @@ #include <node_script.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; - Local<FunctionTemplate> t = FunctionTemplate::New(node::Context::New); + Local<FunctionTemplate> t = FunctionTemplate::New(WrappedContext::New); constructor_template = Persistent<FunctionTemplate>::New(t); constructor_template->InstanceTemplate()->SetInternalFieldCount(1); 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; - node::Context *t = new node::Context(); + WrappedContext *t = new WrappedContext(); t->Wrap(args.This()); return args.This(); } -node::Context::Context() : ObjectWrap() { - context_ = v8::Context::New(); +WrappedContext::WrappedContext() : ObjectWrap() { + context_ = Context::New(); } -node::Context::~Context() { +WrappedContext::~WrappedContext() { context_.Dispose(); } -Local<Object> node::Context::NewInstance() { +Local<Object> WrappedContext::NewInstance() { Local<Object> context = constructor_template->GetFunction()->NewInstance(); return context; } -v8::Persistent<v8::Context> node::Context::GetV8Context() { - return context_; +Persistent<Context> WrappedContext::GetV8Context() { + 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; - Local<FunctionTemplate> t = FunctionTemplate::New(node::Script::New); + Local<FunctionTemplate> t = FunctionTemplate::New(WrappedScript::New); constructor_template = Persistent<FunctionTemplate>::New(t); constructor_template->InstanceTemplate()->SetInternalFieldCount(1); constructor_template->SetClassName(String::NewSymbol("Script")); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "createContext", node::Script::CreateContext); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "runInContext", node::Script::RunInContext); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "runInThisContext", node::Script::RunInThisContext); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "runInNewContext", node::Script::RunInNewContext); - NODE_SET_METHOD(constructor_template, "createContext", node::Script::CreateContext); - NODE_SET_METHOD(constructor_template, "runInContext", node::Script::CompileRunInContext); - NODE_SET_METHOD(constructor_template, "runInThisContext", node::Script::CompileRunInThisContext); - NODE_SET_METHOD(constructor_template, "runInNewContext", node::Script::CompileRunInNewContext); + NODE_SET_PROTOTYPE_METHOD(constructor_template, + "createContext", + WrappedScript::CreateContext); + + NODE_SET_PROTOTYPE_METHOD(constructor_template, + "runInContext", + WrappedScript::RunInContext); - 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()) { return FromConstructorTemplate(constructor_template, args); } HandleScope scope; - node::Script *t = new node::Script(); + WrappedScript *t = new WrappedScript(); t->Wrap(args.Holder()); return - node::Script::EvalMachine<compileCode, thisContext, wrapExternal>(args); + WrappedScript::EvalMachine<compileCode, thisContext, wrapExternal>(args); } -node::Script::~Script() { +WrappedScript::~WrappedScript() { script_.Dispose(); } -Handle<Value> node::Script::CreateContext (const Arguments& args) { +Handle<Value> WrappedScript::CreateContext(const Arguments& args) { HandleScope scope; - Local<v8::Object> context = node::Context::NewInstance(); + Local<Object> context = WrappedContext::NewInstance(); if (args.Length() > 0) { - Local<Object> sandbox = args[0]->ToObject(); 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 - 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 - 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 - 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 - 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 - 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 - node::Script::EvalMachine<compileCode, newContext, returnResult>(args); + WrappedScript::EvalMachine<compileCode, newContext, returnResult>(args); } -template <node::Script::EvalInputFlags iFlag, - node::Script::EvalContextFlags cFlag, - node::Script::EvalOutputFlags oFlag> - Handle<Value> node::Script::EvalMachine(const Arguments& args) { - +template <WrappedScript::EvalInputFlags input_flag, + WrappedScript::EvalContextFlags context_flag, + WrappedScript::EvalOutputFlags output_flag> +Handle<Value> WrappedScript::EvalMachine(const Arguments& args) { HandleScope scope; - if (iFlag == compileCode && args.Length() < 1) { + if (input_flag == compileCode && args.Length() < 1) { return ThrowException(Exception::TypeError( String::New("needs at least 'code' argument."))); } - const int sbIndex = iFlag == compileCode ? 1 : 0; - if (cFlag == userContext && args.Length() < (sbIndex + 1)) { + const int sandbox_index = input_flag == compileCode ? 1 : 0; + if (context_flag == userContext && args.Length() < (sandbox_index + 1)) { return ThrowException(Exception::TypeError( String::New("needs a 'context' argument."))); } Local<String> code; - if (iFlag == compileCode) code = args[0]->ToString(); + if (input_flag == compileCode) code = args[0]->ToString(); Local<Object> sandbox; - if (cFlag == newContext) { - sandbox = args[sbIndex]->IsObject() ? args[sbIndex]->ToObject() : Object::New(); - } else if (cFlag == userContext) { - sandbox = args[sbIndex]->ToObject(); + if (context_flag == newContext) { + sandbox = args[sandbox_index]->IsObject() ? args[sandbox_index]->ToObject() + : Object::New(); + } else if (context_flag == userContext) { + sandbox = args[sandbox_index]->ToObject(); } - const int fnIndex = sbIndex + (cFlag == newContext ? 1 : 0); - Local<String> filename = args.Length() > fnIndex - ? args[fnIndex]->ToString() + const int filename_index = sandbox_index + + (context_flag == newContext ? 1 : 0); + Local<String> filename = args.Length() > filename_index + ? args[filename_index]->ToString() : 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; unsigned int i; - if (cFlag == newContext) { + if (context_flag == newContext) { // 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 - Local<Object> contextArg = args[sbIndex]->ToObject(); - node::Context *nContext = ObjectWrap::Unwrap<node::Context>(sandbox); + Local<Object> contextArg = args[sandbox_index]->ToObject(); + WrappedContext *nContext = ObjectWrap::Unwrap<WrappedContext>(sandbox); context = nContext->GetV8Context(); } // New and user context share code. DRY it up. - if (cFlag == userContext || cFlag == newContext) { + if (context_flag == userContext || context_flag == newContext) { // Enter the context context->Enter(); @@ -226,48 +324,49 @@ template <node::Script::EvalInputFlags iFlag, TryCatch try_catch; Handle<Value> result; - Handle<v8::Script> script; + Handle<Script> script; - if (iFlag == compileCode) { - // well, here node::Script::New would suffice in all cases, but maybe + if (input_flag == compileCode) { + // well, here WrappedScript::New would suffice in all cases, but maybe // Compile has a little better performance where possible - script = oFlag == returnResult ? v8::Script::Compile(code, filename) - : v8::Script::New(code, filename); + script = output_flag == returnResult ? Script::Compile(code, filename) + : Script::New(code, filename); if (script.IsEmpty()) { // 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 return try_catch.ReThrow(); } } else { - node::Script *nScript = ObjectWrap::Unwrap<node::Script>(args.Holder()); - if (!nScript) { + WrappedScript *n_script = ObjectWrap::Unwrap<WrappedScript>(args.Holder()); + if (!n_script) { return ThrowException(Exception::Error( 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( - 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(); if (result.IsEmpty()) return try_catch.ReThrow(); } else { - node::Script *nScript = ObjectWrap::Unwrap<node::Script>(args.Holder()); - if (!nScript) { + WrappedScript *n_script = ObjectWrap::Unwrap<WrappedScript>(args.Holder()); + if (!n_script) { return ThrowException(Exception::Error( 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(); } - if (cFlag == userContext || cFlag == newContext) { + if (context_flag == userContext || context_flag == newContext) { // success! copy changes back onto the sandbox object. keys = context->Global()->GetPropertyNames(); 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! context->DetachGlobal(); context->Exit(); context.Dispose(); - } else if (cFlag == userContext) { + } else if (context_flag == userContext) { // Exit the passed in context. context->Exit(); } @@ -291,11 +390,17 @@ template <node::Script::EvalInputFlags iFlag, return result == args.This() ? result : scope.Close(result); } -void node::InitEvals(Handle<Object> target) { + +void InitEvals(Handle<Object> target) { HandleScope scope; - node::Context::Initialize(target); - node::Script::Initialize(target); + WrappedContext::Initialize(target); + WrappedScript::Initialize(target); } + +} // namespace node + + NODE_MODULE(node_evals, node::InitEvals); + diff --git a/src/node_script.h b/src/node_script.h index bd300459f51..364bd18ca8a 100644 --- a/src/node_script.h +++ b/src/node_script.h @@ -8,54 +8,6 @@ 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); diff --git a/src/platform.h b/src/platform.h index f0252307257..bf7cd52fa3a 100644 --- a/src/platform.h +++ b/src/platform.h @@ -1,9 +1,11 @@ #ifndef NODE_PLATFORM_H_ #define NODE_PLATFORM_H_ +#include <v8.h> + namespace node { -class OS { +class Platform { public: static char** SetupArgs(int argc, char *argv[]); static void SetProcessTitle(char *title); @@ -11,6 +13,11 @@ class OS { static int GetMemory(size_t *rss, size_t *vsize); 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); }; diff --git a/src/platform_cygwin.cc b/src/platform_cygwin.cc index 2c874c74b7d..416cb1735fb 100644 --- a/src/platform_cygwin.cc +++ b/src/platform_cygwin.cc @@ -1,13 +1,21 @@ #include "node.h" #include "platform.h" +#include <v8.h> + #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> namespace node { +using namespace v8; + static char buf[MAXPATHLEN + 1]; 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; } -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. // It would be more efficient to use the UTF-16 value that we can obtain from v8, // 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, // we must query it with getConsoleTitleW 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"); 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); if (*size <= 0) return -1; buffer[*size] = '\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 diff --git a/src/platform_darwin.cc b/src/platform_darwin.cc index f02dc494a39..828d5110564 100644 --- a/src/platform_darwin.cc +++ b/src/platform_darwin.cc @@ -1,27 +1,38 @@ #include "node.h" #include "platform.h" +#include <v8.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 <limits.h> /* PATH_MAX */ +#include <unistd.h> // sysconf +#include <sys/param.h> +#include <sys/sysctl.h> +#include <time.h> + namespace node { + +using namespace v8; + 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; return argv; } -// OS::SetProcessTitle implemented in platform_darwin_proctitle.cc +// Platform::SetProcessTitle implemented in platform_darwin_proctitle.cc } // namespace node #include "platform_darwin_proctitle.cc" namespace node { -const char* OS::GetProcessTitle(int *len) { +const char* Platform::GetProcessTitle(int *len) { if (process_title) { *len = strlen(process_title); return process_title; @@ -32,7 +43,7 @@ const char* OS::GetProcessTitle(int *len) { // Researched by Tim Becker and Michael Knight // 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; 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; int result = _NSGetExecutablePath(buffer, &usize); if (result) return result; @@ -68,4 +79,112 @@ int OS::GetExecutablePath(char* buffer, size_t* size) { 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 diff --git a/src/platform_darwin_proctitle.cc b/src/platform_darwin_proctitle.cc index 6c58ae1c948..e6a1ddd371d 100644 --- a/src/platform_darwin_proctitle.cc +++ b/src/platform_darwin_proctitle.cc @@ -38,7 +38,7 @@ namespace node { -void OS::SetProcessTitle(char *title) { +void Platform::SetProcessTitle(char *title) { static int symbol_lookup_status = 0; // 1=ok, 2=unavailable if (symbol_lookup_status == 2) { // feature is unavailable diff --git a/src/platform_freebsd.cc b/src/platform_freebsd.cc index 0c8b2599f91..6eb5ca2903a 100644 --- a/src/platform_freebsd.cc +++ b/src/platform_freebsd.cc @@ -1,33 +1,41 @@ #include "node.h" #include "platform.h" +#include <v8.h> + #include <stdlib.h> #include <kvm.h> #include <sys/param.h> #include <sys/sysctl.h> #include <sys/user.h> +#include <sys/dkstat.h> +#include <vm/vm_param.h> #include <string.h> #include <paths.h> #include <fcntl.h> #include <unistd.h> +#include <time.h> namespace node { + +using namespace v8; + 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; return argv; } -void OS::SetProcessTitle(char *title) { +void Platform::SetProcessTitle(char *title) { if (process_title) free(process_title); process_title = strdup(title); setproctitle(title); } -const char* OS::GetProcessTitle(int *len) { +const char* Platform::GetProcessTitle(int *len) { if (process_title) { *len = strlen(process_title); return process_title; @@ -36,7 +44,7 @@ const char* OS::GetProcessTitle(int *len) { return NULL; } -int OS::GetMemory(size_t *rss, size_t *vsize) { +int Platform::GetMemory(size_t *rss, size_t *vsize) { kvm_t *kd = NULL; struct kinfo_proc *kinfo = NULL; pid_t pid; @@ -64,7 +72,7 @@ error: } -int OS::GetExecutablePath(char* buffer, size_t* size) { +int Platform::GetExecutablePath(char* buffer, size_t* size) { int mib[4]; mib[0] = CTL_KERN; mib[1] = KERN_PROC; @@ -78,4 +86,125 @@ int OS::GetExecutablePath(char* buffer, size_t* size) { 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, maxcpus, + cur = 0; + char model[512]; + int numcpus; + size_t size; + + size = sizeof(model); + if (sysctlbyname("hw.model", &model, &size, NULL, 0) < 0) { + return -1; + } + size = sizeof(numcpus); + if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0) < 0) { + return -1; + } + + *cpus = Array::New(numcpus); + + size = sizeof(cpuspeed); + if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0) < 0) { + return -1; + } + // kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of ncpu + size = sizeof(maxcpus); + if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) { + return -1; + } + size = maxcpus * CPUSTATES * sizeof(long); + long cp_times[size]; + if (sysctlbyname("kern.cp_times", &cp_times, &size, NULL, 0) < 0) { + return -1; + } + for (int i = 0; i < numcpus; i++) { + cpuinfo = Object::New(); + cputimes = Object::New(); + cputimes->Set(String::New("user"), + Number::New((uint64_t)(cp_times[CP_USER+cur]) * multiplier)); + cputimes->Set(String::New("nice"), + Number::New((uint64_t)(cp_times[CP_NICE+cur]) * multiplier)); + cputimes->Set(String::New("sys"), + Number::New((uint64_t)(cp_times[CP_SYS+cur]) * multiplier)); + cputimes->Set(String::New("idle"), + Number::New((uint64_t)(cp_times[CP_IDLE+cur]) * multiplier)); + cputimes->Set(String::New("irq"), + Number::New((uint64_t)(cp_times[CP_INTR+cur]) * multiplier)); + + 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); + cur+=CPUSTATES; + } + + return 0; +} + +double Platform::GetFreeMemory() { + double pagesize = static_cast<double>(sysconf(_SC_PAGESIZE)); + unsigned long info; + size_t size = sizeof(info); + + if (sysctlbyname("vm.stats.vm.v_free_count", &info, &size, NULL, 0) < 0) { + return -1; + } + + return (static_cast<double>(info)) * pagesize; +} + +double Platform::GetTotalMemory() { +#if defined(HW_PHYSMEM64) + uint64_t info; + static int which[] = {CTL_HW, HW_PHYSMEM64}; +#else + unsigned int info; + static int which[] = {CTL_HW, HW_PHYSMEM}; +#endif + 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 diff --git a/src/platform_linux.cc b/src/platform_linux.cc index 9c4ccc4c99e..00732a0c03e 100644 --- a/src/platform_linux.cc +++ b/src/platform_linux.cc @@ -1,8 +1,13 @@ #include "node.h" #include "platform.h" +#include <v8.h> + #include <sys/param.h> // for MAXPATHLEN -#include <unistd.h> // getpagesize +#include <sys/sysctl.h> +#include <sys/sysinfo.h> +#include <unistd.h> // getpagesize, sysconf +#include <stdio.h> // sscanf, snprintf /* SetProcessTitle */ #include <sys/prctl.h> @@ -10,27 +15,28 @@ #include <stdlib.h> // free #include <string.h> // strdup - namespace node { +using namespace v8; + static char buf[MAXPATHLEN + 1]; static char *process_title; -char** OS::SetupArgs(int argc, char *argv[]) { +char** Platform::SetupArgs(int argc, char *argv[]) { process_title = strdup(argv[0]); return argv; } -void OS::SetProcessTitle(char *title) { +void Platform::SetProcessTitle(char *title) { if (process_title) free(process_title); process_title = strdup(title); prctl(PR_SET_NAME, process_title); } -const char* OS::GetProcessTitle(int *len) { +const char* Platform::GetProcessTitle(int *len) { if (process_title) { *len = strlen(process_title); return process_title; @@ -40,7 +46,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"); if (!f) return -1; @@ -135,11 +141,119 @@ 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); if (*size <= 0) return -1; buffer[*size] = '\0'; return 0; } +int Platform::GetCPUInfo(Local<Array> *cpus) { + HandleScope scope; + 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 %*llu %llu", + &ticks_user, &ticks_nice, &ticks_sys, &ticks_idle, &ticks_intr); + 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(ticks_intr * multiplier)); + + 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() { + struct sysinfo info; + + if (sysinfo(&info) < 0) { + return -1; + } + + return static_cast<double>(info.uptime); +} + +int Platform::GetLoadAvg(Local<Array> *loads) { + struct sysinfo info; + + if (sysinfo(&info) < 0) { + return -1; + } + (*loads)->Set(0, Number::New(static_cast<double>(info.loads[0]) / 65536.0)); + (*loads)->Set(1, Number::New(static_cast<double>(info.loads[1]) / 65536.0)); + (*loads)->Set(2, Number::New(static_cast<double>(info.loads[2]) / 65536.0)); + + return 0; +} + } // namespace node diff --git a/src/platform_openbsd.cc b/src/platform_openbsd.cc new file mode 100644 index 00000000000..b8a3209bcd7 --- /dev/null +++ b/src/platform_openbsd.cc @@ -0,0 +1,201 @@ +#include "node.h" +#include "platform.h" + +#include <v8.h> + +#include <stdlib.h> +#include <kvm.h> +#include <sys/param.h> +#include <sys/sysctl.h> +#include <sys/user.h> +#include <sys/dkstat.h> +#include <uvm/uvm_param.h> +#include <string.h> +#include <paths.h> +#include <fcntl.h> +#include <unistd.h> +#include <time.h> + +#include <stdio.h> +namespace node { + +using namespace v8; + +static char *process_title; + +char** Platform::SetupArgs(int argc, char *argv[]) { + process_title = argc ? strdup(argv[0]) : NULL; + return argv; +} + + +void Platform::SetProcessTitle(char *title) { + if (process_title) free(process_title); + process_title = strdup(title); + setproctitle(title); +} + +const char* Platform::GetProcessTitle(int *len) { + if (process_title) { + *len = strlen(process_title); + return process_title; + } + *len = 0; + return NULL; +} + +int Platform::GetMemory(size_t *rss, size_t *vsize) { + kvm_t *kd = NULL; + struct kinfo_proc2 *kinfo = NULL; + pid_t pid; + int nprocs, max_size = sizeof(struct kinfo_proc2); + size_t page_size = getpagesize(); + + pid = getpid(); + + kd = kvm_open(NULL, _PATH_MEM, NULL, O_RDONLY, "kvm_open"); + if (kd == NULL) goto error; + + kinfo = kvm_getproc2(kd, KERN_PROC_PID, pid, max_size, &nprocs); + if (kinfo == NULL) goto error; + + *rss = kinfo->p_vm_rssize * page_size; + *vsize = kinfo->p_uru_ixrss; + + kvm_close(kd); + + return 0; + +error: + if (kd) kvm_close(kd); + return -1; +} + + +int Platform::GetExecutablePath(char* buffer, size_t* size) { + *size = 0; + return -1; +} + +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; + uint64_t info[CPUSTATES]; + char model[512]; + int numcpus = 1; + static int which[] = {CTL_HW, HW_MODEL, NULL}; + size_t size; + + size = sizeof(model); + if (sysctl(which, 2, &model, &size, NULL, 0) < 0) { + return -1; + } + which[1] = HW_NCPU; + size = sizeof(numcpus); + if (sysctl(which, 2, &numcpus, &size, NULL, 0) < 0) { + return -1; + } + + *cpus = Array::New(numcpus); + + which[1] = HW_CPUSPEED; + size = sizeof(cpuspeed); + if (sysctl(which, 2, &cpuspeed, &size, NULL, 0) < 0) { + return -1; + } + size = sizeof(info); + which[0] = CTL_KERN; + which[1] = KERN_CPTIME2; + for (int i = 0; i < numcpus; i++) { + which[2] = i; + size = sizeof(info); + if (sysctl(which, 3, &info, &size, NULL, 0) < 0) { + return -1; + } + cpuinfo = Object::New(); + cputimes = Object::New(); + cputimes->Set(String::New("user"), + Number::New((uint64_t)(info[CP_USER]) * multiplier)); + cputimes->Set(String::New("nice"), + Number::New((uint64_t)(info[CP_NICE]) * multiplier)); + cputimes->Set(String::New("sys"), + Number::New((uint64_t)(info[CP_SYS]) * multiplier)); + cputimes->Set(String::New("idle"), + Number::New((uint64_t)(info[CP_IDLE]) * multiplier)); + cputimes->Set(String::New("irq"), + Number::New((uint64_t)(info[CP_INTR]) * multiplier)); + + 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); + } + return 0; +} + +double Platform::GetFreeMemory() { + double pagesize = static_cast<double>(sysconf(_SC_PAGESIZE)); + struct uvmexp info; + size_t size = sizeof(info); + static int which[] = {CTL_VM, VM_UVMEXP}; + + if (sysctl(which, 2, &info, &size, NULL, 0) < 0) { + return -1; + } + + return static_cast<double>(info.free) * pagesize; +} + +double Platform::GetTotalMemory() { +#if defined(HW_PHYSMEM64) + uint64_t info; + static int which[] = {CTL_HW, HW_PHYSMEM64}; +#else + unsigned int info; + static int which[] = {CTL_HW, HW_PHYSMEM}; +#endif + 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 diff --git a/src/platform_sunos.cc b/src/platform_sunos.cc index 7723035a3b1..6d70d016809 100644 --- a/src/platform_sunos.cc +++ b/src/platform_sunos.cc @@ -23,24 +23,25 @@ namespace node { +using namespace v8; -char** OS::SetupArgs(int argc, char *argv[]) { +char** Platform::SetupArgs(int argc, char *argv[]) { return argv; } -void OS::SetProcessTitle(char *title) { +void Platform::SetProcessTitle(char *title) { ; } -const char* OS::GetProcessTitle(int *len) { +const char* Platform::GetProcessTitle(int *len) { *len = 0; return NULL; } -int OS::GetMemory(size_t *rss, size_t *vsize) { +int Platform::GetMemory(size_t *rss, size_t *vsize) { pid_t pid = getpid(); size_t page_size = getpagesize(); @@ -67,7 +68,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) { const char *execname = getexecname(); if (!execname) return -1; if (execname[0] == '/') { @@ -86,5 +87,35 @@ int OS::GetExecutablePath(char* buffer, size_t* size) { } +// TODO: libkstat provides all this info. Need to link it though. + + +int Platform::GetCPUInfo(Local<Array> *cpus) { + // http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/psrinfo/psrinfo.pl + return 0; +} + + +double Platform::GetFreeMemory() { + return 0.0; +} + + +double Platform::GetTotalMemory() { + return 0.0; +} + + +double Platform::GetUptime() { + // http://munin-monitoring.org/attachment/ticket/419/uptime + return 0.0; +} + + +int Platform::GetLoadAvg(Local<Array> *loads) { + return 0; +} + + } // namespace node diff --git a/test/simple/test-assert.js b/test/simple/test-assert.js index 4c328402553..e2aa645d4a0 100644 --- a/test/simple/test-assert.js +++ b/test/simple/test-assert.js @@ -165,12 +165,26 @@ assert.throws(function() {assert.ifError(new Error('test error'))}); assert.doesNotThrow(function() {assert.ifError(null)}); assert.doesNotThrow(function() {assert.ifError()}); +// make sure that validating using constructor really works +threw = false; +try { + assert.throws( + function() { + throw {}; + }, + Array + ); +} catch(e) { + threw = true; +} +assert.ok(threw, "wrong constructor validation"); + // use a RegExp to validate error message a.throws(makeBlock(thrower, TypeError), /test/); // use a fn to validate error object a.throws(makeBlock(thrower, TypeError), function(err) { - if (!(err instanceof TypeError) || !/test/.test(err)) { - return false; + if ( (err instanceof TypeError) && /test/.test(err)) { + return true; } }); diff --git a/test/simple/test-buffer.js b/test/simple/test-buffer.js index 818e98cc0ee..e8756a7db4f 100644 --- a/test/simple/test-buffer.js +++ b/test/simple/test-buffer.js @@ -8,8 +8,10 @@ var b = Buffer(1024); // safe constructor console.log('b.length == ' + b.length); assert.strictEqual(1024, b.length); +b[0] = -1; +assert.equal(b[0], 255); + for (var i = 0; i < 1024; i++) { - assert.ok(b[i] >= 0); b[i] = i % 256; } diff --git a/test/simple/test-os-hostname.js b/test/simple/test-os-hostname.js deleted file mode 100644 index b323622717e..00000000000 --- a/test/simple/test-os-hostname.js +++ /dev/null @@ -1,5 +0,0 @@ -var common = require('../common'); -var assert = require('assert'); -var os = require('os'); - -assert.ok(os.getHostname().length > 0); diff --git a/test/simple/test-os.js b/test/simple/test-os.js new file mode 100644 index 00000000000..25cabab3f91 --- /dev/null +++ b/test/simple/test-os.js @@ -0,0 +1,12 @@ +var common = require('../common'); +var assert = require('assert'); +var os = require('os'); + +assert.ok(os.hostname().length > 0); +assert.ok(os.loadavg().length > 0); +assert.ok(os.uptime() > 0); +assert.ok(os.freemem() > 0); +assert.ok(os.totalmem() > 0); +assert.ok(os.cpus().length > 0); +assert.ok(os.type().length > 0); +assert.ok(os.release().length > 0);
\ No newline at end of file diff --git a/test/simple/test-repl.js b/test/simple/test-repl.js index 230907c859d..22b41add013 100644 --- a/test/simple/test-repl.js +++ b/test/simple/test-repl.js @@ -194,7 +194,9 @@ function unix_test() { { client: client_unix, send: 'invoke_me(987)\n', expect: ('\'' + 'invoked 987' + '\'\n' + prompt_unix) }, { client: client_unix, send: 'a = 12345\n', - expect: ('12345' + '\n' + prompt_unix) } + expect: ('12345' + '\n' + prompt_unix) }, + { client: client_unix, send: '{a:1}\n', + expect: ('{ a: 1 }' + '\n' + prompt_unix) }, ]); }); diff --git a/test/simple/test-tls-client-verify.js b/test/simple/test-tls-client-verify.js index 78eb186f6c4..923153b4410 100644 --- a/test/simple/test-tls-client-verify.js +++ b/test/simple/test-tls-client-verify.js @@ -1,3 +1,9 @@ +if (!process.versions.openssl) { + console.error("Skipping because node compiled without OpenSSL."); + process.exit(0); +} + + var testCases = [ { ca: ['ca1-cert'], key: 'agent2-key', diff --git a/test/simple/test-tls-junk-closes-server.js b/test/simple/test-tls-junk-closes-server.js index 57f216fdeb2..f76a1573819 100644 --- a/test/simple/test-tls-junk-closes-server.js +++ b/test/simple/test-tls-junk-closes-server.js @@ -1,3 +1,8 @@ +if (!process.versions.openssl) { + console.error("Skipping because node compiled without OpenSSL."); + process.exit(0); +} + var common = require('../common'); var tls = require('tls'); var fs = require('fs'); diff --git a/test/simple/test-tls-securepair-client.js b/test/simple/test-tls-securepair-client.js index 9bcb7e75d52..2bd4b68c633 100644 --- a/test/simple/test-tls-securepair-client.js +++ b/test/simple/test-tls-securepair-client.js @@ -1,3 +1,13 @@ +// There is a bug with 'openssl s_server' which makes it not flush certain +// important events to stdout when done over a pipe. Therefore we skip this +// test for all openssl versions less than 1.0.0. +if (!process.versions.openssl || + parseInt(process.versions.openssl[0]) < 1) { + console.error("Skipping due to old OpenSSL version."); + process.exit(0); +} + + var common = require('../common'); var join = require('path').join; var net = require('net'); diff --git a/test/simple/test-tls-securepair-server.js b/test/simple/test-tls-securepair-server.js index b172b110010..0131b8c5174 100644 --- a/test/simple/test-tls-securepair-server.js +++ b/test/simple/test-tls-securepair-server.js @@ -1,3 +1,9 @@ +if (!process.versions.openssl) { + console.error("Skipping because node compiled without OpenSSL."); + process.exit(0); +} + + var common = require('../common'); var assert = require('assert'); diff --git a/test/simple/test-tls-server-verify.js b/test/simple/test-tls-server-verify.js index 9d3c094bdaa..914c50f476d 100644 --- a/test/simple/test-tls-server-verify.js +++ b/test/simple/test-tls-server-verify.js @@ -1,3 +1,8 @@ +if (!process.versions.openssl) { + console.error("Skipping because node compiled without OpenSSL."); + process.exit(0); +} + // This is a rather complex test which sets up various TLS servers with node // and connects to them using the 'openssl s_client' command line utility // with various keys. Depending on the certificate authority and other @@ -200,7 +200,7 @@ def configure(conf): conf.env.append_value("CCFLAGS", "-rdynamic") conf.env.append_value("LINKFLAGS_DL", "-rdynamic") - if sys.platform.startswith("freebsd"): + if sys.platform.startswith("freebsd") or sys.platform.startswith("openbsd"): conf.check(lib='kvm', uselib_store='KVM') #if Options.options.debug: @@ -479,7 +479,10 @@ def v8_cmd(bld, variant): , snapshot , profile ) - + + if sys.platform.startswith("sunos"): cmd += ' toolchain=gcc' + + return ("echo '%s' && " % cmd) + cmd |