diff options
Diffstat (limited to 'deps')
251 files changed, 15652 insertions, 2807 deletions
diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index d5c30c7f5..2ff993659 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,61 @@ +2009-05-11: Version 1.2.3 + + Fixed bug in reporting of out-of-memory situations. + + Introduced hidden prototypes on certain builtin prototype objects + such as String.prototype to emulate JSC's behavior of restoring + the original function when deleting functions from those prototype + objects. + + Fixed crash bug in the register allocator. + + +2009-05-04: Version 1.2.2 + + Fixed bug in array sorting for sparse arrays (issue 326). + + Added support for adding a soname when building a shared library + on Linux (issue 151). + + Fixed bug caused by morphing internal ASCII strings to external + two-byte strings. Slices over ASCII strings have to forward ASCII + checks to the underlying buffer string. + + Allowed API call-as-function handlers to be called as + constructors. + + Fixed a crash bug where an external string was disposed but a + slice of the external string survived as a symbol. + + +2009-04-27: Version 1.2.1 + + Added EcmaScript 5 JSON object. + + Fix bug in preemption support on ARM. + + +2009-04-23: Version 1.2.0 + + Optimized floating-point operations on ARM. + + Added a number of extensions to the debugger API. + + Changed the enumeration order for unsigned integer keys to always + be numerical order. + + Added a "read" extension to the shell sample. + + Added support for Array.prototype.reduce and + Array.prototype.reduceRight. + + Added an option to the SCons build to control Microsoft Visual C++ + link-time code generation. + + Fixed a number of bugs (in particular issue 315, issue 316, + issue 317 and issue 318). + + 2009-04-15: Version 1.1.10 Fixed crash bug that occurred when loading a const variable in the @@ -27,13 +85,13 @@ Changed test-debug/ThreadedDebugging to be non-flaky (issue 96). - Fixed step-in handling for Function.prototype.apply and call in + Fixed step-in handling for Function.prototype.apply and call in the debugger (issue 269). Fixed v8::Object::DeleteHiddenValue to not bail out when there are no hidden properties. - Added workaround for crash bug, where external symbol table + Added workaround for crash bug, where external symbol table entries with deleted resources would lead to NPEs when looking up in the symbol table. diff --git a/deps/v8/SConstruct b/deps/v8/SConstruct index 01083cc5d..0c506790e 100644 --- a/deps/v8/SConstruct +++ b/deps/v8/SConstruct @@ -35,6 +35,7 @@ root_dir = dirname(File('SConstruct').rfile().abspath) sys.path.append(join(root_dir, 'tools')) import js2c, utils + # ANDROID_TOP is the top of the Android checkout, fetched from the environment # variable 'TOP'. You will also need to set the CXX, CC, AR and RANLIB # environment variables to the cross-compiling tools. @@ -83,7 +84,8 @@ ANDROID_LINKFLAGS = ['-nostdlib', LIBRARY_FLAGS = { 'all': { - 'CPPDEFINES': ['ENABLE_LOGGING_AND_PROFILING'] + 'CPPDEFINES': ['ENABLE_LOGGING_AND_PROFILING'], + 'CPPPATH': [join(root_dir, 'src')] }, 'gcc': { 'all': { @@ -94,6 +96,7 @@ LIBRARY_FLAGS = { 'CCFLAGS': ['-g', '-O0'], 'CPPDEFINES': ['ENABLE_DISASSEMBLER', 'DEBUG'], 'os:android': { + 'CPPDEFINES': ['ENABLE_DEBUGGER_SUPPORT'], 'CCFLAGS': ['-mthumb'] } }, @@ -102,13 +105,13 @@ LIBRARY_FLAGS = { '-ffunction-sections'], 'os:android': { 'CCFLAGS': ['-mthumb', '-Os'], - 'CPPDEFINES': ['SK_RELEASE', 'NDEBUG'] + 'CPPDEFINES': ['SK_RELEASE', 'NDEBUG', 'ENABLE_DEBUGGER_SUPPORT'] } }, 'os:linux': { 'CCFLAGS': ['-ansi'], 'library:shared': { - 'LIBS': ['pthread', 'rt'] + 'LIBS': ['pthread'] } }, 'os:macos': { @@ -129,9 +132,30 @@ LIBRARY_FLAGS = { '-Wstrict-aliasing=2'], 'CPPPATH': ANDROID_INCLUDES, }, + 'wordsize:32': { + 'arch:x64': { + 'CCFLAGS': ['-m64'], + 'LINKFLAGS': ['-m64'] + } + }, 'wordsize:64': { - 'CCFLAGS': ['-m32'], - 'LINKFLAGS': ['-m32'] + 'arch:ia32': { + 'CCFLAGS': ['-m32'], + 'LINKFLAGS': ['-m32'] + }, + 'arch:arm': { + 'CCFLAGS': ['-m32'], + 'LINKFLAGS': ['-m32'] + } + }, + 'arch:ia32': { + 'CPPDEFINES': ['V8_TARGET_ARCH_IA32'] + }, + 'arch:arm': { + 'CPPDEFINES': ['V8_TARGET_ARCH_ARM'] + }, + 'arch:x64': { + 'CPPDEFINES': ['V8_TARGET_ARCH_X64'] }, 'prof:oprofile': { 'CPPDEFINES': ['ENABLE_OPROFILE_AGENT'] @@ -148,6 +172,9 @@ LIBRARY_FLAGS = { 'ARFLAGS': ['/NOLOGO'], 'CCPDBFLAGS': ['/Zi'] }, + 'arch:ia32': { + 'CPPDEFINES': ['V8_TARGET_ARCH_IA32'] + }, 'mode:debug': { 'CCFLAGS': ['/Od', '/Gm'], 'CPPDEFINES': ['_DEBUG', 'ENABLE_DISASSEMBLER', 'DEBUG'], @@ -160,16 +187,20 @@ LIBRARY_FLAGS = { } }, 'mode:release': { - 'CCFLAGS': ['/O2', '/GL'], - 'LINKFLAGS': ['/OPT:REF', '/OPT:ICF', '/LTCG'], - 'ARFLAGS': ['/LTCG'], + 'CCFLAGS': ['/O2'], + 'LINKFLAGS': ['/OPT:REF', '/OPT:ICF'], 'msvcrt:static': { 'CCFLAGS': ['/MT'] }, 'msvcrt:shared': { 'CCFLAGS': ['/MD'] + }, + 'msvcltcg:on': { + 'CCFLAGS': ['/GL'], + 'LINKFLAGS': ['/LTCG'], + 'ARFLAGS': ['/LTCG'], } - }, + } } } @@ -181,17 +212,16 @@ V8_EXTRA_FLAGS = { 'WARNINGFLAGS': ['-Wall', '-Werror', '-W', '-Wno-unused-parameter'] }, - 'arch:arm': { - 'CPPDEFINES': ['ARM'] - }, - 'arch:android': { - 'CPPDEFINES': ['ARM'] - }, 'os:win32': { 'WARNINGFLAGS': ['-pedantic', '-Wno-long-long'] }, 'os:linux': { - 'WARNINGFLAGS': ['-pedantic'] + 'WARNINGFLAGS': ['-pedantic'], + 'library:shared': { + 'soname:on': { + 'LINKFLAGS': ['-Wl,-soname,${SONAME}'] + } + } }, 'os:macos': { 'WARNINGFLAGS': ['-pedantic'] @@ -209,7 +239,7 @@ V8_EXTRA_FLAGS = { 'LIBS': ['winmm', 'ws2_32'] }, 'arch:arm': { - 'CPPDEFINES': ['ARM'], + 'CPPDEFINES': ['V8_TARGET_ARCH_ARM'], # /wd4996 is to silence the warning about sscanf # used by the arm simulator. 'WARNINGFLAGS': ['/wd4996'] @@ -224,7 +254,7 @@ V8_EXTRA_FLAGS = { MKSNAPSHOT_EXTRA_FLAGS = { 'gcc': { 'os:linux': { - 'LIBS': ['pthread', 'rt'], + 'LIBS': ['pthread'], }, 'os:macos': { 'LIBS': ['pthread'], @@ -238,6 +268,7 @@ MKSNAPSHOT_EXTRA_FLAGS = { }, 'msvc': { 'all': { + 'CPPDEFINES': ['_HAS_EXCEPTIONS=0'], 'LIBS': ['winmm', 'ws2_32'] } } @@ -268,7 +299,7 @@ CCTEST_EXTRA_FLAGS = { 'LIBPATH': [abspath('.')] }, 'os:linux': { - 'LIBS': ['pthread', 'rt'], + 'LIBS': ['pthread'], }, 'os:macos': { 'LIBS': ['pthread'], @@ -279,10 +310,34 @@ CCTEST_EXTRA_FLAGS = { 'os:win32': { 'LIBS': ['winmm', 'ws2_32'] }, - 'wordsize:64': { - 'CCFLAGS': ['-m32'], - 'LINKFLAGS': ['-m32'] + 'os:android': { + 'CPPDEFINES': ['ANDROID', '__ARM_ARCH_5__', '__ARM_ARCH_5T__', + '__ARM_ARCH_5E__', '__ARM_ARCH_5TE__'], + 'CCFLAGS': ANDROID_FLAGS, + 'CPPPATH': ANDROID_INCLUDES, + 'LIBPATH': [ANDROID_TOP + '/out/target/product/generic/obj/lib'], + 'LINKFLAGS': ANDROID_LINKFLAGS, + 'LIBS': ['c', 'stdc++', 'm'], + 'mode:release': { + 'CPPDEFINES': ['SK_RELEASE', 'NDEBUG'] + } }, + 'wordsize:32': { + 'arch:x64': { + 'CCFLAGS': ['-m64'], + 'LINKFLAGS': ['-m64'] + } + }, + 'wordsize:64': { + 'arch:ia32': { + 'CCFLAGS': ['-m32'], + 'LINKFLAGS': ['-m32'] + }, + 'arch:arm': { + 'CCFLAGS': ['-m32'], + 'LINKFLAGS': ['-m32'] + } + } }, 'msvc': { 'all': { @@ -291,6 +346,9 @@ CCTEST_EXTRA_FLAGS = { }, 'library:shared': { 'CPPDEFINES': ['USING_V8_SHARED'] + }, + 'arch:ia32': { + 'CPPDEFINES': ['V8_TARGET_ARCH_IA32'] } } } @@ -307,7 +365,7 @@ SAMPLE_FLAGS = { 'CCFLAGS': ['-fno-rtti', '-fno-exceptions'] }, 'os:linux': { - 'LIBS': ['pthread', 'rt'], + 'LIBS': ['pthread'], }, 'os:macos': { 'LIBS': ['pthread'], @@ -330,9 +388,21 @@ SAMPLE_FLAGS = { 'CPPDEFINES': ['SK_RELEASE', 'NDEBUG'] } }, + 'wordsize:32': { + 'arch:x64': { + 'CCFLAGS': ['-m64'], + 'LINKFLAGS': ['-m64'] + } + }, 'wordsize:64': { - 'CCFLAGS': ['-m32'], - 'LINKFLAGS': ['-m32'] + 'arch:ia32': { + 'CCFLAGS': ['-m32'], + 'LINKFLAGS': ['-m32'] + }, + 'arch:arm': { + 'CCFLAGS': ['-m32'], + 'LINKFLAGS': ['-m32'] + } }, 'mode:release': { 'CCFLAGS': ['-O2'] @@ -359,14 +429,21 @@ SAMPLE_FLAGS = { }, 'mode:release': { 'CCFLAGS': ['/O2'], - 'LINKFLAGS': ['/OPT:REF', '/OPT:ICF', '/LTCG'], + 'LINKFLAGS': ['/OPT:REF', '/OPT:ICF'], 'msvcrt:static': { 'CCFLAGS': ['/MT'] }, 'msvcrt:shared': { 'CCFLAGS': ['/MD'] + }, + 'msvcltcg:on': { + 'CCFLAGS': ['/GL'], + 'LINKFLAGS': ['/LTCG'], } }, + 'arch:ia32': { + 'CPPDEFINES': ['V8_TARGET_ARCH_IA32'] + }, 'mode:debug': { 'CCFLAGS': ['/Od'], 'LINKFLAGS': ['/DEBUG'], @@ -387,7 +464,7 @@ D8_FLAGS = { 'LIBS': ['readline'] }, 'os:linux': { - 'LIBS': ['pthread', 'rt'], + 'LIBS': ['pthread'], }, 'os:macos': { 'LIBS': ['pthread'], @@ -443,17 +520,17 @@ SIMPLE_OPTIONS = { 'toolchain': { 'values': ['gcc', 'msvc'], 'default': TOOLCHAIN_GUESS, - 'help': 'the toolchain to use' + 'help': 'the toolchain to use (' + TOOLCHAIN_GUESS + ')' }, 'os': { 'values': ['freebsd', 'linux', 'macos', 'win32', 'android'], 'default': OS_GUESS, - 'help': 'the os to build for' + 'help': 'the os to build for (' + OS_GUESS + ')' }, 'arch': { - 'values':['arm', 'ia32'], + 'values':['arm', 'ia32', 'x64'], 'default': ARCH_GUESS, - 'help': 'the architecture to build for' + 'help': 'the architecture to build for (' + ARCH_GUESS + ')' }, 'snapshot': { 'values': ['on', 'off', 'nobuild'], @@ -470,10 +547,20 @@ SIMPLE_OPTIONS = { 'default': 'static', 'help': 'the type of library to produce' }, + 'soname': { + 'values': ['on', 'off'], + 'default': 'off', + 'help': 'turn on setting soname for Linux shared library' + }, 'msvcrt': { 'values': ['static', 'shared'], 'default': 'static', - 'help': 'the type of MSVCRT library to use' + 'help': 'the type of Microsoft Visual C++ runtime library to use' + }, + 'msvcltcg': { + 'values': ['on', 'off'], + 'default': 'on', + 'help': 'use Microsoft Visual C++ link-time code generation' }, 'wordsize': { 'values': ['64', '32'], @@ -515,6 +602,49 @@ def GetOptions(): return result +def GetVersionComponents(): + MAJOR_VERSION_PATTERN = re.compile(r"#define\s+MAJOR_VERSION\s+(.*)") + MINOR_VERSION_PATTERN = re.compile(r"#define\s+MINOR_VERSION\s+(.*)") + BUILD_NUMBER_PATTERN = re.compile(r"#define\s+BUILD_NUMBER\s+(.*)") + PATCH_LEVEL_PATTERN = re.compile(r"#define\s+PATCH_LEVEL\s+(.*)") + + patterns = [MAJOR_VERSION_PATTERN, + MINOR_VERSION_PATTERN, + BUILD_NUMBER_PATTERN, + PATCH_LEVEL_PATTERN] + + source = open(join(root_dir, 'src', 'version.cc')).read() + version_components = [] + for pattern in patterns: + match = pattern.search(source) + if match: + version_components.append(match.group(1).strip()) + else: + version_components.append('0') + + return version_components + + +def GetVersion(): + version_components = GetVersionComponents() + + if version_components[len(version_components) - 1] == '0': + version_components.pop() + return '.'.join(version_components) + + +def GetSpecificSONAME(): + SONAME_PATTERN = re.compile(r"#define\s+SONAME\s+\"(.*)\"") + + source = open(join(root_dir, 'src', 'version.cc')).read() + match = SONAME_PATTERN.search(source) + + if match: + return match.group(1).strip() + else: + return '' + + def SplitList(str): return [ s for s in str.split(",") if len(s) > 0 ] @@ -537,6 +667,12 @@ def VerifyOptions(env): Abort("Profiling on windows only supported for static library.") if env['prof'] == 'oprofile' and env['os'] != 'linux': Abort("OProfile is only supported on Linux.") + if env['os'] == 'win32' and env['soname'] == 'on': + Abort("Shared Object soname not applicable for Windows.") + if env['soname'] == 'on' and env['library'] == 'static': + Abort("Shared Object soname not applicable for static library.") + if env['arch'] == 'x64' and env['os'] != 'linux': + Abort("X64 compilation only allowed on Linux OS.") for (name, option) in SIMPLE_OPTIONS.iteritems(): if (not option.get('default')) and (name not in ARGUMENTS): message = ("A value for option %s must be specified (%s)." % @@ -565,13 +701,13 @@ class BuildContext(object): def AddRelevantFlags(self, initial, flags): result = initial.copy() - self.AppendFlags(result, flags.get('all')) toolchain = self.options['toolchain'] if toolchain in flags: self.AppendFlags(result, flags[toolchain].get('all')) for option in sorted(self.options.keys()): value = self.options[option] self.AppendFlags(result, flags[toolchain].get(option + ':' + value)) + self.AppendFlags(result, flags.get('all')) return result def AddRelevantSubFlags(self, options, flags): @@ -667,11 +803,23 @@ def BuildSpecific(env, mode, env_overrides): 'd8': d8_flags } + # Generate library base name. target_id = mode suffix = SUFFIXES[target_id] library_name = 'v8' + suffix + version = GetVersion() + if context.options['soname'] == 'on': + # When building shared object with SONAME version the library name. + library_name += '-' + version env['LIBRARY'] = library_name + # Generate library SONAME if required by the build. + if context.options['soname'] == 'on': + soname = GetSpecificSONAME() + if soname == '': + soname = 'lib' + library_name + '.so' + env['SONAME'] = soname + # Build the object files by invoking SCons recursively. (object_files, shell_files, mksnapshot) = env.SConscript( join('src', 'SConscript'), diff --git a/deps/v8/include/v8-debug.h b/deps/v8/include/v8-debug.h index 4c639c183..3adc0a0d5 100644 --- a/deps/v8/include/v8-debug.h +++ b/deps/v8/include/v8-debug.h @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef V8_DEBUG_H_ -#define V8_DEBUG_H_ +#ifndef V8_V8_DEBUG_H_ +#define V8_V8_DEBUG_H_ #include "v8.h" @@ -79,48 +79,116 @@ enum DebugEvent { }; -/** - * Debug event callback function. - * - * \param event the type of the debug event that triggered the callback - * (enum DebugEvent) - * \param exec_state execution state (JavaScript object) - * \param event_data event specific data (JavaScript object) - * \param data value passed by the user to SetDebugEventListener - */ -typedef void (*DebugEventCallback)(DebugEvent event, - Handle<Object> exec_state, - Handle<Object> event_data, - Handle<Value> data); - - -/** - * Debug message callback function. - * - * \param message the debug message - * \param length length of the message - * \param data the data value passed when registering the message handler - * A DebugMessageHandler does not take posession of the message string, - * and must not rely on the data persisting after the handler returns. - */ -typedef void (*DebugMessageHandler)(const uint16_t* message, int length, - void* data); - -/** - * Debug host dispatch callback function. - * - * \param dispatch the dispatch value - * \param data the data value passed when registering the dispatch handler - */ -typedef void (*DebugHostDispatchHandler)(void* dispatch, - void* data); - - - class EXPORT Debug { public: + /** + * A client object passed to the v8 debugger whose ownership will be taken by + * it. v8 is always responsible for deleting the object. + */ + class ClientData { + public: + virtual ~ClientData() {} + }; + + + /** + * A message object passed to the debug message handler. + */ + class Message { + public: + /** + * Check type of message. + */ + virtual bool IsEvent() const = 0; + virtual bool IsResponse() const = 0; + virtual DebugEvent GetEvent() const = 0; + + /** + * Indicate whether this is a response to a continue command which will + * start the VM running after this is processed. + */ + virtual bool WillStartRunning() const = 0; + + /** + * Access to execution state and event data. Don't store these cross + * callbacks as their content becomes invalid. These objects are from the + * debugger event that started the debug message loop. + */ + virtual Handle<Object> GetExecutionState() const = 0; + virtual Handle<Object> GetEventData() const = 0; + + /** + * Get the debugger protocol JSON. + */ + virtual Handle<String> GetJSON() const = 0; + + /** + * Get the context active when the debug event happened. Note this is not + * the current active context as the JavaScript part of the debugger is + * running in it's own context which is entered at this point. + */ + virtual Handle<Context> GetEventContext() const = 0; + + /** + * Client data passed with the corresponding request if any. This is the + * client_data data value passed into Debug::SendCommand along with the + * request that led to the message or NULL if the message is an event. The + * debugger takes ownership of the data and will delete it even if there is + * no message handler. + */ + virtual ClientData* GetClientData() const = 0; + + virtual ~Message() {} + }; + + + /** + * Debug event callback function. + * + * \param event the type of the debug event that triggered the callback + * (enum DebugEvent) + * \param exec_state execution state (JavaScript object) + * \param event_data event specific data (JavaScript object) + * \param data value passed by the user to SetDebugEventListener + */ + typedef void (*EventCallback)(DebugEvent event, + Handle<Object> exec_state, + Handle<Object> event_data, + Handle<Value> data); + + + /** + * Debug message callback function. + * + * \param message the debug message handler message object + * \param length length of the message + * \param client_data the data value passed when registering the message handler + + * A MessageHandler does not take posession of the message string, + * and must not rely on the data persisting after the handler returns. + * + * This message handler is deprecated. Use MessageHandler2 instead. + */ + typedef void (*MessageHandler)(const uint16_t* message, int length, + ClientData* client_data); + + /** + * Debug message callback function. + * + * \param message the debug message handler message object + + * A MessageHandler does not take posession of the message data, + * and must not rely on the data persisting after the handler returns. + */ + typedef void (*MessageHandler2)(const Message& message); + + /** + * Debug host dispatch callback function. + */ + typedef void (*HostDispatchHandler)(); + // Set a C debug event listener. - static bool SetDebugEventListener(DebugEventCallback that, + static bool SetDebugEventListener(EventCallback that, Handle<Value> data = Handle<Value>()); // Set a JavaScript debug event listener. @@ -130,15 +198,17 @@ class EXPORT Debug { // Break execution of JavaScript. static void DebugBreak(); - // Message based interface. The message protocol is JSON. - static void SetMessageHandler(DebugMessageHandler handler, void* data = NULL, - bool message_handler_thread = true); - static void SendCommand(const uint16_t* command, int length); + // Message based interface. The message protocol is JSON. NOTE the message + // handler thread is not supported any more parameter must be false. + static void SetMessageHandler(MessageHandler handler, + bool message_handler_thread = false); + static void SetMessageHandler2(MessageHandler2 handler); + static void SendCommand(const uint16_t* command, int length, + ClientData* client_data = NULL); // Dispatch interface. - static void SetHostDispatchHandler(DebugHostDispatchHandler handler, - void* data = NULL); - static void SendHostDispatch(void* dispatch); + static void SetHostDispatchHandler(HostDispatchHandler handler, + int period = 100); /** * Run a JavaScript function in the debugger. @@ -176,4 +246,4 @@ class EXPORT Debug { #undef EXPORT -#endif // V8_DEBUG_H_ +#endif // V8_V8_DEBUG_H_ diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index 1ddaee02c..9f59e4e6b 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -41,10 +41,15 @@ #include <stdio.h> #ifdef _WIN32 +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; // NOLINT +typedef unsigned short uint16_t; // NOLINT typedef int int32_t; typedef unsigned int uint32_t; -typedef unsigned short uint16_t; // NOLINT -typedef long long int64_t; // NOLINT +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +// intptr_t is defined in crtdefs.h through stdio.h. // Setup for Windows DLL export/import. When building the V8 DLL the // BUILDING_V8_SHARED needs to be defined. When building a program which uses @@ -529,6 +534,13 @@ class V8EXPORT Script { * Returns the script id value. */ Local<Value> Id(); + + /** + * Associate an additional data object with the script. This is mainly used + * with the debugger as this data object is only available through the + * debugger API. + */ + void SetData(Handle<Value> data); }; @@ -540,9 +552,19 @@ class V8EXPORT Message { Local<String> Get() const; Local<String> GetSourceLine() const; + /** + * Returns the resource name for the script from where the function causing + * the error originates. + */ Handle<Value> GetScriptResourceName() const; /** + * Returns the resource data for the script from where the function causing + * the error originates. + */ + Handle<Value> GetScriptData() const; + + /** * Returns the number, 1-based, of the line where the error occurred. */ int GetLineNumber() const; @@ -805,14 +827,14 @@ class V8EXPORT String : public Primitive { }; /** - * Get the ExternalStringResource for an external string. Only - * valid if IsExternal() returns true. + * Get the ExternalStringResource for an external string. Returns + * NULL if IsExternal() doesn't return true. */ ExternalStringResource* GetExternalStringResource() const; /** * Get the ExternalAsciiStringResource for an external ascii string. - * Only valid if IsExternalAscii() returns true. + * Returns NULL if IsExternalAscii() doesn't return true. */ ExternalAsciiStringResource* GetExternalAsciiStringResource() const; @@ -1028,6 +1050,18 @@ class V8EXPORT Object : public Value { bool Set(Handle<Value> key, Handle<Value> value, PropertyAttribute attribs = None); + + // Sets a local property on this object, bypassing interceptors and + // overriding accessors or read-only properties. + // + // Note that if the object has an interceptor the property will be set + // locally, but since the interceptor takes precedence the local property + // will only be returned if the interceptor doesn't return a value. + // + // Note also that this only works for named properties. + bool ForceSet(Handle<Value> key, + Handle<Value> value, + PropertyAttribute attribs = None); Local<Value> Get(Handle<Value> key); // TODO(1245389): Replace the type-specific versions of these @@ -1093,6 +1127,9 @@ class V8EXPORT Object : public Value { /** * Returns the identity hash for this object. The current implemenation uses * a hidden property on the object to store the identity hash. + * + * The return value will never be 0. Also, it is not guaranteed to be + * unique. */ int GetIdentityHash(); @@ -2043,6 +2080,24 @@ class V8EXPORT V8 { static void ResumeProfiler(); /** + * If logging is performed into a memory buffer (via --logfile=*), allows to + * retrieve previously written messages. This can be used for retrieving + * profiler log data in the application. This function is thread-safe. + * + * Caller provides a destination buffer that must exist during GetLogLines + * call. Only whole log lines are copied into the buffer. + * + * \param from_pos specified a point in a buffer to read from, 0 is the + * beginning of a buffer. It is assumed that caller updates its current + * position using returned size value from the previous call. + * \param dest_buf destination buffer for log data. + * \param max_size size of the destination buffer. + * \returns actual size of log data copied into buffer. + */ + static int GetLogLines(int from_pos, char* dest_buf, int max_size); + + + /** * Releases any resources used by v8 and stops any utility threads * that may be running. Note that disposing v8 is permanent, it * cannot be reinitialized. @@ -2223,6 +2278,14 @@ class V8EXPORT Context { static bool InContext(); /** + * Associate an additional data object with the context. This is mainly used + * with the debugger to provide additional information on the context through + * the debugger API. + */ + void SetData(Handle<Value> data); + Local<Value> GetData(); + + /** * Stack-allocated class which sets the execution context for all * operations executed within a local scope. */ diff --git a/deps/v8/samples/shell.cc b/deps/v8/samples/shell.cc index 087d4fd46..27ed293e7 100644 --- a/deps/v8/samples/shell.cc +++ b/deps/v8/samples/shell.cc @@ -38,6 +38,7 @@ bool ExecuteString(v8::Handle<v8::String> source, bool print_result, bool report_exceptions); v8::Handle<v8::Value> Print(const v8::Arguments& args); +v8::Handle<v8::Value> Read(const v8::Arguments& args); v8::Handle<v8::Value> Load(const v8::Arguments& args); v8::Handle<v8::Value> Quit(const v8::Arguments& args); v8::Handle<v8::Value> Version(const v8::Arguments& args); @@ -52,6 +53,8 @@ int RunMain(int argc, char* argv[]) { v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); // Bind the global 'print' function to the C++ Print callback. global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print)); + // Bind the global 'read' function to the C++ Read callback. + global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read)); // Bind the global 'load' function to the C++ Load callback. global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load)); // Bind the 'quit' function @@ -135,6 +138,25 @@ v8::Handle<v8::Value> Print(const v8::Arguments& args) { } +// The callback that is invoked by v8 whenever the JavaScript 'read' +// function is called. This function loads the content of the file named in +// the argument into a JavaScript string. +v8::Handle<v8::Value> Read(const v8::Arguments& args) { + if (args.Length() != 1) { + return v8::ThrowException(v8::String::New("Bad parameters")); + } + v8::String::Utf8Value file(args[0]); + if (*file == NULL) { + return v8::ThrowException(v8::String::New("Error loading file")); + } + v8::Handle<v8::String> source = ReadFile(*file); + if (source.IsEmpty()) { + return v8::ThrowException(v8::String::New("Error loading file")); + } + return source; +} + + // The callback that is invoked by v8 whenever the JavaScript 'load' // function is called. Loads, compiles and executes its argument // JavaScript file. diff --git a/deps/v8/src/SConscript b/deps/v8/src/SConscript index 97fb7d6ca..59c452b7c 100644..100755 --- a/deps/v8/src/SConscript +++ b/deps/v8/src/SConscript @@ -50,23 +50,36 @@ SOURCES = { 'scopeinfo.cc', 'scopes.cc', 'serialize.cc', 'snapshot-common.cc', 'spaces.cc', 'string-stream.cc', 'stub-cache.cc', 'token.cc', 'top.cc', 'unicode.cc', 'usage-analyzer.cc', 'utils.cc', 'v8-counters.cc', - 'v8.cc', 'v8threads.cc', 'variables.cc', 'virtual-frame.cc', 'zone.cc' + 'v8.cc', 'v8threads.cc', 'variables.cc', 'version.cc', + 'virtual-frame.cc', 'zone.cc' ], 'arch:arm': [ - 'assembler-arm.cc', 'builtins-arm.cc', 'codegen-arm.cc', 'cpu-arm.cc', - 'disasm-arm.cc', 'debug-arm.cc', 'frames-arm.cc', 'ic-arm.cc', - 'jump-target-arm.cc', 'macro-assembler-arm.cc', - 'regexp-macro-assembler-arm.cc', 'register-allocator-arm.cc', - 'stub-cache-arm.cc', 'virtual-frame-arm.cc' + 'arm/assembler-arm.cc', 'arm/builtins-arm.cc', + 'arm/codegen-arm.cc', 'arm/cpu-arm.cc', 'arm/disasm-arm.cc', + 'arm/debug-arm.cc', 'arm/frames-arm.cc', 'arm/ic-arm.cc', + 'arm/jump-target-arm.cc', 'arm/macro-assembler-arm.cc', + 'arm/regexp-macro-assembler-arm.cc', + 'arm/register-allocator-arm.cc', 'arm/stub-cache-arm.cc', + 'arm/virtual-frame-arm.cc' ], 'arch:ia32': [ - 'assembler-ia32.cc', 'builtins-ia32.cc', 'codegen-ia32.cc', - 'cpu-ia32.cc', 'disasm-ia32.cc', 'debug-ia32.cc', 'frames-ia32.cc', - 'ic-ia32.cc', 'jump-target-ia32.cc', 'macro-assembler-ia32.cc', - 'regexp-macro-assembler-ia32.cc', 'register-allocator-ia32.cc', - 'stub-cache-ia32.cc', 'virtual-frame-ia32.cc' + 'ia32/assembler-ia32.cc', 'ia32/builtins-ia32.cc', + 'ia32/codegen-ia32.cc', 'ia32/cpu-ia32.cc', 'ia32/disasm-ia32.cc', + 'ia32/debug-ia32.cc', 'ia32/frames-ia32.cc', 'ia32/ic-ia32.cc', + 'ia32/jump-target-ia32.cc', 'ia32/macro-assembler-ia32.cc', + 'ia32/regexp-macro-assembler-ia32.cc', + 'ia32/register-allocator-ia32.cc', 'ia32/stub-cache-ia32.cc', + 'ia32/virtual-frame-ia32.cc' ], - 'simulator:arm': ['simulator-arm.cc'], + 'arch:x64': [ + 'x64/assembler-x64.cc', 'x64/builtins-x64.cc', + 'x64/codegen-x64.cc', 'x64/cpu-x64.cc', 'x64/disasm-x64.cc', + 'x64/debug-x64.cc', 'x64/frames-x64.cc', 'x64/ic-x64.cc', + 'x64/jump-target-x64.cc', 'x64/macro-assembler-x64.cc', + # 'x64/regexp-macro-assembler-x64.cc', + 'x64/stub-cache-x64.cc' + ], + 'simulator:arm': ['arm/simulator-arm.cc'], 'os:freebsd': ['platform-freebsd.cc', 'platform-posix.cc'], 'os:linux': ['platform-linux.cc', 'platform-posix.cc'], 'os:android': ['platform-linux.cc', 'platform-posix.cc'], @@ -121,6 +134,7 @@ debug-delay.js mirror-delay.js date-delay.js regexp-delay.js +json-delay.js '''.split() diff --git a/deps/v8/src/accessors.cc b/deps/v8/src/accessors.cc index d779eb26a..4cd93be87 100644 --- a/deps/v8/src/accessors.cc +++ b/deps/v8/src/accessors.cc @@ -252,6 +252,24 @@ const AccessorDescriptor Accessors::ScriptColumnOffset = { // +// Accessors::ScriptData +// + + +Object* Accessors::ScriptGetData(Object* object, void*) { + Object* script = JSValue::cast(object)->value(); + return Script::cast(script)->data(); +} + + +const AccessorDescriptor Accessors::ScriptData = { + ScriptGetData, + IllegalSetter, + 0 +}; + + +// // Accessors::ScriptType // @@ -290,6 +308,25 @@ const AccessorDescriptor Accessors::ScriptLineEnds = { // +// Accessors::ScriptGetContextData +// + + +Object* Accessors::ScriptGetContextData(Object* object, void*) { + HandleScope scope; + Handle<Script> script(Script::cast(JSValue::cast(object)->value())); + return script->context_data(); +} + + +const AccessorDescriptor Accessors::ScriptContextData = { + ScriptGetContextData, + IllegalSetter, + 0 +}; + + +// // Accessors::FunctionPrototype // diff --git a/deps/v8/src/accessors.h b/deps/v8/src/accessors.h index 938b0142a..1dd8fdd2f 100644 --- a/deps/v8/src/accessors.h +++ b/deps/v8/src/accessors.h @@ -45,8 +45,10 @@ namespace v8 { namespace internal { V(ScriptId) \ V(ScriptLineOffset) \ V(ScriptColumnOffset) \ + V(ScriptData) \ V(ScriptType) \ V(ScriptLineEnds) \ + V(ScriptContextData) \ V(ObjectPrototype) // Accessors contains all predefined proxy accessors. @@ -84,8 +86,10 @@ class Accessors : public AllStatic { static Object* ScriptGetSource(Object* object, void*); static Object* ScriptGetLineOffset(Object* object, void*); static Object* ScriptGetColumnOffset(Object* object, void*); + static Object* ScriptGetData(Object* object, void*); static Object* ScriptGetType(Object* object, void*); static Object* ScriptGetLineEnds(Object* object, void*); + static Object* ScriptGetContextData(Object* object, void*); static Object* ObjectGetPrototype(Object* receiver, void*); static Object* ObjectSetPrototype(JSObject* receiver, Object* value, void*); diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index a190b9cfb..c250412e4 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -37,6 +37,7 @@ #include "serialize.h" #include "snapshot.h" #include "v8threads.h" +#include "version.h" #define LOG_API(expr) LOG(ApiEntryCall(expr)) @@ -444,6 +445,40 @@ void Context::Exit() { } +void Context::SetData(v8::Handle<Value> data) { + if (IsDeadCheck("v8::Context::SetData()")) return; + ENTER_V8; + { + HandleScope scope; + i::Handle<i::Context> env = Utils::OpenHandle(this); + i::Handle<i::Object> raw_data = Utils::OpenHandle(*data); + ASSERT(env->IsGlobalContext()); + if (env->IsGlobalContext()) { + env->set_data(*raw_data); + } + } +} + + +v8::Local<v8::Value> Context::GetData() { + if (IsDeadCheck("v8::Context::GetData()")) return v8::Local<Value>(); + ENTER_V8; + i::Object* raw_result = NULL; + { + HandleScope scope; + i::Handle<i::Context> env = Utils::OpenHandle(this); + ASSERT(env->IsGlobalContext()); + if (env->IsGlobalContext()) { + raw_result = env->data(); + } else { + return Local<Value>(); + } + } + i::Handle<i::Object> result(raw_result); + return Utils::ToLocal(result); +} + + void** v8::HandleScope::RawClose(void** value) { if (!ApiCheck(!is_closed_, "v8::HandleScope::Close()", @@ -1108,6 +1143,19 @@ Local<Value> Script::Id() { } +void Script::SetData(v8::Handle<Value> data) { + ON_BAILOUT("v8::Script::SetData()", return); + LOG_API("Script::SetData"); + { + HandleScope scope; + i::Handle<i::JSFunction> fun = Utils::OpenHandle(this); + i::Handle<i::Object> raw_data = Utils::OpenHandle(*data); + i::Handle<i::Script> script(i::Script::cast(fun->shared()->script())); + script->set_data(*raw_data); + } +} + + // --- E x c e p t i o n s --- @@ -1199,6 +1247,22 @@ v8::Handle<Value> Message::GetScriptResourceName() const { } +v8::Handle<Value> Message::GetScriptData() const { + if (IsDeadCheck("v8::Message::GetScriptResourceData()")) { + return Local<Value>(); + } + ENTER_V8; + HandleScope scope; + i::Handle<i::JSObject> obj = + i::Handle<i::JSObject>::cast(Utils::OpenHandle(this)); + // Return this.script.data. + i::Handle<i::JSValue> script = + i::Handle<i::JSValue>::cast(GetProperty(obj, "script")); + i::Handle<i::Object> data(i::Script::cast(script->value())->data()); + return scope.Close(Utils::ToLocal(data)); +} + + static i::Handle<i::Object> CallV8HeapFunction(const char* name, i::Handle<i::Object> recv, int argc, @@ -1806,6 +1870,26 @@ bool v8::Object::Set(v8::Handle<Value> key, v8::Handle<Value> value, } +bool v8::Object::ForceSet(v8::Handle<Value> key, + v8::Handle<Value> value, + v8::PropertyAttribute attribs) { + ON_BAILOUT("v8::Object::ForceSet()", return false); + ENTER_V8; + i::Handle<i::JSObject> self = Utils::OpenHandle(this); + i::Handle<i::Object> key_obj = Utils::OpenHandle(*key); + i::Handle<i::Object> value_obj = Utils::OpenHandle(*value); + EXCEPTION_PREAMBLE(); + i::Handle<i::Object> obj = i::ForceSetProperty( + self, + key_obj, + value_obj, + static_cast<PropertyAttributes>(attribs)); + has_pending_exception = obj.is_null(); + EXCEPTION_BAILOUT_CHECK(false); + return true; +} + + Local<Value> v8::Object::Get(v8::Handle<Value> key) { ON_BAILOUT("v8::Object::Get()", return Local<v8::Value>()); ENTER_V8; @@ -2023,7 +2107,12 @@ int v8::Object::GetIdentityHash() { if (hash->IsSmi()) { hash_value = i::Smi::cast(*hash)->value(); } else { - hash_value = random() & i::Smi::kMaxValue; // Limit range to fit a smi. + int attempts = 0; + do { + hash_value = random() & i::Smi::kMaxValue; // Limit range to fit a smi. + attempts++; + } while (hash_value == 0 && attempts < 30); + hash_value = hash_value != 0 ? hash_value : 1; // never return 0 i::SetProperty(hidden_props, hash_symbol, i::Handle<i::Object>(i::Smi::FromInt(hash_value)), @@ -2266,9 +2355,12 @@ v8::String::ExternalStringResource* v8::String::GetExternalStringResource() const { EnsureInitialized("v8::String::GetExternalStringResource()"); i::Handle<i::String> str = Utils::OpenHandle(this); - ASSERT(str->IsExternalTwoByteString()); - void* resource = i::Handle<i::ExternalTwoByteString>::cast(str)->resource(); - return reinterpret_cast<ExternalStringResource*>(resource); + if (i::StringShape(*str).IsExternalTwoByte()) { + void* resource = i::Handle<i::ExternalTwoByteString>::cast(str)->resource(); + return reinterpret_cast<ExternalStringResource*>(resource); + } else { + return NULL; + } } @@ -2276,9 +2368,12 @@ v8::String::ExternalAsciiStringResource* v8::String::GetExternalAsciiStringResource() const { EnsureInitialized("v8::String::GetExternalAsciiStringResource()"); i::Handle<i::String> str = Utils::OpenHandle(this); - ASSERT(str->IsExternalAsciiString()); - void* resource = i::Handle<i::ExternalAsciiString>::cast(str)->resource(); - return reinterpret_cast<ExternalAsciiStringResource*>(resource); + if (i::StringShape(*str).IsExternalAscii()) { + void* resource = i::Handle<i::ExternalAsciiString>::cast(str)->resource(); + return reinterpret_cast<ExternalAsciiStringResource*>(resource); + } else { + return NULL; + } } @@ -2373,7 +2468,9 @@ bool v8::V8::Dispose() { const char* v8::V8::GetVersion() { - return "1.1.10.4"; + static v8::internal::EmbeddedVector<char, 128> buffer; + v8::internal::Version::GetString(buffer); + return buffer.start(); } @@ -2589,10 +2686,13 @@ Local<Value> v8::External::Wrap(void* data) { ENTER_V8; if ((reinterpret_cast<intptr_t>(data) & kAlignedPointerMask) == 0) { uintptr_t data_ptr = reinterpret_cast<uintptr_t>(data); - int data_value = static_cast<int>(data_ptr >> kAlignedPointerShift); + intptr_t data_value = + static_cast<intptr_t>(data_ptr >> kAlignedPointerShift); STATIC_ASSERT(sizeof(data_ptr) == sizeof(data_value)); - i::Handle<i::Object> obj(i::Smi::FromInt(data_value)); - return Utils::ToLocal(obj); + if (i::Smi::IsIntptrValid(data_value)) { + i::Handle<i::Object> obj(i::Smi::FromIntptr(data_value)); + return Utils::ToLocal(obj); + } } return ExternalNewImpl(data); } @@ -2603,7 +2703,8 @@ void* v8::External::Unwrap(v8::Handle<v8::Value> value) { i::Handle<i::Object> obj = Utils::OpenHandle(*value); if (obj->IsSmi()) { // The external value was an aligned pointer. - uintptr_t result = i::Smi::cast(*obj)->value() << kAlignedPointerShift; + uintptr_t result = static_cast<uintptr_t>( + i::Smi::cast(*obj)->value()) << kAlignedPointerShift; return reinterpret_cast<void*>(result); } return ExternalValueImpl(obj); @@ -3021,6 +3122,11 @@ void V8::ResumeProfiler() { #endif } +int V8::GetLogLines(int from_pos, char* dest_buf, int max_size) { +#ifdef ENABLE_LOGGING_AND_PROFILING + return i::Logger::GetLogLines(from_pos, dest_buf, max_size); +#endif +} String::Utf8Value::Utf8Value(v8::Handle<v8::Value> obj) { EnsureInitialized("v8::String::Utf8Value::Utf8Value()"); @@ -3180,8 +3286,8 @@ Local<Value> Exception::Error(v8::Handle<v8::String> raw_message) { // --- D e b u g S u p p o r t --- - -bool Debug::SetDebugEventListener(DebugEventCallback that, Handle<Value> data) { +#ifdef ENABLE_DEBUGGER_SUPPORT +bool Debug::SetDebugEventListener(EventCallback that, Handle<Value> data) { EnsureInitialized("v8::Debug::SetDebugEventListener()"); ON_BAILOUT("v8::Debug::SetDebugEventListener()", return false); ENTER_V8; @@ -3211,31 +3317,54 @@ void Debug::DebugBreak() { } -void Debug::SetMessageHandler(v8::DebugMessageHandler handler, void* data, +static v8::Debug::MessageHandler message_handler = NULL; + +static void MessageHandlerWrapper(const v8::Debug::Message& message) { + if (message_handler) { + v8::String::Value json(message.GetJSON()); + message_handler(*json, json.length(), message.GetClientData()); + } +} + + +void Debug::SetMessageHandler(v8::Debug::MessageHandler handler, bool message_handler_thread) { EnsureInitialized("v8::Debug::SetMessageHandler"); ENTER_V8; - i::Debugger::SetMessageHandler(handler, data, message_handler_thread); -} + // Message handler thread not supported any more. Parameter temporally left in + // the API for client compatability reasons. + CHECK(!message_handler_thread); - -void Debug::SendCommand(const uint16_t* command, int length) { - if (!i::V8::HasBeenSetup()) return; - i::Debugger::ProcessCommand(i::Vector<const uint16_t>(command, length)); + // TODO(sgjesse) support the old message handler API through a simple wrapper. + message_handler = handler; + if (message_handler != NULL) { + i::Debugger::SetMessageHandler(MessageHandlerWrapper); + } else { + i::Debugger::SetMessageHandler(NULL); + } } -void Debug::SetHostDispatchHandler(v8::DebugHostDispatchHandler handler, - void* data) { - EnsureInitialized("v8::Debug::SetHostDispatchHandler"); +void Debug::SetMessageHandler2(v8::Debug::MessageHandler2 handler) { + EnsureInitialized("v8::Debug::SetMessageHandler"); ENTER_V8; - i::Debugger::SetHostDispatchHandler(handler, data); + i::Debugger::SetMessageHandler(handler); } -void Debug::SendHostDispatch(void* dispatch) { +void Debug::SendCommand(const uint16_t* command, int length, + ClientData* client_data) { if (!i::V8::HasBeenSetup()) return; - i::Debugger::ProcessHostDispatch(dispatch); + i::Debugger::ProcessCommand(i::Vector<const uint16_t>(command, length), + client_data); +} + + +void Debug::SetHostDispatchHandler(HostDispatchHandler handler, + int period) { + EnsureInitialized("v8::Debug::SetHostDispatchHandler"); + ENTER_V8; + i::Debugger::SetHostDispatchHandler(handler, period); } @@ -3263,7 +3392,7 @@ Handle<Value> Debug::Call(v8::Handle<v8::Function> fun, bool Debug::EnableAgent(const char* name, int port) { return i::Debugger::StartAgent(name, port); } - +#endif // ENABLE_DEBUGGER_SUPPORT namespace internal { diff --git a/deps/v8/src/assembler-arm-inl.h b/deps/v8/src/arm/assembler-arm-inl.h index 315605e78..fe64761e3 100644 --- a/deps/v8/src/assembler-arm-inl.h +++ b/deps/v8/src/arm/assembler-arm-inl.h @@ -34,10 +34,10 @@ // significantly by Google Inc. // Copyright 2006-2008 the V8 project authors. All rights reserved. -#ifndef V8_ASSEMBLER_ARM_INL_H_ -#define V8_ASSEMBLER_ARM_INL_H_ +#ifndef V8_ARM_ASSEMBLER_ARM_INL_H_ +#define V8_ARM_ASSEMBLER_ARM_INL_H_ -#include "assembler-arm.h" +#include "arm/assembler-arm.h" #include "cpu.h" @@ -246,4 +246,4 @@ void Assembler::set_target_address_at(Address pc, Address target) { } } // namespace v8::internal -#endif // V8_ASSEMBLER_ARM_INL_H_ +#endif // V8_ARM_ASSEMBLER_ARM_INL_H_ diff --git a/deps/v8/src/assembler-arm.cc b/deps/v8/src/arm/assembler-arm.cc index ba7638ec1..191c865a8 100644 --- a/deps/v8/src/assembler-arm.cc +++ b/deps/v8/src/arm/assembler-arm.cc @@ -36,7 +36,7 @@ #include "v8.h" -#include "assembler-arm-inl.h" +#include "arm/assembler-arm-inl.h" #include "serialize.h" namespace v8 { namespace internal { diff --git a/deps/v8/src/assembler-arm.h b/deps/v8/src/arm/assembler-arm.h index f965ebd8a..d7535e0da 100644 --- a/deps/v8/src/assembler-arm.h +++ b/deps/v8/src/arm/assembler-arm.h @@ -37,8 +37,8 @@ // A light-weight ARM Assembler // Generates user mode instructions for the ARM architecture up to version 5 -#ifndef V8_ASSEMBLER_ARM_H_ -#define V8_ASSEMBLER_ARM_H_ +#ifndef V8_ARM_ASSEMBLER_ARM_H_ +#define V8_ARM_ASSEMBLER_ARM_H_ #include "assembler.h" @@ -164,23 +164,23 @@ enum Coprocessor { // Condition field in instructions enum Condition { - eq = 0 << 28, - ne = 1 << 28, - cs = 2 << 28, - hs = 2 << 28, - cc = 3 << 28, - lo = 3 << 28, - mi = 4 << 28, - pl = 5 << 28, - vs = 6 << 28, - vc = 7 << 28, - hi = 8 << 28, - ls = 9 << 28, - ge = 10 << 28, - lt = 11 << 28, - gt = 12 << 28, - le = 13 << 28, - al = 14 << 28 + eq = 0 << 28, // Z set equal. + ne = 1 << 28, // Z clear not equal. + cs = 2 << 28, // C set unsigned higher or same. + hs = 2 << 28, // C set unsigned higher or same. + cc = 3 << 28, // C clear unsigned lower. + lo = 3 << 28, // C clear unsigned lower. + mi = 4 << 28, // N set negative. + pl = 5 << 28, // N clear positive or zero. + vs = 6 << 28, // V set overflow. + vc = 7 << 28, // V clear no overflow. + hi = 8 << 28, // C set, Z clear unsigned higher. + ls = 9 << 28, // C clear or Z set unsigned lower or same. + ge = 10 << 28, // N == V greater or equal. + lt = 11 << 28, // N != V less than. + gt = 12 << 28, // Z clear, N == V greater than. + le = 13 << 28, // Z set or N != V less then or equal + al = 14 << 28 // always. }; @@ -786,4 +786,4 @@ class Assembler : public Malloced { } } // namespace v8::internal -#endif // V8_ASSEMBLER_ARM_H_ +#endif // V8_ARM_ASSEMBLER_ARM_H_ diff --git a/deps/v8/src/builtins-arm.cc b/deps/v8/src/arm/builtins-arm.cc index 2e6f25518..9c7a42ab1 100644 --- a/deps/v8/src/builtins-arm.cc +++ b/deps/v8/src/arm/builtins-arm.cc @@ -34,7 +34,7 @@ namespace v8 { namespace internal { -#define __ masm-> +#define __ ACCESS_MASM(masm) void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) { @@ -58,6 +58,16 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { // -- sp[...]: constructor arguments // ----------------------------------- + Label non_function_call; + // Check that the function is not a smi. + __ tst(r1, Operand(kSmiTagMask)); + __ b(eq, &non_function_call); + // Check that the function is a JSFunction. + __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); + __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); + __ cmp(r2, Operand(JS_FUNCTION_TYPE)); + __ b(ne, &non_function_call); + // Enter a construct frame. __ EnterConstructFrame(); @@ -169,7 +179,17 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { __ LeaveConstructFrame(); __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1)); __ add(sp, sp, Operand(kPointerSize)); - __ mov(pc, Operand(lr)); + __ Jump(lr); + + // r0: number of arguments + // r1: called object + __ bind(&non_function_call); + + // Set expected number of arguments to zero (not changing r0). + __ mov(r2, Operand(0)); + __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); + __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), + RelocInfo::CODE_TARGET); } @@ -218,8 +238,9 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, __ mov(r5, Operand(r4)); __ mov(r6, Operand(r4)); __ mov(r7, Operand(r4)); - if (kR9Available == 1) + if (kR9Available == 1) { __ mov(r9, Operand(r4)); + } // Invoke the code and pass argc as r0. __ mov(r0, Operand(r3)); @@ -234,7 +255,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, // Exit the JS frame and remove the parameters (except function), and return. // Respect ABI stack constraint. __ LeaveInternalFrame(); - __ mov(pc, lr); + __ Jump(lr); // r0: result } @@ -416,15 +437,35 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { __ push(r0); __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_JS); - // Eagerly check for stack-overflow before starting to push the arguments. - // r0: number of arguments - Label okay; + Label no_preemption, retry_preemption; + __ bind(&retry_preemption); ExternalReference stack_guard_limit_address = ExternalReference::address_of_stack_guard_limit(); __ mov(r2, Operand(stack_guard_limit_address)); __ ldr(r2, MemOperand(r2)); + __ cmp(sp, r2); + __ b(hi, &no_preemption); + + // We have encountered a preemption or stack overflow already before we push + // the array contents. Save r0 which is the Smi-tagged length of the array. + __ push(r0); + + // Runtime routines expect at least one argument, so give it a Smi. + __ mov(r0, Operand(Smi::FromInt(0))); + __ push(r0); + __ CallRuntime(Runtime::kStackGuard, 1); + + // Since we returned, it wasn't a stack overflow. Restore r0 and try again. + __ pop(r0); + __ b(&retry_preemption); + + __ bind(&no_preemption); + + // Eagerly check for stack-overflow before starting to push the arguments. + // r0: number of arguments. + // r2: stack limit. + Label okay; __ sub(r2, sp, r2); - __ sub(r2, r2, Operand(3 * kPointerSize)); // limit, index, receiver __ cmp(r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); __ b(hi, &okay); @@ -523,7 +564,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { // Tear down the internal frame and remove function, receiver and args. __ LeaveInternalFrame(); __ add(sp, sp, Operand(3 * kPointerSize)); - __ mov(pc, lr); + __ Jump(lr); } @@ -642,14 +683,14 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { // Exit frame and return. LeaveArgumentsAdaptorFrame(masm); - __ mov(pc, lr); + __ Jump(lr); // ------------------------------------------- // Dont adapt arguments. // ------------------------------------------- __ bind(&dont_adapt_arguments); - __ mov(pc, r3); + __ Jump(r3); } diff --git a/deps/v8/src/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc index 6fdabc3c5..1930a7c2f 100644 --- a/deps/v8/src/codegen-arm.cc +++ b/deps/v8/src/arm/codegen-arm.cc @@ -38,7 +38,8 @@ namespace v8 { namespace internal { -#define __ masm_-> +#define __ ACCESS_MASM(masm_) + // ------------------------------------------------------------------------- // CodeGenState implementation. @@ -146,13 +147,13 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) { frame_->EmitPush(r0); frame_->CallRuntime(Runtime::kNewContext, 1); // r0 holds the result - if (kDebug) { - JumpTarget verified_true(this); - __ cmp(r0, Operand(cp)); - verified_true.Branch(eq); - __ stop("NewContext: r0 is expected to be the same as cp"); - verified_true.Bind(); - } +#ifdef DEBUG + JumpTarget verified_true(this); + __ cmp(r0, Operand(cp)); + verified_true.Branch(eq); + __ stop("NewContext: r0 is expected to be the same as cp"); + verified_true.Bind(); +#endif // Update context local. __ str(cp, frame_->Context()); } @@ -276,7 +277,7 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) { frame_->Exit(); __ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize)); - __ mov(pc, lr); + __ Jump(lr); } // Code generation state must be reset. @@ -653,37 +654,27 @@ void CodeGenerator::ToBoolean(JumpTarget* true_target, } -class GetPropertyStub : public CodeStub { - public: - GetPropertyStub() { } - - private: - Major MajorKey() { return GetProperty; } - int MinorKey() { return 0; } - void Generate(MacroAssembler* masm); -}; - - -class SetPropertyStub : public CodeStub { - public: - SetPropertyStub() { } - - private: - Major MajorKey() { return SetProperty; } - int MinorKey() { return 0; } - void Generate(MacroAssembler* masm); -}; - - class GenericBinaryOpStub : public CodeStub { public: - explicit GenericBinaryOpStub(Token::Value op) : op_(op) { } + GenericBinaryOpStub(Token::Value op, + OverwriteMode mode) + : op_(op), mode_(mode) { } private: Token::Value op_; + OverwriteMode mode_; + + // Minor key encoding in 16 bits. + class ModeBits: public BitField<OverwriteMode, 0, 2> {}; + class OpBits: public BitField<Token::Value, 2, 14> {}; Major MajorKey() { return GenericBinaryOp; } - int MinorKey() { return static_cast<int>(op_); } + int MinorKey() { + // Encode the parameters in a unique 16 bit value. + return OpBits::encode(op_) + | ModeBits::encode(mode_); + } + void Generate(MacroAssembler* masm); const char* GetName() { @@ -708,7 +699,8 @@ class GenericBinaryOpStub : public CodeStub { }; -void CodeGenerator::GenericBinaryOperation(Token::Value op) { +void CodeGenerator::GenericBinaryOperation(Token::Value op, + OverwriteMode overwrite_mode) { VirtualFrame::SpilledScope spilled_scope(this); // sp[0] : y // sp[1] : x @@ -727,7 +719,7 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op) { case Token::SAR: { frame_->EmitPop(r0); // r0 : y frame_->EmitPop(r1); // r1 : x - GenericBinaryOpStub stub(op); + GenericBinaryOpStub stub(op, overwrite_mode); frame_->CallStub(&stub, 0); break; } @@ -767,11 +759,13 @@ class DeferredInlineSmiOperation: public DeferredCode { DeferredInlineSmiOperation(CodeGenerator* generator, Token::Value op, int value, - bool reversed) + bool reversed, + OverwriteMode overwrite_mode) : DeferredCode(generator), op_(op), value_(value), - reversed_(reversed) { + reversed_(reversed), + overwrite_mode_(overwrite_mode) { set_comment("[ DeferredInlinedSmiOperation"); } @@ -781,6 +775,7 @@ class DeferredInlineSmiOperation: public DeferredCode { Token::Value op_; int value_; bool reversed_; + OverwriteMode overwrite_mode_; }; @@ -844,7 +839,7 @@ void DeferredInlineSmiOperation::Generate() { break; } - GenericBinaryOpStub igostub(op_); + GenericBinaryOpStub igostub(op_, overwrite_mode_); Result arg0 = generator()->allocator()->Allocate(r1); ASSERT(arg0.is_valid()); Result arg1 = generator()->allocator()->Allocate(r0); @@ -856,7 +851,8 @@ void DeferredInlineSmiOperation::Generate() { void CodeGenerator::SmiOperation(Token::Value op, Handle<Object> value, - bool reversed) { + bool reversed, + OverwriteMode mode) { VirtualFrame::SpilledScope spilled_scope(this); // NOTE: This is an attempt to inline (a bit) more of the code for // some possible smi operations (like + and -) when (at least) one @@ -875,7 +871,7 @@ void CodeGenerator::SmiOperation(Token::Value op, switch (op) { case Token::ADD: { DeferredCode* deferred = - new DeferredInlineSmiOperation(this, op, int_value, reversed); + new DeferredInlineSmiOperation(this, op, int_value, reversed, mode); __ add(r0, r0, Operand(value), SetCC); deferred->enter()->Branch(vs); @@ -887,7 +883,7 @@ void CodeGenerator::SmiOperation(Token::Value op, case Token::SUB: { DeferredCode* deferred = - new DeferredInlineSmiOperation(this, op, int_value, reversed); + new DeferredInlineSmiOperation(this, op, int_value, reversed, mode); if (!reversed) { __ sub(r0, r0, Operand(value), SetCC); @@ -905,7 +901,7 @@ void CodeGenerator::SmiOperation(Token::Value op, case Token::BIT_XOR: case Token::BIT_AND: { DeferredCode* deferred = - new DeferredInlineSmiOperation(this, op, int_value, reversed); + new DeferredInlineSmiOperation(this, op, int_value, reversed, mode); __ tst(r0, Operand(kSmiTagMask)); deferred->enter()->Branch(ne); switch (op) { @@ -925,12 +921,12 @@ void CodeGenerator::SmiOperation(Token::Value op, __ mov(ip, Operand(value)); frame_->EmitPush(ip); frame_->EmitPush(r0); - GenericBinaryOperation(op); + GenericBinaryOperation(op, mode); } else { int shift_value = int_value & 0x1f; // least significant 5 bits DeferredCode* deferred = - new DeferredInlineSmiOperation(this, op, shift_value, false); + new DeferredInlineSmiOperation(this, op, shift_value, false, mode); __ tst(r0, Operand(kSmiTagMask)); deferred->enter()->Branch(ne); __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // remove tags @@ -982,7 +978,7 @@ void CodeGenerator::SmiOperation(Token::Value op, frame_->EmitPush(ip); frame_->EmitPush(r0); } - GenericBinaryOperation(op); + GenericBinaryOperation(op, mode); break; } @@ -1427,13 +1423,13 @@ void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { } else { frame_->CallRuntime(Runtime::kPushContext, 1); } - if (kDebug) { - JumpTarget verified_true(this); - __ cmp(r0, Operand(cp)); - verified_true.Branch(eq); - __ stop("PushContext: r0 is expected to be the same as cp"); - verified_true.Bind(); - } +#ifdef DEBUG + JumpTarget verified_true(this); + __ cmp(r0, Operand(cp)); + verified_true.Branch(eq); + __ stop("PushContext: r0 is expected to be the same as cp"); + verified_true.Bind(); +#endif // Update context local. __ str(cp, frame_->Context()); ASSERT(frame_->height() == original_height); @@ -1487,8 +1483,8 @@ void CodeGenerator::GenerateFastCaseSwitchJumpTable( // Test for a Smi value in a HeapNumber. __ tst(r0, Operand(kSmiTagMask)); is_smi.Branch(eq); - __ ldr(r1, MemOperand(r0, HeapObject::kMapOffset - kHeapObjectTag)); - __ ldrb(r1, MemOperand(r1, Map::kInstanceTypeOffset - kHeapObjectTag)); + __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); + __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); __ cmp(r1, Operand(HEAP_NUMBER_TYPE)); default_target->Branch(ne); frame_->EmitPush(r0); @@ -2339,7 +2335,9 @@ void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { VirtualFrame::SpilledScope spilled_scope(this); Comment cmnt(masm_, "[ DebuggerStatament"); CodeForStatementPosition(node); +#ifdef ENABLE_DEBUGGER_SUPPORT frame_->CallRuntime(Runtime::kDebugBreak, 0); +#endif // Ignore the return value. ASSERT(frame_->height() == original_height); } @@ -2523,7 +2521,9 @@ void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot, if (s->is_eval_scope()) { Label next, fast; - if (!context.is(tmp)) __ mov(tmp, Operand(context)); + if (!context.is(tmp)) { + __ mov(tmp, Operand(context)); + } __ bind(&next); // Terminate at global context. __ ldr(tmp2, FieldMemOperand(tmp, HeapObject::kMapOffset)); @@ -2934,15 +2934,24 @@ void CodeGenerator::VisitAssignment(Assignment* node) { LoadAndSpill(node->value()); } else { + // +=, *= and similar binary assignments. + // Get the old value of the lhs. target.GetValueAndSpill(NOT_INSIDE_TYPEOF); Literal* literal = node->value()->AsLiteral(); + bool overwrite = + (node->value()->AsBinaryOperation() != NULL && + node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); if (literal != NULL && literal->handle()->IsSmi()) { - SmiOperation(node->binary_op(), literal->handle(), false); + SmiOperation(node->binary_op(), + literal->handle(), + false, + overwrite ? OVERWRITE_RIGHT : NO_OVERWRITE); frame_->EmitPush(r0); } else { LoadAndSpill(node->value()); - GenericBinaryOperation(node->binary_op()); + GenericBinaryOperation(node->binary_op(), + overwrite ? OVERWRITE_RIGHT : NO_OVERWRITE); frame_->EmitPush(r0); } } @@ -3822,19 +3831,39 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { // is a literal small integer. Literal* lliteral = node->left()->AsLiteral(); Literal* rliteral = node->right()->AsLiteral(); + // NOTE: The code below assumes that the slow cases (calls to runtime) + // never return a constant/immutable object. + bool overwrite_left = + (node->left()->AsBinaryOperation() != NULL && + node->left()->AsBinaryOperation()->ResultOverwriteAllowed()); + bool overwrite_right = + (node->right()->AsBinaryOperation() != NULL && + node->right()->AsBinaryOperation()->ResultOverwriteAllowed()); if (rliteral != NULL && rliteral->handle()->IsSmi()) { LoadAndSpill(node->left()); - SmiOperation(node->op(), rliteral->handle(), false); + SmiOperation(node->op(), + rliteral->handle(), + false, + overwrite_right ? OVERWRITE_RIGHT : NO_OVERWRITE); } else if (lliteral != NULL && lliteral->handle()->IsSmi()) { LoadAndSpill(node->right()); - SmiOperation(node->op(), lliteral->handle(), true); + SmiOperation(node->op(), + lliteral->handle(), + true, + overwrite_left ? OVERWRITE_LEFT : NO_OVERWRITE); } else { + OverwriteMode overwrite_mode = NO_OVERWRITE; + if (overwrite_left) { + overwrite_mode = OVERWRITE_LEFT; + } else if (overwrite_right) { + overwrite_mode = OVERWRITE_RIGHT; + } LoadAndSpill(node->left()); LoadAndSpill(node->right()); - GenericBinaryOperation(node->op()); + GenericBinaryOperation(node->op(), overwrite_mode); } frame_->EmitPush(r0); } @@ -4067,7 +4096,8 @@ bool CodeGenerator::HasValidEntryRegisters() { return true; } #undef __ -#define __ masm-> +#define __ ACCESS_MASM(masm) + Handle<String> Reference::GetName() { ASSERT(type_ == NAMED); @@ -4305,167 +4335,80 @@ void Reference::SetValue(InitState init_state) { } -void GetPropertyStub::Generate(MacroAssembler* masm) { - // sp[0]: key - // sp[1]: receiver - Label slow, fast; - // Get the key and receiver object from the stack. - __ ldm(ia, sp, r0.bit() | r1.bit()); - // Check that the key is a smi. - __ tst(r0, Operand(kSmiTagMask)); - __ b(ne, &slow); - __ mov(r0, Operand(r0, ASR, kSmiTagSize)); - // Check that the object isn't a smi. - __ tst(r1, Operand(kSmiTagMask)); - __ b(eq, &slow); - - // Check that the object is some kind of JS object EXCEPT JS Value type. - // In the case that the object is a value-wrapper object, - // we enter the runtime system to make sure that indexing into string - // objects work as intended. - ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); - __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); - __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); - __ cmp(r2, Operand(JS_OBJECT_TYPE)); - __ b(lt, &slow); - - // Get the elements array of the object. - __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); - // Check that the object is in fast mode (not dictionary). - __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset)); - __ cmp(r3, Operand(Factory::hash_table_map())); - __ b(eq, &slow); - // Check that the key (index) is within bounds. - __ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset)); - __ cmp(r0, Operand(r3)); - __ b(lo, &fast); - - // Slow case: Push extra copies of the arguments (2). - __ bind(&slow); - __ ldm(ia, sp, r0.bit() | r1.bit()); - __ stm(db_w, sp, r0.bit() | r1.bit()); - // Do tail-call to runtime routine. - __ TailCallRuntime(ExternalReference(Runtime::kGetProperty), 2); - - // Fast case: Do the load. - __ bind(&fast); - __ add(r3, r1, Operand(Array::kHeaderSize - kHeapObjectTag)); - __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2)); - __ cmp(r0, Operand(Factory::the_hole_value())); - // In case the loaded value is the_hole we have to consult GetProperty - // to ensure the prototype chain is searched. - __ b(eq, &slow); - - __ StubReturn(1); -} - - -void SetPropertyStub::Generate(MacroAssembler* masm) { - // r0 : value - // sp[0] : key - // sp[1] : receiver - - Label slow, fast, array, extra, exit; - // Get the key and the object from the stack. - __ ldm(ia, sp, r1.bit() | r3.bit()); // r1 = key, r3 = receiver - // Check that the key is a smi. - __ tst(r1, Operand(kSmiTagMask)); - __ b(ne, &slow); - // Check that the object isn't a smi. - __ tst(r3, Operand(kSmiTagMask)); - __ b(eq, &slow); - // Get the type of the object from its map. - __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset)); - __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); - // Check if the object is a JS array or not. - __ cmp(r2, Operand(JS_ARRAY_TYPE)); - __ b(eq, &array); - // Check that the object is some kind of JS object. - __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE)); - __ b(lt, &slow); - - - // Object case: Check key against length in the elements array. - __ ldr(r3, FieldMemOperand(r3, JSObject::kElementsOffset)); - // Check that the object is in fast mode (not dictionary). - __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset)); - __ cmp(r2, Operand(Factory::hash_table_map())); - __ b(eq, &slow); - // Untag the key (for checking against untagged length in the fixed array). - __ mov(r1, Operand(r1, ASR, kSmiTagSize)); - // Compute address to store into and check array bounds. - __ add(r2, r3, Operand(Array::kHeaderSize - kHeapObjectTag)); - __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2)); - __ ldr(ip, FieldMemOperand(r3, Array::kLengthOffset)); - __ cmp(r1, Operand(ip)); - __ b(lo, &fast); - - - // Slow case: Push extra copies of the arguments (3). +static void HandleBinaryOpSlowCases(MacroAssembler* masm, + Label* not_smi, + const Builtins::JavaScript& builtin, + Token::Value operation, + int swi_number, + OverwriteMode mode) { + Label slow; + if (mode == NO_OVERWRITE) { + __ bind(not_smi); + } __ bind(&slow); - __ ldm(ia, sp, r1.bit() | r3.bit()); // r0 == value, r1 == key, r3 == object - __ stm(db_w, sp, r0.bit() | r1.bit() | r3.bit()); - // Do tail-call to runtime routine. - __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3); - - - // Extra capacity case: Check if there is extra capacity to - // perform the store and update the length. Used for adding one - // element to the array by writing to array[array.length]. - // r0 == value, r1 == key, r2 == elements, r3 == object - __ bind(&extra); - __ b(ne, &slow); // do not leave holes in the array - __ mov(r1, Operand(r1, ASR, kSmiTagSize)); // untag - __ ldr(ip, FieldMemOperand(r2, Array::kLengthOffset)); - __ cmp(r1, Operand(ip)); - __ b(hs, &slow); - __ mov(r1, Operand(r1, LSL, kSmiTagSize)); // restore tag - __ add(r1, r1, Operand(1 << kSmiTagSize)); // and increment - __ str(r1, FieldMemOperand(r3, JSArray::kLengthOffset)); - __ mov(r3, Operand(r2)); - // NOTE: Computing the address to store into must take the fact - // that the key has been incremented into account. - int displacement = Array::kHeaderSize - kHeapObjectTag - - ((1 << kSmiTagSize) * 2); - __ add(r2, r2, Operand(displacement)); - __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); - __ b(&fast); - - - // Array case: Get the length and the elements array from the JS - // array. Check that the array is in fast mode; if it is the - // length is always a smi. - // r0 == value, r3 == object - __ bind(&array); - __ ldr(r2, FieldMemOperand(r3, JSObject::kElementsOffset)); - __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset)); - __ cmp(r1, Operand(Factory::hash_table_map())); - __ b(eq, &slow); + __ push(r1); + __ push(r0); + __ mov(r0, Operand(1)); // Set number of arguments. + __ InvokeBuiltin(builtin, JUMP_JS); // Tail call. - // Check the key against the length in the array, compute the - // address to store into and fall through to fast case. - __ ldr(r1, MemOperand(sp)); - // r0 == value, r1 == key, r2 == elements, r3 == object. - __ ldr(ip, FieldMemOperand(r3, JSArray::kLengthOffset)); - __ cmp(r1, Operand(ip)); - __ b(hs, &extra); - __ mov(r3, Operand(r2)); - __ add(r2, r2, Operand(Array::kHeaderSize - kHeapObjectTag)); - __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); - - - // Fast case: Do the store. - // r0 == value, r2 == address to store into, r3 == elements - __ bind(&fast); - __ str(r0, MemOperand(r2)); - // Skip write barrier if the written value is a smi. - __ tst(r0, Operand(kSmiTagMask)); - __ b(eq, &exit); - // Update write barrier for the elements array address. - __ sub(r1, r2, Operand(r3)); - __ RecordWrite(r3, r1, r2); - __ bind(&exit); - __ StubReturn(1); + // Could it be a double-double op? If we already have a place to put + // the answer then we can do the op and skip the builtin and runtime call. + if (mode != NO_OVERWRITE) { + __ bind(not_smi); + __ tst(r0, Operand(kSmiTagMask)); + __ b(eq, &slow); // We can't handle a Smi-double combination yet. + __ tst(r1, Operand(kSmiTagMask)); + __ b(eq, &slow); // We can't handle a Smi-double combination yet. + // Get map of r0 into r2. + __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); + // Get type of r0 into r3. + __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceTypeOffset)); + __ cmp(r3, Operand(HEAP_NUMBER_TYPE)); + __ b(ne, &slow); + // Get type of r1 into r3. + __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset)); + // Check they are both the same map (heap number map). + __ cmp(r2, r3); + __ b(ne, &slow); + // Both are doubles. + // Calling convention says that second double is in r2 and r3. + __ ldr(r2, FieldMemOperand(r0, HeapNumber::kValueOffset)); + __ ldr(r3, FieldMemOperand(r0, HeapNumber::kValueOffset + kPointerSize)); + __ push(lr); + if (mode == OVERWRITE_LEFT) { + __ push(r1); + } else { + __ push(r0); + } + // Calling convention says that first double is in r0 and r1. + __ ldr(r0, FieldMemOperand(r1, HeapNumber::kValueOffset)); + __ ldr(r1, FieldMemOperand(r1, HeapNumber::kValueOffset + kPointerSize)); + // Call C routine that may not cause GC or other trouble. + __ mov(r5, Operand(ExternalReference::double_fp_operation(operation))); +#if !defined(__arm__) + // Notify the simulator that we are calling an add routine in C. + __ swi(swi_number); +#else + // Actually call the add routine written in C. + __ Call(r5); +#endif + // Store answer in the overwritable heap number. + __ pop(r4); +#if !defined(__ARM_EABI__) && defined(__arm__) + // Double returned in fp coprocessor register 0 and 1, encoded as register + // cr8. Offsets must be divisible by 4 for coprocessor so we need to + // substract the tag from r4. + __ sub(r5, r4, Operand(kHeapObjectTag)); + __ stc(p1, cr8, MemOperand(r5, HeapNumber::kValueOffset)); +#else + // Double returned in fp coprocessor register 0 and 1. + __ str(r0, FieldMemOperand(r4, HeapNumber::kValueOffset)); + __ str(r1, FieldMemOperand(r4, HeapNumber::kValueOffset + kPointerSize)); +#endif + __ mov(r0, Operand(r4)); + // And we are done. + __ pop(pc); + } } @@ -4474,89 +4417,84 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { // r0 : y // result : r0 + // All ops need to know whether we are dealing with two Smis. Set up r2 to + // tell us that. + __ orr(r2, r1, Operand(r0)); // r2 = x | y; + switch (op_) { case Token::ADD: { - Label slow, exit; - // fast path - __ orr(r2, r1, Operand(r0)); // r2 = x | y; - __ add(r0, r1, Operand(r0), SetCC); // add y optimistically - // go slow-path in case of overflow - __ b(vs, &slow); - // go slow-path in case of non-smi operands - ASSERT(kSmiTag == 0); // adjust code below + Label not_smi; + // Fast path. + ASSERT(kSmiTag == 0); // Adjust code below. __ tst(r2, Operand(kSmiTagMask)); - __ b(eq, &exit); - // slow path - __ bind(&slow); - __ sub(r0, r0, Operand(r1)); // revert optimistic add - __ push(r1); - __ push(r0); - __ mov(r0, Operand(1)); // set number of arguments - __ InvokeBuiltin(Builtins::ADD, JUMP_JS); - // done - __ bind(&exit); + __ b(ne, ¬_smi); + __ add(r0, r1, Operand(r0), SetCC); // Add y optimistically. + // Return if no overflow. + __ Ret(vc); + __ sub(r0, r0, Operand(r1)); // Revert optimistic add. + + HandleBinaryOpSlowCases(masm, + ¬_smi, + Builtins::ADD, + Token::ADD, + assembler::arm::simulator_fp_add, + mode_); break; } case Token::SUB: { - Label slow, exit; - // fast path - __ orr(r2, r1, Operand(r0)); // r2 = x | y; - __ sub(r3, r1, Operand(r0), SetCC); // subtract y optimistically - // go slow-path in case of overflow - __ b(vs, &slow); - // go slow-path in case of non-smi operands - ASSERT(kSmiTag == 0); // adjust code below + Label not_smi; + // Fast path. + ASSERT(kSmiTag == 0); // Adjust code below. __ tst(r2, Operand(kSmiTagMask)); - __ mov(r0, Operand(r3), LeaveCC, eq); // conditionally set r0 to result - __ b(eq, &exit); - // slow path - __ bind(&slow); - __ push(r1); - __ push(r0); - __ mov(r0, Operand(1)); // set number of arguments - __ InvokeBuiltin(Builtins::SUB, JUMP_JS); - // done - __ bind(&exit); + __ b(ne, ¬_smi); + __ sub(r0, r1, Operand(r0), SetCC); // Subtract y optimistically. + // Return if no overflow. + __ Ret(vc); + __ sub(r0, r1, Operand(r0)); // Revert optimistic subtract. + + HandleBinaryOpSlowCases(masm, + ¬_smi, + Builtins::SUB, + Token::SUB, + assembler::arm::simulator_fp_sub, + mode_); break; } case Token::MUL: { - Label slow, exit; - // tag check - __ orr(r2, r1, Operand(r0)); // r2 = x | y; + Label not_smi, slow; ASSERT(kSmiTag == 0); // adjust code below __ tst(r2, Operand(kSmiTagMask)); - __ b(ne, &slow); - // remove tag from one operand (but keep sign), so that result is smi + __ b(ne, ¬_smi); + // Remove tag from one operand (but keep sign), so that result is Smi. __ mov(ip, Operand(r0, ASR, kSmiTagSize)); - // do multiplication - __ smull(r3, r2, r1, ip); // r3 = lower 32 bits of ip*r1 - // go slow on overflows (overflow bit is not set) + // Do multiplication + __ smull(r3, r2, r1, ip); // r3 = lower 32 bits of ip*r1. + // Go slow on overflows (overflow bit is not set). __ mov(ip, Operand(r3, ASR, 31)); __ cmp(ip, Operand(r2)); // no overflow if higher 33 bits are identical __ b(ne, &slow); - // go slow on zero result to handle -0 + // Go slow on zero result to handle -0. __ tst(r3, Operand(r3)); __ mov(r0, Operand(r3), LeaveCC, ne); - __ b(ne, &exit); - // slow case + __ Ret(ne); + // Slow case. __ bind(&slow); - __ push(r1); - __ push(r0); - __ mov(r0, Operand(1)); // set number of arguments - __ InvokeBuiltin(Builtins::MUL, JUMP_JS); - // done - __ bind(&exit); + + HandleBinaryOpSlowCases(masm, + ¬_smi, + Builtins::MUL, + Token::MUL, + assembler::arm::simulator_fp_mul, + mode_); break; } case Token::BIT_OR: case Token::BIT_AND: case Token::BIT_XOR: { - Label slow, exit; - // tag check - __ orr(r2, r1, Operand(r0)); // r2 = x | y; + Label slow; ASSERT(kSmiTag == 0); // adjust code below __ tst(r2, Operand(kSmiTagMask)); __ b(ne, &slow); @@ -4566,7 +4504,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break; default: UNREACHABLE(); } - __ b(&exit); + __ Ret(); __ bind(&slow); __ push(r1); // restore stack __ push(r0); @@ -4584,16 +4522,13 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { default: UNREACHABLE(); } - __ bind(&exit); break; } case Token::SHL: case Token::SHR: case Token::SAR: { - Label slow, exit; - // tag check - __ orr(r2, r1, Operand(r0)); // r2 = x | y; + Label slow; ASSERT(kSmiTag == 0); // adjust code below __ tst(r2, Operand(kSmiTagMask)); __ b(ne, &slow); @@ -4633,7 +4568,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { // tag result and store it in r0 ASSERT(kSmiTag == 0); // adjust code below __ mov(r0, Operand(r3, LSL, kSmiTagSize)); - __ b(&exit); + __ Ret(); // slow case __ bind(&slow); __ push(r1); // restore stack @@ -4645,13 +4580,13 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { case Token::SHL: __ InvokeBuiltin(Builtins::SHL, JUMP_JS); break; default: UNREACHABLE(); } - __ bind(&exit); break; } default: UNREACHABLE(); } - __ Ret(); + // This code should be unreachable. + __ stop("Unreachable"); } @@ -4661,7 +4596,9 @@ void StackCheckStub::Generate(MacroAssembler* masm) { __ ldr(ip, MemOperand(ip)); __ cmp(sp, Operand(ip)); __ b(hs, &within_limit); - // Do tail-call to runtime routine. + // Do tail-call to runtime routine. Runtime routines expect at least one + // argument, so give it a Smi. + __ mov(r0, Operand(Smi::FromInt(0))); __ push(r0); __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1); __ bind(&within_limit); @@ -4721,7 +4658,11 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { __ mov(cp, Operand(0), LeaveCC, eq); // Restore cp otherwise. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); - if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc)); +#ifdef DEBUG + if (FLAG_debug_code) { + __ mov(lr, Operand(pc)); + } +#endif __ pop(pc); } @@ -4784,7 +4725,11 @@ void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) { __ mov(cp, Operand(0), LeaveCC, eq); // Restore cp otherwise. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); - if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc)); +#ifdef DEBUG + if (FLAG_debug_code) { + __ mov(lr, Operand(pc)); + } +#endif __ pop(pc); } @@ -5043,9 +4988,11 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { } __ ldr(ip, MemOperand(ip)); // deref address - // Branch and link to JSEntryTrampoline + // Branch and link to JSEntryTrampoline. We don't use the double underscore + // macro for the add instruction because we don't want the coverage tool + // inserting instructions here after we read the pc. __ mov(lr, Operand(pc)); - __ add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag)); + masm->add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag)); // Unlink this frame from the handler chain. When reading the // address of the next handler, there is no need to use the address @@ -5057,6 +5004,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { // No need to restore registers __ add(sp, sp, Operand(StackHandlerConstants::kSize)); + __ bind(&exit); // r0 holds result // Restore the top frame descriptors from the stack. __ pop(r3); @@ -5068,7 +5016,9 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { // Restore callee-saved registers and return. #ifdef DEBUG - if (FLAG_debug_code) __ mov(lr, Operand(pc)); + if (FLAG_debug_code) { + __ mov(lr, Operand(pc)); + } #endif __ ldm(ia_w, sp, kCalleeSaved | pc.bit()); } @@ -5084,13 +5034,13 @@ void ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) { // Nothing to do: The formal number of parameters has already been // passed in register r0 by calling function. Just return it. - __ mov(pc, lr); + __ Jump(lr); // Arguments adaptor case: Read the arguments length from the // adaptor frame and return it. __ bind(&adaptor); __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset)); - __ mov(pc, lr); + __ Jump(lr); } @@ -5122,7 +5072,7 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { __ sub(r3, r0, r1); __ add(r3, fp, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize)); __ ldr(r0, MemOperand(r3, kDisplacement)); - __ mov(pc, lr); + __ Jump(lr); // Arguments adaptor case: Check index against actual arguments // limit found in the arguments adaptor frame. Use unsigned @@ -5136,7 +5086,7 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { __ sub(r3, r0, r1); __ add(r3, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize)); __ ldr(r0, MemOperand(r3, kDisplacement)); - __ mov(pc, lr); + __ Jump(lr); // Slow-case: Handle non-smi or out-of-bounds access to arguments // by calling the runtime system. diff --git a/deps/v8/src/codegen-arm.h b/deps/v8/src/arm/codegen-arm.h index b072f75ed..c098acdd7 100644 --- a/deps/v8/src/codegen-arm.h +++ b/deps/v8/src/arm/codegen-arm.h @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef V8_CODEGEN_ARM_H_ -#define V8_CODEGEN_ARM_H_ +#ifndef V8_ARM_CODEGEN_ARM_H_ +#define V8_ARM_CODEGEN_ARM_H_ namespace v8 { namespace internal { @@ -35,9 +35,6 @@ class DeferredCode; class RegisterAllocator; class RegisterFile; -// Mode to overwrite BinaryExpression values. -enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT }; - enum InitState { CONST_INIT, NOT_CONST_INIT }; enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; @@ -292,10 +289,13 @@ class CodeGenerator: public AstVisitor { void ToBoolean(JumpTarget* true_target, JumpTarget* false_target); - void GenericBinaryOperation(Token::Value op); + void GenericBinaryOperation(Token::Value op, OverwriteMode overwrite_mode); void Comparison(Condition cc, bool strict = false); - void SmiOperation(Token::Value op, Handle<Object> value, bool reversed); + void SmiOperation(Token::Value op, + Handle<Object> value, + bool reversed, + OverwriteMode mode); void CallWithArguments(ZoneList<Expression*>* arguments, int position); @@ -303,7 +303,17 @@ class CodeGenerator: public AstVisitor { void Branch(bool if_true, JumpTarget* target); void CheckStack(); + struct InlineRuntimeLUT { + void (CodeGenerator::*method)(ZoneList<Expression*>*); + const char* name; + }; + + static InlineRuntimeLUT* FindInlineRuntimeLUT(Handle<String> name); bool CheckForInlineRuntimeCall(CallRuntime* node); + static bool PatchInlineRuntimeEntry(Handle<String> name, + const InlineRuntimeLUT& new_entry, + InlineRuntimeLUT* old_entry); + Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node); void ProcessDeclarations(ZoneList<Declaration*>* declarations); @@ -433,6 +443,8 @@ class CodeGenerator: public AstVisitor { // in a spilled state. bool in_spilled_code_; + static InlineRuntimeLUT kInlineRuntimeLUT[]; + friend class VirtualFrame; friend class JumpTarget; friend class Reference; @@ -443,4 +455,4 @@ class CodeGenerator: public AstVisitor { } } // namespace v8::internal -#endif // V8_CODEGEN_ARM_H_ +#endif // V8_ARM_CODEGEN_ARM_H_ diff --git a/deps/v8/src/constants-arm.h b/deps/v8/src/arm/constants-arm.h index f55396380..66c6a8d86 100644 --- a/deps/v8/src/constants-arm.h +++ b/deps/v8/src/arm/constants-arm.h @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef V8_CONSTANTS_ARM_H_ -#define V8_CONSTANTS_ARM_H_ +#ifndef V8_ARM_CONSTANTS_ARM_H_ +#define V8_ARM_CONSTANTS_ARM_H_ namespace assembler { namespace arm { @@ -106,7 +106,12 @@ enum SoftwareInterruptCodes { call_rt_r5 = 0x10, call_rt_r2 = 0x11, // break point - break_point = 0x20 + break_point = 0x20, + // FP operations. These simulate calling into C for a moment to do fp ops. + // They should trash all caller-save registers. + simulator_fp_add = 0x21, + simulator_fp_sub = 0x22, + simulator_fp_mul = 0x23 }; @@ -232,4 +237,4 @@ class Instr { } } // namespace assembler::arm -#endif // V8_CONSTANTS_ARM_H_ +#endif // V8_ARM_CONSTANTS_ARM_H_ diff --git a/deps/v8/src/cpu-arm.cc b/deps/v8/src/arm/cpu-arm.cc index 736966129..736966129 100644 --- a/deps/v8/src/cpu-arm.cc +++ b/deps/v8/src/arm/cpu-arm.cc diff --git a/deps/v8/src/debug-arm.cc b/deps/v8/src/arm/debug-arm.cc index 9fb77b775..f86f981cb 100644 --- a/deps/v8/src/debug-arm.cc +++ b/deps/v8/src/arm/debug-arm.cc @@ -32,7 +32,7 @@ namespace v8 { namespace internal { - +#ifdef ENABLE_DEBUGGER_SUPPORT // Currently debug break is not supported in frame exit code on ARM. bool BreakLocationIterator::IsDebugBreakAtReturn() { return false; @@ -58,7 +58,7 @@ bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) { } -#define __ masm-> +#define __ ACCESS_MASM(masm) static void Generate_DebugBreakCallHelper(MacroAssembler* masm, @@ -191,5 +191,6 @@ void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) { #undef __ +#endif // ENABLE_DEBUGGER_SUPPORT } } // namespace v8::internal diff --git a/deps/v8/src/disasm-arm.cc b/deps/v8/src/arm/disasm-arm.cc index d19e042df..3b7474dba 100644 --- a/deps/v8/src/disasm-arm.cc +++ b/deps/v8/src/arm/disasm-arm.cc @@ -261,6 +261,15 @@ void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes swi) { case break_point: Print("break_point"); return; + case simulator_fp_add: + Print("simulator_fp_add"); + return; + case simulator_fp_mul: + Print("simulator_fp_mul"); + return; + case simulator_fp_sub: + Print("simulator_fp_sub"); + return; default: out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", diff --git a/deps/v8/src/frames-arm.cc b/deps/v8/src/arm/frames-arm.cc index 121fb75be..d26198ae1 100644 --- a/deps/v8/src/frames-arm.cc +++ b/deps/v8/src/arm/frames-arm.cc @@ -28,7 +28,7 @@ #include "v8.h" #include "frames-inl.h" -#include "assembler-arm-inl.h" +#include "arm/assembler-arm-inl.h" namespace v8 { namespace internal { diff --git a/deps/v8/src/frames-arm.h b/deps/v8/src/arm/frames-arm.h index 930f6e0e0..9a18f3d93 100644 --- a/deps/v8/src/frames-arm.h +++ b/deps/v8/src/arm/frames-arm.h @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef V8_FRAMES_ARM_H_ -#define V8_FRAMES_ARM_H_ +#ifndef V8_ARM_FRAMES_ARM_H_ +#define V8_ARM_FRAMES_ARM_H_ namespace v8 { namespace internal { @@ -376,4 +376,4 @@ inline Object* JavaScriptFrame::function_slot_object() const { } } // namespace v8::internal -#endif // V8_FRAMES_ARM_H_ +#endif // V8_ARM_FRAMES_ARM_H_ diff --git a/deps/v8/src/ic-arm.cc b/deps/v8/src/arm/ic-arm.cc index 4db3980c5..b07c4742d 100644 --- a/deps/v8/src/ic-arm.cc +++ b/deps/v8/src/arm/ic-arm.cc @@ -39,7 +39,7 @@ namespace v8 { namespace internal { // Static IC stub generators. // -#define __ masm-> +#define __ ACCESS_MASM(masm) // Helper function used from LoadIC/CallIC GenerateNormal. @@ -96,7 +96,9 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, // Compute the masked index: (hash + i + i * i) & mask. __ ldr(t1, FieldMemOperand(r2, String::kLengthOffset)); __ mov(t1, Operand(t1, LSR, String::kHashShift)); - if (i > 0) __ add(t1, t1, Operand(Dictionary::GetProbeOffset(i))); + if (i > 0) { + __ add(t1, t1, Operand(Dictionary::GetProbeOffset(i))); + } __ and_(t1, t1, Operand(r3)); // Scale the index by multiplying by the element size. @@ -125,27 +127,20 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, } -// Helper function used to check that a value is either not a function -// or is loaded if it is a function. -static void GenerateCheckNonFunctionOrLoaded(MacroAssembler* masm, - Label* miss, - Register value, - Register scratch) { +// Helper function used to check that a value is either not an object +// or is loaded if it is an object. +static void GenerateCheckNonObjectOrLoaded(MacroAssembler* masm, + Label* miss, + Register value, + Register scratch) { Label done; // Check if the value is a Smi. __ tst(value, Operand(kSmiTagMask)); __ b(eq, &done); - // Check if the value is a function. - __ ldr(scratch, FieldMemOperand(value, HeapObject::kMapOffset)); - __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); - __ cmp(scratch, Operand(JS_FUNCTION_TYPE)); - __ b(ne, &done); - // Check if the function has been loaded. - __ ldr(scratch, - FieldMemOperand(value, JSFunction::kSharedFunctionInfoOffset)); - __ ldr(scratch, - FieldMemOperand(scratch, SharedFunctionInfo::kLazyLoadDataOffset)); - __ cmp(scratch, Operand(Factory::undefined_value())); + // Check if the object has been loaded. + __ ldr(scratch, FieldMemOperand(value, JSObject::kMapOffset)); + __ ldrb(scratch, FieldMemOperand(scratch, Map::kBitField2Offset)); + __ tst(scratch, Operand(1 << Map::kNeedsLoading)); __ b(ne, miss); __ bind(&done); } @@ -282,9 +277,9 @@ static void GenerateNormalHelper(MacroAssembler* masm, __ b(ne, miss); // Check that the function has been loaded. - __ ldr(r0, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); - __ ldr(r0, FieldMemOperand(r0, SharedFunctionInfo::kLazyLoadDataOffset)); - __ cmp(r0, Operand(Factory::undefined_value())); + __ ldr(r0, FieldMemOperand(r1, JSObject::kMapOffset)); + __ ldrb(r0, FieldMemOperand(r0, Map::kBitField2Offset)); + __ tst(r0, Operand(1 << Map::kNeedsLoading)); __ b(ne, miss); // Patch the receiver with the global proxy if necessary. @@ -468,7 +463,7 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) { __ bind(&probe); GenerateDictionaryLoad(masm, &miss, r1, r0); - GenerateCheckNonFunctionOrLoaded(masm, &miss, r0, r1); + GenerateCheckNonObjectOrLoaded(masm, &miss, r0, r1); __ Ret(); // Global object access: Check access rights. @@ -502,10 +497,18 @@ void LoadIC::Generate(MacroAssembler* masm, const ExternalReference& f) { } -// TODO(181): Implement map patching once loop nesting is tracked on -// the ARM platform so we can generate inlined fast-case code for -// array indexing in loops. -void KeyedLoadIC::PatchInlinedMapCheck(Address address, Object* value) { } +// TODO(181): Implement map patching once loop nesting is tracked on the +// ARM platform so we can generate inlined fast-case code loads in +// loops. +void LoadIC::ClearInlinedVersion(Address address) {} +bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) { + return false; +} + +void KeyedLoadIC::ClearInlinedVersion(Address address) {} +bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) { + return false; +} Object* KeyedLoadIC_Miss(Arguments args); diff --git a/deps/v8/src/jump-target-arm.cc b/deps/v8/src/arm/jump-target-arm.cc index 3ce5f308e..6d375e5ce 100644 --- a/deps/v8/src/jump-target-arm.cc +++ b/deps/v8/src/arm/jump-target-arm.cc @@ -35,7 +35,7 @@ namespace v8 { namespace internal { // ------------------------------------------------------------------------- // JumpTarget implementation. -#define __ masm_-> +#define __ ACCESS_MASM(masm_) void JumpTarget::DoJump() { ASSERT(cgen_ != NULL); diff --git a/deps/v8/src/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index 88a300b11..365c1ad7f 100644 --- a/deps/v8/src/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -168,11 +168,11 @@ void MacroAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode, } -void MacroAssembler::Ret() { +void MacroAssembler::Ret(Condition cond) { #if USE_BX - bx(lr); + bx(lr, cond); #else - mov(pc, Operand(lr)); + mov(pc, Operand(lr), LeaveCC, cond); #endif } @@ -320,16 +320,19 @@ void MacroAssembler::EnterExitFrame(StackFrame::Type type) { add(r6, fp, Operand(r4, LSL, kPointerSizeLog2)); add(r6, r6, Operand(ExitFrameConstants::kPPDisplacement - kPointerSize)); +#ifdef ENABLE_DEBUGGER_SUPPORT // Save the state of all registers to the stack from the memory // location. This is needed to allow nested break points. if (type == StackFrame::EXIT_DEBUG) { // Use sp as base to push. CopyRegistersFromMemoryToStack(sp, kJSCallerSaved); } +#endif } void MacroAssembler::LeaveExitFrame(StackFrame::Type type) { +#ifdef ENABLE_DEBUGGER_SUPPORT // Restore the memory copy of the registers by digging them out from // the stack. This is needed to allow nested break points. if (type == StackFrame::EXIT_DEBUG) { @@ -339,6 +342,7 @@ void MacroAssembler::LeaveExitFrame(StackFrame::Type type) { add(r3, fp, Operand(kOffset)); CopyRegistersFromStackToMemory(r3, r2, kJSCallerSaved); } +#endif // Clear top frame. mov(r3, Operand(0)); @@ -348,9 +352,9 @@ void MacroAssembler::LeaveExitFrame(StackFrame::Type type) { // Restore current context from top and clear it in debug mode. mov(ip, Operand(ExternalReference(Top::k_context_address))); ldr(cp, MemOperand(ip)); - if (kDebug) { - str(r3, MemOperand(ip)); - } +#ifdef DEBUG + str(r3, MemOperand(ip)); +#endif // Pop the arguments, restore registers, and return. mov(sp, Operand(fp)); // respect ABI stack constraint @@ -491,6 +495,7 @@ void MacroAssembler::InvokeFunction(Register fun, } +#ifdef ENABLE_DEBUGGER_SUPPORT void MacroAssembler::SaveRegistersToMemory(RegList regs) { ASSERT((regs & ~kJSCallerSaved) == 0); // Copy the content of registers to memory location. @@ -548,7 +553,7 @@ void MacroAssembler::CopyRegistersFromStackToMemory(Register base, } } } - +#endif void MacroAssembler::PushTryHandler(CodeLocation try_location, HandlerType type) { @@ -674,10 +679,10 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, // Load current lexical context from the stack frame. ldr(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset)); // In debug mode, make sure the lexical context is set. - if (kDebug) { - cmp(scratch, Operand(0)); - Check(ne, "we should not have an empty lexical context"); - } +#ifdef DEBUG + cmp(scratch, Operand(0)); + Check(ne, "we should not have an empty lexical context"); +#endif // Load the global context of the current context. int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; diff --git a/deps/v8/src/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h index 4b999fdfc..e336757e0 100644 --- a/deps/v8/src/macro-assembler-arm.h +++ b/deps/v8/src/arm/macro-assembler-arm.h @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef V8_MACRO_ASSEMBLER_ARM_H_ -#define V8_MACRO_ASSEMBLER_ARM_H_ +#ifndef V8_ARM_MACRO_ASSEMBLER_ARM_H_ +#define V8_ARM_MACRO_ASSEMBLER_ARM_H_ #include "assembler.h" @@ -86,7 +86,7 @@ class MacroAssembler: public Assembler { void Call(Register target, Condition cond = al); void Call(byte* target, RelocInfo::Mode rmode, Condition cond = al); void Call(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al); - void Ret(); + void Ret(Condition cond = al); // Jumps to the label at the index given by the Smi in "index". void SmiJumpTable(Register index, Vector<Label*> targets); @@ -138,6 +138,7 @@ class MacroAssembler: public Assembler { InvokeFlag flag); +#ifdef ENABLE_DEBUGGER_SUPPORT // --------------------------------------------------------------------------- // Debugger Support @@ -147,7 +148,7 @@ class MacroAssembler: public Assembler { void CopyRegistersFromStackToMemory(Register base, Register scratch, RegList regs); - +#endif // --------------------------------------------------------------------------- // Exception handling @@ -297,7 +298,16 @@ static inline MemOperand FieldMemOperand(Register object, int offset) { } +#ifdef GENERATED_CODE_COVERAGE +#define CODE_COVERAGE_STRINGIFY(x) #x +#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x) +#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__) +#define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm-> +#else +#define ACCESS_MASM(masm) masm-> +#endif + } } // namespace v8::internal -#endif // V8_MACRO_ASSEMBLER_ARM_H_ +#endif // V8_ARM_MACRO_ASSEMBLER_ARM_H_ diff --git a/deps/v8/src/regexp-macro-assembler-arm.cc b/deps/v8/src/arm/regexp-macro-assembler-arm.cc index bcfddf67e..bf07f0e3d 100644 --- a/deps/v8/src/regexp-macro-assembler-arm.cc +++ b/deps/v8/src/arm/regexp-macro-assembler-arm.cc @@ -28,7 +28,7 @@ #include "v8.h" #include "ast.h" #include "regexp-macro-assembler.h" -#include "regexp-macro-assembler-arm.h" +#include "arm/regexp-macro-assembler-arm.h" namespace v8 { namespace internal { diff --git a/deps/v8/src/regexp-macro-assembler-arm.h b/deps/v8/src/arm/regexp-macro-assembler-arm.h index 51352bc27..2f38bb73e 100644 --- a/deps/v8/src/regexp-macro-assembler-arm.h +++ b/deps/v8/src/arm/regexp-macro-assembler-arm.h @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef REGEXP_MACRO_ASSEMBLER_ARM_H_ -#define REGEXP_MACRO_ASSEMBLER_ARM_H_ +#ifndef V8_ARM_REGEXP_MACRO_ASSEMBLER_ARM_H_ +#define V8_ARM_REGEXP_MACRO_ASSEMBLER_ARM_H_ namespace v8 { namespace internal { @@ -38,4 +38,4 @@ class RegExpMacroAssemblerARM: public RegExpMacroAssembler { }} // namespace v8::internal -#endif /* REGEXP_MACRO_ASSEMBLER_ARM_H_ */ +#endif // V8_ARM_REGEXP_MACRO_ASSEMBLER_ARM_H_ diff --git a/deps/v8/src/register-allocator-arm.cc b/deps/v8/src/arm/register-allocator-arm.cc index 36a4d20e1..d468c84e3 100644 --- a/deps/v8/src/register-allocator-arm.cc +++ b/deps/v8/src/arm/register-allocator-arm.cc @@ -66,6 +66,14 @@ void RegisterAllocator::UnuseReserved(RegisterFile* register_file) { } +bool RegisterAllocator::IsReserved(int reg_code) { + return (reg_code == sp.code()) + || (reg_code == fp.code()) + || (reg_code == cp.code()) + || (reg_code == pc.code()); +} + + void RegisterAllocator::Initialize() { Reset(); // The following registers are live on function entry, saved in the diff --git a/deps/v8/src/simulator-arm.cc b/deps/v8/src/arm/simulator-arm.cc index 5a61107cf..9737e9539 100644 --- a/deps/v8/src/simulator-arm.cc +++ b/deps/v8/src/arm/simulator-arm.cc @@ -30,8 +30,8 @@ #include "v8.h" #include "disasm.h" -#include "constants-arm.h" -#include "simulator-arm.h" +#include "arm/constants-arm.h" +#include "arm/simulator-arm.h" #if !defined(__arm__) @@ -90,12 +90,44 @@ Debugger::~Debugger() { } + +#ifdef GENERATED_CODE_COVERAGE +static FILE* coverage_log = NULL; + + +static void InitializeCoverage() { + char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG"); + if (file_name != NULL) { + coverage_log = fopen(file_name, "aw+"); + } +} + + +void Debugger::Stop(Instr* instr) { + char* str = reinterpret_cast<char*>(instr->InstructionBits() & 0x0fffffff); + if (strlen(str) > 0) { + if (coverage_log != NULL) { + fprintf(coverage_log, "%s\n", str); + fflush(coverage_log); + } + instr->SetInstructionBits(0xe1a00000); // Overwrite with nop. + } + sim_->set_pc(sim_->get_pc() + Instr::kInstrSize); +} + +#else // ndef GENERATED_CODE_COVERAGE + +static void InitializeCoverage() { +} + + void Debugger::Stop(Instr* instr) { const char* str = (const char*)(instr->InstructionBits() & 0x0fffffff); PrintF("Simulator hit %s\n", str); sim_->set_pc(sim_->get_pc() + Instr::kInstrSize); Debug(); } +#endif static const char* reg_names[] = { "r0", "r1", "r2", "r3", @@ -375,6 +407,7 @@ Simulator::Simulator() { // access violation if the simulator ever tries to execute it. registers_[pc] = bad_lr; registers_[lr] = bad_lr; + InitializeCoverage(); } @@ -427,6 +460,37 @@ int32_t Simulator::get_pc() const { } +// For use in calls that take two double values, constructed from r0, r1, r2 +// and r3. +void Simulator::GetFpArgs(double* x, double* y) { + // We use a char buffer to get around the strict-aliasing rules which + // otherwise allow the compiler to optimize away the copy. + char buffer[2 * sizeof(registers_[0])]; + // Registers 0 and 1 -> x. + memcpy(buffer, registers_, sizeof(buffer)); + memcpy(x, buffer, sizeof(buffer)); + // Registers 2 and 3 -> y. + memcpy(buffer, registers_ + 2, sizeof(buffer)); + memcpy(y, buffer, sizeof(buffer)); +} + + +void Simulator::SetFpResult(const double& result) { + char buffer[2 * sizeof(registers_[0])]; + memcpy(buffer, &result, sizeof(buffer)); + // result -> registers 0 and 1. + memcpy(registers_, buffer, sizeof(buffer)); +} + + +void Simulator::TrashCallerSaveRegisters() { + // We don't trash the registers with the return value. + registers_[2] = 0x50Bad4U; + registers_[3] = 0x50Bad4U; + registers_[12] = 0x50Bad4U; +} + + // The ARM cannot do unaligned reads and writes. On some ARM platforms an // interrupt is caused. On others it does a funky rotation thing. For now we // simply disallow unaligned reads, but at some point we may want to move to @@ -862,7 +926,8 @@ typedef int64_t (*SimulatorRuntimeCall)(intptr_t arg0, intptr_t arg1); // Software interrupt instructions are used by the simulator to call into the // C-based V8 runtime. void Simulator::SoftwareInterrupt(Instr* instr) { - switch (instr->SwiField()) { + int swi = instr->SwiField(); + switch (swi) { case call_rt_r5: { SimulatorRuntimeCall target = reinterpret_cast<SimulatorRuntimeCall>(get_register(r5)); @@ -894,6 +959,30 @@ void Simulator::SoftwareInterrupt(Instr* instr) { dbg.Debug(); break; } + { + double x, y, z; + case simulator_fp_add: + GetFpArgs(&x, &y); + z = x + y; + SetFpResult(z); + TrashCallerSaveRegisters(); + set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); + break; + case simulator_fp_sub: + GetFpArgs(&x, &y); + z = x - y; + SetFpResult(z); + TrashCallerSaveRegisters(); + set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); + break; + case simulator_fp_mul: + GetFpArgs(&x, &y); + z = x * y; + SetFpResult(z); + TrashCallerSaveRegisters(); + set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); + break; + } default: { UNREACHABLE(); break; diff --git a/deps/v8/src/simulator-arm.h b/deps/v8/src/arm/simulator-arm.h index 4f3c53d41..2029fd3bc 100644 --- a/deps/v8/src/simulator-arm.h +++ b/deps/v8/src/arm/simulator-arm.h @@ -33,14 +33,14 @@ // which will start execution in the Simulator or forwards to the real entry // on a ARM HW platform. -#ifndef V8_SIMULATOR_ARM_H_ -#define V8_SIMULATOR_ARM_H_ +#ifndef V8_ARM_SIMULATOR_ARM_H_ +#define V8_ARM_SIMULATOR_ARM_H_ #if defined(__arm__) // When running without a simulator we call the entry directly. #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ - entry(p0, p1, p2, p3, p4) + reinterpret_cast<Object*>(entry(p0, p1, p2, p3, p4)) // Calculated the stack limit beyond which we will throw stack overflow errors. // This macro must be called from a C++ method. It relies on being able to take @@ -174,6 +174,12 @@ class Simulator { // Executes one instruction. void InstructionDecode(Instr* instr); + // For use in calls that take two double values, constructed from r0, r1, r2 + // and r3. + void GetFpArgs(double* x, double* y); + void SetFpResult(const double& result); + void TrashCallerSaveRegisters(); + // architecture state int32_t registers_[16]; bool n_flag_; @@ -195,4 +201,4 @@ class Simulator { #endif // defined(__arm__) -#endif // V8_SIMULATOR_ARM_H_ +#endif // V8_ARM_SIMULATOR_ARM_H_ diff --git a/deps/v8/src/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index 211b643fa..56afa0288 100644 --- a/deps/v8/src/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -33,7 +33,7 @@ namespace v8 { namespace internal { -#define __ masm-> +#define __ ACCESS_MASM(masm) static void ProbeTable(MacroAssembler* masm, @@ -183,7 +183,7 @@ void StubCompiler::GenerateLoadField(MacroAssembler* masm, // Check that the maps haven't changed. Register reg = - __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); + masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); GenerateFastPropertyLoad(masm, r0, reg, holder, index); __ Ret(); } @@ -203,7 +203,7 @@ void StubCompiler::GenerateLoadConstant(MacroAssembler* masm, // Check that the maps haven't changed. Register reg = - __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); + masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); // Return the constant value. __ mov(r0, Operand(Handle<Object>(value))); @@ -226,7 +226,7 @@ void StubCompiler::GenerateLoadCallback(MacroAssembler* masm, // Check that the maps haven't changed. Register reg = - __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); + masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); // Push the arguments on the JS stack of the caller. __ push(receiver); // receiver @@ -256,7 +256,7 @@ void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm, // Check that the maps haven't changed. Register reg = - __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); + masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); // Push the arguments on the JS stack of the caller. __ push(receiver); // receiver @@ -456,8 +456,7 @@ void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { #undef __ - -#define __ masm()-> +#define __ ACCESS_MASM(masm()) Object* StubCompiler::CompileLazyCompile(Code::Flags flags) { @@ -511,7 +510,7 @@ Object* CallStubCompiler::CompileCallField(Object* object, // Do the right check and compute the holder register. Register reg = - __ CheckMaps(JSObject::cast(object), r0, holder, r3, r2, &miss); + masm()->CheckMaps(JSObject::cast(object), r0, holder, r3, r2, &miss); GenerateFastPropertyLoad(masm(), r1, reg, holder, index); // Check that the function really is a function. diff --git a/deps/v8/src/virtual-frame-arm.cc b/deps/v8/src/arm/virtual-frame-arm.cc index baf08145b..43100f1ec 100644 --- a/deps/v8/src/virtual-frame-arm.cc +++ b/deps/v8/src/arm/virtual-frame-arm.cc @@ -36,7 +36,8 @@ namespace v8 { namespace internal { // ------------------------------------------------------------------------- // VirtualFrame implementation. -#define __ masm_-> +#define __ ACCESS_MASM(masm_) + // On entry to a function, the virtual frame already contains the // receiver and the parameters. All initial frame elements are in @@ -70,6 +71,16 @@ void VirtualFrame::SyncElementByPushing(int index) { } +void VirtualFrame::SyncRange(int begin, int end) { + // All elements are in memory on ARM (ie, synced). +#ifdef DEBUG + for (int i = begin; i <= end; i++) { + ASSERT(elements_[i].is_synced()); + } +#endif +} + + void VirtualFrame::MergeTo(VirtualFrame* expected) { Comment cmnt(masm_, "[ Merge frame"); // We should always be merging the code generator's current frame to an diff --git a/deps/v8/src/virtual-frame-arm.h b/deps/v8/src/arm/virtual-frame-arm.h index af3c08ce7..371a23e93 100644 --- a/deps/v8/src/virtual-frame-arm.h +++ b/deps/v8/src/arm/virtual-frame-arm.h @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef V8_VIRTUAL_FRAME_ARM_H_ -#define V8_VIRTUAL_FRAME_ARM_H_ +#ifndef V8_ARM_VIRTUAL_FRAME_ARM_H_ +#define V8_ARM_VIRTUAL_FRAME_ARM_H_ #include "register-allocator.h" @@ -477,4 +477,4 @@ class VirtualFrame : public Malloced { } } // namespace v8::internal -#endif // V8_VIRTUAL_FRAME_ARM_H_ +#endif // V8_ARM_VIRTUAL_FRAME_ARM_H_ diff --git a/deps/v8/src/array.js b/deps/v8/src/array.js index d30a98960..ed84b5f72 100644 --- a/deps/v8/src/array.js +++ b/deps/v8/src/array.js @@ -709,32 +709,91 @@ function ArraySort(comparefn) { QuickSort(a, high_start, to); } - var old_length = ToUint32(this.length); - if (old_length < 2) return this; + // 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 + // of a prototype property. + function CopyFromPrototype(obj, length) { + var max = 0; + for (var proto = obj.__proto__; proto; proto = proto.__proto__) { + var indices = %GetArrayKeys(proto, length); + if (indices.length > 0) { + if (indices[0] == -1) { + // It's an interval. + var proto_length = indices[1]; + for (var i = 0; i < proto_length; i++) { + if (!obj.hasOwnProperty(i) && proto.hasOwnProperty(i)) { + obj[i] = proto[i]; + if (i >= max) { max = i + 1; } + } + } + } else { + for (var i = 0; i < indices.length; i++) { + var index = indices[i]; + if (!IS_UNDEFINED(index) && + !obj.hasOwnProperty(index) && proto.hasOwnProperty(index)) { + obj[index] = proto[index]; + if (index >= max) { max = index + 1; } + } + } + } + } + } + return max; + } - %RemoveArrayHoles(this); + // Set a value of "undefined" on all indices in the range from..to + // where a prototype of obj has an element. I.e., shadow all prototype + // elements in that range. + function ShadowPrototypeElements(obj, from, to) { + for (var proto = obj.__proto__; proto; proto = proto.__proto__) { + var indices = %GetArrayKeys(proto, to); + if (indices.length > 0) { + if (indices[0] == -1) { + // It's an interval. + var proto_length = indices[1]; + for (var i = from; i < proto_length; i++) { + if (proto.hasOwnProperty(i)) { + obj[i] = void 0; + } + } + } else { + for (var i = 0; i < indices.length; i++) { + var index = indices[i]; + if (!IS_UNDEFINED(index) && from <= index && + proto.hasOwnProperty(index)) { + obj[index] = void 0; + } + } + } + } + } + } var length = ToUint32(this.length); - - // Move undefined elements to the end of the array. - for (var i = 0; i < length; ) { - if (IS_UNDEFINED(this[i])) { - length--; - this[i] = this[length]; - this[length] = void 0; - } else { - i++; - } + if (length < 2) return this; + + var is_array = IS_ARRAY(this); + var max_prototype_element; + if (!is_array) { + // For compatibility with JSC, we also sort elements inherited from + // the prototype chain on non-Array objects. + // We do this by copying them to this object and sorting only + // local elements. This is not very efficient, but sorting with + // inherited elements happens very, very rarely, if at all. + // The specification allows "implementation dependent" behavior + // if an element on the prototype chain has an element that + // might interact with sorting. + max_prototype_element = CopyFromPrototype(this, length); } - QuickSort(this, 0, length); + var num_non_undefined = %RemoveArrayHoles(this, length); - // We only changed the length of the this object (in - // RemoveArrayHoles) if it was an array. We are not allowed to set - // the length of the this object if it is not an array because this - // might introduce a new length property. - if (IS_ARRAY(this)) { - this.length = old_length; + QuickSort(this, 0, num_non_undefined); + + if (!is_array && (num_non_undefined + 1 < max_prototype_element)) { + // For compatibility with JSC, we shadow any elements in the prototype + // chain that has become exposed by sort moving a hole to its position. + ShadowPrototypeElements(this, num_non_undefined, max_prototype_element); } return this; @@ -879,6 +938,62 @@ function ArrayLastIndexOf(element, index) { } +function ArrayReduce(callback, current) { + if (!IS_FUNCTION(callback)) { + throw MakeTypeError('called_non_callable', [callback]); + } + // Pull out the length so that modifications to the length in the + // loop will not affect the looping. + var length = this.length; + var i = 0; + + find_initial: if (%_ArgumentsLength() < 2) { + for (; i < length; i++) { + current = this[i]; + if (!IS_UNDEFINED(current) || i in this) { + i++; + break find_initial; + } + } + throw MakeTypeError('reduce_no_initial', []); + } + + for (; i < length; i++) { + var element = this[i]; + if (!IS_UNDEFINED(element) || i in this) { + current = callback.call(null, current, element, i, this); + } + } + return current; +} + +function ArrayReduceRight(callback, current) { + if (!IS_FUNCTION(callback)) { + throw MakeTypeError('called_non_callable', [callback]); + } + var i = this.length - 1; + + find_initial: if (%_ArgumentsLength() < 2) { + for (; i >= 0; i--) { + current = this[i]; + if (!IS_UNDEFINED(current) || i in this) { + i--; + break find_initial; + } + } + throw MakeTypeError('reduce_no_initial', []); + } + + for (; i >= 0; i--) { + var element = this[i]; + if (!IS_UNDEFINED(element) || i in this) { + current = callback.call(null, current, element, i, this); + } + } + return current; +} + + // ------------------------------------------------------------------- @@ -890,7 +1005,6 @@ function UpdateFunctionLengths(lengths) { // ------------------------------------------------------------------- - function SetupArray() { // Setup non-enumerable constructor property on the Array.prototype // object. @@ -898,7 +1012,7 @@ function SetupArray() { // Setup non-enumerable functions of the Array.prototype object and // set their names. - InstallFunctions($Array.prototype, DONT_ENUM, $Array( + InstallFunctionsOnHiddenPrototype($Array.prototype, DONT_ENUM, $Array( "toString", ArrayToString, "toLocaleString", ArrayToLocaleString, "join", ArrayJoin, @@ -917,8 +1031,9 @@ function SetupArray() { "every", ArrayEvery, "map", ArrayMap, "indexOf", ArrayIndexOf, - "lastIndexOf", ArrayLastIndexOf - )); + "lastIndexOf", ArrayLastIndexOf, + "reduce", ArrayReduce, + "reduceRight", ArrayReduceRight)); // Manipulate the length of some of the functions to meet // expectations set by ECMA-262 or Mozilla. @@ -930,7 +1045,9 @@ function SetupArray() { ArrayMap: 1, ArrayIndexOf: 1, ArrayLastIndexOf: 1, - ArrayPush: 1 + ArrayPush: 1, + ArrayReduce: 1, + ArrayReduceRight: 1 }); } diff --git a/deps/v8/src/assembler.cc b/deps/v8/src/assembler.cc index ad4b24cc1..ec0e4fd14 100644 --- a/deps/v8/src/assembler.cc +++ b/deps/v8/src/assembler.cc @@ -521,10 +521,10 @@ ExternalReference::ExternalReference(Runtime::Function* f) ExternalReference::ExternalReference(const IC_Utility& ic_utility) : address_(ic_utility.address()) {} - +#ifdef ENABLE_DEBUGGER_SUPPORT ExternalReference::ExternalReference(const Debug_Address& debug_address) : address_(debug_address.address()) {} - +#endif ExternalReference::ExternalReference(StatsCounter* counter) : address_(reinterpret_cast<Address>(counter->GetInternalPointer())) {} @@ -557,29 +557,71 @@ ExternalReference ExternalReference::address_of_regexp_stack_limit() { } -ExternalReference ExternalReference::debug_break() { - return ExternalReference(FUNCTION_ADDR(Debug::Break)); -} - - ExternalReference ExternalReference::new_space_start() { return ExternalReference(Heap::NewSpaceStart()); } + ExternalReference ExternalReference::new_space_allocation_top_address() { return ExternalReference(Heap::NewSpaceAllocationTopAddress()); } + ExternalReference ExternalReference::heap_always_allocate_scope_depth() { return ExternalReference(Heap::always_allocate_scope_depth_address()); } + ExternalReference ExternalReference::new_space_allocation_limit_address() { return ExternalReference(Heap::NewSpaceAllocationLimitAddress()); } + +static double add_two_doubles(double x, double y) { + return x + y; +} + + +static double sub_two_doubles(double x, double y) { + return x - y; +} + + +static double mul_two_doubles(double x, double y) { + return x * y; +} + + +ExternalReference ExternalReference::double_fp_operation( + Token::Value operation) { + typedef double BinaryFPOperation(double x, double y); + BinaryFPOperation* function = NULL; + switch (operation) { + case Token::ADD: + function = &add_two_doubles; + break; + case Token::SUB: + function = &sub_two_doubles; + break; + case Token::MUL: + function = &mul_two_doubles; + break; + default: + UNREACHABLE(); + } + return ExternalReference(FUNCTION_ADDR(function)); +} + + +#ifdef ENABLE_DEBUGGER_SUPPORT +ExternalReference ExternalReference::debug_break() { + return ExternalReference(FUNCTION_ADDR(Debug::Break)); +} + + ExternalReference ExternalReference::debug_step_in_fp_address() { return ExternalReference(Debug::step_in_fp_addr()); } +#endif } } // namespace v8::internal diff --git a/deps/v8/src/assembler.h b/deps/v8/src/assembler.h index 49c9b90f0..8abdbc767 100644 --- a/deps/v8/src/assembler.h +++ b/deps/v8/src/assembler.h @@ -38,6 +38,7 @@ #include "runtime.h" #include "top.h" #include "zone-inl.h" +#include "token.h" namespace v8 { namespace internal { @@ -340,29 +341,15 @@ class RelocIterator: public Malloced { }; -// A stack-allocated code region logs a name for the code generated -// while the region is in effect. This information is used by the -// profiler to categorize ticks within generated code. -class CodeRegion BASE_EMBEDDED { - public: - inline CodeRegion(Assembler* assm, const char *name) : assm_(assm) { - LOG(BeginCodeRegionEvent(this, assm, name)); - } - inline ~CodeRegion() { - LOG(EndCodeRegionEvent(this, assm_)); - } - private: - Assembler* assm_; -}; - - //------------------------------------------------------------------------------ // External function //---------------------------------------------------------------------------- class IC_Utility; -class Debug_Address; class SCTableReference; +#ifdef ENABLE_DEBUGGER_SUPPORT +class Debug_Address; +#endif // An ExternalReference represents a C++ address called from the generated // code. All references to C++ functions and must be encapsulated in an @@ -380,7 +367,9 @@ class ExternalReference BASE_EMBEDDED { explicit ExternalReference(const IC_Utility& ic_utility); +#ifdef ENABLE_DEBUGGER_SUPPORT explicit ExternalReference(const Debug_Address& debug_address); +#endif explicit ExternalReference(StatsCounter* counter); @@ -403,9 +392,6 @@ class ExternalReference BASE_EMBEDDED { // Static variable RegExpStack::limit_address() static ExternalReference address_of_regexp_stack_limit(); - // Function Debug::Break() - static ExternalReference debug_break(); - // Static variable Heap::NewSpaceStart() static ExternalReference new_space_start(); static ExternalReference heap_always_allocate_scope_depth(); @@ -414,11 +400,18 @@ class ExternalReference BASE_EMBEDDED { static ExternalReference new_space_allocation_top_address(); static ExternalReference new_space_allocation_limit_address(); - // Used to check if single stepping is enabled in generated code. - static ExternalReference debug_step_in_fp_address(); + static ExternalReference double_fp_operation(Token::Value operation); Address address() const {return address_;} +#ifdef ENABLE_DEBUGGER_SUPPORT + // Function Debug::Break() + static ExternalReference debug_break(); + + // Used to check if single stepping is enabled in generated code. + static ExternalReference debug_step_in_fp_address(); +#endif + private: explicit ExternalReference(void* address) : address_(reinterpret_cast<Address>(address)) {} diff --git a/deps/v8/src/ast.cc b/deps/v8/src/ast.cc index 1a6010a00..d19e3b3e0 100644 --- a/deps/v8/src/ast.cc +++ b/deps/v8/src/ast.cc @@ -152,6 +152,27 @@ ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) { } +bool ObjectLiteral::IsValidJSON() { + int length = properties()->length(); + for (int i = 0; i < length; i++) { + Property* prop = properties()->at(i); + if (!prop->value()->IsValidJSON()) + return false; + } + return true; +} + + +bool ArrayLiteral::IsValidJSON() { + int length = values()->length(); + for (int i = 0; i < length; i++) { + if (!values()->at(i)->IsValidJSON()) + return false; + } + return true; +} + + void TargetCollector::AddTarget(BreakTarget* target) { // Add the label to the collector, but discard duplicates. int length = targets_->length(); diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h index b496816f7..6a2f67105 100644 --- a/deps/v8/src/ast.h +++ b/deps/v8/src/ast.h @@ -155,6 +155,7 @@ class Expression: public Node { public: virtual Expression* AsExpression() { return this; } + virtual bool IsValidJSON() { return false; } virtual bool IsValidLeftHandSide() { return false; } // Mark the expression as being compiled as an expression @@ -625,6 +626,8 @@ class Literal: public Expression { return handle_.is_identical_to(other->handle_); } + virtual bool IsValidJSON() { return true; } + // Identity testers. bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); } bool IsTrue() const { return handle_.is_identical_to(Factory::true_value()); } @@ -653,6 +656,8 @@ class MaterializedLiteral: public Expression { // constants and simple object and array literals. bool is_simple() const { return is_simple_; } + virtual bool IsValidJSON() { return true; } + int depth() const { return depth_; } private: @@ -704,6 +709,7 @@ class ObjectLiteral: public MaterializedLiteral { virtual ObjectLiteral* AsObjectLiteral() { return this; } virtual void Accept(AstVisitor* v); + virtual bool IsValidJSON(); Handle<FixedArray> constant_properties() const { return constant_properties_; @@ -751,6 +757,7 @@ class ArrayLiteral: public MaterializedLiteral { virtual void Accept(AstVisitor* v); virtual ArrayLiteral* AsArrayLiteral() { return this; } + virtual bool IsValidJSON(); Handle<FixedArray> literals() const { return literals_; } ZoneList<Expression*>* values() const { return values_; } diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index 0a0ed8300..09cf68dea 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -530,7 +530,7 @@ void Genesis::CreateRoots(v8::Handle<v8::ObjectTemplate> global_template, global_context()->function_instance_map()->set_prototype(*empty_function); // Allocate the function map first and then patch the prototype later - Handle<Map> empty_fm = Factory::CopyMap(fm); + Handle<Map> empty_fm = Factory::CopyMapDropDescriptors(fm); empty_fm->set_instance_descriptors(*function_map_descriptors); empty_fm->set_prototype(global_context()->object_function()->prototype()); empty_function->set_map(*empty_fm); @@ -741,6 +741,19 @@ void Genesis::CreateRoots(v8::Handle<v8::ObjectTemplate> global_template, global_context()->set_regexp_function(*regexp_fun); } + { // -- J S O N + Handle<String> name = Factory::NewStringFromAscii(CStrVector("JSON")); + Handle<JSFunction> cons = Factory::NewFunction( + name, + Factory::the_hole_value()); + cons->SetInstancePrototype(global_context()->initial_object_prototype()); + cons->SetInstanceClassName(*name); + Handle<JSObject> json_object = Factory::NewJSObject(cons, TENURED); + ASSERT(json_object->IsJSObject()); + SetProperty(global, name, json_object, DONT_ENUM); + global_context()->set_json_object(*json_object); + } + { // --- arguments_boilerplate_ // Make sure we can recognize argument objects at runtime. // This is done by introducing an anonymous function with @@ -820,6 +833,9 @@ void Genesis::CreateRoots(v8::Handle<v8::ObjectTemplate> global_template, // Initialize the out of memory slot. global_context()->set_out_of_memory(Heap::false_value()); + + // Initialize the data slot. + global_context()->set_data(Heap::undefined_value()); } @@ -832,12 +848,16 @@ bool Genesis::CompileBuiltin(int index) { bool Genesis::CompileNative(Vector<const char> name, Handle<String> source) { HandleScope scope; +#ifdef ENABLE_DEBUGGER_SUPPORT Debugger::set_compiling_natives(true); +#endif bool result = CompileScriptCached(name, source, &natives_cache, NULL, true); ASSERT(Top::has_pending_exception() != result); if (!result) Top::clear_pending_exception(); +#ifdef ENABLE_DEBUGGER_SUPPORT Debugger::set_compiling_natives(false); +#endif return result; } @@ -853,9 +873,7 @@ bool Genesis::CompileScriptCached(Vector<const char> name, // If we can't find the function in the cache, we compile a new // function and insert it into the cache. if (!cache->Lookup(name, &boilerplate)) { -#ifdef DEBUG - ASSERT(StringShape(*source).IsAsciiRepresentation()); -#endif + ASSERT(source->IsAsciiRepresentation()); Handle<String> script_name = Factory::NewStringFromUtf8(name); boilerplate = Compiler::Compile(source, script_name, 0, 0, extension, NULL); @@ -1015,6 +1033,13 @@ bool Genesis::InstallNatives() { Factory::LookupAsciiSymbol("column_offset"), proxy_column_offset, common_attributes); + Handle<Proxy> proxy_data = Factory::NewProxy(&Accessors::ScriptData); + script_descriptors = + Factory::CopyAppendProxyDescriptor( + script_descriptors, + Factory::LookupAsciiSymbol("data"), + proxy_data, + common_attributes); Handle<Proxy> proxy_type = Factory::NewProxy(&Accessors::ScriptType); script_descriptors = Factory::CopyAppendProxyDescriptor( @@ -1030,6 +1055,14 @@ bool Genesis::InstallNatives() { Factory::LookupAsciiSymbol("line_ends"), proxy_line_ends, common_attributes); + Handle<Proxy> proxy_context_data = + Factory::NewProxy(&Accessors::ScriptContextData); + script_descriptors = + Factory::CopyAppendProxyDescriptor( + script_descriptors, + Factory::LookupAsciiSymbol("context_data"), + proxy_context_data, + common_attributes); Handle<Map> script_map = Handle<Map>(script_fun->initial_map()); script_map->set_instance_descriptors(*script_descriptors); @@ -1057,6 +1090,10 @@ bool Genesis::InstallNatives() { Natives::GetIndex("regexp"), Top::global_context(), Handle<Context>(Top::context()->runtime_context())); + SetupLazy(Handle<JSObject>(global_context()->json_object()), + Natives::GetIndex("json"), + Top::global_context(), + Handle<Context>(Top::context()->runtime_context())); } else if (strlen(FLAG_natives_file) != 0) { // Otherwise install natives from natives file if file exists and @@ -1132,6 +1169,7 @@ bool Genesis::InstallSpecialObjects() { Handle<JSObject>(js_global->builtins()), DONT_ENUM); } +#ifdef ENABLE_DEBUGGER_SUPPORT // Expose the debug global object in global if a name for it is specified. if (FLAG_expose_debug_as != NULL && strlen(FLAG_expose_debug_as) != 0) { // If loading fails we just bail out without installing the @@ -1149,6 +1187,7 @@ bool Genesis::InstallSpecialObjects() { SetProperty(js_global, debug_string, Handle<Object>(Debug::debug_context()->global_proxy()), DONT_ENUM); } +#endif return true; } @@ -1403,7 +1442,7 @@ void Genesis::MakeFunctionInstancePrototypeWritable() { Handle<DescriptorArray> function_map_descriptors = ComputeFunctionInstanceDescriptor(false, true); - Handle<Map> fm = Factory::CopyMap(Top::function_map()); + Handle<Map> fm = Factory::CopyMapDropDescriptors(Top::function_map()); fm->set_instance_descriptors(*function_map_descriptors); Top::context()->global_context()->set_function_map(*fm); } @@ -1442,11 +1481,20 @@ void Genesis::BuildSpecialFunctionTable() { Handle<JSFunction> function = Handle<JSFunction>( JSFunction::cast(global->GetProperty(Heap::Array_symbol()))); - Handle<JSObject> prototype = + Handle<JSObject> visible_prototype = Handle<JSObject>(JSObject::cast(function->prototype())); - AddSpecialFunction(prototype, "pop", + // Remember to put push and pop on the hidden prototype if it's there. + Handle<JSObject> push_and_pop_prototype; + Handle<Object> superproto(visible_prototype->GetPrototype()); + if (superproto->IsJSObject() && + JSObject::cast(*superproto)->map()->is_hidden_prototype()) { + push_and_pop_prototype = Handle<JSObject>::cast(superproto); + } else { + push_and_pop_prototype = visible_prototype; + } + AddSpecialFunction(push_and_pop_prototype, "pop", Handle<Code>(Builtins::builtin(Builtins::ArrayPop))); - AddSpecialFunction(prototype, "push", + AddSpecialFunction(push_and_pop_prototype, "push", Handle<Code>(Builtins::builtin(Builtins::ArrayPush))); } diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index c3935f1ae..b27974ffd 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -559,6 +559,7 @@ static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) { } +#ifdef ENABLE_DEBUGGER_SUPPORT static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) { Debug::GenerateLoadICDebugBreak(masm); } @@ -597,7 +598,7 @@ static void Generate_Return_DebugBreakEntry(MacroAssembler* masm) { static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) { Debug::GenerateStubNoRegistersDebugBreak(masm); } - +#endif Object* Builtins::builtins_[builtin_count] = { NULL, }; const char* Builtins::names_[builtin_count] = { NULL, }; diff --git a/deps/v8/src/builtins.h b/deps/v8/src/builtins.h index 853c90e83..4e74a3cc4 100644 --- a/deps/v8/src/builtins.h +++ b/deps/v8/src/builtins.h @@ -83,6 +83,7 @@ namespace v8 { namespace internal { V(FunctionApply, BUILTIN, UNINITIALIZED) +#ifdef ENABLE_DEBUGGER_SUPPORT // Define list of builtins used by the debugger implemented in assembly. #define BUILTIN_LIST_DEBUG_A(V) \ V(Return_DebugBreak, BUILTIN, DEBUG_BREAK) \ @@ -93,7 +94,9 @@ namespace v8 { namespace internal { V(KeyedLoadIC_DebugBreak, KEYED_LOAD_IC, DEBUG_BREAK) \ V(StoreIC_DebugBreak, STORE_IC, DEBUG_BREAK) \ V(KeyedStoreIC_DebugBreak, KEYED_STORE_IC, DEBUG_BREAK) - +#else +#define BUILTIN_LIST_DEBUG_A(V) +#endif // Define list of builtins implemented in JavaScript. #define BUILTINS_LIST_JS(V) \ diff --git a/deps/v8/src/checks.h b/deps/v8/src/checks.h index 0ff79afbc..b302e5bee 100644 --- a/deps/v8/src/checks.h +++ b/deps/v8/src/checks.h @@ -254,7 +254,7 @@ template <int> class StaticAssertionHelper { }; #define ASSERT_TAG_ALIGNED(address) \ - ASSERT((reinterpret_cast<int>(address) & kHeapObjectTagMask) == 0) + ASSERT((reinterpret_cast<intptr_t>(address) & kHeapObjectTagMask) == 0) #define ASSERT_SIZE_TAG_ALIGNED(size) ASSERT((size & kHeapObjectTagMask) == 0) diff --git a/deps/v8/src/code-stubs.h b/deps/v8/src/code-stubs.h index d21b0eed2..67634aa13 100644 --- a/deps/v8/src/code-stubs.h +++ b/deps/v8/src/code-stubs.h @@ -72,7 +72,7 @@ class CodeStub BASE_EMBEDDED { protected: static const int kMajorBits = 5; - static const int kMinorBits = kBitsPerPointer - kMajorBits - kSmiTagSize; + static const int kMinorBits = kBitsPerInt - kSmiTagSize - kMajorBits; private: // Generates the assembler code for the stub. diff --git a/deps/v8/src/codegen.cc b/deps/v8/src/codegen.cc index edc498d14..40c2583f4 100644 --- a/deps/v8/src/codegen.cc +++ b/deps/v8/src/codegen.cc @@ -304,8 +304,10 @@ Handle<JSFunction> CodeGenerator::BuildBoilerplate(FunctionLiteral* node) { node->is_expression(), false, script_, node->inferred_name()); +#ifdef ENABLE_DEBUGGER_SUPPORT // Notify debugger that a new function has been added. Debugger::OnNewFunction(function); +#endif // Set the expected number of properties for instances and return // the resulting function. @@ -384,57 +386,69 @@ void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) { } -struct InlineRuntimeLUT { - void (CodeGenerator::*method)(ZoneList<Expression*>*); - const char* name; + +// Special cases: These 'runtime calls' manipulate the current +// frame and are only used 1 or two places, so we generate them +// inline instead of generating calls to them. They are used +// for implementing Function.prototype.call() and +// Function.prototype.apply(). +CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = { + {&CodeGenerator::GenerateIsSmi, "_IsSmi"}, + {&CodeGenerator::GenerateIsNonNegativeSmi, "_IsNonNegativeSmi"}, + {&CodeGenerator::GenerateIsArray, "_IsArray"}, + {&CodeGenerator::GenerateArgumentsLength, "_ArgumentsLength"}, + {&CodeGenerator::GenerateArgumentsAccess, "_Arguments"}, + {&CodeGenerator::GenerateValueOf, "_ValueOf"}, + {&CodeGenerator::GenerateSetValueOf, "_SetValueOf"}, + {&CodeGenerator::GenerateFastCharCodeAt, "_FastCharCodeAt"}, + {&CodeGenerator::GenerateObjectEquals, "_ObjectEquals"}, + {&CodeGenerator::GenerateLog, "_Log"} }; +CodeGenerator::InlineRuntimeLUT* CodeGenerator::FindInlineRuntimeLUT( + Handle<String> name) { + const int entries_count = + sizeof(kInlineRuntimeLUT) / sizeof(InlineRuntimeLUT); + for (int i = 0; i < entries_count; i++) { + InlineRuntimeLUT* entry = &kInlineRuntimeLUT[i]; + if (name->IsEqualTo(CStrVector(entry->name))) { + return entry; + } + } + return NULL; +} + + bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) { ZoneList<Expression*>* args = node->arguments(); - // Special cases: These 'runtime calls' manipulate the current - // frame and are only used 1 or two places, so we generate them - // inline instead of generating calls to them. They are used - // for implementing Function.prototype.call() and - // Function.prototype.apply(). - static const InlineRuntimeLUT kInlineRuntimeLUT[] = { - {&v8::internal::CodeGenerator::GenerateIsSmi, - "_IsSmi"}, - {&v8::internal::CodeGenerator::GenerateIsNonNegativeSmi, - "_IsNonNegativeSmi"}, - {&v8::internal::CodeGenerator::GenerateIsArray, - "_IsArray"}, - {&v8::internal::CodeGenerator::GenerateArgumentsLength, - "_ArgumentsLength"}, - {&v8::internal::CodeGenerator::GenerateArgumentsAccess, - "_Arguments"}, - {&v8::internal::CodeGenerator::GenerateValueOf, - "_ValueOf"}, - {&v8::internal::CodeGenerator::GenerateSetValueOf, - "_SetValueOf"}, - {&v8::internal::CodeGenerator::GenerateFastCharCodeAt, - "_FastCharCodeAt"}, - {&v8::internal::CodeGenerator::GenerateObjectEquals, - "_ObjectEquals"}, - {&v8::internal::CodeGenerator::GenerateLog, - "_Log"} - }; Handle<String> name = node->name(); if (name->length() > 0 && name->Get(0) == '_') { - for (unsigned i = 0; - i < sizeof(kInlineRuntimeLUT) / sizeof(InlineRuntimeLUT); - i++) { - const InlineRuntimeLUT* entry = kInlineRuntimeLUT + i; - if (name->IsEqualTo(CStrVector(entry->name))) { - ((*this).*(entry->method))(args); - return true; - } + InlineRuntimeLUT* entry = FindInlineRuntimeLUT(name); + if (entry != NULL) { + ((*this).*(entry->method))(args); + return true; } } return false; } +bool CodeGenerator::PatchInlineRuntimeEntry(Handle<String> name, + const CodeGenerator::InlineRuntimeLUT& new_entry, + CodeGenerator::InlineRuntimeLUT* old_entry) { + InlineRuntimeLUT* entry = FindInlineRuntimeLUT(name); + if (entry == NULL) return false; + if (old_entry != NULL) { + old_entry->name = entry->name; + old_entry->method = entry->method; + } + entry->name = new_entry.name; + entry->method = new_entry.method; + return true; +} + + void CodeGenerator::GenerateFastCaseSwitchStatement(SwitchStatement* node, int min_index, int range, diff --git a/deps/v8/src/codegen.h b/deps/v8/src/codegen.h index dd43cc0c8..a6cd693eb 100644 --- a/deps/v8/src/codegen.h +++ b/deps/v8/src/codegen.h @@ -59,7 +59,9 @@ // ComputeCallInitializeInLoop // ProcessDeclarations // DeclareGlobals +// FindInlineRuntimeLUT // CheckForInlineRuntimeCall +// PatchInlineRuntimeEntry // GenerateFastCaseSwitchStatement // GenerateFastCaseSwitchCases // TryGenerateFastCaseSwitchStatement @@ -71,10 +73,17 @@ // CodeForStatementPosition // CodeForSourcePosition -#ifdef ARM -#include "codegen-arm.h" -#else -#include "codegen-ia32.h" + +// Mode to overwrite BinaryExpression values. +enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT }; + + +#if V8_TARGET_ARCH_IA32 +#include "ia32/codegen-ia32.h" +#elif V8_TARGET_ARCH_X64 +#include "x64/codegen-x64.h" +#elif V8_TARGET_ARCH_ARM +#include "arm/codegen-arm.h" #endif namespace v8 { namespace internal { @@ -111,6 +120,9 @@ class DeferredCode: public ZoneObject { JumpTarget* enter() { return &enter_; } void BindExit() { exit_.Bind(0); } void BindExit(Result* result) { exit_.Bind(result, 1); } + void BindExit(Result* result0, Result* result1) { + exit_.Bind(result0, result1, 2); + } void BindExit(Result* result0, Result* result1, Result* result2) { exit_.Bind(result0, result1, result2, 3); } diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc index 63fed4a1b..256c69696 100644 --- a/deps/v8/src/compiler.cc +++ b/deps/v8/src/compiler.cc @@ -80,8 +80,20 @@ static Handle<Code> MakeCode(FunctionLiteral* literal, } +static bool IsValidJSON(FunctionLiteral* lit) { + if (!lit->body()->length() == 1) + return false; + Statement* stmt = lit->body()->at(0); + if (stmt->AsExpressionStatement() == NULL) + return false; + Expression *expr = stmt->AsExpressionStatement()->expression(); + return expr->IsValidJSON(); +} + + static Handle<JSFunction> MakeFunction(bool is_global, bool is_eval, + bool is_json, Handle<Script> script, Handle<Context> context, v8::Extension* extension, @@ -92,8 +104,12 @@ static Handle<JSFunction> MakeFunction(bool is_global, StackGuard guard; PostponeInterruptsScope postpone; + ASSERT(!i::Top::global_context().is_null()); + script->set_context_data((*i::Top::global_context())->data()); +#ifdef ENABLE_DEBUGGER_SUPPORT // Notify debugger Debugger::OnBeforeCompile(script); +#endif // Only allow non-global compiles for eval. ASSERT(is_eval || is_global); @@ -107,6 +123,19 @@ static Handle<JSFunction> MakeFunction(bool is_global, return Handle<JSFunction>::null(); } + // When parsing JSON we do an ordinary parse and then afterwards + // check the AST to ensure it was well-formed. If not we give a + // syntax error. + if (is_json && !IsValidJSON(lit)) { + HandleScope scope; + Handle<JSArray> args = Factory::NewJSArray(1); + Handle<Object> source(script->source()); + SetElement(args, 0, source); + Handle<Object> result = Factory::NewSyntaxError("invalid_json", args); + Top::Throw(*result, NULL); + return Handle<JSFunction>::null(); + } + // Measure how long it takes to do the compilation; only take the // rest of the function into account to avoid overlap with the // parsing statistics. @@ -160,8 +189,10 @@ static Handle<JSFunction> MakeFunction(bool is_global, // the instances of the function. SetExpectedNofPropertiesFromEstimate(fun, lit->expected_property_count()); +#ifdef ENABLE_DEBUGGER_SUPPORT // Notify debugger Debugger::OnAfterCompile(script, fun); +#endif return fun; } @@ -211,6 +242,7 @@ Handle<JSFunction> Compiler::Compile(Handle<String> source, // Compile the function and add it to the cache. result = MakeFunction(true, false, + false, script, Handle<Context>::null(), extension, @@ -233,7 +265,8 @@ Handle<JSFunction> Compiler::Compile(Handle<String> source, Handle<JSFunction> Compiler::CompileEval(Handle<String> source, Handle<Context> context, int line_offset, - bool is_global) { + bool is_global, + bool is_json) { int source_length = source->length(); Counters::total_eval_size.Increment(source_length); Counters::total_compile_size.Increment(source_length); @@ -252,7 +285,13 @@ Handle<JSFunction> Compiler::CompileEval(Handle<String> source, // Create a script object describing the script to be compiled. Handle<Script> script = Factory::NewScript(source); script->set_line_offset(Smi::FromInt(line_offset)); - result = MakeFunction(is_global, true, script, context, NULL, NULL); + result = MakeFunction(is_global, + true, + is_json, + script, + context, + NULL, + NULL); if (!result.is_null()) { CompilationCache::PutEval(source, context, entry, result); } diff --git a/deps/v8/src/compiler.h b/deps/v8/src/compiler.h index 4f589b7ee..8abe130d8 100644 --- a/deps/v8/src/compiler.h +++ b/deps/v8/src/compiler.h @@ -60,7 +60,8 @@ class Compiler : public AllStatic { static Handle<JSFunction> CompileEval(Handle<String> source, Handle<Context> context, int line_offset, - bool is_global); + bool is_global, + bool is_json); // Compile from function info (used for lazy compilation). Returns // true on success and false if the compilation resulted in a stack diff --git a/deps/v8/src/contexts.h b/deps/v8/src/contexts.h index 3c25bd3ea..f56143175 100644 --- a/deps/v8/src/contexts.h +++ b/deps/v8/src/contexts.h @@ -64,6 +64,7 @@ enum ContextLookupFlags { V(OBJECT_FUNCTION_INDEX, JSFunction, object_function) \ V(ARRAY_FUNCTION_INDEX, JSFunction, array_function) \ V(DATE_FUNCTION_INDEX, JSFunction, date_function) \ + V(JSON_OBJECT_INDEX, JSObject, json_object) \ V(REGEXP_FUNCTION_INDEX, JSFunction, regexp_function) \ V(INITIAL_OBJECT_PROTOTYPE_INDEX, JSObject, initial_object_prototype) \ V(CREATE_DATE_FUN_INDEX, JSFunction, create_date_fun) \ @@ -93,7 +94,8 @@ enum ContextLookupFlags { V(SCRIPT_FUNCTION_INDEX, JSFunction, script_function) \ V(CONTEXT_EXTENSION_FUNCTION_INDEX, JSFunction, context_extension_function) \ V(OUT_OF_MEMORY_INDEX, Object, out_of_memory) \ - V(MAP_CACHE_INDEX, Object, map_cache) + V(MAP_CACHE_INDEX, Object, map_cache) \ + V(CONTEXT_DATA_INDEX, Object, data) // JSFunctions are pairs (context, function code), sometimes also called // closures. A Context object is used to represent function contexts and @@ -186,6 +188,7 @@ class Context: public FixedArray { OBJECT_FUNCTION_INDEX, ARRAY_FUNCTION_INDEX, DATE_FUNCTION_INDEX, + JSON_OBJECT_INDEX, REGEXP_FUNCTION_INDEX, CREATE_DATE_FUN_INDEX, TO_NUMBER_FUN_INDEX, @@ -211,6 +214,7 @@ class Context: public FixedArray { CONTEXT_EXTENSION_FUNCTION_INDEX, OUT_OF_MEMORY_INDEX, MAP_CACHE_INDEX, + CONTEXT_DATA_INDEX, GLOBAL_CONTEXT_SLOTS }; diff --git a/deps/v8/src/d8.cc b/deps/v8/src/d8.cc index 9648168b3..70143c3c0 100644 --- a/deps/v8/src/d8.cc +++ b/deps/v8/src/d8.cc @@ -163,6 +163,22 @@ Handle<Value> Shell::Print(const Arguments& args) { } +Handle<Value> Shell::Read(const Arguments& args) { + if (args.Length() != 1) { + return ThrowException(String::New("Bad parameters")); + } + String::Utf8Value file(args[0]); + if (*file == NULL) { + return ThrowException(String::New("Error loading file")); + } + Handle<String> source = ReadFile(*file); + if (source.IsEmpty()) { + return ThrowException(String::New("Error loading file")); + } + return source; +} + + Handle<Value> Shell::Load(const Arguments& args) { for (int i = 0; i < args.Length(); i++) { HandleScope handle_scope; @@ -246,6 +262,7 @@ Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) { } +#ifdef ENABLE_DEBUGGER_SUPPORT Handle<Object> Shell::DebugMessageDetails(Handle<String> message) { Context::Scope context_scope(utility_context_); Handle<Object> global = utility_context_->Global(); @@ -266,6 +283,7 @@ Handle<Value> Shell::DebugCommandToJSONRequest(Handle<String> command) { Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv); return val; } +#endif int32_t* Counter::Bind(const char* name, bool is_histogram) { @@ -381,6 +399,7 @@ void Shell::Initialize() { HandleScope scope; Handle<ObjectTemplate> global_template = ObjectTemplate::New(); global_template->Set(String::New("print"), FunctionTemplate::New(Print)); + global_template->Set(String::New("read"), FunctionTemplate::New(Read)); global_template->Set(String::New("load"), FunctionTemplate::New(Load)); global_template->Set(String::New("quit"), FunctionTemplate::New(Quit)); global_template->Set(String::New("version"), FunctionTemplate::New(Version)); @@ -406,11 +425,13 @@ void Shell::Initialize() { global_template->Set(String::New("arguments"), Utils::ToLocal(arguments_jsarray)); +#ifdef ENABLE_DEBUGGER_SUPPORT // Install the debugger object in the utility scope i::Debug::Load(); i::JSObject* debug = i::Debug::debug_context()->global(); utility_context_->Global()->Set(String::New("$debug"), Utils::ToLocal(&debug)); +#endif // Run the d8 shell utility script in the utility context int source_index = i::NativesCollection<i::D8>::GetIndex("d8"); @@ -436,8 +457,10 @@ void Shell::Initialize() { evaluation_context_ = Context::New(NULL, global_template); evaluation_context_->SetSecurityToken(Undefined()); +#ifdef ENABLE_DEBUGGER_SUPPORT // Set the security token of the debug context to allow access. i::Debug::debug_context()->set_security_token(i::Heap::undefined_value()); +#endif } @@ -555,6 +578,8 @@ void ShellThread::Run() { Handle<ObjectTemplate> global_template = ObjectTemplate::New(); global_template->Set(String::New("print"), FunctionTemplate::New(Shell::Print)); + global_template->Set(String::New("read"), + FunctionTemplate::New(Shell::Read)); global_template->Set(String::New("load"), FunctionTemplate::New(Shell::Load)); global_template->Set(String::New("yield"), @@ -690,6 +715,7 @@ int Shell::Main(int argc, char* argv[]) { Locker::StartPreemption(preemption_interval); } +#ifdef ENABLE_DEBUGGER_SUPPORT // Run the remote debugger if requested. if (i::FLAG_remote_debugger) { RunRemoteDebugger(i::FLAG_debugger_port); @@ -705,6 +731,7 @@ int Shell::Main(int argc, char* argv[]) { if (i::FLAG_debugger && !i::FLAG_debugger_agent) { v8::Debug::SetDebugEventListener(HandleDebugEvent); } +#endif } if (run_shell) RunShell(); diff --git a/deps/v8/src/d8.h b/deps/v8/src/d8.h index 342a0d2c2..092e3a381 100644 --- a/deps/v8/src/d8.h +++ b/deps/v8/src/d8.h @@ -132,13 +132,16 @@ class Shell: public i::AllStatic { static int Main(int argc, char* argv[]); static Handle<Array> GetCompletions(Handle<String> text, Handle<String> full); +#ifdef ENABLE_DEBUGGER_SUPPORT static Handle<Object> DebugMessageDetails(Handle<String> message); static Handle<Value> DebugCommandToJSONRequest(Handle<String> command); +#endif static Handle<Value> Print(const Arguments& args); static Handle<Value> Yield(const Arguments& args); static Handle<Value> Quit(const Arguments& args); static Handle<Value> Version(const Arguments& args); + static Handle<Value> Read(const Arguments& args); static Handle<Value> Load(const Arguments& args); // The OS object on the global object contains methods for performing // operating system calls: diff --git a/deps/v8/src/d8.js b/deps/v8/src/d8.js index e2766d06c..ea2fb4498 100644 --- a/deps/v8/src/d8.js +++ b/deps/v8/src/d8.js @@ -653,17 +653,47 @@ DebugRequest.prototype.breakCommandToJSONRequest_ = function(args) { // Process arguments if any. if (args && args.length > 0) { var target = args; + var type = 'function'; + var line; + var column; var condition; + var pos; - var pos = args.indexOf(' '); + // Check for breakpoint condition. + pos = args.indexOf(' '); if (pos > 0) { target = args.substring(0, pos); condition = args.substring(pos + 1, args.length); } + // Check for script breakpoint (name:line[:column]). If no ':' in break + // specification it is considered a function break point. + pos = target.indexOf(':'); + if (pos > 0) { + type = 'script'; + var tmp = target.substring(pos + 1, target.length); + target = target.substring(0, pos); + + // Check for both line and column. + pos = tmp.indexOf(':'); + if (pos > 0) { + column = parseInt(tmp.substring(pos + 1, tmp.length)) - 1; + line = parseInt(tmp.substring(0, pos)) - 1; + } else { + line = parseInt(tmp) - 1; + } + } else if (target[0] == '#' && target[target.length - 1] == '#') { + type = 'handle'; + target = target.substring(1, target.length - 1); + } else { + type = 'function'; + } + request.arguments = {}; - request.arguments.type = 'function'; + request.arguments.type = type; request.arguments.target = target; + request.arguments.line = line; + request.arguments.column = column; request.arguments.condition = condition; } else { throw new Error('Invalid break arguments.'); @@ -721,6 +751,9 @@ DebugRequest.prototype.helpCommand_ = function(args) { } print('break location [condition]'); + print(' break on named function: location is a function name'); + print(' break on function: location is #<id>#'); + print(' break on script position: location is name:line[:column]'); print('clear <breakpoint #>'); print('backtrace [from frame #] [to frame #]]'); print('frame <frame #>'); diff --git a/deps/v8/src/date-delay.js b/deps/v8/src/date-delay.js index 2421e5bae..f06e8b75b 100644 --- a/deps/v8/src/date-delay.js +++ b/deps/v8/src/date-delay.js @@ -985,6 +985,25 @@ function DateToGMTString() { } +function PadInt(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; +} + + +function DateToISOString() { + return this.getUTCFullYear() + '-' + PadInt(this.getUTCMonth() + 1) + + '-' + PadInt(this.getUTCDate()) + 'T' + PadInt(this.getUTCHours()) + + ':' + PadInt(this.getUTCMinutes()) + ':' + PadInt(this.getUTCSeconds()) + + 'Z'; +} + + +function DateToJSON(key) { + return CheckJSONPrimitive(this.toISOString()); +} + + // ------------------------------------------------------------------- function SetupDate() { @@ -1000,7 +1019,7 @@ function SetupDate() { // Setup non-enumerable functions of the Date prototype object and // set their names. - InstallFunctions($Date.prototype, DONT_ENUM, $Array( + InstallFunctionsOnHiddenPrototype($Date.prototype, DONT_ENUM, $Array( "toString", DateToString, "toDateString", DateToDateString, "toTimeString", DateToTimeString, @@ -1044,7 +1063,9 @@ function SetupDate() { "toGMTString", DateToGMTString, "toUTCString", DateToUTCString, "getYear", DateGetYear, - "setYear", DateSetYear + "setYear", DateSetYear, + "toISOString", DateToISOString, + "toJSON", DateToJSON )); } diff --git a/deps/v8/src/dateparser-inl.h b/deps/v8/src/dateparser-inl.h index 734c151d2..61a8c72e2 100644 --- a/deps/v8/src/dateparser-inl.h +++ b/deps/v8/src/dateparser-inl.h @@ -25,6 +25,9 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifndef V8_DATEPARSER_INL_H_ +#define V8_DATEPARSER_INL_H_ + namespace v8 { namespace internal { template <typename Char> @@ -104,3 +107,5 @@ bool DateParser::Parse(Vector<Char> str, FixedArray* out) { } } } // namespace v8::internal + +#endif // V8_DATEPARSER_INL_H_ diff --git a/deps/v8/src/debug-agent.cc b/deps/v8/src/debug-agent.cc index e865e0e29..63f143a79 100644 --- a/deps/v8/src/debug-agent.cc +++ b/deps/v8/src/debug-agent.cc @@ -29,16 +29,17 @@ #include "v8.h" #include "debug-agent.h" +#ifdef ENABLE_DEBUGGER_SUPPORT namespace v8 { namespace internal { - // Public V8 debugger API message handler function. This function just delegates // to the debugger agent through it's data parameter. -void DebuggerAgentMessageHandler(const uint16_t* message, int length, - void *data) { - reinterpret_cast<DebuggerAgent*>(data)->DebuggerMessage(message, length); +void DebuggerAgentMessageHandler(const v8::Debug::Message& message) { + DebuggerAgent::instance_->DebuggerMessage(message); } +// static +DebuggerAgent* DebuggerAgent::instance_ = NULL; // Debugger agent main thread. void DebuggerAgent::Run() { @@ -105,7 +106,7 @@ void DebuggerAgent::CreateSession(Socket* client) { // Create a new session and hook up the debug message handler. session_ = new DebuggerAgentSession(this, client); - v8::Debug::SetMessageHandler(DebuggerAgentMessageHandler, this); + v8::Debug::SetMessageHandler2(DebuggerAgentMessageHandler); session_->Start(); } @@ -123,13 +124,14 @@ void DebuggerAgent::CloseSession() { } -void DebuggerAgent::DebuggerMessage(const uint16_t* message, int length) { +void DebuggerAgent::DebuggerMessage(const v8::Debug::Message& message) { ScopedLock with(session_access_); // Forward the message handling to the session. if (session_ != NULL) { - session_->DebuggerMessage(Vector<uint16_t>(const_cast<uint16_t*>(message), - length)); + v8::String::Value val(message.GetJSON()); + session_->DebuggerMessage(Vector<uint16_t>(const_cast<uint16_t*>(*val), + val.length())); } } @@ -410,5 +412,6 @@ int DebuggerAgentUtil::ReceiveAll(const Socket* conn, char* data, int len) { return total_received; } - } } // namespace v8::internal + +#endif // ENABLE_DEBUGGER_SUPPORT diff --git a/deps/v8/src/debug-agent.h b/deps/v8/src/debug-agent.h index 177af0c9e..a3c6025cd 100644 --- a/deps/v8/src/debug-agent.h +++ b/deps/v8/src/debug-agent.h @@ -25,15 +25,15 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef V8_V8_DEBUG_AGENT_H_ -#define V8_V8_DEBUG_AGENT_H_ +#ifndef V8_DEBUG_AGENT_H_ +#define V8_DEBUG_AGENT_H_ +#ifdef ENABLE_DEBUGGER_SUPPORT #include "../include/v8-debug.h" #include "platform.h" namespace v8 { namespace internal { - // Forward decelrations. class DebuggerAgentSession; @@ -46,15 +46,21 @@ class DebuggerAgent: public Thread { : name_(StrDup(name)), port_(port), server_(OS::CreateSocket()), terminate_(false), session_access_(OS::CreateMutex()), session_(NULL), - terminate_now_(OS::CreateSemaphore(0)) {} - ~DebuggerAgent() { delete server_; } + terminate_now_(OS::CreateSemaphore(0)) { + ASSERT(instance_ == NULL); + instance_ = this; + } + ~DebuggerAgent() { + instance_ = NULL; + delete server_; + } void Shutdown(); private: void Run(); void CreateSession(Socket* socket); - void DebuggerMessage(const uint16_t* message, int length); + void DebuggerMessage(const v8::Debug::Message& message); void CloseSession(); void OnSessionClosed(DebuggerAgentSession* session); @@ -66,9 +72,10 @@ class DebuggerAgent: public Thread { DebuggerAgentSession* session_; // Current active session if any. Semaphore* terminate_now_; // Semaphore to signal termination. + static DebuggerAgent* instance_; + friend class DebuggerAgentSession; - friend void DebuggerAgentMessageHandler(const uint16_t* message, int length, - void *data); + friend void DebuggerAgentMessageHandler(const v8::Debug::Message& message); DISALLOW_COPY_AND_ASSIGN(DebuggerAgent); }; @@ -111,7 +118,8 @@ class DebuggerAgentUtil { static int ReceiveAll(const Socket* conn, char* data, int len); }; - } } // namespace v8::internal -#endif // V8_V8_DEBUG_AGENT_H_ +#endif // ENABLE_DEBUGGER_SUPPORT + +#endif // V8_DEBUG_AGENT_H_ diff --git a/deps/v8/src/debug-delay.js b/deps/v8/src/debug-delay.js index 9944fb330..ff7d6fbd9 100644 --- a/deps/v8/src/debug-delay.js +++ b/deps/v8/src/debug-delay.js @@ -977,6 +977,7 @@ CompileEvent.prototype.script = function() { CompileEvent.prototype.toJSONProtocol = function() { var o = new ProtocolMessage(); + o.running = true; if (this.before_) { o.event = "beforeCompile"; } else { @@ -1021,6 +1022,9 @@ function MakeScriptObject_(script, include_source) { columnOffset: script.columnOffset(), lineCount: script.lineCount(), }; + if (!IS_UNDEFINED(script.data())) { + o.data = script.data(); + } if (include_source) { o.source = script.source(); } @@ -1058,6 +1062,14 @@ function ProtocolMessage(request) { } +ProtocolMessage.prototype.setOption = function(name, value) { + if (!this.options_) { + this.options_ = {}; + } + this.options_[name] = value; +} + + ProtocolMessage.prototype.failed = function(message) { this.success = false; this.message = message; @@ -1086,7 +1098,7 @@ ProtocolMessage.prototype.toJSONProtocol = function() { if (this.body) { json += ',"body":'; // Encode the body part. - var serializer = MakeMirrorSerializer(true); + var serializer = MakeMirrorSerializer(true, this.options_); if (this.body instanceof Mirror) { json += serializer.serializeValue(this.body); } else if (this.body instanceof Array) { @@ -1130,7 +1142,7 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request) try { try { // Convert the JSON string to an object. - request = %CompileString('(' + json_request + ')', 0)(); + request = %CompileString('(' + json_request + ')', 0, false)(); // Create an initial response. response = this.createResponse(request); @@ -1270,11 +1282,12 @@ DebugCommandProcessor.prototype.setBreakPointRequest_ = var ignoreCount = request.arguments.ignoreCount; // Check for legal arguments. - if (!type || !target) { + if (!type || IS_UNDEFINED(target)) { response.failed('Missing argument "type" or "target"'); return; } - if (type != 'function' && type != 'script' && type != 'scriptId') { + if (type != 'function' && type != 'handle' && + type != 'script' && type != 'scriptId') { response.failed('Illegal type "' + type + '"'); return; } @@ -1303,6 +1316,20 @@ DebugCommandProcessor.prototype.setBreakPointRequest_ = // Set function break point. break_point_number = Debug.setBreakPoint(f, line, column, condition); + } else if (type == 'handle') { + // Find the object pointed by the specified handle. + var handle = parseInt(target, 10); + var mirror = LookupMirror(handle); + if (!mirror) { + return response.failed('Object #' + handle + '# not found'); + } + if (!mirror.isFunction()) { + return response.failed('Object #' + handle + '# is not a function'); + } + + // Set function break point. + break_point_number = Debug.setBreakPoint(mirror.value(), + line, column, condition); } else if (type == 'script') { // set script break point. break_point_number = @@ -1547,20 +1574,24 @@ DebugCommandProcessor.prototype.lookupRequest_ = function(request, response) { } // Pull out arguments. - var handle = request.arguments.handle; + var handles = request.arguments.handles; // Check for legal arguments. - if (IS_UNDEFINED(handle)) { - return response.failed('Argument "handle" missing'); + if (IS_UNDEFINED(handles)) { + return response.failed('Argument "handles" missing'); } - // Lookup handle. - var mirror = LookupMirror(handle); - if (mirror) { - response.body = mirror; - } else { - return response.failed('Object #' + handle + '# not found'); + // Lookup handles. + var mirrors = {}; + for (var i = 0; i < handles.length; i++) { + var handle = handles[i]; + var mirror = LookupMirror(handle); + if (!mirror) { + return response.failed('Object #' + handle + '# not found'); + } + mirrors[handle] = mirror; } + response.body = mirrors; }; @@ -1657,6 +1688,7 @@ DebugCommandProcessor.prototype.scriptsRequest_ = function(request, response) { if (!IS_UNDEFINED(request.arguments.includeSource)) { includeSource = %ToBoolean(request.arguments.includeSource); + response.setOption('includeSource', includeSource); } } @@ -1667,22 +1699,7 @@ DebugCommandProcessor.prototype.scriptsRequest_ = function(request, response) { for (var i = 0; i < scripts.length; i++) { if (types & ScriptTypeFlag(scripts[i].type)) { - var script = {}; - if (scripts[i].name) { - script.name = scripts[i].name; - } - script.id = scripts[i].id; - script.lineOffset = scripts[i].line_offset; - script.columnOffset = scripts[i].column_offset; - script.lineCount = scripts[i].lineCount(); - if (includeSource) { - script.source = scripts[i].source; - } else { - script.sourceStart = scripts[i].source.substring(0, 80); - } - script.sourceLength = scripts[i].source.length; - script.type = scripts[i].type; - response.body.push(script); + response.body.push(MakeMirror(scripts[i])); } } }; diff --git a/deps/v8/src/debug.cc b/deps/v8/src/debug.cc index a4bb04dc6..8422a6710 100644 --- a/deps/v8/src/debug.cc +++ b/deps/v8/src/debug.cc @@ -35,12 +35,17 @@ #include "debug.h" #include "execution.h" #include "global-handles.h" +#include "ic.h" +#include "ic-inl.h" #include "natives.h" #include "stub-cache.h" #include "log.h" +#include "../include/v8-debug.h" + namespace v8 { namespace internal { +#ifdef ENABLE_DEBUGGER_SUPPORT static void PrintLn(v8::Local<v8::Value> value) { v8::Local<v8::String> s = value->ToString(); char* data = NewArray<char>(s->Length() + 1); @@ -288,14 +293,8 @@ void BreakLocationIterator::SetDebugBreak() { // Patch the frame exit code with a break point. SetDebugBreakAtReturn(); } else { - // Patch the original code with the current address as the current address - // might have changed by the inline caching since the code was copied. - original_rinfo()->set_target_address(rinfo()->target_address()); - - // Patch the code to invoke the builtin debug break function matching the - // calling convention used by the call site. - Handle<Code> dbgbrk_code(Debug::FindDebugBreak(rinfo())); - rinfo()->set_target_address(dbgbrk_code->entry()); + // Patch the IC call. + SetDebugBreakAtIC(); } ASSERT(IsDebugBreak()); } @@ -306,8 +305,8 @@ void BreakLocationIterator::ClearDebugBreak() { // Restore the frame exit code. ClearDebugBreakAtReturn(); } else { - // Patch the code to the original invoke. - rinfo()->set_target_address(original_rinfo()->target_address()); + // Patch the IC call. + ClearDebugBreakAtIC(); } ASSERT(!IsDebugBreak()); } @@ -360,6 +359,37 @@ bool BreakLocationIterator::IsDebugBreak() { } +void BreakLocationIterator::SetDebugBreakAtIC() { + // Patch the original code with the current address as the current address + // might have changed by the inline caching since the code was copied. + original_rinfo()->set_target_address(rinfo()->target_address()); + + RelocInfo::Mode mode = rmode(); + if (RelocInfo::IsCodeTarget(mode)) { + Address target = rinfo()->target_address(); + Handle<Code> code(Code::GetCodeFromTargetAddress(target)); + + // Patch the code to invoke the builtin debug break function matching the + // calling convention used by the call site. + Handle<Code> dbgbrk_code(Debug::FindDebugBreak(code, mode)); + rinfo()->set_target_address(dbgbrk_code->entry()); + + // For stubs that refer back to an inlined version clear the cached map for + // the inlined case to always go through the IC. As long as the break point + // is set the patching performed by the runtime system will take place in + // the code copy and will therefore have no effect on the running code + // keeping it from using the inlined code. + if (code->is_keyed_load_stub()) KeyedLoadIC::ClearInlinedVersion(pc()); + } +} + + +void BreakLocationIterator::ClearDebugBreakAtIC() { + // Patch the code to the original invoke. + rinfo()->set_target_address(original_rinfo()->target_address()); +} + + Object* BreakLocationIterator::BreakPointObjects() { return debug_info_->GetBreakPointObjects(code_position()); } @@ -1055,48 +1085,42 @@ bool Debug::IsBreakStub(Code* code) { // Find the builtin to use for invoking the debug break -Handle<Code> Debug::FindDebugBreak(RelocInfo* rinfo) { +Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) { // Find the builtin debug break function matching the calling convention // used by the call site. - RelocInfo::Mode mode = rinfo->rmode(); - - if (RelocInfo::IsCodeTarget(mode)) { - Address target = rinfo->target_address(); - Code* code = Code::GetCodeFromTargetAddress(target); - if (code->is_inline_cache_stub()) { - if (code->is_call_stub()) { - return ComputeCallDebugBreak(code->arguments_count()); - } - if (code->is_load_stub()) { - return Handle<Code>(Builtins::builtin(Builtins::LoadIC_DebugBreak)); - } - if (code->is_store_stub()) { - return Handle<Code>(Builtins::builtin(Builtins::StoreIC_DebugBreak)); - } - if (code->is_keyed_load_stub()) { - Handle<Code> result = - Handle<Code>(Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak)); - return result; - } - if (code->is_keyed_store_stub()) { - Handle<Code> result = - Handle<Code>(Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak)); - return result; - } + if (code->is_inline_cache_stub()) { + if (code->is_call_stub()) { + return ComputeCallDebugBreak(code->arguments_count()); } - if (RelocInfo::IsConstructCall(mode)) { + if (code->is_load_stub()) { + return Handle<Code>(Builtins::builtin(Builtins::LoadIC_DebugBreak)); + } + if (code->is_store_stub()) { + return Handle<Code>(Builtins::builtin(Builtins::StoreIC_DebugBreak)); + } + if (code->is_keyed_load_stub()) { Handle<Code> result = - Handle<Code>(Builtins::builtin(Builtins::ConstructCall_DebugBreak)); + Handle<Code>(Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak)); return result; } - if (code->kind() == Code::STUB) { - ASSERT(code->major_key() == CodeStub::CallFunction || - code->major_key() == CodeStub::StackCheck); + if (code->is_keyed_store_stub()) { Handle<Code> result = - Handle<Code>(Builtins::builtin(Builtins::StubNoRegisters_DebugBreak)); + Handle<Code>(Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak)); return result; } } + if (RelocInfo::IsConstructCall(mode)) { + Handle<Code> result = + Handle<Code>(Builtins::builtin(Builtins::ConstructCall_DebugBreak)); + return result; + } + if (code->kind() == Code::STUB) { + ASSERT(code->major_key() == CodeStub::CallFunction || + code->major_key() == CodeStub::StackCheck); + Handle<Code> result = + Handle<Code>(Builtins::builtin(Builtins::StubNoRegisters_DebugBreak)); + return result; + } UNREACHABLE(); return Handle<Code>::null(); @@ -1396,17 +1420,13 @@ Handle<Object> Debugger::event_listener_data_ = Handle<Object>(); bool Debugger::compiling_natives_ = false; bool Debugger::is_loading_debugger_ = false; bool Debugger::never_unload_debugger_ = false; -DebugMessageThread* Debugger::message_thread_ = NULL; -v8::DebugMessageHandler Debugger::message_handler_ = NULL; +v8::Debug::MessageHandler2 Debugger::message_handler_ = NULL; bool Debugger::message_handler_cleared_ = false; -void* Debugger::message_handler_data_ = NULL; -v8::DebugHostDispatchHandler Debugger::host_dispatch_handler_ = NULL; -void* Debugger::host_dispatch_handler_data_ = NULL; +v8::Debug::HostDispatchHandler Debugger::host_dispatch_handler_ = NULL; +int Debugger::host_dispatch_micros_ = 100 * 1000; DebuggerAgent* Debugger::agent_ = NULL; -LockingMessageQueue Debugger::command_queue_(kQueueInitialSize); -LockingMessageQueue Debugger::message_queue_(kQueueInitialSize); +LockingCommandMessageQueue Debugger::command_queue_(kQueueInitialSize); Semaphore* Debugger::command_received_ = OS::CreateSemaphore(0); -Semaphore* Debugger::message_received_ = OS::CreateSemaphore(0); Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name, @@ -1534,8 +1554,8 @@ void Debugger::OnException(Handle<Object> exception, bool uncaught) { return; } - // Process debug event - ProcessDebugEvent(v8::Exception, event_data, false); + // Process debug event. + ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false); // Return to continue execution from where the exception was thrown. } @@ -1566,8 +1586,10 @@ void Debugger::OnDebugBreak(Handle<Object> break_points_hit, return; } - // Process debug event - ProcessDebugEvent(v8::Break, event_data, auto_continue); + // Process debug event. + ProcessDebugEvent(v8::Break, + Handle<JSObject>::cast(event_data), + auto_continue); } @@ -1591,8 +1613,10 @@ void Debugger::OnBeforeCompile(Handle<Script> script) { return; } - // Process debug event - ProcessDebugEvent(v8::BeforeCompile, event_data, false); + // Process debug event. + ProcessDebugEvent(v8::BeforeCompile, + Handle<JSObject>::cast(event_data), + true); } @@ -1652,8 +1676,10 @@ void Debugger::OnAfterCompile(Handle<Script> script, Handle<JSFunction> fun) { if (caught_exception) { return; } - // Process debug event - ProcessDebugEvent(v8::AfterCompile, event_data, false); + // Process debug event. + ProcessDebugEvent(v8::AfterCompile, + Handle<JSObject>::cast(event_data), + true); } @@ -1678,12 +1704,12 @@ void Debugger::OnNewFunction(Handle<JSFunction> function) { return; } // Process debug event. - ProcessDebugEvent(v8::NewFunction, event_data, false); + ProcessDebugEvent(v8::NewFunction, Handle<JSObject>::cast(event_data), true); } void Debugger::ProcessDebugEvent(v8::DebugEvent event, - Handle<Object> event_data, + Handle<JSObject> event_data, bool auto_continue) { HandleScope scope; @@ -1695,7 +1721,10 @@ void Debugger::ProcessDebugEvent(v8::DebugEvent event, } // First notify the message handler if any. if (message_handler_ != NULL) { - NotifyMessageHandler(event, exec_state, event_data, auto_continue); + NotifyMessageHandler(event, + Handle<JSObject>::cast(exec_state), + event_data, + auto_continue); } // Notify registered debug event listener. This can be either a C or a // JavaScript function. @@ -1703,11 +1732,11 @@ void Debugger::ProcessDebugEvent(v8::DebugEvent event, if (event_listener_->IsProxy()) { // C debug event listener. Handle<Proxy> callback_obj(Handle<Proxy>::cast(event_listener_)); - v8::DebugEventCallback callback = - FUNCTION_CAST<v8::DebugEventCallback>(callback_obj->proxy()); + v8::Debug::EventCallback callback = + FUNCTION_CAST<v8::Debug::EventCallback>(callback_obj->proxy()); callback(event, v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)), - v8::Utils::ToLocal(Handle<JSObject>::cast(event_data)), + v8::Utils::ToLocal(event_data), v8::Utils::ToLocal(Handle<Object>::cast(event_listener_data_))); } else { // JavaScript debug event listener. @@ -1718,7 +1747,7 @@ void Debugger::ProcessDebugEvent(v8::DebugEvent event, const int argc = 4; Object** argv[argc] = { Handle<Object>(Smi::FromInt(event)).location(), exec_state.location(), - event_data.location(), + Handle<Object>::cast(event_data).location(), event_listener_data_.location() }; Handle<Object> result = Execution::TryCall(fun, Top::global(), argc, argv, &caught_exception); @@ -1748,25 +1777,26 @@ void Debugger::UnloadDebugger() { void Debugger::NotifyMessageHandler(v8::DebugEvent event, - Handle<Object> exec_state, - Handle<Object> event_data, + Handle<JSObject> exec_state, + Handle<JSObject> event_data, bool auto_continue) { HandleScope scope; if (!Debug::Load()) return; // Process the individual events. - bool interactive = false; + bool sendEventMessage = false; switch (event) { case v8::Break: - interactive = true; // Break event is always interactive + sendEventMessage = !auto_continue; break; case v8::Exception: - interactive = true; // Exception event is always interactive + sendEventMessage = true; break; case v8::BeforeCompile: break; case v8::AfterCompile: + sendEventMessage = true; break; case v8::NewFunction: break; @@ -1774,8 +1804,25 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event, UNREACHABLE(); } - // Done if not interactive. - if (!interactive) return; + // The debug command interrupt flag might have been set when the command was + // added. It should be enough to clear the flag only once while we are in the + // debugger. + ASSERT(Debug::InDebugger()); + StackGuard::Continue(DEBUGCOMMAND); + + // Notify the debugger that a debug event has occurred unless auto continue is + // active in which case no event is send. + if (sendEventMessage) { + MessageImpl message = MessageImpl::NewEvent( + event, + auto_continue, + Handle<JSObject>::cast(exec_state), + Handle<JSObject>::cast(event_data)); + InvokeMessageHandler(message); + } + if (auto_continue && !HasCommands()) { + return; + } // Get the DebugCommandProcessor. v8::Local<v8::Object> api_exec_state = @@ -1792,45 +1839,30 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event, return; } - // Notify the debugger that a debug event has occurred unless auto continue is - // active in which case no event is send. - if (!auto_continue) { - bool success = SendEventMessage(event_data); - if (!success) { - // If failed to notify debugger just continue running. - return; - } - } - // Process requests from the debugger. while (true) { // Wait for new command in the queue. - command_received_->Wait(); - - // The debug command interrupt flag might have been set when the command was - // added. - StackGuard::Continue(DEBUGCOMMAND); + if (Debugger::host_dispatch_handler_) { + // In case there is a host dispatch - do periodic dispatches. + if (!command_received_->Wait(host_dispatch_micros_)) { + // Timout expired, do the dispatch. + Debugger::host_dispatch_handler_(); + continue; + } + } else { + // In case there is no host dispatch - just wait. + command_received_->Wait(); + } // Get the command from the queue. - Vector<uint16_t> command = command_queue_.Get(); + CommandMessage command = command_queue_.Get(); Logger::DebugTag("Got request from command queue, in interactive loop."); if (!Debugger::IsDebuggerActive()) { + // Delete command text and user data. + command.Dispose(); return; } - // Check if the command is a host dispatch. - if (command[0] == 0) { - if (Debugger::host_dispatch_handler_) { - int32_t dispatch = (command[1] << 16) | command[2]; - Debugger::host_dispatch_handler_(reinterpret_cast<void*>(dispatch), - Debugger::host_dispatch_handler_data_); - } - if (auto_continue && !HasCommands()) { - return; - } - continue; - } - // Invoke JavaScript to process the debug request. v8::Local<v8::String> fun_name; v8::Local<v8::Function> fun; @@ -1838,8 +1870,9 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event, v8::TryCatch try_catch; fun_name = v8::String::New("processDebugRequest"); fun = v8::Function::Cast(*cmd_processor->Get(fun_name)); - request = v8::String::New(reinterpret_cast<uint16_t*>(command.start()), - command.length()); + + request = v8::String::New(command.text().start(), + command.text().length()); static const int kArgc = 1; v8::Handle<Value> argv[kArgc] = { request }; v8::Local<v8::Value> response_val = fun->Call(cmd_processor, kArgc, argv); @@ -1875,13 +1908,16 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event, response = try_catch.Exception()->ToString(); } - // Convert text result to C string. - v8::String::Value val(response); - Vector<uint16_t> str(reinterpret_cast<uint16_t*>(*val), - response->Length()); - // Return the result. - SendMessage(str); + MessageImpl message = MessageImpl::NewResponse( + event, + running, + Handle<JSObject>::cast(exec_state), + Handle<JSObject>::cast(event_data), + Handle<String>(Utils::OpenHandle(*response)), + command.client_data()); + InvokeMessageHandler(message); + command.Dispose(); // Return from debug event processing if either the VM is put into the // runnning state (through a continue command) or auto continue is active @@ -1927,18 +1963,11 @@ void Debugger::SetEventListener(Handle<Object> callback, } -void Debugger::SetMessageHandler(v8::DebugMessageHandler handler, void* data, - bool message_handler_thread) { +void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) { ScopedLock with(debugger_access_); message_handler_ = handler; - message_handler_data_ = data; - if (handler != NULL) { - if (!message_thread_ && message_handler_thread) { - message_thread_ = new DebugMessageThread(); - message_thread_->Start(); - } - } else { + if (handler == NULL) { // Indicate that the message handler was recently cleared. message_handler_cleared_ = true; @@ -1951,87 +1980,37 @@ void Debugger::SetMessageHandler(v8::DebugMessageHandler handler, void* data, } -void Debugger::SetHostDispatchHandler(v8::DebugHostDispatchHandler handler, - void* data) { +void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler, + int period) { host_dispatch_handler_ = handler; - host_dispatch_handler_data_ = data; + host_dispatch_micros_ = period * 1000; } // Calls the registered debug message handler. This callback is part of the -// public API. Messages are kept internally as Vector<uint16_t> strings, which -// are allocated in various places and deallocated by the calling function -// sometime after this call. -void Debugger::InvokeMessageHandler(Vector<uint16_t> message) { +// public API. +void Debugger::InvokeMessageHandler(MessageImpl message) { ScopedLock with(debugger_access_); if (message_handler_ != NULL) { - message_handler_(message.start(), message.length(), message_handler_data_); - } -} - - -void Debugger::SendMessage(Vector<uint16_t> message) { - if (message_thread_ == NULL) { - // If there is no message thread just invoke the message handler from the - // V8 thread. - InvokeMessageHandler(message); - } else { - // Put a copy of the message coming from V8 on the queue. The new copy of - // the event string is destroyed by the message thread. - Vector<uint16_t> message_copy = message.Clone(); - Logger::DebugTag("Put message on event message_queue."); - message_queue_.Put(message_copy); - message_received_->Signal(); - } -} - - -bool Debugger::SendEventMessage(Handle<Object> event_data) { - v8::HandleScope scope; - // Call toJSONProtocol on the debug event object. - v8::Local<v8::Object> api_event_data = - v8::Utils::ToLocal(Handle<JSObject>::cast(event_data)); - v8::Local<v8::String> fun_name = v8::String::New("toJSONProtocol"); - v8::Local<v8::Function> fun = - v8::Function::Cast(*api_event_data->Get(fun_name)); - v8::TryCatch try_catch; - v8::Local<v8::Value> json_event = *fun->Call(api_event_data, 0, NULL); - v8::Local<v8::String> json_event_string; - if (!try_catch.HasCaught()) { - if (!json_event->IsUndefined()) { - json_event_string = json_event->ToString(); - if (FLAG_trace_debug_json) { - PrintLn(json_event_string); - } - v8::String::Value val(json_event_string); - Vector<uint16_t> str(reinterpret_cast<uint16_t*>(*val), - json_event_string->Length()); - SendMessage(str); - } else { - SendMessage(Vector<uint16_t>::empty()); - } - } else { - PrintLn(try_catch.Exception()); - return false; + message_handler_(message); } - return true; } // Puts a command coming from the public API on the queue. Creates // a copy of the command string managed by the debugger. Up to this // point, the command data was managed by the API client. Called -// by the API client thread. This is where the API client hands off -// processing of the command to the DebugMessageThread thread. -// The new copy of the command is destroyed in HandleCommand(). -void Debugger::ProcessCommand(Vector<const uint16_t> command) { - // Make a copy of the command. Need to cast away const for Clone to work. - Vector<uint16_t> command_copy = +// by the API client thread. +void Debugger::ProcessCommand(Vector<const uint16_t> command, + v8::Debug::ClientData* client_data) { + // Need to cast away const. + CommandMessage message = CommandMessage::New( Vector<uint16_t>(const_cast<uint16_t*>(command.start()), - command.length()).Clone(); + command.length()), + client_data); Logger::DebugTag("Put command on command_queue."); - command_queue_.Put(command_copy); + command_queue_.Put(message); command_received_->Signal(); // Set the debug command break flag to have the command processed. @@ -2046,23 +2025,6 @@ bool Debugger::HasCommands() { } -void Debugger::ProcessHostDispatch(void* dispatch) { - // Puts a host dispatch comming from the public API on the queue. - uint16_t hack[3]; - hack[0] = 0; - hack[1] = reinterpret_cast<uint32_t>(dispatch) >> 16; - hack[2] = reinterpret_cast<uint32_t>(dispatch) & 0xFFFF; - Logger::DebugTag("Put dispatch on command_queue."); - command_queue_.Put(Vector<uint16_t>(hack, 3).Clone()); - command_received_->Signal(); - - // Set the debug command break flag to have the host dispatch processed. - if (!Debug::InDebugger()) { - StackGuard::DebugCommand(); - } -} - - bool Debugger::IsDebuggerActive() { ScopedLock with(debugger_access_); @@ -2118,47 +2080,152 @@ void Debugger::StopAgent() { } -void Debugger::TearDown() { - if (message_thread_ != NULL) { - message_thread_->Stop(); - delete message_thread_; - message_thread_ = NULL; - } +MessageImpl MessageImpl::NewEvent(DebugEvent event, + bool running, + Handle<JSObject> exec_state, + Handle<JSObject> event_data) { + MessageImpl message(true, event, running, + exec_state, event_data, Handle<String>(), NULL); + return message; +} + + +MessageImpl MessageImpl::NewResponse(DebugEvent event, + bool running, + Handle<JSObject> exec_state, + Handle<JSObject> event_data, + Handle<String> response_json, + v8::Debug::ClientData* client_data) { + MessageImpl message(false, event, running, + exec_state, event_data, response_json, client_data); + return message; +} + + +MessageImpl::MessageImpl(bool is_event, + DebugEvent event, + bool running, + Handle<JSObject> exec_state, + Handle<JSObject> event_data, + Handle<String> response_json, + v8::Debug::ClientData* client_data) + : is_event_(is_event), + event_(event), + running_(running), + exec_state_(exec_state), + event_data_(event_data), + response_json_(response_json), + client_data_(client_data) {} + + +bool MessageImpl::IsEvent() const { + return is_event_; +} + + +bool MessageImpl::IsResponse() const { + return !is_event_; +} + + +DebugEvent MessageImpl::GetEvent() const { + return event_; +} + + +bool MessageImpl::WillStartRunning() const { + return running_; +} + + +v8::Handle<v8::Object> MessageImpl::GetExecutionState() const { + return v8::Utils::ToLocal(exec_state_); +} + + +v8::Handle<v8::Object> MessageImpl::GetEventData() const { + return v8::Utils::ToLocal(event_data_); } -void DebugMessageThread::Run() { - // Sends debug events to an installed debugger message callback. - while (keep_running_) { - // Wait and Get are paired so that semaphore count equals queue length. - Debugger::message_received_->Wait(); - Logger::DebugTag("Get message from event message_queue."); - Vector<uint16_t> message = Debugger::message_queue_.Get(); - if (message.length() > 0) { - Debugger::InvokeMessageHandler(message); +v8::Handle<v8::String> MessageImpl::GetJSON() const { + v8::HandleScope scope; + + if (IsEvent()) { + // Call toJSONProtocol on the debug event object. + Handle<Object> fun = GetProperty(event_data_, "toJSONProtocol"); + if (!fun->IsJSFunction()) { + return v8::Handle<v8::String>(); + } + bool caught_exception; + Handle<Object> json = Execution::TryCall(Handle<JSFunction>::cast(fun), + event_data_, + 0, NULL, &caught_exception); + if (caught_exception || !json->IsString()) { + return v8::Handle<v8::String>(); } + return scope.Close(v8::Utils::ToLocal(Handle<String>::cast(json))); + } else { + return v8::Utils::ToLocal(response_json_); } } -void DebugMessageThread::Stop() { - keep_running_ = false; - Debugger::SendMessage(Vector<uint16_t>(NULL, 0)); - Join(); +v8::Handle<v8::Context> MessageImpl::GetEventContext() const { + return v8::Utils::ToLocal(Debug::debugger_entry()->GetContext()); +} + + +v8::Debug::ClientData* MessageImpl::GetClientData() const { + return client_data_; } -MessageQueue::MessageQueue(int size) : start_(0), end_(0), size_(size) { - messages_ = NewArray<Vector<uint16_t> >(size); +CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()), + client_data_(NULL) { } -MessageQueue::~MessageQueue() { +CommandMessage::CommandMessage(const Vector<uint16_t>& text, + v8::Debug::ClientData* data) + : text_(text), + client_data_(data) { +} + + +CommandMessage::~CommandMessage() { +} + + +void CommandMessage::Dispose() { + text_.Dispose(); + delete client_data_; + client_data_ = NULL; +} + + +CommandMessage CommandMessage::New(const Vector<uint16_t>& command, + v8::Debug::ClientData* data) { + return CommandMessage(command.Clone(), data); +} + + +CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0), + size_(size) { + messages_ = NewArray<CommandMessage>(size); +} + + +CommandMessageQueue::~CommandMessageQueue() { + while (!IsEmpty()) { + CommandMessage m = Get(); + m.Dispose(); + } DeleteArray(messages_); } -Vector<uint16_t> MessageQueue::Get() { +CommandMessage CommandMessageQueue::Get() { ASSERT(!IsEmpty()); int result = start_; start_ = (start_ + 1) % size_; @@ -2166,7 +2233,7 @@ Vector<uint16_t> MessageQueue::Get() { } -void MessageQueue::Put(const Vector<uint16_t>& message) { +void CommandMessageQueue::Put(const CommandMessage& message) { if ((end_ + 1) % size_ == start_) { Expand(); } @@ -2175,53 +2242,57 @@ void MessageQueue::Put(const Vector<uint16_t>& message) { } -void MessageQueue::Expand() { - MessageQueue new_queue(size_ * 2); +void CommandMessageQueue::Expand() { + CommandMessageQueue new_queue(size_ * 2); while (!IsEmpty()) { new_queue.Put(Get()); } - Vector<uint16_t>* array_to_free = messages_; + CommandMessage* array_to_free = messages_; *this = new_queue; new_queue.messages_ = array_to_free; + // Make the new_queue empty so that it doesn't call Dispose on any messages. + new_queue.start_ = new_queue.end_; // Automatic destructor called on new_queue, freeing array_to_free. } -LockingMessageQueue::LockingMessageQueue(int size) : queue_(size) { +LockingCommandMessageQueue::LockingCommandMessageQueue(int size) + : queue_(size) { lock_ = OS::CreateMutex(); } -LockingMessageQueue::~LockingMessageQueue() { +LockingCommandMessageQueue::~LockingCommandMessageQueue() { delete lock_; } -bool LockingMessageQueue::IsEmpty() const { +bool LockingCommandMessageQueue::IsEmpty() const { ScopedLock sl(lock_); return queue_.IsEmpty(); } -Vector<uint16_t> LockingMessageQueue::Get() { +CommandMessage LockingCommandMessageQueue::Get() { ScopedLock sl(lock_); - Vector<uint16_t> result = queue_.Get(); - Logger::DebugEvent("Get", result); + CommandMessage result = queue_.Get(); + Logger::DebugEvent("Get", result.text()); return result; } -void LockingMessageQueue::Put(const Vector<uint16_t>& message) { +void LockingCommandMessageQueue::Put(const CommandMessage& message) { ScopedLock sl(lock_); queue_.Put(message); - Logger::DebugEvent("Put", message); + Logger::DebugEvent("Put", message.text()); } -void LockingMessageQueue::Clear() { +void LockingCommandMessageQueue::Clear() { ScopedLock sl(lock_); queue_.Clear(); } +#endif // ENABLE_DEBUGGER_SUPPORT } } // namespace v8::internal diff --git a/deps/v8/src/debug.h b/deps/v8/src/debug.h index 8822c5025..35336cb1d 100644 --- a/deps/v8/src/debug.h +++ b/deps/v8/src/debug.h @@ -25,10 +25,9 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef V8_V8_DEBUG_H_ -#define V8_V8_DEBUG_H_ +#ifndef V8_DEBUG_H_ +#define V8_DEBUG_H_ -#include "../include/v8-debug.h" #include "assembler.h" #include "code-stubs.h" #include "debug-agent.h" @@ -38,6 +37,8 @@ #include "string-stream.h" #include "v8threads.h" +#ifdef ENABLE_DEBUGGER_SUPPORT +#include "../include/v8-debug.h" namespace v8 { namespace internal { @@ -131,6 +132,10 @@ class BreakLocationIterator { private: void SetDebugBreak(); void ClearDebugBreak(); + + void SetDebugBreakAtIC(); + void ClearDebugBreakAtIC(); + bool IsDebugBreakAtReturn(); void SetDebugBreakAtReturn(); void ClearDebugBreakAtReturn(); @@ -204,7 +209,7 @@ class Debug { static bool IsBreakStub(Code* code); // Find the builtin to use for invoking the debug break - static Handle<Code> FindDebugBreak(RelocInfo* rinfo); + static Handle<Code> FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode); static Handle<Object> GetSourceBreakLocations( Handle<SharedFunctionInfo> shared); @@ -396,48 +401,117 @@ class Debug { }; -// A Queue of Vector<uint16_t> objects. A thread-safe version is -// LockingMessageQueue, based on this class. -class MessageQueue BASE_EMBEDDED { +// Message delivered to the message handler callback. This is either a debugger +// event or the response to a command. +class MessageImpl: public v8::Debug::Message { + public: + // Create a message object for a debug event. + static MessageImpl NewEvent(DebugEvent event, + bool running, + Handle<JSObject> exec_state, + Handle<JSObject> event_data); + + // Create a message object for the response to a debug command. + static MessageImpl NewResponse(DebugEvent event, + bool running, + Handle<JSObject> exec_state, + Handle<JSObject> event_data, + Handle<String> response_json, + v8::Debug::ClientData* client_data); + + // Implementation of interface v8::Debug::Message. + virtual bool IsEvent() const; + virtual bool IsResponse() const; + virtual DebugEvent GetEvent() const; + virtual bool WillStartRunning() const; + virtual v8::Handle<v8::Object> GetExecutionState() const; + virtual v8::Handle<v8::Object> GetEventData() const; + virtual v8::Handle<v8::String> GetJSON() const; + virtual v8::Handle<v8::Context> GetEventContext() const; + virtual v8::Debug::ClientData* GetClientData() const; + + private: + MessageImpl(bool is_event, + DebugEvent event, + bool running, + Handle<JSObject> exec_state, + Handle<JSObject> event_data, + Handle<String> response_json, + v8::Debug::ClientData* client_data); + + bool is_event_; // Does this message represent a debug event? + DebugEvent event_; // Debug event causing the break. + bool running_; // Will the VM start running after this event? + Handle<JSObject> exec_state_; // Current execution state. + Handle<JSObject> event_data_; // Data associated with the event. + Handle<String> response_json_; // Response JSON if message holds a response. + v8::Debug::ClientData* client_data_; // Client data passed with the request. +}; + + +// Message send by user to v8 debugger or debugger output message. +// In addition to command text it may contain a pointer to some user data +// which are expected to be passed along with the command reponse to message +// handler. +class CommandMessage { public: - explicit MessageQueue(int size); - ~MessageQueue(); + static CommandMessage New(const Vector<uint16_t>& command, + v8::Debug::ClientData* data); + CommandMessage(); + ~CommandMessage(); + + // Deletes user data and disposes of the text. + void Dispose(); + Vector<uint16_t> text() const { return text_; } + v8::Debug::ClientData* client_data() const { return client_data_; } + private: + CommandMessage(const Vector<uint16_t>& text, + v8::Debug::ClientData* data); + + Vector<uint16_t> text_; + v8::Debug::ClientData* client_data_; +}; + +// A Queue of CommandMessage objects. A thread-safe version is +// LockingCommandMessageQueue, based on this class. +class CommandMessageQueue BASE_EMBEDDED { + public: + explicit CommandMessageQueue(int size); + ~CommandMessageQueue(); bool IsEmpty() const { return start_ == end_; } - Vector<uint16_t> Get(); - void Put(const Vector<uint16_t>& message); + CommandMessage Get(); + void Put(const CommandMessage& message); void Clear() { start_ = end_ = 0; } // Queue is empty after Clear(). private: // Doubles the size of the message queue, and copies the messages. void Expand(); - Vector<uint16_t>* messages_; + CommandMessage* messages_; int start_; int end_; int size_; // The size of the queue buffer. Queue can hold size-1 messages. }; -// LockingMessageQueue is a thread-safe circular buffer of Vector<uint16_t> -// messages. The message data is not managed by LockingMessageQueue. +// LockingCommandMessageQueue is a thread-safe circular buffer of CommandMessage +// messages. The message data is not managed by LockingCommandMessageQueue. // Pointers to the data are passed in and out. Implemented by adding a -// Mutex to MessageQueue. Includes logging of all puts and gets. -class LockingMessageQueue BASE_EMBEDDED { +// Mutex to CommandMessageQueue. Includes logging of all puts and gets. +class LockingCommandMessageQueue BASE_EMBEDDED { public: - explicit LockingMessageQueue(int size); - ~LockingMessageQueue(); + explicit LockingCommandMessageQueue(int size); + ~LockingCommandMessageQueue(); bool IsEmpty() const; - Vector<uint16_t> Get(); - void Put(const Vector<uint16_t>& message); + CommandMessage Get(); + void Put(const CommandMessage& message); void Clear(); private: - MessageQueue queue_; + CommandMessageQueue queue_; Mutex* lock_; - DISALLOW_COPY_AND_ASSIGN(LockingMessageQueue); + DISALLOW_COPY_AND_ASSIGN(LockingCommandMessageQueue); }; -class DebugMessageThread; - class Debugger { public: static void DebugRequest(const uint16_t* json_request, int length); @@ -465,36 +539,27 @@ class Debugger { Handle<JSFunction> fun); static void OnNewFunction(Handle<JSFunction> fun); static void ProcessDebugEvent(v8::DebugEvent event, - Handle<Object> event_data, + Handle<JSObject> event_data, bool auto_continue); static void NotifyMessageHandler(v8::DebugEvent event, - Handle<Object> exec_state, - Handle<Object> event_data, + Handle<JSObject> exec_state, + Handle<JSObject> event_data, bool auto_continue); static void SetEventListener(Handle<Object> callback, Handle<Object> data); - static void SetMessageHandler(v8::DebugMessageHandler handler, void* data, - bool message_handler_thread); - static void TearDown(); - static void SetHostDispatchHandler(v8::DebugHostDispatchHandler handler, - void* data); + static void SetMessageHandler(v8::Debug::MessageHandler2 handler); + static void SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler, + int period); // Invoke the message handler function. - static void InvokeMessageHandler(Vector< uint16_t> message); - - // Send a message to the message handler eiher through the message thread or - // directly. - static void SendMessage(Vector<uint16_t> message); - - // Send the JSON message for a debug event. - static bool SendEventMessage(Handle<Object> event_data); + static void InvokeMessageHandler(MessageImpl message); // Add a debugger command to the command queue. - static void ProcessCommand(Vector<const uint16_t> command); + static void ProcessCommand(Vector<const uint16_t> command, + v8::Debug::ClientData* client_data = NULL); // Check whether there are commands in the command queue. static bool HasCommands(); - static void ProcessHostDispatch(void* dispatch); static Handle<Object> Call(Handle<JSFunction> fun, Handle<Object> data, bool* pending_exception); @@ -537,42 +602,18 @@ class Debugger { static bool compiling_natives_; // Are we compiling natives? static bool is_loading_debugger_; // Are we loading the debugger? static bool never_unload_debugger_; // Can we unload the debugger? - static DebugMessageThread* message_thread_; - static v8::DebugMessageHandler message_handler_; + static v8::Debug::MessageHandler2 message_handler_; static bool message_handler_cleared_; // Was message handler cleared? - static void* message_handler_data_; - static v8::DebugHostDispatchHandler host_dispatch_handler_; - static void* host_dispatch_handler_data_; + static v8::Debug::HostDispatchHandler host_dispatch_handler_; + static int host_dispatch_micros_; static DebuggerAgent* agent_; static const int kQueueInitialSize = 4; - static LockingMessageQueue command_queue_; - static LockingMessageQueue message_queue_; + static LockingCommandMessageQueue command_queue_; static Semaphore* command_received_; // Signaled for each command received. - static Semaphore* message_received_; // Signalled for each message send. friend class EnterDebugger; - friend class DebugMessageThread; -}; - - -// Thread to read messages from the message queue and invoke the debug message -// handler in another thread as the V8 thread. This thread is started if the -// registration of the debug message handler requested to be called in a thread -// seperate from the V8 thread. -class DebugMessageThread: public Thread { - public: - DebugMessageThread() : keep_running_(true) {} - virtual ~DebugMessageThread() {} - - // Main function of DebugMessageThread thread. - void Run(); - void Stop(); - - private: - bool keep_running_; - DISALLOW_COPY_AND_ASSIGN(DebugMessageThread); }; @@ -646,6 +687,9 @@ class EnterDebugger BASE_EMBEDDED { // Check whether there are any JavaScript frames on the stack. inline bool HasJavaScriptFrames() { return has_js_frames_; } + // Get the active context from before entering the debugger. + inline Handle<Context> GetContext() { return save_.context(); } + private: EnterDebugger* prev_; // Previous debugger entry if entered recursively. JavaScriptFrameIterator it_; @@ -719,4 +763,6 @@ class Debug_Address { } } // namespace v8::internal -#endif // V8_V8_DEBUG_H_ +#endif // ENABLE_DEBUGGER_SUPPORT + +#endif // V8_DEBUG_H_ diff --git a/deps/v8/src/execution.cc b/deps/v8/src/execution.cc index 03017d017..32dde9e4c 100644 --- a/deps/v8/src/execution.cc +++ b/deps/v8/src/execution.cc @@ -32,10 +32,12 @@ #include "api.h" #include "codegen-inl.h" -#ifdef ARM -#include "simulator-arm.h" -#else // ia32 -#include "simulator-ia32.h" +#if V8_TARGET_ARCH_IA32 +#include "ia32/simulator-ia32.h" +#elif V8_TARGET_ARCH_X64 +#include "x64/simulator-x64.h" +#elif V8_TARGET_ARCH_ARM +#include "arm/simulator-arm.h" #endif #include "debug.h" @@ -305,6 +307,7 @@ void StackGuard::Preempt() { } +#ifdef ENABLE_DEBUGGER_SUPPORT bool StackGuard::IsDebugBreak() { ExecutionAccess access; return thread_local_.interrupt_flags_ & DEBUGBREAK; @@ -331,7 +334,7 @@ void StackGuard::DebugCommand() { set_limits(kInterruptLimit, access); } } - +#endif void StackGuard::Continue(InterruptFlag after_what) { ExecutionAccess access; @@ -539,6 +542,7 @@ static Object* RuntimePreempt() { ContextSwitcher::PreemptionReceived(); +#ifdef ENABLE_DEBUGGER_SUPPORT if (Debug::InDebugger()) { // If currently in the debugger don't do any actual preemption but record // that preemption occoured while in the debugger. @@ -548,11 +552,17 @@ static Object* RuntimePreempt() { v8::Unlocker unlocker; Thread::YieldCPU(); } +#else + // Perform preemption. + v8::Unlocker unlocker; + Thread::YieldCPU(); +#endif return Heap::undefined_value(); } +#ifdef ENABLE_DEBUGGER_SUPPORT Object* Execution::DebugBreakHelper() { // Just continue if breaks are disabled. if (Debug::disable_break()) { @@ -598,12 +608,14 @@ Object* Execution::DebugBreakHelper() { // Return to continue execution. return Heap::undefined_value(); } - +#endif Object* Execution::HandleStackGuardInterrupt() { +#ifdef ENABLE_DEBUGGER_SUPPORT if (StackGuard::IsDebugBreak() || StackGuard::IsDebugCommand()) { DebugBreakHelper(); } +#endif if (StackGuard::IsPreempted()) RuntimePreempt(); if (StackGuard::IsInterrupted()) { // interrupt @@ -626,7 +638,7 @@ v8::Handle<v8::FunctionTemplate> GCExtension::GetNativeFunction( v8::Handle<v8::Value> GCExtension::GC(const v8::Arguments& args) { // All allocation spaces other than NEW_SPACE have the same effect. - Heap::CollectGarbage(0, OLD_DATA_SPACE); + Heap::CollectAllGarbage(); return v8::Undefined(); } diff --git a/deps/v8/src/execution.h b/deps/v8/src/execution.h index 6531572e4..6f2f68922 100644 --- a/deps/v8/src/execution.h +++ b/deps/v8/src/execution.h @@ -118,8 +118,9 @@ class Execution : public AllStatic { Handle<JSFunction> fun, Handle<Object> pos, Handle<Object> is_global); - +#ifdef ENABLE_DEBUGGER_SUPPORT static Object* DebugBreakHelper(); +#endif // If the stack guard is triggered, but it is not an actual // stack overflow, then handle the interruption accordingly. @@ -158,11 +159,13 @@ class StackGuard BASE_EMBEDDED { static void Preempt(); static bool IsInterrupted(); static void Interrupt(); - static bool IsDebugBreak(); + static void Continue(InterruptFlag after_what); +#ifdef ENABLE_DEBUGGER_SUPPORT static void DebugBreak(); - static bool IsDebugCommand(); static void DebugCommand(); - static void Continue(InterruptFlag after_what); + static bool IsDebugBreak(); + static bool IsDebugCommand(); +#endif private: // You should hold the ExecutionAccess lock when calling this method. diff --git a/deps/v8/src/factory.cc b/deps/v8/src/factory.cc index e29c84d2b..4b0b7f51f 100644 --- a/deps/v8/src/factory.cc +++ b/deps/v8/src/factory.cc @@ -167,14 +167,17 @@ Handle<Script> Factory::NewScript(Handle<String> source) { Heap::SetLastScriptId(Smi::FromInt(id)); // Create and initialize script object. + Handle<Proxy> wrapper = Factory::NewProxy(0, TENURED); Handle<Script> script = Handle<Script>::cast(NewStruct(SCRIPT_TYPE)); script->set_source(*source); script->set_name(Heap::undefined_value()); script->set_id(Heap::last_script_id()); script->set_line_offset(Smi::FromInt(0)); script->set_column_offset(Smi::FromInt(0)); + script->set_data(Heap::undefined_value()); + script->set_context_data(Heap::undefined_value()); script->set_type(Smi::FromInt(SCRIPT_TYPE_NORMAL)); - script->set_wrapper(*Factory::NewProxy(0, TENURED)); + script->set_wrapper(*wrapper); script->set_line_ends(Heap::undefined_value()); return script; @@ -207,14 +210,14 @@ Handle<JSObject> Factory::NewFunctionPrototype(Handle<JSFunction> function) { } -Handle<Map> Factory::CopyMap(Handle<Map> src) { - CALL_HEAP_FUNCTION(src->Copy(), Map); +Handle<Map> Factory::CopyMapDropDescriptors(Handle<Map> src) { + CALL_HEAP_FUNCTION(src->CopyDropDescriptors(), Map); } Handle<Map> Factory::CopyMap(Handle<Map> src, int extra_inobject_properties) { - Handle<Map> copy = CopyMap(src); + Handle<Map> copy = CopyMapDropDescriptors(src); // Check that we do not overflow the instance size when adding the // extra inobject properties. int instance_size_delta = extra_inobject_properties * kPointerSize; @@ -671,6 +674,7 @@ Handle<Object> Factory::ToObject(Handle<Object> object, } +#ifdef ENABLE_DEBUGGER_SUPPORT Handle<DebugInfo> Factory::NewDebugInfo(Handle<SharedFunctionInfo> shared) { // Get the original code of the function. Handle<Code> code(shared->code()); @@ -700,6 +704,7 @@ Handle<DebugInfo> Factory::NewDebugInfo(Handle<SharedFunctionInfo> shared) { return debug_info; } +#endif Handle<JSObject> Factory::NewArgumentsObject(Handle<Object> callee, diff --git a/deps/v8/src/factory.h b/deps/v8/src/factory.h index 2564c3c54..6ac2706ec 100644 --- a/deps/v8/src/factory.h +++ b/deps/v8/src/factory.h @@ -153,7 +153,7 @@ class Factory : public AllStatic { static Handle<JSObject> NewFunctionPrototype(Handle<JSFunction> function); - static Handle<Map> CopyMap(Handle<Map> map); + static Handle<Map> CopyMapDropDescriptors(Handle<Map> map); // Copy the map adding more inobject properties if possible without // overflowing the instance size. @@ -310,8 +310,9 @@ class Factory : public AllStatic { uint32_t key, Handle<Object> value); +#ifdef ENABLE_DEBUGGER_SUPPORT static Handle<DebugInfo> NewDebugInfo(Handle<SharedFunctionInfo> shared); - +#endif // Return a map using the map cache in the global context. // The key the an ordered set of property names. diff --git a/deps/v8/src/frames-inl.h b/deps/v8/src/frames-inl.h index cb03e2fd7..bf46f6bf7 100644 --- a/deps/v8/src/frames-inl.h +++ b/deps/v8/src/frames-inl.h @@ -29,12 +29,14 @@ #define V8_FRAMES_INL_H_ #include "frames.h" -#ifdef ARM -#include "frames-arm.h" -#else -#include "frames-ia32.h" -#endif +#if V8_TARGET_ARCH_IA32 +#include "ia32/frames-ia32.h" +#elif V8_TARGET_ARCH_X64 +#include "x64/frames-x64.h" +#elif V8_TARGET_ARCH_ARM +#include "arm/frames-arm.h" +#endif namespace v8 { namespace internal { diff --git a/deps/v8/src/frames.cc b/deps/v8/src/frames.cc index 88c723d69..1eedbf640 100644 --- a/deps/v8/src/frames.cc +++ b/deps/v8/src/frames.cc @@ -647,10 +647,10 @@ void EntryFrame::Iterate(ObjectVisitor* v) const { handler->Iterate(v); // Make sure that there's the entry frame does not contain more than // one stack handler. - if (kDebug) { - it.Advance(); - ASSERT(it.done()); - } +#ifdef DEBUG + it.Advance(); + ASSERT(it.done()); +#endif } diff --git a/deps/v8/src/func-name-inferrer.cc b/deps/v8/src/func-name-inferrer.cc index ef0c7dbb4..75f7a9937 100644 --- a/deps/v8/src/func-name-inferrer.cc +++ b/deps/v8/src/func-name-inferrer.cc @@ -63,11 +63,12 @@ Handle<String> FuncNameInferrer::MakeNameFromStackHelper(int pos, } -void FuncNameInferrer::MaybeInferFunctionName() { - if (func_to_infer_ != NULL) { - func_to_infer_->set_inferred_name(MakeNameFromStack()); - func_to_infer_ = NULL; +void FuncNameInferrer::InferFunctionsNames() { + Handle<String> func_name = MakeNameFromStack(); + for (int i = 0; i < funcs_to_infer_.length(); ++i) { + funcs_to_infer_[i]->set_inferred_name(func_name); } + funcs_to_infer_.Rewind(0); } diff --git a/deps/v8/src/func-name-inferrer.h b/deps/v8/src/func-name-inferrer.h index 9dcf7c59f..d8270c364 100644 --- a/deps/v8/src/func-name-inferrer.h +++ b/deps/v8/src/func-name-inferrer.h @@ -45,7 +45,7 @@ class FuncNameInferrer BASE_EMBEDDED { FuncNameInferrer() : entries_stack_(10), names_stack_(5), - func_to_infer_(NULL), + funcs_to_infer_(4), dot_(Factory::NewStringFromAscii(CStrVector("."))) { } @@ -57,39 +57,34 @@ class FuncNameInferrer BASE_EMBEDDED { entries_stack_.Add(names_stack_.length()); } - void Leave() { - ASSERT(IsOpen()); - names_stack_.Rewind(entries_stack_.RemoveLast()); - } - void PushName(Handle<String> name) { if (IsOpen()) { names_stack_.Add(name); } } - void SetFuncToInfer(FunctionLiteral* func_to_infer) { + void AddFunction(FunctionLiteral* func_to_infer) { if (IsOpen()) { - // If we encounter another function literal after already having - // encountered one, the second one replaces the first. - func_to_infer_ = func_to_infer; + funcs_to_infer_.Add(func_to_infer); } } void InferAndLeave() { ASSERT(IsOpen()); - MaybeInferFunctionName(); - Leave(); + if (!funcs_to_infer_.is_empty()) { + InferFunctionsNames(); + } + names_stack_.Rewind(entries_stack_.RemoveLast()); } private: Handle<String> MakeNameFromStack(); Handle<String> MakeNameFromStackHelper(int pos, Handle<String> prev); - void MaybeInferFunctionName(); + void InferFunctionsNames(); List<int> entries_stack_; List<Handle<String> > names_stack_; - FunctionLiteral* func_to_infer_; + List<FunctionLiteral*> funcs_to_infer_; Handle<String> dot_; DISALLOW_COPY_AND_ASSIGN(FuncNameInferrer); diff --git a/deps/v8/src/global-handles.cc b/deps/v8/src/global-handles.cc index c2194fc89..46b7db322 100644 --- a/deps/v8/src/global-handles.cc +++ b/deps/v8/src/global-handles.cc @@ -258,7 +258,7 @@ void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) { } -void GlobalHandles::MarkWeakRoots(WeakSlotCallback f) { +void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) { for (Node* current = head_; current != NULL; current = current->next()) { if (current->state_ == Node::WEAK) { if (f(¤t->object_)) { diff --git a/deps/v8/src/global-handles.h b/deps/v8/src/global-handles.h index c5f44503b..e6e9de1d1 100644 --- a/deps/v8/src/global-handles.h +++ b/deps/v8/src/global-handles.h @@ -98,8 +98,9 @@ class GlobalHandles : public AllStatic { // Iterates over all weak roots in heap. static void IterateWeakRoots(ObjectVisitor* v); - // Mark the weak pointers based on the callback. - static void MarkWeakRoots(WeakSlotCallback f); + // Find all weak handles satisfying the callback predicate, mark + // them as pending. + static void IdentifyWeakHandles(WeakSlotCallback f); // Add an object group. // Should only used in GC callback function before a collection. diff --git a/deps/v8/src/globals.h b/deps/v8/src/globals.h index 1579c3dfd..a0b5ac363 100644 --- a/deps/v8/src/globals.h +++ b/deps/v8/src/globals.h @@ -28,27 +28,27 @@ #ifndef V8_GLOBALS_H_ #define V8_GLOBALS_H_ -// ----------------------------------------------------------------------------- -// Types -// Visual Studio C++ is missing the stdint.h header file. Instead we define -// standard integer types for Windows here. - -#ifdef _MSC_VER -typedef signed char int8_t; -typedef unsigned char uint8_t; -typedef short int16_t; // NOLINT -typedef unsigned short uint16_t; // NOLINT -typedef int int32_t; -typedef unsigned int uint32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else // _MSC_VER -#include <stdint.h> // for intptr_t -#endif // _MSC_VER - - namespace v8 { namespace internal { +// Processor architecture detection. For more info on what's defined, see: +// http://msdn.microsoft.com/en-us/library/b0084kay.aspx +// http://www.agner.org/optimize/calling_conventions.pdf +// or with gcc, run: "echo | gcc -E -dM -" +#if defined(_M_X64) || defined(__x86_64__) +#define V8_HOST_ARCH_X64 1 +#define V8_HOST_ARCH_64_BIT 1 +#define V8_HOST_CAN_READ_UNALIGNED 1 +#elif defined(_M_IX86) || defined(__i386__) +#define V8_HOST_ARCH_IA32 1 +#define V8_HOST_ARCH_32_BIT 1 +#define V8_HOST_CAN_READ_UNALIGNED 1 +#elif defined(__ARMEL__) +#define V8_HOST_ARCH_ARM 1 +#define V8_HOST_ARCH_32_BIT 1 +#else +#error Your architecture was not detected as supported by v8 +#endif + // Support for alternative bool type. This is only enabled if the code is // compiled with USE_MYBOOL defined. This catches some nasty type bugs. // For instance, 'bool b = "false";' results in b == true! This is a hidden @@ -69,58 +69,73 @@ typedef unsigned int __my_bool__; typedef uint8_t byte; typedef byte* Address; +// Define our own macros for writing 64-bit constants. This is less fragile +// than defining __STDC_CONSTANT_MACROS before including <stdint.h>, and it +// works on compilers that don't have it (like MSVC). +#if V8_HOST_ARCH_64_BIT +#ifdef _MSC_VER +#define V8_UINT64_C(x) (x ## UI64) +#define V8_INT64_C(x) (x ## I64) +#define V8_PTR_PREFIX "ll" +#else +#define V8_UINT64_C(x) (x ## UL) +#define V8_INT64_C(x) (x ## L) +#define V8_PTR_PREFIX "l" +#endif +#else // V8_HOST_ARCH_64_BIT +#define V8_PTR_PREFIX "" +#endif + +#define V8PRIp V8_PTR_PREFIX "x" + // Code-point values in Unicode 4.0 are 21 bits wide. typedef uint16_t uc16; -typedef signed int uc32; - -#ifndef ARM -#define CAN_READ_UNALIGNED 1 -#endif +typedef int32_t uc32; // ----------------------------------------------------------------------------- // Constants -#ifdef DEBUG -const bool kDebug = true; -#else -const bool kDebug = false; -#endif // DEBUG - const int KB = 1024; const int MB = KB * KB; const int GB = KB * KB * KB; const int kMaxInt = 0x7FFFFFFF; const int kMinInt = -kMaxInt - 1; +const uint32_t kMaxUInt32 = 0xFFFFFFFFu; + const int kCharSize = sizeof(char); // NOLINT const int kShortSize = sizeof(short); // NOLINT const int kIntSize = sizeof(int); // NOLINT const int kDoubleSize = sizeof(double); // NOLINT const int kPointerSize = sizeof(void*); // NOLINT +#if V8_HOST_ARCH_64_BIT +const int kPointerSizeLog2 = 3; +#else const int kPointerSizeLog2 = 2; +#endif -const int kObjectAlignmentBits = 2; -const int kObjectAlignmentMask = (1 << kObjectAlignmentBits) - 1; -const int kObjectAlignment = 1 << kObjectAlignmentBits; +const int kObjectAlignmentBits = kPointerSizeLog2; +const intptr_t kObjectAlignmentMask = (1 << kObjectAlignmentBits) - 1; +const intptr_t kObjectAlignment = 1 << kObjectAlignmentBits; // Tag information for HeapObject. const int kHeapObjectTag = 1; const int kHeapObjectTagSize = 2; -const int kHeapObjectTagMask = (1 << kHeapObjectTagSize) - 1; +const intptr_t kHeapObjectTagMask = (1 << kHeapObjectTagSize) - 1; // Tag information for Smi. const int kSmiTag = 0; const int kSmiTagSize = 1; -const int kSmiTagMask = (1 << kSmiTagSize) - 1; +const intptr_t kSmiTagMask = (1 << kSmiTagSize) - 1; // Tag information for Failure. const int kFailureTag = 3; const int kFailureTagSize = 2; -const int kFailureTagMask = (1 << kFailureTagSize) - 1; +const intptr_t kFailureTagMask = (1 << kFailureTagSize) - 1; const int kBitsPerByte = 8; @@ -129,11 +144,21 @@ const int kBitsPerPointer = kPointerSize * kBitsPerByte; const int kBitsPerInt = kIntSize * kBitsPerByte; -// Zap-value: The value used for zapping dead objects. Should be a recognizable -// illegal heap object pointer. +// Zap-value: The value used for zapping dead objects. +// Should be a recognizable hex value tagged as a heap object pointer. +#ifdef V8_HOST_ARCH_64_BIT +const Address kZapValue = + reinterpret_cast<Address>(V8_UINT64_C(0xdeadbeedbeadbeed)); +const Address kHandleZapValue = + reinterpret_cast<Address>(V8_UINT64_C(0x1baddead0baddead)); +const Address kFromSpaceZapValue = + reinterpret_cast<Address>(V8_UINT64_C(0x1beefdad0beefdad)); +#else const Address kZapValue = reinterpret_cast<Address>(0xdeadbeed); const Address kHandleZapValue = reinterpret_cast<Address>(0xbaddead); const Address kFromSpaceZapValue = reinterpret_cast<Address>(0xbeefdad); +#endif + // ----------------------------------------------------------------------------- // Forward declarations for frequently used classes @@ -146,7 +171,6 @@ class Assembler; class BreakableStatement; class Code; class CodeGenerator; -class CodeRegion; class CodeStub; class Context; class Debug; @@ -377,13 +401,13 @@ enum StateTag { // Testers for test. #define HAS_SMI_TAG(value) \ - ((reinterpret_cast<int>(value) & kSmiTagMask) == kSmiTag) + ((reinterpret_cast<intptr_t>(value) & kSmiTagMask) == kSmiTag) #define HAS_FAILURE_TAG(value) \ - ((reinterpret_cast<int>(value) & kFailureTagMask) == kFailureTag) + ((reinterpret_cast<intptr_t>(value) & kFailureTagMask) == kFailureTag) #define HAS_HEAP_OBJECT_TAG(value) \ - ((reinterpret_cast<int>(value) & kHeapObjectTagMask) == kHeapObjectTag) + ((reinterpret_cast<intptr_t>(value) & kHeapObjectTagMask) == kHeapObjectTag) // OBJECT_SIZE_ALIGN returns the value aligned HeapObject size #define OBJECT_SIZE_ALIGN(value) \ @@ -492,7 +516,7 @@ F FUNCTION_CAST(Address addr) { // exception'. // // Bit_cast uses the memcpy exception to move the bits from a variable of one -// type o a variable of another type. Of course the end result is likely to +// type of a variable of another type. Of course the end result is likely to // be implementation dependent. Most compilers (gcc-4.2 and MSVC 2005) // will completely optimize bit_cast away. // diff --git a/deps/v8/src/handles.cc b/deps/v8/src/handles.cc index 60d82362f..773483d60 100644 --- a/deps/v8/src/handles.cc +++ b/deps/v8/src/handles.cc @@ -212,10 +212,20 @@ Handle<Object> SetProperty(Handle<Object> object, } -Handle<Object> IgnoreAttributesAndSetLocalProperty(Handle<JSObject> object, - Handle<String> key, - Handle<Object> value, - PropertyAttributes attributes) { +Handle<Object> ForceSetProperty(Handle<JSObject> object, + Handle<Object> key, + Handle<Object> value, + PropertyAttributes attributes) { + CALL_HEAP_FUNCTION( + Runtime::ForceSetObjectProperty(object, key, value, attributes), Object); +} + + +Handle<Object> IgnoreAttributesAndSetLocalProperty( + Handle<JSObject> object, + Handle<String> key, + Handle<Object> value, + PropertyAttributes attributes) { CALL_HEAP_FUNCTION(object-> IgnoreAttributesAndSetLocalProperty(*key, *value, attributes), Object); } @@ -491,17 +501,6 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object) { break; } - // Compute the property keys. - content = UnionOfKeys(content, GetEnumPropertyKeys(current)); - - // Add the property keys from the interceptor. - if (current->HasNamedInterceptor()) { - v8::Handle<v8::Array> result = - GetKeysForNamedInterceptor(object, current); - if (!result.IsEmpty()) - content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); - } - // Compute the element keys. Handle<FixedArray> element_keys = Factory::NewFixedArray(current->NumberOfEnumElements()); @@ -515,6 +514,17 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object) { if (!result.IsEmpty()) content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); } + + // Compute the property keys. + content = UnionOfKeys(content, GetEnumPropertyKeys(current)); + + // Add the property keys from the interceptor. + if (current->HasNamedInterceptor()) { + v8::Handle<v8::Array> result = + GetKeysForNamedInterceptor(object, current); + if (!result.IsEmpty()) + content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); + } } } return content; @@ -549,7 +559,7 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object) { index++; } } - (*storage)->SortPairs(*sort_array); + (*storage)->SortPairs(*sort_array, sort_array->length()); Handle<FixedArray> bridge_storage = Factory::NewFixedArray(DescriptorArray::kEnumCacheBridgeLength); DescriptorArray* desc = object->map()->instance_descriptors(); @@ -617,9 +627,9 @@ OptimizedObjectForAddingMultipleProperties:: } -void LoadLazy(Handle<JSFunction> fun, bool* pending_exception) { +void LoadLazy(Handle<JSObject> obj, bool* pending_exception) { HandleScope scope; - Handle<FixedArray> info(FixedArray::cast(fun->shared()->lazy_load_data())); + Handle<FixedArray> info(FixedArray::cast(obj->map()->constructor())); int index = Smi::cast(info->get(0))->value(); ASSERT(index >= 0); Handle<Context> compile_context(Context::cast(info->get(1))); @@ -651,6 +661,7 @@ void LoadLazy(Handle<JSFunction> fun, bool* pending_exception) { // We shouldn't get here if compiling the script failed. ASSERT(!boilerplate.is_null()); +#ifdef ENABLE_DEBUGGER_SUPPORT // When the debugger running in its own context touches lazy loaded // functions loading can be triggered. In that case ensure that the // execution of the boilerplate is in the correct context. @@ -659,30 +670,43 @@ void LoadLazy(Handle<JSFunction> fun, bool* pending_exception) { Top::context() == *Debug::debug_context()) { Top::set_context(*compile_context); } +#endif // Reset the lazy load data before running the script to make sure // not to get recursive lazy loading. - fun->shared()->set_lazy_load_data(Heap::undefined_value()); + obj->map()->set_needs_loading(false); + obj->map()->set_constructor(info->get(3)); // Run the script. Handle<JSFunction> script_fun( Factory::NewFunctionFromBoilerplate(boilerplate, function_context)); Execution::Call(script_fun, receiver, 0, NULL, pending_exception); - // If lazy loading failed, restore the unloaded state of fun. - if (*pending_exception) fun->shared()->set_lazy_load_data(*info); + // If lazy loading failed, restore the unloaded state of obj. + if (*pending_exception) { + obj->map()->set_needs_loading(true); + obj->map()->set_constructor(*info); + } } -void SetupLazy(Handle<JSFunction> fun, +void SetupLazy(Handle<JSObject> obj, int index, Handle<Context> compile_context, Handle<Context> function_context) { - Handle<FixedArray> arr = Factory::NewFixedArray(3); + Handle<FixedArray> arr = Factory::NewFixedArray(4); arr->set(0, Smi::FromInt(index)); arr->set(1, *compile_context); // Compile in this context arr->set(2, *function_context); // Set function context to this - fun->shared()->set_lazy_load_data(*arr); + arr->set(3, obj->map()->constructor()); // Remember the constructor + Handle<Map> old_map(obj->map()); + Handle<Map> new_map = Factory::CopyMapDropTransitions(old_map); + obj->set_map(*new_map); + new_map->set_needs_loading(true); + // Store the lazy loading info in the constructor field. We'll + // reestablish the constructor from the fixed array after loading. + new_map->set_constructor(*arr); + ASSERT(!obj->IsLoaded()); } } } // namespace v8::internal diff --git a/deps/v8/src/handles.h b/deps/v8/src/handles.h index c8e534eec..652d6c70e 100644 --- a/deps/v8/src/handles.h +++ b/deps/v8/src/handles.h @@ -196,6 +196,11 @@ Handle<Object> SetProperty(Handle<Object> object, Handle<Object> value, PropertyAttributes attributes); +Handle<Object> ForceSetProperty(Handle<JSObject> object, + Handle<Object> key, + Handle<Object> value, + PropertyAttributes attributes); + Handle<Object> IgnoreAttributesAndSetLocalProperty(Handle<JSObject> object, Handle<String> key, Handle<Object> value, @@ -296,11 +301,11 @@ bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag); bool CompileLazyInLoop(Handle<JSFunction> function, ClearExceptionFlag flag); // These deal with lazily loaded properties. -void SetupLazy(Handle<JSFunction> fun, +void SetupLazy(Handle<JSObject> obj, int index, Handle<Context> compile_context, Handle<Context> function_context); -void LoadLazy(Handle<JSFunction> fun, bool* pending_exception); +void LoadLazy(Handle<JSObject> obj, bool* pending_exception); class NoHandleAllocation BASE_EMBEDDED { public: diff --git a/deps/v8/src/heap-inl.h b/deps/v8/src/heap-inl.h index 6090dd48c..86165ee1b 100644 --- a/deps/v8/src/heap-inl.h +++ b/deps/v8/src/heap-inl.h @@ -251,11 +251,11 @@ void Heap::SetLastScriptId(Object* last_script_id) { __object__ = FUNCTION_CALL; \ } \ if (!__object__->IsFailure()) RETURN_VALUE; \ - if (__object__->IsOutOfMemoryFailure()) { \ + if (__object__->IsOutOfMemoryFailure() || \ + __object__->IsRetryAfterGC()) { \ /* TODO(1181417): Fix this. */ \ v8::internal::V8::FatalProcessOutOfMemory("CALL_AND_RETRY_2"); \ } \ - ASSERT(!__object__->IsRetryAfterGC()); \ RETURN_EMPTY; \ } while (false) diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index 7a8b7288d..6d600152e 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -538,7 +538,7 @@ class ScavengeVisitor: public ObjectVisitor { // Shared state read by the scavenge collector and set by ScavengeObject. -static Address promoted_top = NULL; +static Address promoted_rear = NULL; #ifdef DEBUG @@ -554,24 +554,34 @@ class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor { } } }; -#endif -void Heap::Scavenge() { -#ifdef DEBUG - if (FLAG_enable_slow_asserts) { - VerifyNonPointerSpacePointersVisitor v; - HeapObjectIterator it(code_space_); - while (it.has_next()) { - HeapObject* object = it.next(); - if (object->IsCode()) { - Code::cast(object)->ConvertICTargetsFromAddressToObject(); - } + +static void VerifyNonPointerSpacePointers() { + // Verify that there are no pointers to new space in spaces where we + // do not expect them. + VerifyNonPointerSpacePointersVisitor v; + HeapObjectIterator code_it(Heap::code_space()); + while (code_it.has_next()) { + HeapObject* object = code_it.next(); + if (object->IsCode()) { + Code::cast(object)->ConvertICTargetsFromAddressToObject(); + object->Iterate(&v); + Code::cast(object)->ConvertICTargetsFromObjectToAddress(); + } else { + // If we find non-code objects in code space (e.g., free list + // nodes) we want to verify them as well. object->Iterate(&v); - if (object->IsCode()) { - Code::cast(object)->ConvertICTargetsFromObjectToAddress(); - } } } + + HeapObjectIterator data_it(Heap::old_data_space()); + while (data_it.has_next()) data_it.next()->Iterate(&v); +} +#endif + +void Heap::Scavenge() { +#ifdef DEBUG + if (FLAG_enable_slow_asserts) VerifyNonPointerSpacePointers(); #endif gc_state_ = SCAVENGE; @@ -596,72 +606,70 @@ void Heap::Scavenge() { new_space_.Flip(); new_space_.ResetAllocationInfo(); - // We need to sweep newly copied objects which can be in either the to space - // or the old space. For to space objects, we use a mark. Newly copied - // objects lie between the mark and the allocation top. For objects - // promoted to old space, we write their addresses downward from the top of - // the new space. Sweeping newly promoted objects requires an allocation - // pointer and a mark. Note that the allocation pointer 'top' actually - // moves downward from the high address in the to space. + // We need to sweep newly copied objects which can be either in the + // to space or promoted to the old generation. For to-space + // objects, we treat the bottom of the to space as a queue. Newly + // copied and unswept objects lie between a 'front' mark and the + // allocation pointer. + // + // Promoted objects can go into various old-generation spaces, and + // can be allocated internally in the spaces (from the free list). + // We treat the top of the to space as a queue of addresses of + // promoted objects. The addresses of newly promoted and unswept + // objects lie between a 'front' mark and a 'rear' mark that is + // updated as a side effect of promoting an object. // - // There is guaranteed to be enough room at the top of the to space for the - // addresses of promoted objects: every object promoted frees up its size in - // bytes from the top of the new space, and objects are at least one pointer - // in size. Using the new space to record promoted addresses makes the - // scavenge collector agnostic to the allocation strategy (eg, linear or - // free-list) used in old space. - Address new_mark = new_space_.ToSpaceLow(); - Address promoted_mark = new_space_.ToSpaceHigh(); - promoted_top = new_space_.ToSpaceHigh(); + // There is guaranteed to be enough room at the top of the to space + // for the addresses of promoted objects: every object promoted + // frees up its size in bytes from the top of the new space, and + // objects are at least one pointer in size. + Address new_space_front = new_space_.ToSpaceLow(); + Address promoted_front = new_space_.ToSpaceHigh(); + promoted_rear = new_space_.ToSpaceHigh(); ScavengeVisitor scavenge_visitor; // Copy roots. IterateRoots(&scavenge_visitor); - // Copy objects reachable from the old generation. By definition, there - // are no intergenerational pointers in code or data spaces. + // Copy objects reachable from weak pointers. + GlobalHandles::IterateWeakRoots(&scavenge_visitor); + + // Copy objects reachable from the old generation. By definition, + // there are no intergenerational pointers in code or data spaces. IterateRSet(old_pointer_space_, &ScavengePointer); IterateRSet(map_space_, &ScavengePointer); lo_space_->IterateRSet(&ScavengePointer); - bool has_processed_weak_pointers = false; - - while (true) { - ASSERT(new_mark <= new_space_.top()); - ASSERT(promoted_mark >= promoted_top); + do { + ASSERT(new_space_front <= new_space_.top()); + ASSERT(promoted_front >= promoted_rear); + + // The addresses new_space_front and new_space_.top() define a + // queue of unprocessed copied objects. Process them until the + // queue is empty. + while (new_space_front < new_space_.top()) { + HeapObject* object = HeapObject::FromAddress(new_space_front); + object->Iterate(&scavenge_visitor); + new_space_front += object->Size(); + } - // Copy objects reachable from newly copied objects. - while (new_mark < new_space_.top() || promoted_mark > promoted_top) { - // Sweep newly copied objects in the to space. The allocation pointer - // can change during sweeping. - Address previous_top = new_space_.top(); - SemiSpaceIterator new_it(new_space(), new_mark); - while (new_it.has_next()) { - new_it.next()->Iterate(&scavenge_visitor); - } - new_mark = previous_top; - - // Sweep newly copied objects in the old space. The promotion 'top' - // pointer could change during sweeping. - previous_top = promoted_top; - for (Address current = promoted_mark - kPointerSize; - current >= previous_top; - current -= kPointerSize) { - HeapObject* object = HeapObject::cast(Memory::Object_at(current)); - object->Iterate(&scavenge_visitor); - UpdateRSet(object); - } - promoted_mark = previous_top; + // The addresses promoted_front and promoted_rear define a queue + // of unprocessed addresses of promoted objects. Process them + // until the queue is empty. + while (promoted_front > promoted_rear) { + promoted_front -= kPointerSize; + HeapObject* object = + HeapObject::cast(Memory::Object_at(promoted_front)); + object->Iterate(&scavenge_visitor); + UpdateRSet(object); } - if (has_processed_weak_pointers) break; // We are done. - // Copy objects reachable from weak pointers. - GlobalHandles::IterateWeakRoots(&scavenge_visitor); - has_processed_weak_pointers = true; - } + // Take another spin if there are now unswept objects in new space + // (there are currently no more unswept promoted objects). + } while (new_space_front < new_space_.top()); // Set age mark. - new_space_.set_age_mark(new_mark); + new_space_.set_age_mark(new_space_.top()); LOG(ResourceEvent("scavenge", "end")); @@ -882,8 +890,8 @@ void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) { if (target_space == Heap::old_pointer_space_) { // Record the object's address at the top of the to space, to allow // it to be swept by the scavenger. - promoted_top -= kPointerSize; - Memory::Object_at(promoted_top) = *p; + promoted_rear -= kPointerSize; + Memory::Object_at(promoted_rear) = *p; } else { #ifdef DEBUG // Objects promoted to the data space should not have pointers to @@ -939,6 +947,7 @@ Object* Heap::AllocateMap(InstanceType instance_type, int instance_size) { map->set_code_cache(empty_fixed_array()); map->set_unused_property_fields(0); map->set_bit_field(0); + map->set_bit_field2(0); return map; } @@ -1409,7 +1418,6 @@ Object* Heap::AllocateSharedFunctionInfo(Object* name) { share->set_formal_parameter_count(0); share->set_instance_class_name(Object_symbol()); share->set_function_data(undefined_value()); - share->set_lazy_load_data(undefined_value()); share->set_script(undefined_value()); share->set_start_position_and_type(0); share->set_debug_info(undefined_value()); @@ -1423,8 +1431,8 @@ Object* Heap::AllocateConsString(String* first, int first_length = first->length(); int second_length = second->length(); int length = first_length + second_length; - bool is_ascii = StringShape(first).IsAsciiRepresentation() - && StringShape(second).IsAsciiRepresentation(); + bool is_ascii = first->IsAsciiRepresentation() + && second->IsAsciiRepresentation(); // If the resulting string is small make a flat string. if (length < String::kMinNonFlatLength) { @@ -1484,15 +1492,15 @@ Object* Heap::AllocateSlicedString(String* buffer, Map* map; if (length <= String::kMaxShortStringSize) { - map = StringShape(buffer).IsAsciiRepresentation() ? + map = buffer->IsAsciiRepresentation() ? short_sliced_ascii_string_map() : short_sliced_string_map(); } else if (length <= String::kMaxMediumStringSize) { - map = StringShape(buffer).IsAsciiRepresentation() ? + map = buffer->IsAsciiRepresentation() ? medium_sliced_ascii_string_map() : medium_sliced_string_map(); } else { - map = StringShape(buffer).IsAsciiRepresentation() ? + map = buffer->IsAsciiRepresentation() ? long_sliced_ascii_string_map() : long_sliced_string_map(); } @@ -1524,7 +1532,7 @@ Object* Heap::AllocateSubString(String* buffer, buffer->TryFlatten(); } - Object* result = StringShape(buffer).IsAsciiRepresentation() + Object* result = buffer->IsAsciiRepresentation() ? AllocateRawAsciiString(length) : AllocateRawTwoByteString(length); if (result->IsFailure()) return result; @@ -2679,7 +2687,10 @@ void Heap::IterateStrongRoots(ObjectVisitor* v) { SYNCHRONIZE_TAG("bootstrapper"); Top::Iterate(v); SYNCHRONIZE_TAG("top"); + +#ifdef ENABLE_DEBUGGER_SUPPORT Debug::Iterate(v); +#endif SYNCHRONIZE_TAG("debug"); CompilationCache::Iterate(v); SYNCHRONIZE_TAG("compilationcache"); diff --git a/deps/v8/src/assembler-ia32-inl.h b/deps/v8/src/ia32/assembler-ia32-inl.h index c5213a7dc..a3d24b276 100644 --- a/deps/v8/src/assembler-ia32-inl.h +++ b/deps/v8/src/ia32/assembler-ia32-inl.h @@ -34,8 +34,8 @@ // A light-weight IA32 Assembler. -#ifndef V8_ASSEMBLER_IA32_INL_H_ -#define V8_ASSEMBLER_IA32_INL_H_ +#ifndef V8_IA32_ASSEMBLER_IA32_INL_H_ +#define V8_IA32_ASSEMBLER_IA32_INL_H_ #include "cpu.h" @@ -299,4 +299,4 @@ Operand::Operand(int32_t disp, RelocInfo::Mode rmode) { } } // namespace v8::internal -#endif // V8_ASSEMBLER_IA32_INL_H_ +#endif // V8_IA32_ASSEMBLER_IA32_INL_H_ diff --git a/deps/v8/src/assembler-ia32.cc b/deps/v8/src/ia32/assembler-ia32.cc index 8549261a8..3a2d3f82d 100644 --- a/deps/v8/src/assembler-ia32.cc +++ b/deps/v8/src/ia32/assembler-ia32.cc @@ -283,6 +283,10 @@ bool Operand::is_reg(Register reg) const { *pc_++ = (x) +#ifdef GENERATED_CODE_COVERAGE +static void InitCoverageLog(); +#endif + // spare_buffer_ static byte* spare_buffer_ = NULL; @@ -315,9 +319,11 @@ Assembler::Assembler(void* buffer, int buffer_size) { // Clear the buffer in debug mode unless it was provided by the // caller in which case we can't be sure it's okay to overwrite // existing code in it; see CodePatcher::CodePatcher(...). - if (kDebug && own_buffer_) { +#ifdef DEBUG + if (own_buffer_) { memset(buffer_, 0xCC, buffer_size); // int3 } +#endif // setup buffer pointers ASSERT(buffer_ != NULL); @@ -329,6 +335,9 @@ Assembler::Assembler(void* buffer, int buffer_size) { current_position_ = RelocInfo::kNoPosition; written_statement_position_ = current_statement_position_; written_position_ = current_position_; +#ifdef GENERATED_CODE_COVERAGE + InitCoverageLog(); +#endif } @@ -2073,9 +2082,9 @@ void Assembler::GrowBuffer() { // Clear the buffer in debug mode. Use 'int3' instructions to make // sure to get into problems if we ever run uninitialized code. - if (kDebug) { - memset(desc.buffer, 0xCC, desc.buffer_size); - } +#ifdef DEBUG + memset(desc.buffer, 0xCC, desc.buffer_size); +#endif // copy the data int pc_delta = desc.buffer - buffer_; @@ -2202,4 +2211,30 @@ void Assembler::WriteInternalReference(int position, const Label& bound_label) { long_at_put(position, label_loc); } + +#ifdef GENERATED_CODE_COVERAGE +static FILE* coverage_log = NULL; + + +static void InitCoverageLog() { + char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG"); + if (file_name != NULL) { + coverage_log = fopen(file_name, "aw+"); + } +} + + +void LogGeneratedCodeCoverage(const char* file_line) { + const char* return_address = (&file_line)[-1]; + char* push_insn = const_cast<char*>(return_address - 12); + push_insn[0] = 0xeb; // Relative branch insn. + push_insn[1] = 13; // Skip over coverage insns. + if (coverage_log != NULL) { + fprintf(coverage_log, "%s\n", file_line); + fflush(coverage_log); + } +} + +#endif + } } // namespace v8::internal diff --git a/deps/v8/src/assembler-ia32.h b/deps/v8/src/ia32/assembler-ia32.h index a6640937e..4c995882e 100644 --- a/deps/v8/src/assembler-ia32.h +++ b/deps/v8/src/ia32/assembler-ia32.h @@ -34,8 +34,8 @@ // A light-weight IA32 Assembler. -#ifndef V8_ASSEMBLER_IA32_H_ -#define V8_ASSEMBLER_IA32_H_ +#ifndef V8_IA32_ASSEMBLER_IA32_H_ +#define V8_IA32_ASSEMBLER_IA32_H_ namespace v8 { namespace internal { @@ -860,4 +860,4 @@ class EnsureSpace BASE_EMBEDDED { } } // namespace v8::internal -#endif // V8_ASSEMBLER_IA32_H_ +#endif // V8_IA32_ASSEMBLER_IA32_H_ diff --git a/deps/v8/src/builtins-ia32.cc b/deps/v8/src/ia32/builtins-ia32.cc index 0e9de8c0f..5c7ba8e1b 100644 --- a/deps/v8/src/builtins-ia32.cc +++ b/deps/v8/src/ia32/builtins-ia32.cc @@ -32,7 +32,7 @@ namespace v8 { namespace internal { -#define __ masm-> +#define __ ACCESS_MASM(masm) void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) { @@ -54,6 +54,14 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { // -- edi: constructor function // ----------------------------------- + Label non_function_call; + // Check that function is not a smi. + __ test(edi, Immediate(kSmiTagMask)); + __ j(zero, &non_function_call); + // Check that function is a JSFunction. + __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); + __ j(not_equal, &non_function_call); + // Enter a construct frame. __ EnterConstructFrame(); @@ -69,16 +77,12 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { Label rt_call, allocated; if (FLAG_inline_new) { Label undo_allocation; +#ifdef ENABLE_DEBUGGER_SUPPORT ExternalReference debug_step_in_fp = ExternalReference::debug_step_in_fp_address(); __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0)); __ j(not_equal, &rt_call); - // Check that function is not a Smi. - __ test(edi, Immediate(kSmiTagMask)); - __ j(zero, &rt_call); - // Check that function is a JSFunction - __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); - __ j(not_equal, &rt_call); +#endif // Verified that the constructor is a JSFunction. // Load the initial map and verify that it is in fact a map. @@ -300,6 +304,16 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver __ push(ecx); __ ret(0); + + // edi: called object + // eax: number of arguments + __ bind(&non_function_call); + + // Set expected number of arguments to zero (not changing eax). + __ Set(ebx, Immediate(0)); + __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); + __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), + RelocInfo::CODE_TARGET); } diff --git a/deps/v8/src/codegen-ia32.cc b/deps/v8/src/ia32/codegen-ia32.cc index 663f235d7..e260ab2d3 100644 --- a/deps/v8/src/codegen-ia32.cc +++ b/deps/v8/src/ia32/codegen-ia32.cc @@ -30,6 +30,7 @@ #include "bootstrapper.h" #include "codegen-inl.h" #include "debug.h" +#include "ic-inl.h" #include "parser.h" #include "register-allocator-inl.h" #include "runtime.h" @@ -37,7 +38,7 @@ namespace v8 { namespace internal { -#define __ masm_-> +#define __ ACCESS_MASM(masm_) // ------------------------------------------------------------------------- // CodeGenState implementation. @@ -1274,12 +1275,9 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, smi_value, overwrite_mode); __ Set(answer.reg(), Immediate(value)); - if (operand->is_register()) { - __ sub(answer.reg(), Operand(operand->reg())); - } else { - ASSERT(operand->is_constant()); - __ sub(Operand(answer.reg()), Immediate(operand->handle())); - } + // We are in the reversed case so they can't both be Smi constants. + ASSERT(operand->is_register()); + __ sub(answer.reg(), Operand(operand->reg())); } else { operand->ToRegister(); frame_->Spill(operand->reg()); @@ -1374,23 +1372,26 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, operand->ToRegister(); __ test(operand->reg(), Immediate(kSmiTagMask)); deferred->enter()->Branch(not_zero, operand, not_taken); - Result answer = allocator()->Allocate(); - ASSERT(answer.is_valid()); - __ mov(answer.reg(), operand->reg()); - ASSERT(kSmiTag == 0); // adjust code if not the case - // We do no shifts, only the Smi conversion, if shift_value is 1. - if (shift_value == 0) { - __ sar(answer.reg(), kSmiTagSize); - } else if (shift_value > 1) { - __ shl(answer.reg(), shift_value - 1); + if (shift_value != 0) { + Result answer = allocator()->Allocate(); + ASSERT(answer.is_valid()); + __ mov(answer.reg(), operand->reg()); + ASSERT(kSmiTag == 0); // adjust code if not the case + // We do no shifts, only the Smi conversion, if shift_value is 1. + if (shift_value > 1) { + __ shl(answer.reg(), shift_value - 1); + } + // Convert int result to Smi, checking that it is in int range. + ASSERT(kSmiTagSize == times_2); // adjust code if not the case + __ add(answer.reg(), Operand(answer.reg())); + deferred->enter()->Branch(overflow, operand, not_taken); + operand->Unuse(); + deferred->BindExit(&answer); + frame_->Push(&answer); + } else { + deferred->BindExit(operand); + frame_->Push(operand); } - // Convert int result to Smi, checking that it is in int range. - ASSERT(kSmiTagSize == times_2); // adjust code if not the case - __ add(answer.reg(), Operand(answer.reg())); - deferred->enter()->Branch(overflow, operand, not_taken); - operand->Unuse(); - deferred->BindExit(&answer); - frame_->Push(&answer); } break; } @@ -1411,11 +1412,7 @@ void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, deferred->enter()->Branch(not_zero, operand, not_taken); frame_->Spill(operand->reg()); if (op == Token::BIT_AND) { - if (int_value == 0) { - __ xor_(Operand(operand->reg()), operand->reg()); - } else { - __ and_(Operand(operand->reg()), Immediate(value)); - } + __ and_(Operand(operand->reg()), Immediate(value)); } else if (op == Token::BIT_XOR) { if (int_value != 0) { __ xor_(Operand(operand->reg()), Immediate(value)); @@ -2009,18 +2006,18 @@ void CodeGenerator::GenerateReturnSequence(Result* return_value) { // Add a label for checking the size of the code used for returning. Label check_exit_codesize; - __ bind(&check_exit_codesize); + masm_->bind(&check_exit_codesize); // Leave the frame and return popping the arguments and the // receiver. frame_->Exit(); - __ ret((scope_->num_parameters() + 1) * kPointerSize); + masm_->ret((scope_->num_parameters() + 1) * kPointerSize); DeleteFrame(); // Check that the size of the code used for returning matches what is // expected by the debugger. ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, - __ SizeOfCodeGeneratedSince(&check_exit_codesize)); + masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); } @@ -2143,7 +2140,7 @@ void CodeGenerator::GenerateFastCaseSwitchJumpTable( times_1, 0x0, RelocInfo::INTERNAL_REFERENCE)); smi_value.Unuse(); // Calculate address to overwrite later with actual address of table. - int32_t jump_table_ref = __ pc_offset() - sizeof(int32_t); + int32_t jump_table_ref = masm_->pc_offset() - sizeof(int32_t); __ Align(4); Label table_start; __ bind(&table_start); @@ -3179,10 +3176,12 @@ void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { ASSERT(!in_spilled_code()); Comment cmnt(masm_, "[ DebuggerStatement"); CodeForStatementPosition(node); +#ifdef ENABLE_DEBUGGER_SUPPORT // Spill everything, even constants, to the frame. frame_->SpillAll(); frame_->CallRuntime(Runtime::kDebugBreak, 0); // Ignore the return value. +#endif } @@ -3384,7 +3383,9 @@ Result CodeGenerator::LoadFromGlobalSlotCheckExtensions( // Loop up the context chain. There is no frame effect so it is // safe to use raw labels here. Label next, fast; - if (!context.reg().is(tmp.reg())) __ mov(tmp.reg(), context.reg()); + if (!context.reg().is(tmp.reg())) { + __ mov(tmp.reg(), context.reg()); + } __ bind(&next); // Terminate at global context. __ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset), @@ -3410,7 +3411,10 @@ Result CodeGenerator::LoadFromGlobalSlotCheckExtensions( ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT; Result answer = frame_->CallLoadIC(mode); - + // A test eax instruction following the call signals that the inobject + // property case was inlined. Ensure that there is not a test eax + // instruction here. + __ nop(); // Discard the global object. The result is in answer. frame_->Drop(); return answer; @@ -3933,6 +3937,9 @@ void CodeGenerator::VisitAssignment(Assignment* node) { } else { Literal* literal = node->value()->AsLiteral(); + bool overwrite_value = + (node->value()->AsBinaryOperation() != NULL && + node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); Variable* right_var = node->value()->AsVariableProxy()->AsVariable(); // There are two cases where the target is not read in the right hand // side, that are easy to test for: the right hand side is a literal, @@ -3945,7 +3952,9 @@ void CodeGenerator::VisitAssignment(Assignment* node) { target.GetValue(NOT_INSIDE_TYPEOF); } Load(node->value()); - GenericBinaryOperation(node->binary_op(), node->type()); + GenericBinaryOperation(node->binary_op(), + node->type(), + overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); } if (var != NULL && @@ -4535,6 +4544,17 @@ void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { } +void CodeGenerator::GenerateGetFramePointer(ZoneList<Expression*>* args) { + ASSERT(args->length() == 0); + ASSERT(kSmiTagSize == 1 && kSmiTag == 0); // shifting code depends on this + Result ebp_as_smi = allocator_->Allocate(); + ASSERT(ebp_as_smi.is_valid()); + __ mov(ebp_as_smi.reg(), Operand(ebp)); + __ shr(ebp_as_smi.reg(), kSmiTagSize); + frame_->Push(&ebp_as_smi); +} + + void CodeGenerator::VisitCallRuntime(CallRuntime* node) { if (CheckForInlineRuntimeCall(node)) { return; @@ -5228,6 +5248,48 @@ bool CodeGenerator::HasValidEntryRegisters() { #endif +class DeferredReferenceGetNamedValue: public DeferredCode { + public: + DeferredReferenceGetNamedValue(CodeGenerator* cgen, Handle<String> name) + : DeferredCode(cgen), name_(name) { + set_comment("[ DeferredReferenceGetNamedValue"); + } + + virtual void Generate(); + + Label* patch_site() { return &patch_site_; } + + private: + Label patch_site_; + Handle<String> name_; +}; + + +void DeferredReferenceGetNamedValue::Generate() { + CodeGenerator* cgen = generator(); + Result receiver(cgen); + enter()->Bind(&receiver); + + cgen->frame()->Push(&receiver); + cgen->frame()->Push(name_); + Result answer = cgen->frame()->CallLoadIC(RelocInfo::CODE_TARGET); + // The call must be followed by a test eax instruction to indicate + // that the inobject property case was inlined. + ASSERT(answer.is_register() && answer.reg().is(eax)); + // Store the delta to the map check instruction here in the test instruction. + // Use masm_-> instead of the double underscore macro since the latter can't + // return a value. + int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); + // Here we use masm_-> instead of the double underscore macro because + // this is the instruction that gets patched and coverage code gets in + // the way. + masm_->test(answer.reg(), Immediate(-delta_to_patch_site)); + __ IncrementCounter(&Counters::named_load_inline_miss, 1); + receiver = cgen->frame()->Pop(); + exit_.Jump(&receiver, &answer); +} + + class DeferredReferenceGetKeyedValue: public DeferredCode { public: DeferredReferenceGetKeyedValue(CodeGenerator* generator, bool is_global) @@ -5268,9 +5330,14 @@ void DeferredReferenceGetKeyedValue::Generate() { // instruction. ASSERT(value.is_register() && value.reg().is(eax)); // The delta from the start of the map-compare instruction to the - // test eax instruction. - int delta_to_patch_site = __ SizeOfCodeGeneratedSince(patch_site()); - __ test(value.reg(), Immediate(-delta_to_patch_site)); + // test instruction. We use masm_ directly here instead of the + // double underscore macro because the macro sometimes uses macro + // expansion to turn into something that can't return a value. This + // is encountered when doing generated code coverage tests. + int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); + // Here we use masm_-> instead of the double underscore macro because this + // is the instruction that gets patched and coverage code gets in the way. + masm_->test(value.reg(), Immediate(-delta_to_patch_site)); __ IncrementCounter(&Counters::keyed_load_inline_miss, 1); // The receiver and key were spilled by the call, so their state as @@ -5284,7 +5351,7 @@ void DeferredReferenceGetKeyedValue::Generate() { #undef __ -#define __ masm-> +#define __ ACCESS_MASM(masm) Handle<String> Reference::GetName() { ASSERT(type_ == NAMED); @@ -5324,16 +5391,66 @@ void Reference::GetValue(TypeofState typeof_state) { // thrown below, we must distinguish between the two kinds of // loads (typeof expression loads must not throw a reference // error). - Comment cmnt(masm, "[ Load from named Property"); - cgen_->frame()->Push(GetName()); - Variable* var = expression_->AsVariableProxy()->AsVariable(); - ASSERT(var == NULL || var->is_global()); - RelocInfo::Mode mode = (var == NULL) - ? RelocInfo::CODE_TARGET - : RelocInfo::CODE_TARGET_CONTEXT; - Result answer = cgen_->frame()->CallLoadIC(mode); - cgen_->frame()->Push(&answer); + bool is_global = var != NULL; + ASSERT(!is_global || var->is_global()); + + if (is_global || cgen_->scope()->is_global_scope()) { + // Do not inline the inobject property case for loads from the + // global object or loads in toplevel code. + Comment cmnt(masm, "[ Load from named Property"); + cgen_->frame()->Push(GetName()); + + RelocInfo::Mode mode = is_global + ? RelocInfo::CODE_TARGET_CONTEXT + : RelocInfo::CODE_TARGET; + Result answer = cgen_->frame()->CallLoadIC(mode); + // A test eax instruction following the call signals that the + // inobject property case was inlined. Ensure that there is not + // a test eax instruction here. + __ nop(); + cgen_->frame()->Push(&answer); + } else { + // Inline the inobject property case. + Comment cmnt(masm, "[ Inlined named property load"); + DeferredReferenceGetNamedValue* deferred = + new DeferredReferenceGetNamedValue(cgen_, GetName()); + Result receiver = cgen_->frame()->Pop(); + receiver.ToRegister(); + // Check that the receiver is a heap object. + __ test(receiver.reg(), Immediate(kSmiTagMask)); + deferred->enter()->Branch(zero, &receiver, not_taken); + + // Preallocate the value register to ensure that there is no + // spill emitted between the patch site label and the offset in + // the load instruction. + Result value = cgen_->allocator()->Allocate(); + ASSERT(value.is_valid()); + __ bind(deferred->patch_site()); + // This is the map check instruction that will be patched (so we can't + // use the double underscore macro that may insert instructions). + // Initially use an invalid map to force a failure. + masm->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset), + Immediate(Factory::null_value())); + // This branch is always a forwards branch so it's always a fixed + // size which allows the assert below to succeed and patching to work. + deferred->enter()->Branch(not_equal, &receiver, not_taken); + + // The delta from the patch label to the load offset must be + // statically known. + ASSERT(masm->SizeOfCodeGeneratedSince(deferred->patch_site()) == + LoadIC::kOffsetToLoadInstruction); + // The initial (invalid) offset has to be large enough to force + // a 32-bit instruction encoding to allow patching with an + // arbitrary offset. Use kMaxInt (minus kHeapObjectTag). + int offset = kMaxInt; + masm->mov(value.reg(), FieldOperand(receiver.reg(), offset)); + + __ IncrementCounter(&Counters::named_load_inline, 1); + deferred->BindExit(&receiver, &value); + cgen_->frame()->Push(&receiver); + cgen_->frame()->Push(&value); + } break; } @@ -5369,7 +5486,9 @@ void Reference::GetValue(TypeofState typeof_state) { // Initially, use an invalid map. The map is patched in the IC // initialization code. __ bind(deferred->patch_site()); - __ cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset), + // Use masm-> here instead of the double underscore macro since extra + // coverage code can interfere with the patching. + masm->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset), Immediate(Factory::null_value())); deferred->enter()->Branch(not_equal, &receiver, &key, not_taken); @@ -5566,7 +5685,7 @@ void ToBooleanStub::Generate(MacroAssembler* masm) { #undef __ -#define __ masm_-> +#define __ ACCESS_MASM(masm_) Result DeferredInlineBinaryOperation::GenerateInlineCode(Result* left, Result* right) { @@ -5794,10 +5913,10 @@ Result DeferredInlineBinaryOperation::GenerateInlineCode(Result* left, // Right operand must be in register cl because x86 likes it that way. if (right->reg().is(ecx)) { // Right is already in the right place. Left may be in the - // same register, which causes problems. Use answer instead. - if (left->reg().is(ecx)) { - *left = answer; - } + // same register, which causes problems. Always use answer + // instead of left, even if left is not ecx, since this avoids + // spilling left. + *left = answer; } else if (left->reg().is(ecx)) { generator()->frame()->Spill(left->reg()); __ mov(left->reg(), right->reg()); @@ -5811,6 +5930,9 @@ Result DeferredInlineBinaryOperation::GenerateInlineCode(Result* left, ASSERT(reg_ecx.is_valid()); __ mov(ecx, right->reg()); *right = reg_ecx; + // Answer and left both contain the left operand. Use answer, so + // left is not spilled. + *left = answer; } ASSERT(left->reg().is_valid()); ASSERT(!left->reg().is(ecx)); @@ -5860,16 +5982,10 @@ Result DeferredInlineBinaryOperation::GenerateInlineCode(Result* left, case Token::SHL: { __ shl(left->reg()); // Check that the *signed* result fits in a smi. - // - // TODO(207): Can reduce registers from 4 to 3 by - // preallocating ecx. JumpTarget result_ok(generator()); - Result smi_test_reg = generator()->allocator()->Allocate(); - ASSERT(smi_test_reg.is_valid()); - __ lea(smi_test_reg.reg(), Operand(left->reg(), 0x40000000)); - __ test(smi_test_reg.reg(), Immediate(0x80000000)); - smi_test_reg.Unuse(); - result_ok.Branch(zero, left, taken); + __ cmp(left->reg(), 0xc0000000); + result_ok.Branch(positive, left, taken); + __ shr(left->reg()); ASSERT(kSmiTag == 0); __ shl(left->reg(), kSmiTagSize); @@ -5900,7 +6016,7 @@ Result DeferredInlineBinaryOperation::GenerateInlineCode(Result* left, #undef __ -#define __ masm-> +#define __ ACCESS_MASM(masm) void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { // Perform fast-case smi code for the operation (eax <op> ebx) and @@ -6169,11 +6285,15 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { case Token::SHR: __ shr(eax); break; default: UNREACHABLE(); } - - // Check if result is non-negative and fits in a smi. - __ test(eax, Immediate(0xc0000000)); - __ j(not_zero, &non_smi_result); - + if (op_ == Token::SHR) { + // Check if result is non-negative and fits in a smi. + __ test(eax, Immediate(0xc0000000)); + __ j(not_zero, &non_smi_result); + } else { + // Check if result fits in a smi. + __ cmp(eax, 0xc0000000); + __ j(negative, &non_smi_result); + } // Tag smi result and return. ASSERT(kSmiTagSize == times_2); // adjust code if not the case __ lea(eax, Operand(eax, eax, times_1, kSmiTag)); @@ -6225,7 +6345,9 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { } // SHR should return uint32 - go to runtime for non-smi/negative result. - if (op_ == Token::SHR) __ bind(&non_smi_result); + if (op_ == Token::SHR) { + __ bind(&non_smi_result); + } __ mov(eax, Operand(esp, 1 * kPointerSize)); __ mov(edx, Operand(esp, 2 * kPointerSize)); break; diff --git a/deps/v8/src/ia32/codegen-ia32.h b/deps/v8/src/ia32/codegen-ia32.h new file mode 100644 index 000000000..0e019570e --- /dev/null +++ b/deps/v8/src/ia32/codegen-ia32.h @@ -0,0 +1,633 @@ +// Copyright 2006-2008 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. + +#ifndef V8_IA32_CODEGEN_IA32_H_ +#define V8_IA32_CODEGEN_IA32_H_ + +namespace v8 { namespace internal { + +// Forward declarations +class DeferredCode; +class RegisterAllocator; +class RegisterFile; + +enum InitState { CONST_INIT, NOT_CONST_INIT }; +enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; + + +// ------------------------------------------------------------------------- +// Reference support + +// A reference is a C++ stack-allocated object that keeps an ECMA +// reference on the execution stack while in scope. For variables +// the reference is empty, indicating that it isn't necessary to +// store state on the stack for keeping track of references to those. +// For properties, we keep either one (named) or two (indexed) values +// on the execution stack to represent the reference. + +class Reference BASE_EMBEDDED { + public: + // The values of the types is important, see size(). + enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 }; + Reference(CodeGenerator* cgen, Expression* expression); + ~Reference(); + + Expression* expression() const { return expression_; } + Type type() const { return type_; } + void set_type(Type value) { + ASSERT(type_ == ILLEGAL); + type_ = value; + } + + // The size the reference takes up on the stack. + int size() const { return (type_ == ILLEGAL) ? 0 : type_; } + + bool is_illegal() const { return type_ == ILLEGAL; } + bool is_slot() const { return type_ == SLOT; } + bool is_property() const { return type_ == NAMED || type_ == KEYED; } + + // Return the name. Only valid for named property references. + Handle<String> GetName(); + + // Generate code to push the value of the reference on top of the + // expression stack. The reference is expected to be already on top of + // the expression stack, and it is left in place with its value above it. + void GetValue(TypeofState typeof_state); + + // Like GetValue except that the slot is expected to be written to before + // being read from again. Thae value of the reference may be invalidated, + // causing subsequent attempts to read it to fail. + void TakeValue(TypeofState typeof_state); + + // Generate code to store the value on top of the expression stack in the + // reference. The reference is expected to be immediately below the value + // on the expression stack. The stored value is left in place (with the + // reference intact below it) to support chained assignments. + void SetValue(InitState init_state); + + private: + CodeGenerator* cgen_; + Expression* expression_; + Type type_; +}; + + +// ------------------------------------------------------------------------- +// Control destinations. + +// A control destination encapsulates a pair of jump targets and a +// flag indicating which one is the preferred fall-through. The +// preferred fall-through must be unbound, the other may be already +// bound (ie, a backward target). +// +// The true and false targets may be jumped to unconditionally or +// control may split conditionally. Unconditional jumping and +// splitting should be emitted in tail position (as the last thing +// when compiling an expression) because they can cause either label +// to be bound or the non-fall through to be jumped to leaving an +// invalid virtual frame. +// +// The labels in the control destination can be extracted and +// manipulated normally without affecting the state of the +// destination. + +class ControlDestination BASE_EMBEDDED { + public: + ControlDestination(JumpTarget* true_target, + JumpTarget* false_target, + bool true_is_fall_through) + : true_target_(true_target), + false_target_(false_target), + true_is_fall_through_(true_is_fall_through), + is_used_(false) { + ASSERT(true_is_fall_through ? !true_target->is_bound() + : !false_target->is_bound()); + } + + // Accessors for the jump targets. Directly jumping or branching to + // or binding the targets will not update the destination's state. + JumpTarget* true_target() const { return true_target_; } + JumpTarget* false_target() const { return false_target_; } + + // True if the the destination has been jumped to unconditionally or + // control has been split to both targets. This predicate does not + // test whether the targets have been extracted and manipulated as + // raw jump targets. + bool is_used() const { return is_used_; } + + // True if the destination is used and the true target (respectively + // false target) was the fall through. If the target is backward, + // "fall through" included jumping unconditionally to it. + bool true_was_fall_through() const { + return is_used_ && true_is_fall_through_; + } + + bool false_was_fall_through() const { + return is_used_ && !true_is_fall_through_; + } + + // Emit a branch to one of the true or false targets, and bind the + // other target. Because this binds the fall-through target, it + // should be emitted in tail position (as the last thing when + // compiling an expression). + void Split(Condition cc) { + ASSERT(!is_used_); + if (true_is_fall_through_) { + false_target_->Branch(NegateCondition(cc)); + true_target_->Bind(); + } else { + true_target_->Branch(cc); + false_target_->Bind(); + } + is_used_ = true; + } + + // Emit an unconditional jump in tail position, to the true target + // (if the argument is true) or the false target. The "jump" will + // actually bind the jump target if it is forward, jump to it if it + // is backward. + void Goto(bool where) { + ASSERT(!is_used_); + JumpTarget* target = where ? true_target_ : false_target_; + if (target->is_bound()) { + target->Jump(); + } else { + target->Bind(); + } + is_used_ = true; + true_is_fall_through_ = where; + } + + // Mark this jump target as used as if Goto had been called, but + // without generating a jump or binding a label (the control effect + // should have already happened). This is used when the left + // subexpression of the short-circuit boolean operators are + // compiled. + void Use(bool where) { + ASSERT(!is_used_); + ASSERT((where ? true_target_ : false_target_)->is_bound()); + is_used_ = true; + true_is_fall_through_ = where; + } + + // Swap the true and false targets but keep the same actual label as + // the fall through. This is used when compiling negated + // expressions, where we want to swap the targets but preserve the + // state. + void Invert() { + JumpTarget* temp_target = true_target_; + true_target_ = false_target_; + false_target_ = temp_target; + + true_is_fall_through_ = !true_is_fall_through_; + } + + private: + // True and false jump targets. + JumpTarget* true_target_; + JumpTarget* false_target_; + + // Before using the destination: true if the true target is the + // preferred fall through, false if the false target is. After + // using the destination: true if the true target was actually used + // as the fall through, false if the false target was. + bool true_is_fall_through_; + + // True if the Split or Goto functions have been called. + bool is_used_; +}; + + +// ------------------------------------------------------------------------- +// Code generation state + +// The state is passed down the AST by the code generator (and back up, in +// the form of the state of the jump target pair). It is threaded through +// the call stack. Constructing a state implicitly pushes it on the owning +// code generator's stack of states, and destroying one implicitly pops it. +// +// The code generator state is only used for expressions, so statements have +// the initial state. + +class CodeGenState BASE_EMBEDDED { + public: + // Create an initial code generator state. Destroying the initial state + // leaves the code generator with a NULL state. + explicit CodeGenState(CodeGenerator* owner); + + // Create a code generator state based on a code generator's current + // state. The new state may or may not be inside a typeof, and has its + // own control destination. + CodeGenState(CodeGenerator* owner, + TypeofState typeof_state, + ControlDestination* destination); + + // Destroy a code generator state and restore the owning code generator's + // previous state. + ~CodeGenState(); + + // Accessors for the state. + TypeofState typeof_state() const { return typeof_state_; } + ControlDestination* destination() const { return destination_; } + + private: + // The owning code generator. + CodeGenerator* owner_; + + // A flag indicating whether we are compiling the immediate subexpression + // of a typeof expression. + TypeofState typeof_state_; + + // A control destination in case the expression has a control-flow + // effect. + ControlDestination* destination_; + + // The previous state of the owning code generator, restored when + // this state is destroyed. + CodeGenState* previous_; +}; + + + + +// ------------------------------------------------------------------------- +// CodeGenerator + +class CodeGenerator: public AstVisitor { + public: + // Takes a function literal, generates code for it. This function should only + // be called by compiler.cc. + static Handle<Code> MakeCode(FunctionLiteral* fun, + Handle<Script> script, + bool is_eval); + +#ifdef ENABLE_LOGGING_AND_PROFILING + static bool ShouldGenerateLog(Expression* type); +#endif + + static void SetFunctionInfo(Handle<JSFunction> fun, + int length, + int function_token_position, + int start_position, + int end_position, + bool is_expression, + bool is_toplevel, + Handle<Script> script, + Handle<String> inferred_name); + + // Accessors + MacroAssembler* masm() { return masm_; } + + VirtualFrame* frame() const { return frame_; } + + bool has_valid_frame() const { return frame_ != NULL; } + + // Set the virtual frame to be new_frame, with non-frame register + // reference counts given by non_frame_registers. The non-frame + // register reference counts of the old frame are returned in + // non_frame_registers. + void SetFrame(VirtualFrame* new_frame, RegisterFile* non_frame_registers); + + void DeleteFrame(); + + RegisterAllocator* allocator() const { return allocator_; } + + CodeGenState* state() { return state_; } + void set_state(CodeGenState* state) { state_ = state; } + + void AddDeferred(DeferredCode* code) { deferred_.Add(code); } + + bool in_spilled_code() const { return in_spilled_code_; } + void set_in_spilled_code(bool flag) { in_spilled_code_ = flag; } + + private: + // Construction/Destruction + CodeGenerator(int buffer_size, Handle<Script> script, bool is_eval); + virtual ~CodeGenerator() { delete masm_; } + + // Accessors + Scope* scope() const { return scope_; } + + // Clearing and generating deferred code. + void ClearDeferred(); + void ProcessDeferred(); + + bool is_eval() { return is_eval_; } + + // State + TypeofState typeof_state() const { return state_->typeof_state(); } + ControlDestination* destination() const { return state_->destination(); } + + // Track loop nesting level. + int loop_nesting() const { return loop_nesting_; } + void IncrementLoopNesting() { loop_nesting_++; } + void DecrementLoopNesting() { loop_nesting_--; } + + + // Node visitors. + void VisitStatements(ZoneList<Statement*>* statements); + +#define DEF_VISIT(type) \ + void Visit##type(type* node); + NODE_LIST(DEF_VISIT) +#undef DEF_VISIT + + // Visit a statement and then spill the virtual frame if control flow can + // reach the end of the statement (ie, it does not exit via break, + // continue, return, or throw). This function is used temporarily while + // the code generator is being transformed. + void VisitAndSpill(Statement* statement); + + // Visit a list of statements and then spill the virtual frame if control + // flow can reach the end of the list. + void VisitStatementsAndSpill(ZoneList<Statement*>* statements); + + // Main code generation function + void GenCode(FunctionLiteral* fun); + + // Generate the return sequence code. Should be called no more than + // once per compiled function, immediately after binding the return + // target (which can not be done more than once). + void GenerateReturnSequence(Result* return_value); + + // The following are used by class Reference. + void LoadReference(Reference* ref); + void UnloadReference(Reference* ref); + + Operand ContextOperand(Register context, int index) const { + return Operand(context, Context::SlotOffset(index)); + } + + Operand SlotOperand(Slot* slot, Register tmp); + + Operand ContextSlotOperandCheckExtensions(Slot* slot, + Result tmp, + JumpTarget* slow); + + // Expressions + Operand GlobalObject() const { + return ContextOperand(esi, Context::GLOBAL_INDEX); + } + + void LoadCondition(Expression* x, + TypeofState typeof_state, + ControlDestination* destination, + bool force_control); + void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF); + void LoadGlobal(); + void LoadGlobalReceiver(); + + // Generate code to push the value of an expression on top of the frame + // and then spill the frame fully to memory. This function is used + // temporarily while the code generator is being transformed. + void LoadAndSpill(Expression* expression, + TypeofState typeof_state = NOT_INSIDE_TYPEOF); + + // Read a value from a slot and leave it on top of the expression stack. + void LoadFromSlot(Slot* slot, TypeofState typeof_state); + Result LoadFromGlobalSlotCheckExtensions(Slot* slot, + TypeofState typeof_state, + JumpTarget* slow); + + // Store the value on top of the expression stack into a slot, leaving the + // value in place. + void StoreToSlot(Slot* slot, InitState init_state); + + // Special code for typeof expressions: Unfortunately, we must + // be careful when loading the expression in 'typeof' + // expressions. We are not allowed to throw reference errors for + // non-existing properties of the global object, so we must make it + // look like an explicit property access, instead of an access + // through the context chain. + void LoadTypeofExpression(Expression* x); + + // Translate the value on top of the frame into control flow to the + // control destination. + void ToBoolean(ControlDestination* destination); + + void GenericBinaryOperation( + Token::Value op, + SmiAnalysis* type, + OverwriteMode overwrite_mode); + + // If possible, combine two constant smi values using op to produce + // a smi result, and push it on the virtual frame, all at compile time. + // Returns true if it succeeds. Otherwise it has no effect. + bool FoldConstantSmis(Token::Value op, int left, int right); + + // Emit code to perform a binary operation on a constant + // smi and a likely smi. Consumes the Result *operand. + void ConstantSmiBinaryOperation(Token::Value op, + Result* operand, + Handle<Object> constant_operand, + SmiAnalysis* type, + bool reversed, + OverwriteMode overwrite_mode); + + // Emit code to perform a binary operation on two likely smis. + // The code to handle smi arguments is produced inline. + // Consumes the Results *left and *right. + void LikelySmiBinaryOperation(Token::Value op, + Result* left, + Result* right, + OverwriteMode overwrite_mode); + + void Comparison(Condition cc, + bool strict, + ControlDestination* destination); + + // To prevent long attacker-controlled byte sequences, integer constants + // from the JavaScript source are loaded in two parts if they are larger + // than 16 bits. + static const int kMaxSmiInlinedBits = 16; + bool IsUnsafeSmi(Handle<Object> value); + // Load an integer constant x into a register target using + // at most 16 bits of user-controlled data per assembly operation. + void LoadUnsafeSmi(Register target, Handle<Object> value); + + void CallWithArguments(ZoneList<Expression*>* arguments, int position); + + void CheckStack(); + + struct InlineRuntimeLUT { + void (CodeGenerator::*method)(ZoneList<Expression*>*); + const char* name; + }; + + static InlineRuntimeLUT* FindInlineRuntimeLUT(Handle<String> name); + bool CheckForInlineRuntimeCall(CallRuntime* node); + static bool PatchInlineRuntimeEntry(Handle<String> name, + const InlineRuntimeLUT& new_entry, + InlineRuntimeLUT* old_entry); + + Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node); + void ProcessDeclarations(ZoneList<Declaration*>* declarations); + + Handle<Code> ComputeCallInitialize(int argc); + Handle<Code> ComputeCallInitializeInLoop(int argc); + + // Declare global variables and functions in the given array of + // name/value pairs. + void DeclareGlobals(Handle<FixedArray> pairs); + + // Instantiate the function boilerplate. + void InstantiateBoilerplate(Handle<JSFunction> boilerplate); + + // Support for type checks. + void GenerateIsSmi(ZoneList<Expression*>* args); + void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args); + void GenerateIsArray(ZoneList<Expression*>* args); + + // Support for arguments.length and arguments[?]. + void GenerateArgumentsLength(ZoneList<Expression*>* args); + void GenerateArgumentsAccess(ZoneList<Expression*>* args); + + // Support for accessing the value field of an object (used by Date). + void GenerateValueOf(ZoneList<Expression*>* args); + void GenerateSetValueOf(ZoneList<Expression*>* args); + + // Fast support for charCodeAt(n). + void GenerateFastCharCodeAt(ZoneList<Expression*>* args); + + // Fast support for object equality testing. + void GenerateObjectEquals(ZoneList<Expression*>* args); + + void GenerateLog(ZoneList<Expression*>* args); + + void GenerateGetFramePointer(ZoneList<Expression*>* args); + + // Methods and constants for fast case switch statement support. + // + // Only allow fast-case switch if the range of labels is at most + // this factor times the number of case labels. + // Value is derived from comparing the size of code generated by the normal + // switch code for Smi-labels to the size of a single pointer. If code + // quality increases this number should be decreased to match. + static const int kFastSwitchMaxOverheadFactor = 5; + + // Minimal number of switch cases required before we allow jump-table + // optimization. + static const int kFastSwitchMinCaseCount = 5; + + // The limit of the range of a fast-case switch, as a factor of the number + // of cases of the switch. Each platform should return a value that + // is optimal compared to the default code generated for a switch statement + // on that platform. + int FastCaseSwitchMaxOverheadFactor(); + + // The minimal number of cases in a switch before the fast-case switch + // optimization is enabled. Each platform should return a value that + // is optimal compared to the default code generated for a switch statement + // on that platform. + int FastCaseSwitchMinCaseCount(); + + // Allocate a jump table and create code to jump through it. + // Should call GenerateFastCaseSwitchCases to generate the code for + // all the cases at the appropriate point. + void GenerateFastCaseSwitchJumpTable(SwitchStatement* node, + int min_index, + int range, + Label* fail_label, + Vector<Label*> case_targets, + Vector<Label> case_labels); + + // Generate the code for cases for the fast case switch. + // Called by GenerateFastCaseSwitchJumpTable. + void GenerateFastCaseSwitchCases(SwitchStatement* node, + Vector<Label> case_labels, + VirtualFrame* start_frame); + + // Fast support for constant-Smi switches. + void GenerateFastCaseSwitchStatement(SwitchStatement* node, + int min_index, + int range, + int default_index); + + // Fast support for constant-Smi switches. Tests whether switch statement + // permits optimization and calls GenerateFastCaseSwitch if it does. + // Returns true if the fast-case switch was generated, and false if not. + bool TryGenerateFastCaseSwitchStatement(SwitchStatement* node); + + // Methods used to indicate which source code is generated for. Source + // positions are collected by the assembler and emitted with the relocation + // information. + void CodeForFunctionPosition(FunctionLiteral* fun); + void CodeForReturnPosition(FunctionLiteral* fun); + void CodeForStatementPosition(Node* node); + void CodeForSourcePosition(int pos); + +#ifdef DEBUG + // True if the registers are valid for entry to a block. There should be + // no frame-external references to eax, ebx, ecx, edx, or edi. + bool HasValidEntryRegisters(); +#endif + + bool is_eval_; // Tells whether code is generated for eval. + Handle<Script> script_; + List<DeferredCode*> deferred_; + + // Assembler + MacroAssembler* masm_; // to generate code + + // Code generation state + Scope* scope_; + VirtualFrame* frame_; + RegisterAllocator* allocator_; + CodeGenState* state_; + int loop_nesting_; + + // Jump targets. + // The target of the return from the function. + BreakTarget function_return_; + + // True if the function return is shadowed (ie, jumping to the target + // function_return_ does not jump to the true function return, but rather + // to some unlinking code). + bool function_return_is_shadowed_; + + // True when we are in code that expects the virtual frame to be fully + // spilled. Some virtual frame function are disabled in DEBUG builds when + // called from spilled code, because they do not leave the virtual frame + // in a spilled state. + bool in_spilled_code_; + + static InlineRuntimeLUT kInlineRuntimeLUT[]; + + friend class VirtualFrame; + friend class JumpTarget; + friend class Reference; + friend class Result; + + friend class CodeGeneratorPatcher; // Used in test-log-ia32.cc + + DISALLOW_COPY_AND_ASSIGN(CodeGenerator); +}; + + +} } // namespace v8::internal + +#endif // V8_IA32_CODEGEN_IA32_H_ diff --git a/deps/v8/src/cpu-ia32.cc b/deps/v8/src/ia32/cpu-ia32.cc index 9cd6b10bd..9cd6b10bd 100644 --- a/deps/v8/src/cpu-ia32.cc +++ b/deps/v8/src/ia32/cpu-ia32.cc diff --git a/deps/v8/src/debug-ia32.cc b/deps/v8/src/ia32/debug-ia32.cc index 6d59889aa..9503cfca7 100644 --- a/deps/v8/src/debug-ia32.cc +++ b/deps/v8/src/ia32/debug-ia32.cc @@ -33,6 +33,7 @@ namespace v8 { namespace internal { +#ifdef ENABLE_DEBUGGER_SUPPORT // A debug break in the frame exit code is identified by a call instruction. bool BreakLocationIterator::IsDebugBreakAtReturn() { @@ -67,7 +68,7 @@ bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) { } -#define __ masm-> +#define __ ACCESS_MASM(masm) static void Generate_DebugBreakCallHelper(MacroAssembler* masm, @@ -214,5 +215,6 @@ void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) { #undef __ +#endif // ENABLE_DEBUGGER_SUPPORT } } // namespace v8::internal diff --git a/deps/v8/src/disasm-ia32.cc b/deps/v8/src/ia32/disasm-ia32.cc index 458844e05..458844e05 100644 --- a/deps/v8/src/disasm-ia32.cc +++ b/deps/v8/src/ia32/disasm-ia32.cc diff --git a/deps/v8/src/frames-ia32.cc b/deps/v8/src/ia32/frames-ia32.cc index 1bc62ec22..1bc62ec22 100644 --- a/deps/v8/src/frames-ia32.cc +++ b/deps/v8/src/ia32/frames-ia32.cc diff --git a/deps/v8/src/frames-ia32.h b/deps/v8/src/ia32/frames-ia32.h index 518b1ca55..f86dbe4c1 100644 --- a/deps/v8/src/frames-ia32.h +++ b/deps/v8/src/ia32/frames-ia32.h @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef V8_FRAMES_IA32_H_ -#define V8_FRAMES_IA32_H_ +#ifndef V8_IA32_FRAMES_IA32_H_ +#define V8_IA32_FRAMES_IA32_H_ namespace v8 { namespace internal { @@ -288,4 +288,4 @@ inline Object* JavaScriptFrame::function_slot_object() const { } } // namespace v8::internal -#endif // V8_FRAMES_IA32_H_ +#endif // V8_IA32_FRAMES_IA32_H_ diff --git a/deps/v8/src/ic-ia32.cc b/deps/v8/src/ia32/ic-ia32.cc index 9060f2de9..4231bfae7 100644 --- a/deps/v8/src/ic-ia32.cc +++ b/deps/v8/src/ia32/ic-ia32.cc @@ -38,7 +38,7 @@ namespace v8 { namespace internal { // Static IC stub generators. // -#define __ masm-> +#define __ ACCESS_MASM(masm) // Helper function used to load a property from a dictionary backing storage. @@ -91,7 +91,9 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label, // Compute the masked index: (hash + i + i * i) & mask. __ mov(r1, FieldOperand(name, String::kLengthOffset)); __ shr(r1, String::kHashShift); - if (i > 0) __ add(Operand(r1), Immediate(Dictionary::GetProbeOffset(i))); + if (i > 0) { + __ add(Operand(r1), Immediate(Dictionary::GetProbeOffset(i))); + } __ and_(r1, Operand(r2)); // Scale the index by multiplying by the element size. @@ -121,23 +123,19 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label, } -// Helper function used to check that a value is either not a function -// or is loaded if it is a function. -static void GenerateCheckNonFunctionOrLoaded(MacroAssembler* masm, Label* miss, - Register value, Register scratch) { +// Helper function used to check that a value is either not an object +// or is loaded if it is an object. +static void GenerateCheckNonObjectOrLoaded(MacroAssembler* masm, Label* miss, + Register value, Register scratch) { Label done; // Check if the value is a Smi. __ test(value, Immediate(kSmiTagMask)); __ j(zero, &done, not_taken); - // Check if the value is a function. - __ CmpObjectType(value, JS_FUNCTION_TYPE, scratch); - __ j(not_equal, &done, taken); - // Check if the function has been loaded. - __ mov(scratch, FieldOperand(value, JSFunction::kSharedFunctionInfoOffset)); - __ mov(scratch, - FieldOperand(scratch, SharedFunctionInfo::kLazyLoadDataOffset)); - __ cmp(scratch, Factory::undefined_value()); - __ j(not_equal, miss, not_taken); + // Check if the object has been loaded. + __ mov(scratch, FieldOperand(value, JSFunction::kMapOffset)); + __ mov(scratch, FieldOperand(scratch, Map::kBitField2Offset)); + __ test(scratch, Immediate(1 << Map::kNeedsLoading)); + __ j(not_zero, miss, not_taken); __ bind(&done); } @@ -266,7 +264,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { __ j(not_zero, &slow, not_taken); // Probe the dictionary leaving result in ecx. GenerateDictionaryLoad(masm, &slow, ebx, ecx, edx, eax); - GenerateCheckNonFunctionOrLoaded(masm, &slow, ecx, edx); + GenerateCheckNonObjectOrLoaded(masm, &slow, ecx, edx); __ mov(eax, Operand(ecx)); __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); __ ret(0); @@ -491,10 +489,10 @@ static void GenerateNormalHelper(MacroAssembler* masm, __ j(not_equal, miss, not_taken); // Check that the function has been loaded. - __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); - __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kLazyLoadDataOffset)); - __ cmp(edx, Factory::undefined_value()); - __ j(not_equal, miss, not_taken); + __ mov(edx, FieldOperand(edi, JSFunction::kMapOffset)); + __ mov(edx, FieldOperand(edx, Map::kBitField2Offset)); + __ test(edx, Immediate(1 << Map::kNeedsLoading)); + __ j(not_zero, miss, not_taken); // Patch the receiver with the global proxy if necessary. if (is_global_object) { @@ -681,7 +679,7 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) { // Search the dictionary placing the result in eax. __ bind(&probe); GenerateDictionaryLoad(masm, &miss, edx, eax, ebx, ecx); - GenerateCheckNonFunctionOrLoaded(masm, &miss, eax, edx); + GenerateCheckNonObjectOrLoaded(masm, &miss, eax, edx); __ ret(0); // Global object access: Check access rights. @@ -727,24 +725,70 @@ void LoadIC::Generate(MacroAssembler* masm, const ExternalReference& f) { } -void KeyedLoadIC::PatchInlinedMapCheck(Address address, Object* value) { - static const byte kTestEaxByte = 0xA9; +// One byte opcode for test eax,0xXXXXXXXX. +static const byte kTestEaxByte = 0xA9; + + +void LoadIC::ClearInlinedVersion(Address address) { + // Reset the map check of the inlined inobject property load (if + // present) to guarantee failure by holding an invalid map (the null + // value). The offset can be patched to anything. + PatchInlinedLoad(address, Heap::null_value(), kMaxInt); +} + + +void KeyedLoadIC::ClearInlinedVersion(Address address) { + // Insert null as the map to check for to make sure the map check fails + // sending control flow to the IC instead of the inlined version. + PatchInlinedLoad(address, Heap::null_value()); +} + + +bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) { + // The address of the instruction following the call. + Address test_instruction_address = address + 4; + // If the instruction following the call is not a test eax, nothing + // was inlined. + if (*test_instruction_address != kTestEaxByte) return false; + + Address delta_address = test_instruction_address + 1; + // The delta to the start of the map check instruction. + int delta = *reinterpret_cast<int*>(delta_address); + + // The map address is the last 4 bytes of the 7-byte + // operand-immediate compare instruction, so we add 3 to get the + // offset to the last 4 bytes. + Address map_address = test_instruction_address + delta + 3; + *(reinterpret_cast<Object**>(map_address)) = map; + + // The offset is in the last 4 bytes of a six byte + // memory-to-register move instruction, so we add 2 to get the + // offset to the last 4 bytes. + Address offset_address = + test_instruction_address + delta + kOffsetToLoadInstruction + 2; + *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag; + return true; +} + + +bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) { Address test_instruction_address = address + 4; // 4 = stub address // The keyed load has a fast inlined case if the IC call instruction // is immediately followed by a test instruction. - if (*test_instruction_address == kTestEaxByte) { - // Fetch the offset from the test instruction to the map cmp - // instruction. This offset is stored in the last 4 bytes of the - // 5 byte test instruction. - Address offset_address = test_instruction_address + 1; - int offset_value = *(reinterpret_cast<int*>(offset_address)); - // Compute the map address. The map address is in the last 4 - // bytes of the 7-byte operand-immediate compare instruction, so - // we add 3 to the offset to get the map address. - Address map_address = test_instruction_address + offset_value + 3; - // patch the map check. - (*(reinterpret_cast<Object**>(map_address))) = value; - } + if (*test_instruction_address != kTestEaxByte) return false; + + // Fetch the offset from the test instruction to the map cmp + // instruction. This offset is stored in the last 4 bytes of the 5 + // byte test instruction. + Address delta_address = test_instruction_address + 1; + int delta = *reinterpret_cast<int*>(delta_address); + // Compute the map address. The map address is in the last 4 bytes + // of the 7-byte operand-immediate compare instruction, so we add 3 + // to the offset to get the map address. + Address map_address = test_instruction_address + delta + 3; + // Patch the map check. + *(reinterpret_cast<Object**>(map_address)) = map; + return true; } diff --git a/deps/v8/src/jump-target-ia32.cc b/deps/v8/src/ia32/jump-target-ia32.cc index 8afb0a8ad..6c7d6e35b 100644 --- a/deps/v8/src/jump-target-ia32.cc +++ b/deps/v8/src/ia32/jump-target-ia32.cc @@ -35,7 +35,7 @@ namespace v8 { namespace internal { // ------------------------------------------------------------------------- // JumpTarget implementation. -#define __ masm_-> +#define __ ACCESS_MASM(masm_) void JumpTarget::DoJump() { ASSERT(cgen_ != NULL); @@ -115,11 +115,13 @@ void JumpTarget::DoBranch(Condition cc, Hint hint) { __ bind(&original_fall_through); } else { - // Forward branch. A copy of the current frame is added to the end - // of the list of frames reaching the target block and a branch to - // the merge code is emitted. + // Forward branch. A copy of the current frame is added to the end of the + // list of frames reaching the target block and a branch to the merge code + // is emitted. Use masm_-> instead of __ as forward branches are expected + // to be a fixed size (no inserted coverage-checking instructions please). + // This is used in Reference::GetValue. AddReachingFrame(new VirtualFrame(cgen_->frame())); - __ j(cc, &merge_labels_.last(), hint); + masm_->j(cc, &merge_labels_.last(), hint); is_linked_ = true; } } diff --git a/deps/v8/src/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc index 4fad3be67..d6d5800fe 100644 --- a/deps/v8/src/macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/macro-assembler-ia32.cc @@ -216,6 +216,7 @@ void MacroAssembler::RecordWrite(Register object, int offset, } +#ifdef ENABLE_DEBUGGER_SUPPORT void MacroAssembler::SaveRegistersToMemory(RegList regs) { ASSERT((regs & ~kJSCallerSaved) == 0); // Copy the content of registers to memory location. @@ -290,7 +291,7 @@ void MacroAssembler::CopyRegistersFromStackToMemory(Register base, } } } - +#endif void MacroAssembler::Set(Register dst, const Immediate& x) { if (x.is_zero()) { @@ -378,6 +379,7 @@ void MacroAssembler::EnterExitFrame(StackFrame::Type type) { mov(edi, Operand(eax)); lea(esi, Operand(ebp, eax, times_4, offset)); +#ifdef ENABLE_DEBUGGER_SUPPORT // Save the state of all registers to the stack from the memory // location. This is needed to allow nested break points. if (type == StackFrame::EXIT_DEBUG) { @@ -389,6 +391,7 @@ void MacroAssembler::EnterExitFrame(StackFrame::Type type) { // associated with this issue). PushRegistersFromMemory(kJSCallerSaved); } +#endif // Reserve space for two arguments: argc and argv. sub(Operand(esp), Immediate(2 * kPointerSize)); @@ -406,6 +409,7 @@ void MacroAssembler::EnterExitFrame(StackFrame::Type type) { void MacroAssembler::LeaveExitFrame(StackFrame::Type type) { +#ifdef ENABLE_DEBUGGER_SUPPORT // Restore the memory copy of the registers by digging them out from // the stack. This is needed to allow nested break points. if (type == StackFrame::EXIT_DEBUG) { @@ -416,6 +420,7 @@ void MacroAssembler::LeaveExitFrame(StackFrame::Type type) { lea(ebx, Operand(ebp, kOffset)); CopyRegistersFromStackToMemory(ebx, ecx, kJSCallerSaved); } +#endif // Get the return address from the stack and restore the frame pointer. mov(ecx, Operand(ebp, 1 * kPointerSize)); @@ -427,9 +432,9 @@ void MacroAssembler::LeaveExitFrame(StackFrame::Type type) { // Restore current context from top and clear it in debug mode. ExternalReference context_address(Top::k_context_address); mov(esi, Operand::StaticVariable(context_address)); - if (kDebug) { - mov(Operand::StaticVariable(context_address), Immediate(0)); - } +#ifdef DEBUG + mov(Operand::StaticVariable(context_address), Immediate(0)); +#endif // Push the return address to get ready to return. push(ecx); diff --git a/deps/v8/src/ia32/macro-assembler-ia32.h b/deps/v8/src/ia32/macro-assembler-ia32.h new file mode 100644 index 000000000..cd7a23391 --- /dev/null +++ b/deps/v8/src/ia32/macro-assembler-ia32.h @@ -0,0 +1,371 @@ +// Copyright 2006-2008 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. + +#ifndef V8_IA32_MACRO_ASSEMBLER_IA32_H_ +#define V8_IA32_MACRO_ASSEMBLER_IA32_H_ + +#include "assembler.h" + +namespace v8 { namespace internal { + +// Forward declaration. +class JumpTarget; + + +// Helper types to make flags easier to read at call sites. +enum InvokeFlag { + CALL_FUNCTION, + JUMP_FUNCTION +}; + +enum CodeLocation { + IN_JAVASCRIPT, + IN_JS_ENTRY, + IN_C_ENTRY +}; + +enum HandlerType { + TRY_CATCH_HANDLER, + TRY_FINALLY_HANDLER, + JS_ENTRY_HANDLER +}; + + +// MacroAssembler implements a collection of frequently used macros. +class MacroAssembler: public Assembler { + public: + MacroAssembler(void* buffer, int size); + + // --------------------------------------------------------------------------- + // GC Support + + // Set the remembered set bit for [object+offset]. + // object is the object being stored into, value is the object being stored. + // If offset is zero, then the scratch register contains the array index into + // the elements array represented as a Smi. + // All registers are clobbered by the operation. + void RecordWrite(Register object, + int offset, + Register value, + Register scratch); + +#ifdef ENABLE_DEBUGGER_SUPPORT + // --------------------------------------------------------------------------- + // Debugger Support + + void SaveRegistersToMemory(RegList regs); + void RestoreRegistersFromMemory(RegList regs); + void PushRegistersFromMemory(RegList regs); + void PopRegistersToMemory(RegList regs); + void CopyRegistersFromStackToMemory(Register base, + Register scratch, + RegList regs); +#endif + + // --------------------------------------------------------------------------- + // Activation frames + + void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); } + void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); } + + void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); } + void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); } + + // Enter specific kind of exit frame; either EXIT or + // EXIT_DEBUG. Expects the number of arguments in register eax and + // sets up the number of arguments in register edi and the pointer + // to the first argument in register esi. + void EnterExitFrame(StackFrame::Type type); + + // Leave the current exit frame. Expects the return value in + // register eax:edx (untouched) and the pointer to the first + // argument in register esi. + void LeaveExitFrame(StackFrame::Type type); + + + // --------------------------------------------------------------------------- + // JavaScript invokes + + // Invoke the JavaScript function code by either calling or jumping. + void InvokeCode(const Operand& code, + const ParameterCount& expected, + const ParameterCount& actual, + InvokeFlag flag); + + void InvokeCode(Handle<Code> code, + const ParameterCount& expected, + const ParameterCount& actual, + RelocInfo::Mode rmode, + InvokeFlag flag); + + // Invoke the JavaScript function in the given register. Changes the + // current context to the context in the function before invoking. + void InvokeFunction(Register function, + const ParameterCount& actual, + InvokeFlag flag); + + // Invoke specified builtin JavaScript function. Adds an entry to + // the unresolved list if the name does not resolve. + void InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag); + + // Store the code object for the given builtin in the target register. + void GetBuiltinEntry(Register target, Builtins::JavaScript id); + + // Expression support + void Set(Register dst, const Immediate& x); + void Set(const Operand& dst, const Immediate& x); + + // Compare object type for heap object. + // Incoming register is heap_object and outgoing register is map. + void CmpObjectType(Register heap_object, InstanceType type, Register map); + + // Compare instance type for map. + void CmpInstanceType(Register map, InstanceType type); + + // FCmp is similar to integer cmp, but requires unsigned + // jcc instructions (je, ja, jae, jb, jbe, je, and jz). + void FCmp(); + + // --------------------------------------------------------------------------- + // Exception handling + + // Push a new try handler and link into try handler chain. + // The return address must be pushed before calling this helper. + // On exit, eax contains TOS (next_sp). + void PushTryHandler(CodeLocation try_location, HandlerType type); + + + // --------------------------------------------------------------------------- + // Inline caching support + + // Generates code that verifies that the maps of objects in the + // prototype chain of object hasn't changed since the code was + // generated and branches to the miss label if any map has. If + // necessary the function also generates code for security check + // in case of global object holders. The scratch and holder + // registers are always clobbered, but the object register is only + // clobbered if it the same as the holder register. The function + // returns a register containing the holder - either object_reg or + // holder_reg. + Register CheckMaps(JSObject* object, Register object_reg, + JSObject* holder, Register holder_reg, + Register scratch, Label* miss); + + // Generate code for checking access rights - used for security checks + // on access to global objects across environments. The holder register + // is left untouched, but the scratch register is clobbered. + void CheckAccessGlobalProxy(Register holder_reg, + Register scratch, + Label* miss); + + + // --------------------------------------------------------------------------- + // Support functions. + + // Check if result is zero and op is negative. + void NegativeZeroTest(Register result, Register op, Label* then_label); + + // Check if result is zero and op is negative in code using jump targets. + void NegativeZeroTest(CodeGenerator* cgen, + Register result, + Register op, + JumpTarget* then_target); + + // Check if result is zero and any of op1 and op2 are negative. + // Register scratch is destroyed, and it must be different from op2. + void NegativeZeroTest(Register result, Register op1, Register op2, + Register scratch, Label* then_label); + + // Try to get function prototype of a function and puts the value in + // the result register. Checks that the function really is a + // function and jumps to the miss label if the fast checks fail. The + // function register will be untouched; the other registers may be + // clobbered. + void TryGetFunctionPrototype(Register function, + Register result, + Register scratch, + Label* miss); + + // Generates code for reporting that an illegal operation has + // occurred. + void IllegalOperation(int num_arguments); + + // --------------------------------------------------------------------------- + // Runtime calls + + // Call a code stub. + void CallStub(CodeStub* stub); + + // Return from a code stub after popping its arguments. + void StubReturn(int argc); + + // Call a runtime routine. + // Eventually this should be used for all C calls. + void CallRuntime(Runtime::Function* f, int num_arguments); + + // Convenience function: Same as above, but takes the fid instead. + void CallRuntime(Runtime::FunctionId id, int num_arguments); + + // Tail call of a runtime routine (jump). + // Like JumpToBuiltin, but also takes care of passing the number + // of arguments. + void TailCallRuntime(const ExternalReference& ext, int num_arguments); + + // Jump to the builtin routine. + void JumpToBuiltin(const ExternalReference& ext); + + + // --------------------------------------------------------------------------- + // Utilities + + void Ret(); + + struct Unresolved { + int pc; + uint32_t flags; // see Bootstrapper::FixupFlags decoders/encoders. + const char* name; + }; + List<Unresolved>* unresolved() { return &unresolved_; } + + Handle<Object> CodeObject() { return code_object_; } + + + // --------------------------------------------------------------------------- + // StatsCounter support + + void SetCounter(StatsCounter* counter, int value); + void IncrementCounter(StatsCounter* counter, int value); + void DecrementCounter(StatsCounter* counter, int value); + + + // --------------------------------------------------------------------------- + // Debugging + + // Calls Abort(msg) if the condition cc is not satisfied. + // Use --debug_code to enable. + void Assert(Condition cc, const char* msg); + + // Like Assert(), but always enabled. + void Check(Condition cc, const char* msg); + + // Print a message to stdout and abort execution. + void Abort(const char* msg); + + // Verify restrictions about code generated in stubs. + void set_generating_stub(bool value) { generating_stub_ = value; } + bool generating_stub() { return generating_stub_; } + void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; } + bool allow_stub_calls() { return allow_stub_calls_; } + + private: + List<Unresolved> unresolved_; + bool generating_stub_; + bool allow_stub_calls_; + Handle<Object> code_object_; // This handle will be patched with the code + // code object on installation. + + // Helper functions for generating invokes. + void InvokePrologue(const ParameterCount& expected, + const ParameterCount& actual, + Handle<Code> code_constant, + const Operand& code_operand, + Label* done, + InvokeFlag flag); + + // Get the code for the given builtin. Returns if able to resolve + // the function in the 'resolved' flag. + Handle<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved); + + // Activation support. + void EnterFrame(StackFrame::Type type); + void LeaveFrame(StackFrame::Type type); +}; + + +// The code patcher is used to patch (typically) small parts of code e.g. for +// debugging and other types of instrumentation. When using the code patcher +// the exact number of bytes specified must be emitted. Is not legal to emit +// relocation information. If any of these constraints are violated it causes +// an assertion. +class CodePatcher { + public: + CodePatcher(byte* address, int size); + virtual ~CodePatcher(); + + // Macro assembler to emit code. + MacroAssembler* masm() { return &masm_; } + + private: + byte* address_; // The address of the code being patched. + int size_; // Number of bytes of the expected patch size. + MacroAssembler masm_; // Macro assembler used to generate the code. +}; + + +// ----------------------------------------------------------------------------- +// Static helper functions. + +// Generate an Operand for loading a field from an object. +static inline Operand FieldOperand(Register object, int offset) { + return Operand(object, offset - kHeapObjectTag); +} + + +// Generate an Operand for loading an indexed field from an object. +static inline Operand FieldOperand(Register object, + Register index, + ScaleFactor scale, + int offset) { + return Operand(object, index, scale, offset - kHeapObjectTag); +} + + +#ifdef GENERATED_CODE_COVERAGE +extern void LogGeneratedCodeCoverage(const char* file_line); +#define CODE_COVERAGE_STRINGIFY(x) #x +#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x) +#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__) +#define ACCESS_MASM(masm) { \ + byte* ia32_coverage_function = \ + reinterpret_cast<byte*>(FUNCTION_ADDR(LogGeneratedCodeCoverage)); \ + masm->pushfd(); \ + masm->pushad(); \ + masm->push(Immediate(reinterpret_cast<int>(&__FILE_LINE__))); \ + masm->call(ia32_coverage_function, RelocInfo::RUNTIME_ENTRY); \ + masm->pop(eax); \ + masm->popad(); \ + masm->popfd(); \ + } \ + masm-> +#else +#define ACCESS_MASM(masm) masm-> +#endif + + +} } // namespace v8::internal + +#endif // V8_IA32_MACRO_ASSEMBLER_IA32_H_ diff --git a/deps/v8/src/regexp-macro-assembler-ia32.cc b/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc index c2f76b4de..2a0cefd77 100644 --- a/deps/v8/src/regexp-macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc @@ -32,8 +32,8 @@ #include "regexp-stack.h" #include "macro-assembler.h" #include "regexp-macro-assembler.h" -#include "macro-assembler-ia32.h" -#include "regexp-macro-assembler-ia32.h" +#include "ia32/macro-assembler-ia32.h" +#include "ia32/regexp-macro-assembler-ia32.h" namespace v8 { namespace internal { @@ -86,7 +86,7 @@ namespace v8 { namespace internal { * byte* stack_area_top) */ -#define __ masm_-> +#define __ ACCESS_MASM(masm_) RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32( Mode mode, @@ -974,7 +974,7 @@ RegExpMacroAssemblerIA32::Result RegExpMacroAssemblerIA32::Match( int start_offset = previous_index; int end_offset = subject_ptr->length(); - bool is_ascii = StringShape(*subject).IsAsciiRepresentation(); + bool is_ascii = subject->IsAsciiRepresentation(); if (StringShape(subject_ptr).IsCons()) { subject_ptr = ConsString::cast(subject_ptr)->first(); @@ -985,7 +985,7 @@ RegExpMacroAssemblerIA32::Result RegExpMacroAssemblerIA32::Match( subject_ptr = slice->buffer(); } // Ensure that an underlying string has the same ascii-ness. - ASSERT(StringShape(subject_ptr).IsAsciiRepresentation() == is_ascii); + ASSERT(subject_ptr->IsAsciiRepresentation() == is_ascii); ASSERT(subject_ptr->IsExternalString() || subject_ptr->IsSeqString()); // String is now either Sequential or External int char_size_shift = is_ascii ? 0 : 1; @@ -1112,7 +1112,7 @@ const byte* RegExpMacroAssemblerIA32::StringCharacterPosition(String* subject, ASSERT(subject->IsExternalString() || subject->IsSeqString()); ASSERT(start_index >= 0); ASSERT(start_index <= subject->length()); - if (StringShape(subject).IsAsciiRepresentation()) { + if (subject->IsAsciiRepresentation()) { const byte* address; if (StringShape(subject).IsExternal()) { const char* data = ExternalAsciiString::cast(subject)->resource()->data(); @@ -1152,7 +1152,7 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address, Handle<String> subject(frame_entry<String*>(re_frame, kInputString)); // Current string. - bool is_ascii = StringShape(*subject).IsAsciiRepresentation(); + bool is_ascii = subject->IsAsciiRepresentation(); ASSERT(re_code->instruction_start() <= *return_address); ASSERT(*return_address <= @@ -1171,7 +1171,7 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address, } // String might have changed. - if (StringShape(*subject).IsAsciiRepresentation() != is_ascii) { + if (subject->IsAsciiRepresentation() != is_ascii) { // If we changed between an ASCII and an UC16 string, the specialized // code cannot be used, and we need to restart regexp matching from // scratch (including, potentially, compiling a new version of the code). diff --git a/deps/v8/src/regexp-macro-assembler-ia32.h b/deps/v8/src/ia32/regexp-macro-assembler-ia32.h index 0309f2004..8c5dd24cc 100644 --- a/deps/v8/src/regexp-macro-assembler-ia32.h +++ b/deps/v8/src/ia32/regexp-macro-assembler-ia32.h @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef REGEXP_MACRO_ASSEMBLER_IA32_H_ -#define REGEXP_MACRO_ASSEMBLER_IA32_H_ +#ifndef V8_IA32_REGEXP_MACRO_ASSEMBLER_IA32_H_ +#define V8_IA32_REGEXP_MACRO_ASSEMBLER_IA32_H_ namespace v8 { namespace internal { @@ -282,4 +282,4 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler { }} // namespace v8::internal -#endif /* REGEXP_MACRO_ASSEMBLER_IA32_H_ */ +#endif // V8_IA32_REGEXP_MACRO_ASSEMBLER_IA32_H_ diff --git a/deps/v8/src/register-allocator-ia32.cc b/deps/v8/src/ia32/register-allocator-ia32.cc index a89882748..b72d76556 100644 --- a/deps/v8/src/register-allocator-ia32.cc +++ b/deps/v8/src/ia32/register-allocator-ia32.cc @@ -97,6 +97,12 @@ void RegisterAllocator::UnuseReserved(RegisterFile* register_file) { } +bool RegisterAllocator::IsReserved(int reg_code) { + // Test below relies on the order of register codes. + return reg_code >= esp.code() && reg_code <= esi.code(); +} + + void RegisterAllocator::Initialize() { Reset(); // The following register is live on function entry, saved in the diff --git a/deps/v8/src/simulator-ia32.cc b/deps/v8/src/ia32/simulator-ia32.cc index ab8169375..ab8169375 100644 --- a/deps/v8/src/simulator-ia32.cc +++ b/deps/v8/src/ia32/simulator-ia32.cc diff --git a/deps/v8/src/simulator-ia32.h b/deps/v8/src/ia32/simulator-ia32.h index 2267721cf..4d02c03ab 100644 --- a/deps/v8/src/simulator-ia32.h +++ b/deps/v8/src/ia32/simulator-ia32.h @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef V8_SIMULATOR_IA32_H_ -#define V8_SIMULATOR_IA32_H_ +#ifndef V8_IA32_SIMULATOR_IA32_H_ +#define V8_IA32_SIMULATOR_IA32_H_ // Since there is no simulator for the ia32 architecture the only thing we can @@ -44,4 +44,4 @@ (reinterpret_cast<uintptr_t>(this) >= limit ? \ reinterpret_cast<uintptr_t>(this) - limit : 0) -#endif // V8_SIMULATOR_IA32_H_ +#endif // V8_IA32_SIMULATOR_IA32_H_ diff --git a/deps/v8/src/stub-cache-ia32.cc b/deps/v8/src/ia32/stub-cache-ia32.cc index 19777e6a7..bdfc3d6c3 100644 --- a/deps/v8/src/stub-cache-ia32.cc +++ b/deps/v8/src/ia32/stub-cache-ia32.cc @@ -33,7 +33,7 @@ namespace v8 { namespace internal { -#define __ masm-> +#define __ ACCESS_MASM(masm) static void ProbeTable(MacroAssembler* masm, @@ -256,7 +256,7 @@ void StubCompiler::GenerateLoadField(MacroAssembler* masm, // Check that the maps haven't changed. Register reg = - __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); + masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); // Get the value from the properties. GenerateFastPropertyLoad(masm, eax, reg, holder, index); @@ -279,7 +279,7 @@ void StubCompiler::GenerateLoadCallback(MacroAssembler* masm, // Check that the maps haven't changed. Register reg = - __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); + masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); // Push the arguments on the JS stack of the caller. __ pop(scratch2); // remove return address @@ -310,7 +310,7 @@ void StubCompiler::GenerateLoadConstant(MacroAssembler* masm, // Check that the maps haven't changed. Register reg = - __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); + masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); // Return the constant value. __ mov(eax, Handle<Object>(value)); @@ -332,7 +332,7 @@ void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm, // Check that the maps haven't changed. Register reg = - __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); + masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); // Push the arguments on the JS stack of the caller. __ pop(scratch2); // remove return address @@ -440,7 +440,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, #undef __ -#define __ masm()-> +#define __ ACCESS_MASM(masm()) // TODO(1241006): Avoid having lazy compile stubs specialized by the @@ -485,7 +485,7 @@ Object* CallStubCompiler::CompileCallField(Object* object, // Do the right check and compute the holder register. Register reg = - __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss); + masm()->CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss); GenerateFastPropertyLoad(masm(), edi, reg, holder, index); @@ -656,7 +656,7 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object, // Check that maps have not changed and compute the holder register. Register reg = - __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss); + masm()->CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss); // Enter an internal frame. __ EnterInternalFrame(); diff --git a/deps/v8/src/virtual-frame-ia32.cc b/deps/v8/src/ia32/virtual-frame-ia32.cc index eb3befca3..ff9f60cdf 100644 --- a/deps/v8/src/virtual-frame-ia32.cc +++ b/deps/v8/src/ia32/virtual-frame-ia32.cc @@ -33,7 +33,7 @@ namespace v8 { namespace internal { -#define __ masm_-> +#define __ ACCESS_MASM(masm_) // ------------------------------------------------------------------------- // VirtualFrame implementation. @@ -158,6 +158,28 @@ void VirtualFrame::SyncElementByPushing(int index) { } +// Clear the dirty bits for the range of elements in +// [min(stack_pointer_ + 1,begin), end]. +void VirtualFrame::SyncRange(int begin, int end) { + ASSERT(begin >= 0); + ASSERT(end < elements_.length()); + // Sync elements below the range if they have not been materialized + // on the stack. + int start = Min(begin, stack_pointer_ + 1); + + // If positive we have to adjust the stack pointer. + int delta = end - stack_pointer_; + if (delta > 0) { + stack_pointer_ = end; + __ sub(Operand(esp), Immediate(delta * kPointerSize)); + } + + for (int i = start; i <= end; i++) { + if (!elements_[i].is_synced()) SyncElementBelowStackPointer(i); + } +} + + void VirtualFrame::MergeTo(VirtualFrame* expected) { Comment cmnt(masm_, "[ Merge frame"); // We should always be merging the code generator's current frame to an @@ -288,64 +310,33 @@ void VirtualFrame::MergeMoveRegistersToRegisters(VirtualFrame* expected) { // We have already done X-to-memory moves. ASSERT(stack_pointer_ >= expected->stack_pointer_); - // Perform register-to-register moves. - int start = 0; - int end = elements_.length() - 1; - bool any_moves_blocked; // Did we fail to make some moves this iteration? - bool should_break_cycles = false; - bool any_moves_made; // Did we make any progress this iteration? - do { - any_moves_blocked = false; - any_moves_made = false; - int first_move_blocked = kIllegalIndex; - int last_move_blocked = kIllegalIndex; - for (int i = start; i <= end; i++) { - FrameElement source = elements_[i]; - FrameElement target = expected->elements_[i]; - if (source.is_register() && target.is_register()) { - if (target.reg().is(source.reg())) { - if (target.is_synced() && !source.is_synced()) { - __ mov(Operand(ebp, fp_relative(i)), source.reg()); - } - elements_[i] = target; - } else { - // We need to move source to target. - if (is_used(target.reg())) { - // The move is blocked because the target contains valid data. - // If we are stuck with only cycles remaining, then we spill source. - // Otherwise, we just need more iterations. - if (should_break_cycles) { - SpillElementAt(i); - should_break_cycles = false; - } else { // Record a blocked move. - if (!any_moves_blocked) { - first_move_blocked = i; - } - last_move_blocked = i; - any_moves_blocked = true; - } - } else { - // The move is not blocked. This frame element can be moved from - // its source register to its target register. - if (target.is_synced() && !source.is_synced()) { - SyncElementAt(i); - } - Use(target.reg(), i); - Unuse(source.reg()); - elements_[i] = target; - __ mov(target.reg(), source.reg()); - any_moves_made = true; - } - } + for (int i = 0; i < kNumRegisters; i++) { + // Move the right value into register i if it is currently in a register. + int index = expected->register_locations_[i]; + int use_index = register_locations_[i]; + // Fast check if register is unused in target or already correct + if (index != kIllegalIndex + && index != use_index + && elements_[index].is_register()) { + Register source = elements_[index].reg(); + Register target = { i }; + if (use_index == kIllegalIndex) { // Target is currently unused. + // Copy contents of source from source to target. + // Set frame element register to target. + elements_[index].set_reg(target); + Use(target, index); + Unuse(source); + __ mov(target, source); + } else { + // Exchange contents of registers source and target. + elements_[use_index].set_reg(source); + elements_[index].set_reg(target); + register_locations_[target.code()] = index; + register_locations_[source.code()] = use_index; + __ xchg(source, target); } } - // Update control flags for next iteration. - should_break_cycles = (any_moves_blocked && !any_moves_made); - if (any_moves_blocked) { - start = first_move_blocked; - end = last_move_blocked; - } - } while (any_moves_blocked); + } } @@ -354,19 +345,22 @@ void VirtualFrame::MergeMoveMemoryToRegisters(VirtualFrame *expected) { // final step and is done from the bottom up so that the backing // elements of copies are in their correct locations when we // encounter the copies. - for (int i = 0; i < elements_.length(); i++) { - FrameElement source = elements_[i]; - FrameElement target = expected->elements_[i]; - if (target.is_register() && !source.is_register()) { + for (int i = 0; i < kNumRegisters; i++) { + int index = expected->register_locations_[i]; + if (index != kIllegalIndex) { + FrameElement source = elements_[index]; + FrameElement target = expected->elements_[index]; switch (source.type()) { case FrameElement::INVALID: // Fall through. - case FrameElement::REGISTER: UNREACHABLE(); break; - + case FrameElement::REGISTER: + ASSERT(source.reg().is(target.reg())); + continue; // Go to next iteration. Skips Use(target.reg()) below. + break; case FrameElement::MEMORY: - ASSERT(i <= stack_pointer_); - __ mov(target.reg(), Operand(ebp, fp_relative(i))); + ASSERT(index <= stack_pointer_); + __ mov(target.reg(), Operand(ebp, fp_relative(index))); break; case FrameElement::CONSTANT: @@ -378,11 +372,25 @@ void VirtualFrame::MergeMoveMemoryToRegisters(VirtualFrame *expected) { break; case FrameElement::COPY: { - FrameElement backing = elements_[source.index()]; + int backing_index = source.index(); + FrameElement backing = elements_[backing_index]; ASSERT(backing.is_memory() || backing.is_register()); if (backing.is_memory()) { - ASSERT(source.index() <= stack_pointer_); - __ mov(target.reg(), Operand(ebp, fp_relative(source.index()))); + ASSERT(backing_index <= stack_pointer_); + // Code optimization if backing store should also move + // to a register: move backing store to its register first. + if (expected->elements_[backing_index].is_register()) { + FrameElement new_backing = expected->elements_[backing_index]; + Register new_backing_reg = new_backing.reg(); + ASSERT(!is_used(new_backing_reg)); + elements_[backing_index] = new_backing; + Use(new_backing_reg, backing_index); + __ mov(new_backing_reg, + Operand(ebp, fp_relative(backing_index))); + __ mov(target.reg(), new_backing_reg); + } else { + __ mov(target.reg(), Operand(ebp, fp_relative(backing_index))); + } } else { __ mov(target.reg(), backing.reg()); } @@ -390,11 +398,11 @@ void VirtualFrame::MergeMoveMemoryToRegisters(VirtualFrame *expected) { } // Ensure the proper sync state. If the source was memory no // code needs to be emitted. - if (target.is_synced() && !source.is_memory()) { - SyncElementAt(i); + if (target.is_synced() && !source.is_synced()) { + __ mov(Operand(ebp, fp_relative(index)), target.reg()); } - Use(target.reg(), i); - elements_[i] = target; + Use(target.reg(), index); + elements_[index] = target; } } } @@ -467,7 +475,7 @@ void VirtualFrame::AllocateStackSlots(int count) { // we sync them with the actual frame to allocate space for spilling // them later. First sync everything above the stack pointer so we can // use pushes to allocate and initialize the locals. - SyncRange(stack_pointer_ + 1, elements_.length()); + SyncRange(stack_pointer_ + 1, elements_.length() - 1); Handle<Object> undefined = Factory::undefined_value(); FrameElement initial_value = FrameElement::ConstantElement(undefined, FrameElement::SYNCED); @@ -615,6 +623,12 @@ void VirtualFrame::StoreToFrameSlotAt(int index) { InvalidateFrameSlotAt(index); + // InvalidateFrameSlotAt can potentially change any frame element, due + // to spilling registers to allocate temporaries in order to preserve + // the copy-on-write semantics of aliased elements. Reload top from + // the frame. + top = elements_[top_index]; + if (top.is_copy()) { // There are two cases based on the relative positions of the // stored-to slot and the backing slot of the top element. diff --git a/deps/v8/src/virtual-frame-ia32.h b/deps/v8/src/ia32/virtual-frame-ia32.h index 113ccc692..298eda21d 100644 --- a/deps/v8/src/virtual-frame-ia32.h +++ b/deps/v8/src/ia32/virtual-frame-ia32.h @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef V8_VIRTUAL_FRAME_IA32_H_ -#define V8_VIRTUAL_FRAME_IA32_H_ +#ifndef V8_IA32_VIRTUAL_FRAME_IA32_H_ +#define V8_IA32_VIRTUAL_FRAME_IA32_H_ #include "register-allocator.h" @@ -490,4 +490,4 @@ class VirtualFrame : public Malloced { } } // namespace v8::internal -#endif // V8_VIRTUAL_FRAME_IA32_H_ +#endif // V8_IA32_VIRTUAL_FRAME_IA32_H_ diff --git a/deps/v8/src/ic-inl.h b/deps/v8/src/ic-inl.h index f5ce0adf1..bb5696281 100644 --- a/deps/v8/src/ic-inl.h +++ b/deps/v8/src/ic-inl.h @@ -39,6 +39,7 @@ Address IC::address() { // Get the address of the call. Address result = pc() - Assembler::kTargetAddrToReturnAddrDist; +#ifdef ENABLE_DEBUGGER_SUPPORT // First check if any break points are active if not just return the address // of the call. if (!Debug::has_break_points()) return result; @@ -55,6 +56,9 @@ Address IC::address() { // No break point here just return the address of the call. return result; } +#else + return result; +#endif } diff --git a/deps/v8/src/ic.cc b/deps/v8/src/ic.cc index d7bd76440..ccdf3cab4 100644 --- a/deps/v8/src/ic.cc +++ b/deps/v8/src/ic.cc @@ -42,7 +42,7 @@ static char TransitionMarkFromState(IC::State state) { switch (state) { case UNINITIALIZED: return '0'; case UNINITIALIZED_IN_LOOP: return 'L'; - case PREMONOMORPHIC: return '0'; + case PREMONOMORPHIC: return 'P'; case MONOMORPHIC: return '1'; case MONOMORPHIC_PROTOTYPE_FAILURE: return '^'; case MEGAMORPHIC: return 'N'; @@ -100,6 +100,7 @@ IC::IC(FrameDepth depth) { } +#ifdef ENABLE_DEBUGGER_SUPPORT Address IC::OriginalCodeAddress() { HandleScope scope; // Compute the JavaScript frame for the frame pointer of this IC @@ -126,7 +127,7 @@ Address IC::OriginalCodeAddress() { int delta = original_code->instruction_start() - code->instruction_start(); return addr + delta; } - +#endif IC::State IC::StateFrom(Code* target, Object* receiver) { IC::State state = target->ic_state(); @@ -236,13 +237,14 @@ void KeyedLoadIC::Clear(Address address, Code* target) { // Make sure to also clear the map used in inline fast cases. If we // do not clear these maps, cached code can keep objects alive // through the embedded maps. - PatchInlinedMapCheck(address, Heap::null_value()); + ClearInlinedVersion(address); SetTargetAtAddress(address, initialize_stub()); } void LoadIC::Clear(Address address, Code* target) { if (target->ic_state() == UNINITIALIZED) return; + ClearInlinedVersion(address); SetTargetAtAddress(address, initialize_stub()); } @@ -356,6 +358,7 @@ Object* CallIC::LoadFunction(State state, if (opt->IsJSFunction()) return opt; } +#ifdef ENABLE_DEBUGGER_SUPPORT // Handle stepping into a function if step into is active. if (Debug::StepInActive()) { // Protect the result in a handle as the debugger can allocate and might @@ -365,6 +368,7 @@ Object* CallIC::LoadFunction(State state, Debug::HandleStepIn(function, fp(), false); return *function; } +#endif return result; } @@ -520,6 +524,31 @@ Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) { LOG(SuspectReadEvent(*name, *object)); } + bool can_be_inlined = + FLAG_use_ic && + state == PREMONOMORPHIC && + lookup.IsValid() && + lookup.IsLoaded() && + lookup.IsCacheable() && + lookup.holder() == *object && + lookup.type() == FIELD && + !object->IsAccessCheckNeeded(); + + if (can_be_inlined) { + Map* map = lookup.holder()->map(); + // Property's index in the properties array. If negative we have + // an inobject property. + int index = lookup.GetFieldIndex() - map->inobject_properties(); + if (index < 0) { + // Index is an offset from the end of the object. + int offset = map->instance_size() + (index * kPointerSize); + if (PatchInlinedLoad(address(), map, offset)) { + set_target(megamorphic_stub()); + return lookup.holder()->FastPropertyAt(lookup.GetFieldIndex()); + } + } + } + // Update inline cache and stub cache. if (FLAG_use_ic && lookup.IsLoaded()) { UpdateCaches(&lookup, state, object, name); @@ -731,7 +760,7 @@ Object* KeyedLoadIC::Load(State state, !object->IsJSValue() && !JSObject::cast(*object)->HasIndexedInterceptor()) { Map* map = JSObject::cast(*object)->map(); - PatchInlinedMapCheck(address(), map); + PatchInlinedLoad(address(), map); } } diff --git a/deps/v8/src/ic.h b/deps/v8/src/ic.h index bbe1f6ddd..11fd60454 100644 --- a/deps/v8/src/ic.h +++ b/deps/v8/src/ic.h @@ -107,9 +107,11 @@ class IC { Address fp() const { return fp_; } Address pc() const { return *pc_address_; } +#ifdef ENABLE_DEBUGGER_SUPPORT // Computes the address in the original code when the code running is // containing break points (calls to DebugBreakXXX builtins). Address OriginalCodeAddress(); +#endif // Set the call-site target. void set_target(Code* code) { SetTargetAtAddress(address(), code); } @@ -214,6 +216,11 @@ class LoadIC: public IC { static void GenerateStringLength(MacroAssembler* masm); static void GenerateFunctionPrototype(MacroAssembler* masm); + // The offset from the inlined patch site to the start of the + // inlined load instruction. It is 7 bytes (test eax, imm) plus + // 6 bytes (jne slow_label). + static const int kOffsetToLoadInstruction = 13; + private: static void Generate(MacroAssembler* masm, const ExternalReference& f); @@ -236,6 +243,12 @@ class LoadIC: public IC { } static void Clear(Address address, Code* target); + + // Clear the use of the inlined version. + static void ClearInlinedVersion(Address address); + + static bool PatchInlinedLoad(Address address, Object* map, int index); + friend class IC; }; @@ -252,6 +265,9 @@ class KeyedLoadIC: public IC { static void GeneratePreMonomorphic(MacroAssembler* masm); static void GenerateGeneric(MacroAssembler* masm); + // Clear the use of the inlined version. + static void ClearInlinedVersion(Address address); + private: static void Generate(MacroAssembler* masm, const ExternalReference& f); @@ -279,7 +295,7 @@ class KeyedLoadIC: public IC { // Support for patching the map that is checked in an inlined // version of keyed load. - static void PatchInlinedMapCheck(Address address, Object* map); + static bool PatchInlinedLoad(Address address, Object* map); friend class IC; }; diff --git a/deps/v8/src/interpreter-irregexp.cc b/deps/v8/src/interpreter-irregexp.cc index 1cc5c5a1d..77bcc9074 100644 --- a/deps/v8/src/interpreter-irregexp.cc +++ b/deps/v8/src/interpreter-irregexp.cc @@ -130,13 +130,13 @@ static void TraceInterpreter(const byte* code_base, static int32_t Load32Aligned(const byte* pc) { - ASSERT((reinterpret_cast<int>(pc) & 3) == 0); + ASSERT((reinterpret_cast<intptr_t>(pc) & 3) == 0); return *reinterpret_cast<const int32_t *>(pc); } static int32_t Load16Aligned(const byte* pc) { - ASSERT((reinterpret_cast<int>(pc) & 1) == 0); + ASSERT((reinterpret_cast<intptr_t>(pc) & 1) == 0); return *reinterpret_cast<const uint16_t *>(pc); } @@ -574,7 +574,7 @@ bool IrregexpInterpreter::Match(Handle<ByteArray> code_array, AssertNoAllocation a; const byte* code_base = code_array->GetDataStartAddress(); uc16 previous_char = '\n'; - if (StringShape(*subject).IsAsciiRepresentation()) { + if (subject->IsAsciiRepresentation()) { Vector<const char> subject_vector = subject->ToAsciiVector(); if (start_position != 0) previous_char = subject_vector[start_position - 1]; return RawMatch(code_base, diff --git a/deps/v8/src/json-delay.js b/deps/v8/src/json-delay.js new file mode 100644 index 000000000..90150c6f1 --- /dev/null +++ b/deps/v8/src/json-delay.js @@ -0,0 +1,254 @@ +// Copyright 2009 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. + +var $JSON = global.JSON; + +function ParseJSONUnfiltered(text) { + var s = $String(text); + var f = %CompileString("(" + text + ")", -1, true); + return f(); +} + +function Revive(holder, name, reviver) { + var val = holder[name]; + if (IS_OBJECT(val)) { + if (IS_ARRAY(val)) { + var length = val.length; + for (var i = 0; i < length; i++) { + var newElement = Revive(val, $String(i), reviver); + val[i] = newElement; + } + } else { + for (var p in val) { + if (ObjectHasOwnProperty.call(val, p)) { + var newElement = Revive(val, p, reviver); + if (IS_UNDEFINED(newElement)) { + delete val[p]; + } else { + val[p] = newElement; + } + } + } + } + } + return reviver.call(holder, name, val); +} + +function JSONParse(text, reviver) { + var unfiltered = ParseJSONUnfiltered(text); + if (IS_FUNCTION(reviver)) { + return Revive({'': unfiltered}, '', reviver); + } else { + return unfiltered; + } +} + +var characterQuoteCache = { + '\"': '\\"', + '\\': '\\\\', + '/': '\\/', + '\b': '\\b', + '\f': '\\f', + '\n': '\\n', + '\r': '\\r', + '\t': '\\t', + '\x0B': '\\u000b' +}; + +function QuoteSingleJSONCharacter(c) { + if (c in characterQuoteCache) + return characterQuoteCache[c]; + var charCode = c.charCodeAt(0); + var result; + if (charCode < 16) result = '\\u000'; + else if (charCode < 256) result = '\\u00'; + else if (charCode < 4096) result = '\\u0'; + else result = '\\u'; + result += charCode.toString(16); + characterQuoteCache[c] = result; + return result; +} + +function QuoteJSONString(str) { + var quotable = /[\\\"\x00-\x1f\x80-\uffff]/g; + return '"' + str.replace(quotable, QuoteSingleJSONCharacter) + '"'; +} + +function StackContains(stack, val) { + var length = stack.length; + for (var i = 0; i < length; i++) { + if (stack[i] === val) + return true; + } + return false; +} + +function SerializeArray(value, replacer, stack, indent, gap) { + if (StackContains(stack, value)) + throw MakeTypeError('circular_structure', []); + stack.push(value); + var stepback = indent; + indent += gap; + var partial = []; + var len = value.length; + for (var i = 0; i < len; i++) { + var strP = JSONSerialize($String(i), value, replacer, stack, + indent, gap); + if (IS_UNDEFINED(strP)) + strP = "null"; + partial.push(strP); + } + var final; + if (gap == "") { + final = "[" + partial.join(",") + "]"; + } else if (partial.length > 0) { + var separator = ",\n" + indent; + final = "[\n" + indent + partial.join(separator) + "\n" + + stepback + "]"; + } else { + final = "[]"; + } + stack.pop(); + return final; +} + +function SerializeObject(value, replacer, stack, indent, gap) { + if (StackContains(stack, value)) + throw MakeTypeError('circular_structure', []); + stack.push(value); + var stepback = indent; + indent += gap; + var partial = []; + if (IS_ARRAY(replacer)) { + var length = replacer.length; + for (var i = 0; i < length; i++) { + if (ObjectHasOwnProperty.call(replacer, i)) { + var p = replacer[i]; + var strP = JSONSerialize(p, value, replacer, stack, indent, gap); + if (!IS_UNDEFINED(strP)) { + var member = QuoteJSONString(p) + ":"; + if (gap != "") member += " "; + member += strP; + partial.push(member); + } + } + } + } else { + for (var p in value) { + if (ObjectHasOwnProperty.call(value, p)) { + var strP = JSONSerialize(p, value, replacer, stack, indent, gap); + if (!IS_UNDEFINED(strP)) { + var member = QuoteJSONString(p) + ":"; + if (gap != "") member += " "; + member += strP; + partial.push(member); + } + } + } + } + var final; + if (gap == "") { + final = "{" + partial.join(",") + "}"; + } else if (partial.length > 0) { + var separator = ",\n" + indent; + final = "{\n" + indent + partial.join(separator) + "\n" + + stepback + "}"; + } else { + final = "{}"; + } + stack.pop(); + return final; +} + +function JSONSerialize(key, holder, replacer, stack, indent, gap) { + var value = holder[key]; + if (IS_OBJECT(value) && value) { + var toJSON = value.toJSON; + if (IS_FUNCTION(toJSON)) + value = toJSON.call(value, key); + } + if (IS_FUNCTION(replacer)) + value = replacer.call(holder, key, value); + // Unwrap value if necessary + if (IS_OBJECT(value)) { + if (IS_NUMBER_WRAPPER(value)) { + value = $Number(value); + } else if (IS_STRING_WRAPPER(value)) { + value = $String(value); + } + } + switch (typeof value) { + case "string": + return QuoteJSONString(value); + case "object": + if (!value) { + return "null"; + } else if (IS_ARRAY(value)) { + return SerializeArray(value, replacer, stack, indent, gap); + } else { + return SerializeObject(value, replacer, stack, indent, gap); + } + case "number": + return $isFinite(value) ? $String(value) : "null"; + case "boolean": + return value ? "true" : "false"; + } +} + +function JSONStringify(value, replacer, space) { + var stack = []; + var indent = ""; + if (IS_OBJECT(space)) { + // Unwrap 'space' if it is wrapped + if (IS_NUMBER_WRAPPER(space)) { + space = $Number(space); + } else if (IS_STRING_WRAPPER(space)) { + space = $String(space); + } + } + var gap; + if (IS_NUMBER(space)) { + space = $Math.min(space, 100); + gap = ""; + for (var i = 0; i < space; i++) + gap += " "; + } else if (IS_STRING(space)) { + gap = space; + } else { + gap = ""; + } + return JSONSerialize('', {'': value}, replacer, stack, indent, gap); +} + +function SetupJSON() { + InstallFunctions($JSON, DONT_ENUM, $Array( + "parse", JSONParse, + "stringify", JSONStringify + )); +} + +SetupJSON(); diff --git a/deps/v8/src/jsregexp.cc b/deps/v8/src/jsregexp.cc index 40241e6fd..ebaefc0d7 100644 --- a/deps/v8/src/jsregexp.cc +++ b/deps/v8/src/jsregexp.cc @@ -42,11 +42,14 @@ #include "regexp-macro-assembler-irregexp.h" #include "regexp-stack.h" -#ifdef ARM -#include "regexp-macro-assembler-arm.h" -#else // IA32 -#include "macro-assembler-ia32.h" -#include "regexp-macro-assembler-ia32.h" +#ifdef V8_TARGET_ARCH_IA32 +#include "ia32/macro-assembler-ia32.h" +#include "ia32/regexp-macro-assembler-ia32.h" +#elif V8_TARGET_ARCH_X64 +#include "x64/macro-assembler-x64.h" +#include "x64/regexp-macro-assembler-x64.h" +#elif V8_TARGET_ARCH_ARM +#include "arm/regexp-macro-assembler-arm.h" #endif #include "interpreter-irregexp.h" @@ -424,12 +427,10 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp, Handle<String> original_subject = subject; Handle<FixedArray> regexp(FixedArray::cast(jsregexp->data())); if (UseNativeRegexp()) { -#ifdef ARM - UNREACHABLE(); -#else +#if V8_TARGET_ARCH_IA32 RegExpMacroAssemblerIA32::Result res; do { - bool is_ascii = StringShape(*subject).IsAsciiRepresentation(); + bool is_ascii = subject->IsAsciiRepresentation(); if (!EnsureCompiledIrregexp(jsregexp, is_ascii)) { return Handle<Object>::null(); } @@ -450,9 +451,11 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp, || res == RegExpMacroAssemblerIA32::FAILURE); rc = (res == RegExpMacroAssemblerIA32::SUCCESS); +#else + UNREACHABLE(); #endif } else { - bool is_ascii = StringShape(*subject).IsAsciiRepresentation(); + bool is_ascii = subject->IsAsciiRepresentation(); if (!EnsureCompiledIrregexp(jsregexp, is_ascii)) { return Handle<Object>::null(); } @@ -2510,7 +2513,7 @@ void LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { int ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler) { int preload_characters = EatsAtLeast(4, 0); -#ifdef CAN_READ_UNALIGNED +#ifdef V8_HOST_CAN_READ_UNALIGNED bool ascii = compiler->ascii(); if (ascii) { if (preload_characters > 4) preload_characters = 4; @@ -4434,9 +4437,13 @@ RegExpEngine::CompilationResult RegExpEngine::Compile(RegExpCompileData* data, NodeInfo info = *node->info(); if (RegExpImpl::UseNativeRegexp()) { -#ifdef ARM +#ifdef V8_TARGET_ARCH_ARM UNREACHABLE(); -#else // IA32 +#endif +#ifdef V8_TARGET_ARCH_X64 + UNREACHABLE(); +#endif +#ifdef V8_TARGET_ARCH_IA32 RegExpMacroAssemblerIA32::Mode mode; if (is_ascii) { mode = RegExpMacroAssemblerIA32::ASCII; diff --git a/deps/v8/src/jsregexp.h b/deps/v8/src/jsregexp.h index e8249749f..9fa0ecef0 100644 --- a/deps/v8/src/jsregexp.h +++ b/deps/v8/src/jsregexp.h @@ -37,10 +37,10 @@ class RegExpMacroAssembler; class RegExpImpl { public: static inline bool UseNativeRegexp() { -#ifdef ARM - return false; -#else +#ifdef V8_TARGET_ARCH_IA32 return FLAG_regexp_native; +#else + return false; #endif } // Creates a regular expression literal in the old space. @@ -1003,14 +1003,14 @@ class ChoiceNode: public RegExpNode { virtual bool try_to_emit_quick_check_for_alternative(int i) { return true; } protected: - int GreedyLoopTextLength(GuardedAlternative *alternative); + int GreedyLoopTextLength(GuardedAlternative* alternative); ZoneList<GuardedAlternative>* alternatives_; private: friend class DispatchTableConstructor; friend class Analysis; void GenerateGuard(RegExpMacroAssembler* macro_assembler, - Guard *guard, + Guard* guard, Trace* trace); int CalculatePreloadCharacters(RegExpCompiler* compiler); void EmitOutOfLineContinuation(RegExpCompiler* compiler, @@ -1288,7 +1288,7 @@ FOR_EACH_NODE_TYPE(DECLARE_VISIT) void set_choice_index(int value) { choice_index_ = value; } protected: - DispatchTable *table_; + DispatchTable* table_; int choice_index_; bool ignore_case_; }; diff --git a/deps/v8/src/jump-target.cc b/deps/v8/src/jump-target.cc index 047588bdb..6e41270ee 100644 --- a/deps/v8/src/jump-target.cc +++ b/deps/v8/src/jump-target.cc @@ -189,28 +189,44 @@ void JumpTarget::ComputeEntryFrame(int mergable_elements) { } } - // Compute the registers already reserved by values in the frame. - // Count the reserved registers to avoid using them. - RegisterFile frame_registers = RegisterAllocator::Reserved(); - for (int i = 0; i < length; i++) { - FrameElement* element = elements[i]; - if (element != NULL && element->is_register()) { - frame_registers.Use(element->reg()); + // Build the new frame. A freshly allocated frame has memory elements + // for the parameters and some platform-dependent elements (e.g., + // return address). Replace those first. + entry_frame_ = new VirtualFrame(cgen_); + int index = 0; + for (; index < entry_frame_->elements_.length(); index++) { + // If the element is determined, set it now. Count registers. Mark + // elements as copied exactly when they have a copy. Undetermined + // elements are initially recorded as if in memory. + if (elements[index] != NULL) { + entry_frame_->elements_[index] = *elements[index]; + entry_frame_->elements_[index].clear_copied(); + if (elements[index]->is_register()) { + entry_frame_->register_locations_[elements[index]->reg().code()] = + index; + } else if (elements[index]->is_copy()) { + entry_frame_->elements_[elements[index]->index()].set_copied(); + } } } - - // Build the new frame. The frame already has memory elements for - // the parameters (including the receiver) and the return address. - // We will fill it up with memory elements. - entry_frame_ = new VirtualFrame(cgen_); - while (entry_frame_->elements_.length() < length) { - entry_frame_->elements_.Add(FrameElement::MemoryElement()); + // Then fill in the rest of the frame with new elements. + for (; index < length; index++) { + if (elements[index] == NULL) { + entry_frame_->elements_.Add(FrameElement::MemoryElement()); + } else { + entry_frame_->elements_.Add(*elements[index]); + entry_frame_->elements_[index].clear_copied(); + if (elements[index]->is_register()) { + entry_frame_->register_locations_[elements[index]->reg().code()] = + index; + } else if (elements[index]->is_copy()) { + entry_frame_->elements_[elements[index]->index()].set_copied(); + } + } } - - // Copy the already-determined frame elements to the entry frame, - // and allocate any still-undetermined frame elements to registers - // or memory, from the top down. + // Allocate any still-undetermined frame elements to registers or + // memory, from the top down. for (int i = length - 1; i >= 0; i--) { if (elements[i] == NULL) { // If the value is synced on all frames, put it in memory. This @@ -234,7 +250,7 @@ void JumpTarget::ComputeEntryFrame(int mergable_elements) { for (int j = 0; j < reaching_frames_.length(); j++) { FrameElement element = reaching_frames_[j]->elements_[i]; if (element.is_register() && - !frame_registers.is_used(element.reg())) { + !entry_frame_->is_used(element.reg())) { candidate_registers.Use(element.reg()); if (candidate_registers.count(element.reg()) > max_count) { max_count = candidate_registers.count(element.reg()); @@ -245,40 +261,32 @@ void JumpTarget::ComputeEntryFrame(int mergable_elements) { // If there was no preferred choice consider any free register. if (best_reg_code == no_reg.code_) { for (int j = 0; j < kNumRegisters; j++) { - if (!frame_registers.is_used(j)) { + if (!entry_frame_->is_used(j) && !RegisterAllocator::IsReserved(j)) { best_reg_code = j; break; } } } - // If there was a register choice, use it. If not do nothing - // (the element is already recorded as in memory) if (best_reg_code != no_reg.code_) { + // If there was a register choice, use it. Preserve the copied + // flag on the element. + bool is_copied = entry_frame_->elements_[i].is_copied(); Register reg = { best_reg_code }; - frame_registers.Use(reg); entry_frame_->elements_[i] = FrameElement::RegisterElement(reg, FrameElement::NOT_SYNCED); + if (is_copied) entry_frame_->elements_[i].set_copied(); + entry_frame_->register_locations_[best_reg_code] = i; } - } else { - // The element is already determined. - entry_frame_->elements_[i] = *elements[i]; + // If there was no register found, the element is already + // recorded as in memory. } } - // Set the copied flags in the frame to be exact. This assumes that - // the backing store of copies is always lower in the frame. - // Set the register locations to their index in the frame. + // Set the static type of frame elements. for (int i = 0; i < length; i++) { FrameElement* current = &entry_frame_->elements_[i]; - current->clear_copied(); - if (current->is_copy()) { - entry_frame_->elements_[current->index()].set_copied(); - } else if (current->is_register()) { - entry_frame_->register_locations_[current->reg().code()] = i; - } - if (direction_ == BIDIRECTIONAL && i >= high_water_mark) { current->set_static_type(StaticType::unknown()); } else { diff --git a/deps/v8/src/list-inl.h b/deps/v8/src/list-inl.h index 6dbd214d7..e3d251fba 100644 --- a/deps/v8/src/list-inl.h +++ b/deps/v8/src/list-inl.h @@ -1,4 +1,4 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// Copyright 2006-2009 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: @@ -38,21 +38,36 @@ void List<T, P>::Add(const T& element) { if (length_ < capacity_) { data_[length_++] = element; } else { - // Grow the list capacity by 50%, but make sure to let it grow - // even when the capacity is zero (possible initial case). - int new_capacity = 1 + capacity_ + (capacity_ >> 1); - T* new_data = NewData(new_capacity); - memcpy(new_data, data_, capacity_ * sizeof(T)); - // Since the element reference could be an element of the list, - // assign it to the new backing store before deleting the old. - new_data[length_++] = element; - DeleteData(data_); - data_ = new_data; - capacity_ = new_capacity; + List<T, P>::ResizeAdd(element); } } +// Use two layers of inlining so that the non-inlined function can +// use the same implementation as the inlined version. +template<typename T, class P> +void List<T, P>::ResizeAdd(const T& element) { + ResizeAddInternal(element); +} + + +template<typename T, class P> +void List<T, P>::ResizeAddInternal(const T& element) { + ASSERT(length_ >= capacity_); + // Grow the list capacity by 50%, but make sure to let it grow + // even when the capacity is zero (possible initial case). + int new_capacity = 1 + capacity_ + (capacity_ >> 1); + T* new_data = List<T, P>::NewData(new_capacity); + memcpy(new_data, data_, capacity_ * sizeof(T)); + // Since the element reference could be an element of the list, + // assign it to the new backing store before deleting the old. + new_data[length_++] = element; + List<T, P>::DeleteData(data_); + data_ = new_data; + capacity_ = new_capacity; +} + + template<typename T, class P> Vector<T> List<T, P>::AddBlock(T value, int count) { int start = length_; diff --git a/deps/v8/src/list.h b/deps/v8/src/list.h index dc2f1158d..92d23ea39 100644 --- a/deps/v8/src/list.h +++ b/deps/v8/src/list.h @@ -118,9 +118,24 @@ class List { INLINE(T* NewData(int n)) { return static_cast<T*>(P::New(n * sizeof(T))); } INLINE(void DeleteData(T* data)) { P::Delete(data); } + // Increase the capacity of a full list, and add an element. + // List must be full already. + void ResizeAdd(const T& element); + + // Inlined implementation of ResizeAdd, shared by inlined and + // non-inlined versions of ResizeAdd. + void ResizeAddInternal(const T& element); + DISALLOW_COPY_AND_ASSIGN(List); }; +class FrameElement; + +// Add() is inlined, ResizeAdd() called by Add() is inlined except for +// Lists of FrameElements, and ResizeAddInternal() is inlined in ResizeAdd(). +template <> +void List<FrameElement, + FreeStoreAllocationPolicy>::ResizeAdd(const FrameElement& element); } } // namespace v8::internal diff --git a/deps/v8/src/log.cc b/deps/v8/src/log.cc index d9e304d60..5297a302d 100644 --- a/deps/v8/src/log.cc +++ b/deps/v8/src/log.cc @@ -164,7 +164,7 @@ void StackTracer::Trace(TickSample* sample) { // class Ticker: public Sampler { public: - explicit Ticker(int interval, unsigned int low_stack_bound): + explicit Ticker(int interval, uintptr_t low_stack_bound): Sampler(interval, FLAG_prof), window_(NULL), profiler_(NULL), stack_tracer_(low_stack_bound) {} @@ -285,8 +285,179 @@ void Profiler::Run() { #ifdef ENABLE_LOGGING_AND_PROFILING + +// Functions and data for performing output of log messages. +class Log : public AllStatic { + public: + // Opens stdout for logging. + static void OpenStdout(); + + // Opens file for logging. + static void OpenFile(const char* name); + + // Opens memory buffer for logging. + static void OpenMemoryBuffer(); + + // Frees all resources acquired in Open... functions. + static void Close(); + + // See description in v8.h. + static int GetLogLines(int from_pos, char* dest_buf, int max_size); + + static bool is_enabled() { return output_.handle != NULL; } + + typedef int (*WritePtr)(const char* msg, int length); + private: + static void Init(); + + // Write functions assume that mutex_ is acquired by the caller. + static WritePtr Write; + + static int WriteToFile(const char* msg, int length) { + ASSERT(output_.handle != NULL); + int rv = fwrite(msg, 1, length, output_.handle); + ASSERT(length == rv); + return rv; + } + + static int WriteToMemory(const char* msg, int length) { + ASSERT(output_.buffer != NULL); + ASSERT(output_buffer_write_pos_ >= output_.buffer); + if (output_buffer_write_pos_ + length + <= output_.buffer + kOutputBufferSize) { + memcpy(output_buffer_write_pos_, msg, length); + output_buffer_write_pos_ += length; + return length; + } else { + // Memory buffer is full, ignore write. + return 0; + } + } + + // When logging is active, output_ refers the file or memory buffer + // events are written to. + // mutex_ should be acquired before using output_. + union Output { + FILE* handle; + char* buffer; + }; + static Output output_; + + // mutex_ is a Mutex used for enforcing exclusive + // access to the formatting buffer and the log file or log memory buffer. + static Mutex* mutex_; + + // Size of buffer used for memory logging. + static const int kOutputBufferSize = 2 * 1024 * 1024; + + // Writing position in a memory buffer. + static char* output_buffer_write_pos_; + + // Size of buffer used for formatting log messages. + static const int kMessageBufferSize = 2048; + + // Buffer used for formatting log messages. This is a singleton buffer and + // mutex_ should be acquired before using it. + static char* message_buffer_; + + friend class LogMessageBuilder; +}; + + +Log::WritePtr Log::Write = NULL; +Log::Output Log::output_ = {NULL}; +Mutex* Log::mutex_ = NULL; +char* Log::output_buffer_write_pos_ = NULL; +char* Log::message_buffer_ = NULL; + + +void Log::Init() { + mutex_ = OS::CreateMutex(); + message_buffer_ = NewArray<char>(kMessageBufferSize); +} + + +void Log::OpenStdout() { + ASSERT(output_.handle == NULL); + output_.handle = stdout; + Write = WriteToFile; + Init(); +} + + +void Log::OpenFile(const char* name) { + ASSERT(output_.handle == NULL); + output_.handle = OS::FOpen(name, OS::LogFileOpenMode); + Write = WriteToFile; + Init(); +} + + +void Log::OpenMemoryBuffer() { + ASSERT(output_.buffer == NULL); + output_.buffer = NewArray<char>(kOutputBufferSize); + output_buffer_write_pos_ = output_.buffer; + Write = WriteToMemory; + Init(); +} + + +void Log::Close() { + if (Write == WriteToFile) { + fclose(output_.handle); + output_.handle = NULL; + } else if (Write == WriteToMemory) { + DeleteArray(output_.buffer); + output_.buffer = NULL; + } else { + ASSERT(Write == NULL); + } + Write = NULL; + + delete mutex_; + mutex_ = NULL; + + DeleteArray(message_buffer_); + message_buffer_ = NULL; +} + + +int Log::GetLogLines(int from_pos, char* dest_buf, int max_size) { + if (Write != WriteToMemory) return 0; + ASSERT(output_.buffer != NULL); + ASSERT(output_buffer_write_pos_ >= output_.buffer); + ASSERT(from_pos >= 0); + ASSERT(max_size >= 0); + int actual_size = max_size; + char* buffer_read_pos = output_.buffer + from_pos; + ScopedLock sl(mutex_); + if (actual_size == 0 + || output_buffer_write_pos_ == output_.buffer + || buffer_read_pos >= output_buffer_write_pos_) { + // No data requested or can be returned. + return 0; + } + if (buffer_read_pos + actual_size > output_buffer_write_pos_) { + // Requested size overlaps with current writing position and + // needs to be truncated. + actual_size = output_buffer_write_pos_ - buffer_read_pos; + ASSERT(actual_size == 0 || buffer_read_pos[actual_size - 1] == '\n'); + } else { + // Find previous log line boundary. + char* end_pos = buffer_read_pos + actual_size - 1; + while (end_pos >= buffer_read_pos && *end_pos != '\n') --end_pos; + actual_size = end_pos - buffer_read_pos + 1; + } + ASSERT(actual_size <= max_size); + if (actual_size > 0) { + memcpy(dest_buf, buffer_read_pos, actual_size); + } + return actual_size; +} + + // Utility class for formatting log messages. It fills the message into the -// static buffer in Logger. +// static buffer in Log. class LogMessageBuilder BASE_EMBEDDED { public: explicit LogMessageBuilder(); @@ -309,45 +480,45 @@ class LogMessageBuilder BASE_EMBEDDED { // Create a message builder starting from position 0. This acquires the mutex // in the logger as well. -LogMessageBuilder::LogMessageBuilder(): sl(Logger::mutex_), pos_(0) { - ASSERT(Logger::message_buffer_ != NULL); +LogMessageBuilder::LogMessageBuilder(): sl(Log::mutex_), pos_(0) { + ASSERT(Log::message_buffer_ != NULL); } // Append string data to the log message. void LogMessageBuilder::Append(const char* format, ...) { - Vector<char> buf(Logger::message_buffer_ + pos_, - Logger::kMessageBufferSize - pos_); + Vector<char> buf(Log::message_buffer_ + pos_, + Log::kMessageBufferSize - pos_); va_list args; va_start(args, format); Append(format, args); va_end(args); - ASSERT(pos_ <= Logger::kMessageBufferSize); + ASSERT(pos_ <= Log::kMessageBufferSize); } // Append string data to the log message. void LogMessageBuilder::Append(const char* format, va_list args) { - Vector<char> buf(Logger::message_buffer_ + pos_, - Logger::kMessageBufferSize - pos_); + Vector<char> buf(Log::message_buffer_ + pos_, + Log::kMessageBufferSize - pos_); int result = v8::internal::OS::VSNPrintF(buf, format, args); // Result is -1 if output was truncated. if (result >= 0) { pos_ += result; } else { - pos_ = Logger::kMessageBufferSize; + pos_ = Log::kMessageBufferSize; } - ASSERT(pos_ <= Logger::kMessageBufferSize); + ASSERT(pos_ <= Log::kMessageBufferSize); } // Append a character to the log message. void LogMessageBuilder::Append(const char c) { - if (pos_ < Logger::kMessageBufferSize) { - Logger::message_buffer_[pos_++] = c; + if (pos_ < Log::kMessageBufferSize) { + Log::message_buffer_[pos_++] = c; } - ASSERT(pos_ <= Logger::kMessageBufferSize); + ASSERT(pos_ <= Log::kMessageBufferSize); } @@ -366,7 +537,7 @@ void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) { if (len > 0x1000) len = 0x1000; if (show_impl_info) { - Append(StringShape(str).IsAsciiRepresentation() ? 'a' : '2'); + Append(str->IsAsciiRepresentation() ? 'a' : '2'); if (StringShape(str).IsExternal()) Append('e'); if (StringShape(str).IsSymbol()) @@ -391,18 +562,14 @@ void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) { // Write the log message to the log file currently opened. void LogMessageBuilder::WriteToLogFile() { - ASSERT(pos_ <= Logger::kMessageBufferSize); - size_t rv = fwrite(Logger::message_buffer_, 1, pos_, Logger::logfile_); - ASSERT(rv == static_cast<size_t>(pos_)); - USE(rv); + ASSERT(pos_ <= Log::kMessageBufferSize); + Log::Write(Log::message_buffer_, pos_); } // Write a null-terminated string to to the log file currently opened. void LogMessageBuilder::WriteCStringToLogFile(const char* str) { - size_t len = strlen(str); - size_t rv = fwrite(str, 1, len, Logger::logfile_); - ASSERT(rv == len); - USE(rv); + int len = strlen(str); + Log::Write(str, len); } #endif @@ -411,20 +578,22 @@ void LogMessageBuilder::WriteCStringToLogFile(const char* str) { // Logger class implementation. // Ticker* Logger::ticker_ = NULL; -char* Logger::message_buffer_ = NULL; -FILE* Logger::logfile_ = NULL; Profiler* Logger::profiler_ = NULL; -Mutex* Logger::mutex_ = NULL; VMState* Logger::current_state_ = NULL; VMState Logger::bottom_state_(EXTERNAL); SlidingStateWindow* Logger::sliding_state_window_ = NULL; + +bool Logger::is_enabled() { + return Log::is_enabled(); +} + #endif // ENABLE_LOGGING_AND_PROFILING void Logger::Preamble(const char* content) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_code) return; + if (!Log::is_enabled() || !FLAG_log_code) return; LogMessageBuilder msg; msg.WriteCStringToLogFile(content); #endif @@ -440,7 +609,7 @@ void Logger::StringEvent(const char* name, const char* value) { #ifdef ENABLE_LOGGING_AND_PROFILING void Logger::UncheckedStringEvent(const char* name, const char* value) { - if (logfile_ == NULL) return; + if (!Log::is_enabled()) return; LogMessageBuilder msg; msg.Append("%s,\"%s\"\n", name, value); msg.WriteToLogFile(); @@ -450,7 +619,7 @@ void Logger::UncheckedStringEvent(const char* name, const char* value) { void Logger::IntEvent(const char* name, int value) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log) return; + if (!Log::is_enabled() || !FLAG_log) return; LogMessageBuilder msg; msg.Append("%s,%d\n", name, value); msg.WriteToLogFile(); @@ -460,10 +629,9 @@ void Logger::IntEvent(const char* name, int value) { void Logger::HandleEvent(const char* name, Object** location) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_handles) return; + if (!Log::is_enabled() || !FLAG_log_handles) return; LogMessageBuilder msg; - msg.Append("%s,0x%x\n", name, - reinterpret_cast<unsigned int>(location)); + msg.Append("%s,0x%%"V8PRIp"\n", name, location); msg.WriteToLogFile(); #endif } @@ -471,10 +639,10 @@ void Logger::HandleEvent(const char* name, Object** location) { #ifdef ENABLE_LOGGING_AND_PROFILING // ApiEvent is private so all the calls come from the Logger class. It is the -// caller's responsibility to ensure that logfile_ is not NULL and that +// caller's responsibility to ensure that log is enabled and that // FLAG_log_api is true. void Logger::ApiEvent(const char* format, ...) { - ASSERT(logfile_ != NULL && FLAG_log_api); + ASSERT(Log::is_enabled() && FLAG_log_api); LogMessageBuilder msg; va_list ap; va_start(ap, format); @@ -487,7 +655,7 @@ void Logger::ApiEvent(const char* format, ...) { void Logger::ApiNamedSecurityCheck(Object* key) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_api) return; + if (!Log::is_enabled() || !FLAG_log_api) return; if (key->IsString()) { SmartPointer<char> str = String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); @@ -505,7 +673,7 @@ void Logger::SharedLibraryEvent(const char* library_path, unsigned start, unsigned end) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_prof) return; + if (!Log::is_enabled() || !FLAG_prof) return; LogMessageBuilder msg; msg.Append("shared-library,\"%s\",0x%08x,0x%08x\n", library_path, start, end); @@ -518,7 +686,7 @@ void Logger::SharedLibraryEvent(const wchar_t* library_path, unsigned start, unsigned end) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_prof) return; + if (!Log::is_enabled() || !FLAG_prof) return; LogMessageBuilder msg; msg.Append("shared-library,\"%ls\",0x%08x,0x%08x\n", library_path, start, end); @@ -573,7 +741,7 @@ void Logger::LogRegExpSource(Handle<JSRegExp> regexp) { void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_regexp) return; + if (!Log::is_enabled() || !FLAG_log_regexp) return; LogMessageBuilder msg; msg.Append("regexp-compile,"); LogRegExpSource(regexp); @@ -585,7 +753,7 @@ void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) { void Logger::LogRuntime(Vector<const char> format, JSArray* args) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_runtime) return; + if (!Log::is_enabled() || !FLAG_log_runtime) return; HandleScope scope; LogMessageBuilder msg; for (int i = 0; i < format.length(); i++) { @@ -626,7 +794,7 @@ void Logger::LogRuntime(Vector<const char> format, JSArray* args) { void Logger::ApiIndexedSecurityCheck(uint32_t index) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_api) return; + if (!Log::is_enabled() || !FLAG_log_api) return; ApiEvent("api,check-security,%u\n", index); #endif } @@ -637,7 +805,7 @@ void Logger::ApiNamedPropertyAccess(const char* tag, Object* name) { #ifdef ENABLE_LOGGING_AND_PROFILING ASSERT(name->IsString()); - if (logfile_ == NULL || !FLAG_log_api) return; + if (!Log::is_enabled() || !FLAG_log_api) return; String* class_name_obj = holder->class_name(); SmartPointer<char> class_name = class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); @@ -651,7 +819,7 @@ void Logger::ApiIndexedPropertyAccess(const char* tag, JSObject* holder, uint32_t index) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_api) return; + if (!Log::is_enabled() || !FLAG_log_api) return; String* class_name_obj = holder->class_name(); SmartPointer<char> class_name = class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); @@ -661,7 +829,7 @@ void Logger::ApiIndexedPropertyAccess(const char* tag, void Logger::ApiObjectAccess(const char* tag, JSObject* object) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_api) return; + if (!Log::is_enabled() || !FLAG_log_api) return; String* class_name_obj = object->class_name(); SmartPointer<char> class_name = class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); @@ -672,7 +840,7 @@ void Logger::ApiObjectAccess(const char* tag, JSObject* object) { void Logger::ApiEntryCall(const char* name) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_api) return; + if (!Log::is_enabled() || !FLAG_log_api) return; Logger::ApiEvent("api,%s\n", name); #endif } @@ -680,10 +848,9 @@ void Logger::ApiEntryCall(const char* name) { void Logger::NewEvent(const char* name, void* object, size_t size) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log) return; + if (!Log::is_enabled() || !FLAG_log) return; LogMessageBuilder msg; - msg.Append("new,%s,0x%x,%u\n", name, - reinterpret_cast<unsigned int>(object), + msg.Append("new,%s,0x%%"V8PRIp",%u\n", name, object, static_cast<unsigned int>(size)); msg.WriteToLogFile(); #endif @@ -692,10 +859,9 @@ void Logger::NewEvent(const char* name, void* object, size_t size) { void Logger::DeleteEvent(const char* name, void* object) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log) return; + if (!Log::is_enabled() || !FLAG_log) return; LogMessageBuilder msg; - msg.Append("delete,%s,0x%x\n", name, - reinterpret_cast<unsigned int>(object)); + msg.Append("delete,%s,0x%%"V8PRIp"\n", name, object); msg.WriteToLogFile(); #endif } @@ -703,10 +869,9 @@ void Logger::DeleteEvent(const char* name, void* object) { void Logger::CodeCreateEvent(const char* tag, Code* code, const char* comment) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_code) return; + if (!Log::is_enabled() || !FLAG_log_code) return; LogMessageBuilder msg; - msg.Append("code-creation,%s,0x%x,%d,\"", tag, - reinterpret_cast<unsigned int>(code->address()), + msg.Append("code-creation,%s,0x%"V8PRIp",%d,\"", tag, code->address(), code->ExecutableSize()); for (const char* p = comment; *p != '\0'; p++) { if (*p == '"') { @@ -723,12 +888,11 @@ void Logger::CodeCreateEvent(const char* tag, Code* code, const char* comment) { void Logger::CodeCreateEvent(const char* tag, Code* code, String* name) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_code) return; + if (!Log::is_enabled() || !FLAG_log_code) return; LogMessageBuilder msg; SmartPointer<char> str = name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); - msg.Append("code-creation,%s,0x%x,%d,\"%s\"\n", tag, - reinterpret_cast<unsigned int>(code->address()), + msg.Append("code-creation,%s,0x%"V8PRIp",%d,\"%s\"\n", tag, code->address(), code->ExecutableSize(), *str); msg.WriteToLogFile(); #endif @@ -738,14 +902,14 @@ void Logger::CodeCreateEvent(const char* tag, Code* code, String* name) { void Logger::CodeCreateEvent(const char* tag, Code* code, String* name, String* source, int line) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_code) return; + if (!Log::is_enabled() || !FLAG_log_code) return; LogMessageBuilder msg; SmartPointer<char> str = name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); SmartPointer<char> sourcestr = source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); - msg.Append("code-creation,%s,0x%x,%d,\"%s %s:%d\"\n", tag, - reinterpret_cast<unsigned int>(code->address()), + msg.Append("code-creation,%s,0x%"V8PRIp",%d,\"%s %s:%d\"\n", + tag, code->address(), code->ExecutableSize(), *str, *sourcestr, line); msg.WriteToLogFile(); @@ -755,10 +919,10 @@ void Logger::CodeCreateEvent(const char* tag, Code* code, String* name, void Logger::CodeCreateEvent(const char* tag, Code* code, int args_count) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_code) return; + if (!Log::is_enabled() || !FLAG_log_code) return; LogMessageBuilder msg; - msg.Append("code-creation,%s,0x%x,%d,\"args_count: %d\"\n", tag, - reinterpret_cast<unsigned int>(code->address()), + msg.Append("code-creation,%s,0x%"V8PRIp",%d,\"args_count: %d\"\n", tag, + code->address(), code->ExecutableSize(), args_count); msg.WriteToLogFile(); @@ -768,10 +932,10 @@ void Logger::CodeCreateEvent(const char* tag, Code* code, int args_count) { void Logger::RegExpCodeCreateEvent(Code* code, String* source) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_code) return; + if (!Log::is_enabled() || !FLAG_log_code) return; LogMessageBuilder msg; - msg.Append("code-creation,%s,0x%x,%d,\"", "RegExp", - reinterpret_cast<unsigned int>(code->address()), + msg.Append("code-creation,%s,0x%"V8PRIp",%d,\"", "RegExp", + code->address(), code->ExecutableSize()); msg.AppendDetailed(source, false); msg.Append("\"\n"); @@ -782,11 +946,9 @@ void Logger::RegExpCodeCreateEvent(Code* code, String* source) { void Logger::CodeAllocateEvent(Code* code, Assembler* assem) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_code) return; + if (!Log::is_enabled() || !FLAG_log_code) return; LogMessageBuilder msg; - msg.Append("code-allocate,0x%x,0x%x\n", - reinterpret_cast<unsigned int>(code->address()), - reinterpret_cast<unsigned int>(assem)); + msg.Append("code-allocate,0x%"V8PRIp",0x%"V8PRIp"\n", code->address(), assem); msg.WriteToLogFile(); #endif } @@ -794,11 +956,9 @@ void Logger::CodeAllocateEvent(Code* code, Assembler* assem) { void Logger::CodeMoveEvent(Address from, Address to) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_code) return; + if (!Log::is_enabled() || !FLAG_log_code) return; LogMessageBuilder msg; - msg.Append("code-move,0x%x,0x%x\n", - reinterpret_cast<unsigned int>(from), - reinterpret_cast<unsigned int>(to)); + msg.Append("code-move,0x%"V8PRIp",0x%"V8PRIp"\n", from, to); msg.WriteToLogFile(); #endif } @@ -806,38 +966,9 @@ void Logger::CodeMoveEvent(Address from, Address to) { void Logger::CodeDeleteEvent(Address from) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_code) return; + if (!Log::is_enabled() || !FLAG_log_code) return; LogMessageBuilder msg; - msg.Append("code-delete,0x%x\n", reinterpret_cast<unsigned int>(from)); - msg.WriteToLogFile(); -#endif -} - - -void Logger::BeginCodeRegionEvent(CodeRegion* region, - Assembler* masm, - const char* name) { -#ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_code) return; - LogMessageBuilder msg; - msg.Append("begin-code-region,0x%x,0x%x,0x%x,%s\n", - reinterpret_cast<unsigned int>(region), - reinterpret_cast<unsigned int>(masm), - masm->pc_offset(), - name); - msg.WriteToLogFile(); -#endif -} - - -void Logger::EndCodeRegionEvent(CodeRegion* region, Assembler* masm) { -#ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_code) return; - LogMessageBuilder msg; - msg.Append("end-code-region,0x%x,0x%x,0x%x\n", - reinterpret_cast<unsigned int>(region), - reinterpret_cast<unsigned int>(masm), - masm->pc_offset()); + msg.Append("code-delete,0x%"V8PRIp"\n", from); msg.WriteToLogFile(); #endif } @@ -845,7 +976,7 @@ void Logger::EndCodeRegionEvent(CodeRegion* region, Assembler* masm) { void Logger::ResourceEvent(const char* name, const char* tag) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log) return; + if (!Log::is_enabled() || !FLAG_log) return; LogMessageBuilder msg; msg.Append("%s,%s,", name, tag); @@ -863,12 +994,11 @@ void Logger::ResourceEvent(const char* name, const char* tag) { void Logger::SuspectReadEvent(String* name, Object* obj) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_suspect) return; + if (!Log::is_enabled() || !FLAG_log_suspect) return; LogMessageBuilder msg; String* class_name = obj->IsJSObject() ? JSObject::cast(obj)->class_name() : Heap::empty_string(); - ScopedLock sl(mutex_); msg.Append("suspect-read,"); msg.Append(class_name); msg.Append(','); @@ -883,7 +1013,7 @@ void Logger::SuspectReadEvent(String* name, Object* obj) { void Logger::HeapSampleBeginEvent(const char* space, const char* kind) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_gc) return; + if (!Log::is_enabled() || !FLAG_log_gc) return; LogMessageBuilder msg; msg.Append("heap-sample-begin,\"%s\",\"%s\"\n", space, kind); msg.WriteToLogFile(); @@ -893,7 +1023,7 @@ void Logger::HeapSampleBeginEvent(const char* space, const char* kind) { void Logger::HeapSampleEndEvent(const char* space, const char* kind) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_gc) return; + if (!Log::is_enabled() || !FLAG_log_gc) return; LogMessageBuilder msg; msg.Append("heap-sample-end,\"%s\",\"%s\"\n", space, kind); msg.WriteToLogFile(); @@ -903,7 +1033,7 @@ void Logger::HeapSampleEndEvent(const char* space, const char* kind) { void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log_gc) return; + if (!Log::is_enabled() || !FLAG_log_gc) return; LogMessageBuilder msg; msg.Append("heap-sample-item,%s,%d,%d\n", type, number, bytes); msg.WriteToLogFile(); @@ -913,7 +1043,7 @@ void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) { void Logger::DebugTag(const char* call_site_tag) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log) return; + if (!Log::is_enabled() || !FLAG_log) return; LogMessageBuilder msg; msg.Append("debug-tag,%s\n", call_site_tag); msg.WriteToLogFile(); @@ -923,7 +1053,7 @@ void Logger::DebugTag(const char* call_site_tag) { void Logger::DebugEvent(const char* event_type, Vector<uint16_t> parameter) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL || !FLAG_log) return; + if (!Log::is_enabled() || !FLAG_log) return; StringBuilder s(parameter.length() + 1); for (int i = 0; i < parameter.length(); ++i) { s.AddCharacter(static_cast<char>(parameter[i])); @@ -942,15 +1072,15 @@ void Logger::DebugEvent(const char* event_type, Vector<uint16_t> parameter) { #ifdef ENABLE_LOGGING_AND_PROFILING void Logger::TickEvent(TickSample* sample, bool overflow) { - if (logfile_ == NULL || !FLAG_prof) return; + if (!Log::is_enabled() || !FLAG_prof) return; LogMessageBuilder msg; - msg.Append("tick,0x%x,0x%x,%d", sample->pc, sample->sp, + msg.Append("tick,0x%"V8PRIp",0x%"V8PRIp",%d", sample->pc, sample->sp, static_cast<int>(sample->state)); if (overflow) { msg.Append(",overflow"); } for (int i = 0; i < sample->frames_count; ++i) { - msg.Append(",0x%x", reinterpret_cast<uint32_t>(sample->stack[i])); + msg.Append(",0x%"V8PRIp, sample->stack[i]); } msg.Append('\n'); msg.WriteToLogFile(); @@ -970,6 +1100,12 @@ void Logger::PauseProfiler() { void Logger::ResumeProfiler() { profiler_->resume(); } + + +int Logger::GetLogLines(int from_pos, char* dest_buf, int max_size) { + return Log::GetLogLines(from_pos, dest_buf, max_size); +} + #endif @@ -996,7 +1132,9 @@ bool Logger::Setup() { // If we're logging anything, we need to open the log file. if (open_log_file) { if (strcmp(FLAG_logfile, "-") == 0) { - logfile_ = stdout; + Log::OpenStdout(); + } else if (strcmp(FLAG_logfile, "*") == 0) { + Log::OpenMemoryBuffer(); } else if (strchr(FLAG_logfile, '%') != NULL) { // If there's a '%' in the log file name we have to expand // placeholders. @@ -1032,12 +1170,10 @@ bool Logger::Setup() { } } SmartPointer<const char> expanded = stream.ToCString(); - logfile_ = OS::FOpen(*expanded, OS::LogFileOpenMode); + Log::OpenFile(*expanded); } else { - logfile_ = OS::FOpen(FLAG_logfile, OS::LogFileOpenMode); + Log::OpenFile(FLAG_logfile); } - message_buffer_ = NewArray<char>(kMessageBufferSize); - mutex_ = OS::CreateMutex(); } current_state_ = &bottom_state_; @@ -1045,7 +1181,7 @@ bool Logger::Setup() { // as log is initialized early with V8, we can assume that JS execution // frames can never reach this point on stack int stack_var; - ticker_ = new Ticker(1, reinterpret_cast<unsigned int>(&stack_var)); + ticker_ = new Ticker(1, reinterpret_cast<uintptr_t>(&stack_var)); if (FLAG_sliding_state_window && sliding_state_window_ == NULL) { sliding_state_window_ = new SlidingStateWindow(); @@ -1079,13 +1215,7 @@ void Logger::TearDown() { delete ticker_; - if (logfile_ != NULL) { - fclose(logfile_); - logfile_ = NULL; - delete mutex_; - mutex_ = NULL; - DeleteArray(message_buffer_); - } + Log::Close(); #endif } diff --git a/deps/v8/src/log.h b/deps/v8/src/log.h index bbcfa42c6..5f3c188c5 100644 --- a/deps/v8/src/log.h +++ b/deps/v8/src/log.h @@ -103,10 +103,10 @@ class VMState BASE_EMBEDDED { class Logger { public: - // Opens the file for logging if the right flags are set. + // Acquires resources for logging if the right flags are set. static bool Setup(); - // Closes file opened in Setup. + // Frees resources acquired in Setup. static void TearDown(); // Enable the computation of a sliding window of states. @@ -174,11 +174,6 @@ class Logger { static void CodeMoveEvent(Address from, Address to); // Emits a code delete event. static void CodeDeleteEvent(Address from); - // Emits region delimiters - static void BeginCodeRegionEvent(CodeRegion* region, - Assembler* masm, - const char* name); - static void EndCodeRegionEvent(CodeRegion* region, Assembler* masm); // ==== Events logged by --log-gc. ==== // Heap sampling events: start, end, and individual types. @@ -206,7 +201,7 @@ class Logger { return current_state_ ? current_state_->state() : OTHER; } - static bool is_enabled() { return logfile_ != NULL; } + static bool is_enabled(); // Pause/Resume collection of profiling data. // When data collection is paused, Tick events are discarded until @@ -215,6 +210,10 @@ class Logger { static void PauseProfiler(); static void ResumeProfiler(); + // If logging is performed into a memory buffer, allows to + // retrieve previously written messages. See v8.h. + static int GetLogLines(int from_pos, char* dest_buf, int max_size); + private: // Emits the source code of a regexp. Used by regexp events. @@ -228,17 +227,6 @@ class Logger { // Logs a StringEvent regardless of whether FLAG_log is true. static void UncheckedStringEvent(const char* name, const char* value); - // Size of buffer used for formatting log messages. - static const int kMessageBufferSize = 2048; - - // Buffer used for formatting log messages. This is a singleton buffer and - // mutex_ should be acquired before using it. - static char* message_buffer_; - - // When logging is active, logfile_ refers the file events are written to. - // mutex_ should be acquired before using logfile_. - static FILE* logfile_; - // The sampler used by the profiler and the sliding state window. static Ticker* ticker_; @@ -247,10 +235,6 @@ class Logger { // of samples. static Profiler* profiler_; - // mutex_ is a Mutex used for enforcing exclusive - // access to the formatting buffer and the log file. - static Mutex* mutex_; - // A stack of VM states. static VMState* current_state_; @@ -263,7 +247,6 @@ class Logger { // Internal implementation classes with access to // private members. - friend class LogMessageBuilder; friend class EventLog; friend class TimeLog; friend class Profiler; @@ -278,12 +261,12 @@ class Logger { // Class that extracts stack trace, used for profiling. class StackTracer BASE_EMBEDDED { public: - explicit StackTracer(unsigned int low_stack_bound) + explicit StackTracer(uintptr_t low_stack_bound) : low_stack_bound_(low_stack_bound) { } void Trace(TickSample* sample); private: - unsigned int low_stack_bound_; + uintptr_t low_stack_bound_; }; diff --git a/deps/v8/src/macro-assembler.h b/deps/v8/src/macro-assembler.h index 84a1eef39..116381bb3 100644 --- a/deps/v8/src/macro-assembler.h +++ b/deps/v8/src/macro-assembler.h @@ -28,23 +28,25 @@ #ifndef V8_MACRO_ASSEMBLER_H_ #define V8_MACRO_ASSEMBLER_H_ -#ifdef ARM - -#include "constants-arm.h" +#if V8_TARGET_ARCH_IA32 #include "assembler.h" -#include "assembler-arm.h" -#include "assembler-arm-inl.h" +#include "ia32/assembler-ia32.h" +#include "ia32/assembler-ia32-inl.h" #include "code.h" // must be after assembler_*.h -#include "macro-assembler-arm.h" - -#else // ia32 - +#include "ia32/macro-assembler-ia32.h" +#elif V8_TARGET_ARCH_X64 #include "assembler.h" -#include "assembler-ia32.h" -#include "assembler-ia32-inl.h" +#include "x64/assembler-x64.h" +#include "x64/assembler-x64-inl.h" #include "code.h" // must be after assembler_*.h -#include "macro-assembler-ia32.h" - +#include "x64/macro-assembler-x64.h" +#elif V8_TARGET_ARCH_ARM +#include "arm/constants-arm.h" +#include "assembler.h" +#include "arm/assembler-arm.h" +#include "arm/assembler-arm-inl.h" +#include "code.h" // must be after assembler_*.h +#include "arm/macro-assembler-arm.h" #endif #endif // V8_MACRO_ASSEMBLER_H_ diff --git a/deps/v8/src/macros.py b/deps/v8/src/macros.py index d78ecd94d..ebfd816a0 100644 --- a/deps/v8/src/macros.py +++ b/deps/v8/src/macros.py @@ -84,6 +84,8 @@ macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean'); macro IS_REGEXP(arg) = %HasRegExpClass(arg); macro IS_ARRAY(arg) = %HasArrayClass(arg); macro IS_DATE(arg) = %HasDateClass(arg); +macro IS_NUMBER_WRAPPER(arg) = %HasNumberClass(arg); +macro IS_STRING_WRAPPER(arg) = %HasStringClass(arg); macro IS_ERROR(arg) = (%ClassOf(arg) === 'Error'); macro IS_SCRIPT(arg) = (%ClassOf(arg) === 'Script'); macro FLOOR(arg) = %Math_floor(arg); diff --git a/deps/v8/src/mark-compact.cc b/deps/v8/src/mark-compact.cc index c55345dc1..48774ec5b 100644 --- a/deps/v8/src/mark-compact.cc +++ b/deps/v8/src/mark-compact.cc @@ -555,25 +555,62 @@ static void ScanOverflowedObjects(T* it) { } -bool MarkCompactCollector::MustBeMarked(Object** p) { - // Check whether *p is a HeapObject pointer. - if (!(*p)->IsHeapObject()) return false; - return !HeapObject::cast(*p)->IsMarked(); +bool MarkCompactCollector::IsUnmarkedHeapObject(Object** p) { + return (*p)->IsHeapObject() && !HeapObject::cast(*p)->IsMarked(); } -void MarkCompactCollector::ProcessRoots(RootMarkingVisitor* visitor) { - // Mark the heap roots gray, including global variables, stack variables, - // etc. - Heap::IterateStrongRoots(visitor); +class SymbolMarkingVisitor : public ObjectVisitor { + public: + void VisitPointers(Object** start, Object** end) { + MarkingVisitor marker; + for (Object** p = start; p < end; p++) { + if (!(*p)->IsHeapObject()) continue; - // Take care of the symbol table specially. + HeapObject* object = HeapObject::cast(*p); + // If the object is marked, we have marked or are in the process + // of marking subparts. + if (object->IsMarked()) continue; + + // The object is unmarked, we do not need to unmark to use its + // map. + Map* map = object->map(); + object->IterateBody(map->instance_type(), + object->SizeFromMap(map), + &marker); + } + } +}; + + +void MarkCompactCollector::MarkSymbolTable() { + // Objects reachable from symbols are marked as live so as to ensure + // that if the symbol itself remains alive after GC for any reason, + // and if it is a sliced string or a cons string backed by an + // external string (even indirectly), then the external string does + // not receive a weak reference callback. SymbolTable* symbol_table = SymbolTable::cast(Heap::symbol_table()); - // 1. Mark the prefix of the symbol table gray. - symbol_table->IteratePrefix(visitor); - // 2. Mark the symbol table black (ie, do not push it on the marking stack - // or mark it overflowed). + // Mark the symbol table itself. SetMark(symbol_table); + // Explicitly mark the prefix. + MarkingVisitor marker; + symbol_table->IteratePrefix(&marker); + ProcessMarkingStack(&marker); + // Mark subparts of the symbols but not the symbols themselves + // (unless reachable from another symbol). + SymbolMarkingVisitor symbol_marker; + symbol_table->IterateElements(&symbol_marker); + ProcessMarkingStack(&marker); +} + + +void MarkCompactCollector::MarkRoots(RootMarkingVisitor* visitor) { + // Mark the heap roots including global variables, stack variables, + // etc., and all objects reachable from them. + Heap::IterateStrongRoots(visitor); + + // Handle the symbol table specially. + MarkSymbolTable(); // There may be overflowed objects in the heap. Visit them now. while (marking_stack.overflowed()) { @@ -715,21 +752,22 @@ void MarkCompactCollector::MarkLiveObjects() { ASSERT(!marking_stack.overflowed()); RootMarkingVisitor root_visitor; - ProcessRoots(&root_visitor); + MarkRoots(&root_visitor); - // The objects reachable from the roots are marked black, unreachable - // objects are white. Mark objects reachable from object groups with at - // least one marked object, and continue until no new objects are - // reachable from the object groups. + // The objects reachable from the roots are marked, yet unreachable + // objects are unmarked. Mark objects reachable from object groups + // containing at least one marked object, and continue until no new + // objects are reachable from the object groups. ProcessObjectGroups(root_visitor.stack_visitor()); - // The objects reachable from the roots or object groups are marked black, - // unreachable objects are white. Process objects reachable only from - // weak global handles. + // The objects reachable from the roots or object groups are marked, + // yet unreachable objects are unmarked. Mark objects reachable + // only from weak global handles. // - // First we mark weak pointers not yet reachable. - GlobalHandles::MarkWeakRoots(&MustBeMarked); - // Then we process weak pointers and process the transitive closure. + // First we identify nonlive weak handles and mark them as pending + // destruction. + GlobalHandles::IdentifyWeakHandles(&IsUnmarkedHeapObject); + // Then we mark the objects and process the transitive closure. GlobalHandles::IterateWeakRoots(&root_visitor); while (marking_stack.overflowed()) { RefillMarkingStack(); diff --git a/deps/v8/src/mark-compact.h b/deps/v8/src/mark-compact.h index 9a92ade5f..bfa2c3ce5 100644 --- a/deps/v8/src/mark-compact.h +++ b/deps/v8/src/mark-compact.h @@ -172,7 +172,11 @@ class MarkCompactCollector: public AllStatic { static void MarkDescriptorArray(DescriptorArray* descriptors); // Mark the heap roots and all objects reachable from them. - static void ProcessRoots(RootMarkingVisitor* visitor); + static void MarkRoots(RootMarkingVisitor* visitor); + + // Mark the symbol table specially. References to symbols from the + // symbol table are weak. + static void MarkSymbolTable(); // Mark objects in object groups that have at least one object in the // group marked. @@ -198,8 +202,9 @@ class MarkCompactCollector: public AllStatic { // flag on the marking stack. static void RefillMarkingStack(); - // Callback function for telling whether the object *p must be marked. - static bool MustBeMarked(Object** p); + // Callback function for telling whether the object *p is an unmarked + // heap object. + static bool IsUnmarkedHeapObject(Object** p); #ifdef DEBUG static void UpdateLiveObjectCount(HeapObject* obj); diff --git a/deps/v8/src/math.js b/deps/v8/src/math.js index 5b7c396cd..86d6dd101 100644 --- a/deps/v8/src/math.js +++ b/deps/v8/src/math.js @@ -164,7 +164,7 @@ function SetupMath() { // Setup non-enumerable functions of the Math object and // set their names. - InstallFunctions($Math, DONT_ENUM, $Array( + InstallFunctionsOnHiddenPrototype($Math, DONT_ENUM, $Array( "random", MathRandom, "abs", MathAbs, "acos", MathAcos, diff --git a/deps/v8/src/messages.js b/deps/v8/src/messages.js index cd9a1e8d6..df8a2d1d7 100644 --- a/deps/v8/src/messages.js +++ b/deps/v8/src/messages.js @@ -98,6 +98,7 @@ const kMessages = { instanceof_function_expected: "Expecting a function in instanceof check, but got %0", instanceof_nonobject_proto: "Function has non-object prototype '%0' in instanceof check", null_to_object: "Cannot convert null to object", + reduce_no_initial: "Reduce of empty array with no initial value", // RangeError invalid_array_length: "Invalid array length", invalid_array_apply_length: "Function.prototype.apply supports only up to 1024 arguments", @@ -113,6 +114,9 @@ const kMessages = { illegal_return: "Illegal return statement", error_loading_debugger: "Error loading debugger %0", no_input_to_regexp: "No input to %0", + result_not_primitive: "Result of %0 must be a primitive, was %1", + invalid_json: "String '%0' is not valid JSON", + circular_structure: "Converting circular structure to JSON" }; diff --git a/deps/v8/src/mirror-delay.js b/deps/v8/src/mirror-delay.js index 9c9d713da..30f19f0a0 100644 --- a/deps/v8/src/mirror-delay.js +++ b/deps/v8/src/mirror-delay.js @@ -155,6 +155,7 @@ const ERROR_TYPE = 'error'; const PROPERTY_TYPE = 'property'; const FRAME_TYPE = 'frame'; const SCRIPT_TYPE = 'script'; +const CONTEXT_TYPE = 'context'; // Maximum length when sending strings through the JSON protocol. const kMaxProtocolStringLength = 80; @@ -364,6 +365,15 @@ Mirror.prototype.isScript = function() { /** + * Check whether the mirror reflects a context. + * @returns {boolean} True if the mirror reflects a context + */ +Mirror.prototype.isContext = function() { + return this instanceof ContextMirror; +} + + +/** * Allocate a handle id for this object. */ Mirror.prototype.allocateHandle_ = function() { @@ -756,6 +766,15 @@ FunctionMirror.prototype.name = function() { /** + * Returns the inferred name of the function. + * @return {string} Name of the function + */ +FunctionMirror.prototype.inferredName = function() { + return %FunctionGetInferredName(this.value_); +}; + + +/** * Returns the source code for the function. * @return {string or undefined} The source code for the function. If the * function is not resolved undefined will be returned. @@ -857,6 +876,11 @@ UnresolvedFunctionMirror.prototype.name = function() { }; +UnresolvedFunctionMirror.prototype.inferredName = function() { + return undefined; +}; + + UnresolvedFunctionMirror.prototype.propertyNames = function(kind, limit) { return []; } @@ -1547,6 +1571,7 @@ FrameMirror.prototype.toText = function(opt_locals) { function ScriptMirror(script) { Mirror.call(this, SCRIPT_TYPE); this.script_ = script; + this.context_ = new ContextMirror(script.context_data); this.allocateHandle_(); } inherits(ScriptMirror, Mirror); @@ -1582,6 +1607,11 @@ ScriptMirror.prototype.columnOffset = function() { }; +ScriptMirror.prototype.data = function() { + return this.script_.data; +}; + + ScriptMirror.prototype.scriptType = function() { return this.script_.type; }; @@ -1603,6 +1633,11 @@ ScriptMirror.prototype.sourceSlice = function (opt_from_line, opt_to_line) { } +ScriptMirror.prototype.context = function() { + return this.context_; +}; + + ScriptMirror.prototype.toText = function() { var result = ''; result += this.name(); @@ -1620,13 +1655,35 @@ ScriptMirror.prototype.toText = function() { /** + * Mirror object for context. + * @param {Object} data The context data + * @constructor + * @extends Mirror + */ +function ContextMirror(data) { + Mirror.call(this, CONTEXT_TYPE); + this.data_ = data; + this.allocateHandle_(); +} +inherits(ContextMirror, Mirror); + + +ContextMirror.prototype.data = function() { + return this.data_; +}; + + +/** * Returns a mirror serializer * * @param {boolean} details Set to true to include details + * @param {Object} options Options comtrolling the serialization + * The following options can be set: + * includeSource: include ths full source of scripts * @returns {MirrorSerializer} mirror serializer */ -function MakeMirrorSerializer(details) { - return new JSONProtocolSerializer(details); +function MakeMirrorSerializer(details, options) { + return new JSONProtocolSerializer(details, options); } @@ -1636,8 +1693,9 @@ function MakeMirrorSerializer(details) { * serialized * @constructor */ -function JSONProtocolSerializer(details) { +function JSONProtocolSerializer(details, options) { this.details_ = details; + this.options_ = options; this.mirrors_ = [ ]; } @@ -1689,6 +1747,11 @@ JSONProtocolSerializer.prototype.serializeReferencedObjects = function() { } +JSONProtocolSerializer.prototype.includeSource_ = function() { + return this.options_ && this.options_.includeSource; +} + + JSONProtocolSerializer.prototype.add_ = function(mirror) { // If this mirror is already in the list just return. for (var i = 0; i < this.mirrors_.length; i++) { @@ -1707,7 +1770,7 @@ JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference, // If serializing a reference to a mirror just return the reference and add // the mirror to the referenced mirrors. if (reference && - (mirror.isValue() || mirror.isScript())) { + (mirror.isValue() || mirror.isScript() || mirror.isContext())) { this.add_(mirror); return '{"ref":' + mirror.handle() + '}'; } @@ -1716,7 +1779,7 @@ JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference, var content = new Array(); // Add the mirror handle. - if (mirror.isValue() || mirror.isScript()) { + if (mirror.isValue() || mirror.isScript() || mirror.isContext()) { content.push(MakeJSONPair_('handle', NumberToJSON_(mirror.handle()))); } @@ -1782,8 +1845,29 @@ JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference, NumberToJSON_(mirror.columnOffset()))); content.push(MakeJSONPair_('lineCount', NumberToJSON_(mirror.lineCount()))); + if (mirror.data()) { + content.push(MakeJSONPair_('data', JSON.stringify(mirror.data()))); + } + if (this.includeSource_()) { + content.push(MakeJSONPair_('source', + StringToJSON_(mirror.source()))); + } else { + var sourceStart = mirror.source().substring(0, 80); + content.push(MakeJSONPair_('sourceStart', + StringToJSON_(sourceStart))); + } + content.push(MakeJSONPair_('sourceLength', + NumberToJSON_(mirror.source().length))); content.push(MakeJSONPair_('scriptType', NumberToJSON_(mirror.scriptType()))); + if (mirror.context()) { + content.push(MakeJSONPair_('context', + this.serializeReference(mirror.context()))); + } + break; + + case CONTEXT_TYPE: + content.push(MakeJSONPair_('data', JSON.stringify(mirror.data()))); break; } @@ -1830,6 +1914,10 @@ JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content, if (mirror.isFunction()) { // Add function specific properties. content.push(MakeJSONPair_('name', StringToJSON_(mirror.name()))); + if (!IS_UNDEFINED(mirror.inferredName())) { + content.push(MakeJSONPair_('inferredName', + StringToJSON_(mirror.inferredName()))); + } content.push(MakeJSONPair_('resolved', BooleanToJSON_(mirror.resolved()))); if (mirror.resolved()) { content.push(MakeJSONPair_('source', StringToJSON_(mirror.source()))); diff --git a/deps/v8/src/objects-debug.cc b/deps/v8/src/objects-debug.cc index f40fd3e6b..e17201478 100644 --- a/deps/v8/src/objects-debug.cc +++ b/deps/v8/src/objects-debug.cc @@ -558,8 +558,6 @@ void SharedFunctionInfo::SharedFunctionInfoPrint() { code()->ShortPrint(); PrintF("\n - source code = "); GetSourceCode()->ShortPrint(); - PrintF("\n - lazy load: %s", - lazy_load_data() == Heap::undefined_value() ? "no" : "yes"); // Script files are often large, hard to read. // PrintF("\n - script ="); // script()->Print(); @@ -579,7 +577,6 @@ void SharedFunctionInfo::SharedFunctionInfoVerify() { VerifyObjectField(kCodeOffset); VerifyObjectField(kInstanceClassNameOffset); VerifyObjectField(kExternalReferenceDataOffset); - VerifyObjectField(kLazyLoadDataOffset); VerifyObjectField(kScriptOffset); VerifyObjectField(kDebugInfoOffset); } @@ -924,7 +921,11 @@ void Script::ScriptVerify() { VerifyPointer(name()); line_offset()->SmiVerify(); column_offset()->SmiVerify(); + VerifyPointer(data()); + VerifyPointer(wrapper()); type()->SmiVerify(); + VerifyPointer(line_ends()); + VerifyPointer(id()); } diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index c2143ea02..782117808 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -144,14 +144,14 @@ bool Object::IsSeqString() { bool Object::IsSeqAsciiString() { if (!IsString()) return false; return StringShape(String::cast(this)).IsSequential() && - StringShape(String::cast(this)).IsAsciiRepresentation(); + String::cast(this)->IsAsciiRepresentation(); } bool Object::IsSeqTwoByteString() { if (!IsString()) return false; return StringShape(String::cast(this)).IsSequential() && - StringShape(String::cast(this)).IsTwoByteRepresentation(); + String::cast(this)->IsTwoByteRepresentation(); } @@ -164,14 +164,14 @@ bool Object::IsExternalString() { bool Object::IsExternalAsciiString() { if (!IsString()) return false; return StringShape(String::cast(this)).IsExternal() && - StringShape(String::cast(this)).IsAsciiRepresentation(); + String::cast(this)->IsAsciiRepresentation(); } bool Object::IsExternalTwoByteString() { if (!IsString()) return false; return StringShape(String::cast(this)).IsExternal() && - StringShape(String::cast(this)).IsTwoByteRepresentation(); + String::cast(this)->IsTwoByteRepresentation(); } @@ -211,13 +211,28 @@ bool StringShape::IsSymbol() { } -bool StringShape::IsAsciiRepresentation() { - return (type_ & kStringEncodingMask) == kAsciiStringTag; +bool String::IsAsciiRepresentation() { + uint32_t type = map()->instance_type(); + if ((type & kStringRepresentationMask) == kSlicedStringTag) { + return SlicedString::cast(this)->buffer()->IsAsciiRepresentation(); + } + if ((type & kStringRepresentationMask) == kConsStringTag && + ConsString::cast(this)->second()->length() == 0) { + return ConsString::cast(this)->first()->IsAsciiRepresentation(); + } + return (type & kStringEncodingMask) == kAsciiStringTag; } -bool StringShape::IsTwoByteRepresentation() { - return (type_ & kStringEncodingMask) == kTwoByteStringTag; +bool String::IsTwoByteRepresentation() { + uint32_t type = map()->instance_type(); + if ((type & kStringRepresentationMask) == kSlicedStringTag) { + return SlicedString::cast(this)->buffer()->IsTwoByteRepresentation(); + } else if ((type & kStringRepresentationMask) == kConsStringTag && + ConsString::cast(this)->second()->length() == 0) { + return ConsString::cast(this)->first()->IsTwoByteRepresentation(); + } + return (type & kStringEncodingMask) == kTwoByteStringTag; } @@ -668,12 +683,20 @@ Object** HeapObject::RawField(HeapObject* obj, int byte_offset) { int Smi::value() { - return reinterpret_cast<int>(this) >> kSmiTagSize; + return static_cast<int>(reinterpret_cast<intptr_t>(this) >> kSmiTagSize); } Smi* Smi::FromInt(int value) { ASSERT(Smi::IsValid(value)); + intptr_t tagged_value = + (static_cast<intptr_t>(value) << kSmiTagSize) | kSmiTag; + return reinterpret_cast<Smi*>(tagged_value); +} + + +Smi* Smi::FromIntptr(intptr_t value) { + ASSERT(Smi::IsValid(value)); return reinterpret_cast<Smi*>((value << kSmiTagSize) | kSmiTag); } @@ -724,7 +747,7 @@ Failure* Failure::OutOfMemoryException() { int Failure::value() const { - return reinterpret_cast<int>(this) >> kFailureTagSize; + return static_cast<int>(reinterpret_cast<intptr_t>(this) >> kFailureTagSize); } @@ -742,7 +765,8 @@ Failure* Failure::RetryAfterGC(int requested_bytes) { Failure* Failure::Construct(Type type, int value) { int info = (value << kFailureTypeTagSize) | type; ASSERT(Smi::IsValid(info)); // Same validation check as in Smi - return reinterpret_cast<Failure*>((info << kFailureTagSize) | kFailureTag); + return reinterpret_cast<Failure*>( + static_cast<intptr_t>((info << kFailureTagSize) | kFailureTag)); } @@ -768,6 +792,18 @@ bool Smi::IsValid(int value) { } +bool Smi::IsIntptrValid(intptr_t value) { +#ifdef DEBUG + bool in_range = (value >= kMinValue) && (value <= kMaxValue); +#endif + // See Smi::IsValid(int) for description. + bool result = + ((static_cast<uintptr_t>(value) + 0x40000000U) < 0x80000000U); + ASSERT(result == in_range); + return result; +} + + MapWord MapWord::FromMap(Map* map) { return MapWord(reinterpret_cast<uintptr_t>(map)); } @@ -1476,7 +1512,7 @@ void String::Set(int index, uint16_t value) { ASSERT(index >= 0 && index < length()); ASSERT(StringShape(this).IsSequential()); - return StringShape(this).IsAsciiRepresentation() + return this->IsAsciiRepresentation() ? SeqAsciiString::cast(this)->SeqAsciiStringSet(index, value) : SeqTwoByteString::cast(this)->SeqTwoByteStringSet(index, value); } @@ -1576,11 +1612,6 @@ int SeqAsciiString::SeqAsciiStringSize(InstanceType instance_type) { String* ConsString::first() { - ASSERT(String::cast(READ_FIELD(this, kSecondOffset))->length() != 0 || - StringShape( - String::cast( - READ_FIELD(this, kFirstOffset))).IsAsciiRepresentation() - == StringShape(this).IsAsciiRepresentation()); return String::cast(READ_FIELD(this, kFirstOffset)); } @@ -1613,10 +1644,6 @@ void ConsString::set_second(String* value, WriteBarrierMode mode) { String* SlicedString::buffer() { - ASSERT( - StringShape( - String::cast(READ_FIELD(this, kBufferOffset))).IsAsciiRepresentation() - == StringShape(this).IsAsciiRepresentation()); return String::cast(READ_FIELD(this, kBufferOffset)); } @@ -1811,6 +1838,16 @@ void Map::set_bit_field(byte value) { } +byte Map::bit_field2() { + return READ_BYTE_FIELD(this, kBitField2Offset); +} + + +void Map::set_bit_field2(byte value) { + WRITE_BYTE_FIELD(this, kBitField2Offset, value); +} + + void Map::set_non_instance_prototype(bool value) { if (value) { set_bit_field(bit_field() | (1 << kHasNonInstancePrototype)); @@ -2053,10 +2090,13 @@ ACCESSORS(Script, name, Object, kNameOffset) ACCESSORS(Script, id, Object, kIdOffset) ACCESSORS(Script, line_offset, Smi, kLineOffsetOffset) ACCESSORS(Script, column_offset, Smi, kColumnOffsetOffset) +ACCESSORS(Script, data, Object, kDataOffset) +ACCESSORS(Script, context_data, Object, kContextOffset) ACCESSORS(Script, wrapper, Proxy, kWrapperOffset) ACCESSORS(Script, type, Smi, kTypeOffset) ACCESSORS(Script, line_ends, Object, kLineEndsOffset) +#ifdef ENABLE_DEBUGGER_SUPPORT ACCESSORS(DebugInfo, shared, SharedFunctionInfo, kSharedFunctionInfoIndex) ACCESSORS(DebugInfo, original_code, Code, kOriginalCodeIndex) ACCESSORS(DebugInfo, code, Code, kPatchedCodeIndex) @@ -2066,13 +2106,13 @@ ACCESSORS(BreakPointInfo, code_position, Smi, kCodePositionIndex) ACCESSORS(BreakPointInfo, source_position, Smi, kSourcePositionIndex) ACCESSORS(BreakPointInfo, statement_position, Smi, kStatementPositionIndex) ACCESSORS(BreakPointInfo, break_point_objects, Object, kBreakPointObjectsIndex) +#endif ACCESSORS(SharedFunctionInfo, name, Object, kNameOffset) ACCESSORS(SharedFunctionInfo, instance_class_name, Object, kInstanceClassNameOffset) ACCESSORS(SharedFunctionInfo, function_data, Object, kExternalReferenceDataOffset) -ACCESSORS(SharedFunctionInfo, lazy_load_data, Object, kLazyLoadDataOffset) ACCESSORS(SharedFunctionInfo, script, Object, kScriptOffset) ACCESSORS(SharedFunctionInfo, debug_info, Object, kDebugInfoOffset) ACCESSORS(SharedFunctionInfo, inferred_name, String, kInferredNameOffset) @@ -2138,8 +2178,8 @@ bool JSFunction::IsBoilerplate() { } -bool JSFunction::IsLoaded() { - return shared()->lazy_load_data() == Heap::undefined_value(); +bool JSObject::IsLoaded() { + return !map()->needs_loading(); } diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index 9c640f463..9a7f7aa67 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -43,22 +43,6 @@ namespace v8 { namespace internal { -#define FIELD_ADDR(p, offset) \ - (reinterpret_cast<byte*>(p) + offset - kHeapObjectTag) - - -#define WRITE_FIELD(p, offset, value) \ - (*reinterpret_cast<Object**>(FIELD_ADDR(p, offset)) = value) - - -#define WRITE_INT_FIELD(p, offset, value) \ - (*reinterpret_cast<int*>(FIELD_ADDR(p, offset)) = value) - - -#define WRITE_BARRIER(object, offset) \ - Heap::RecordWrite(object->address(), offset); - - // Getters and setters are stored in a fixed array property. These are // constants for their indices. const int kGetterIndex = 0; @@ -374,7 +358,7 @@ Object* JSObject::GetLazyProperty(Object* receiver, Handle<Object> receiver_handle(receiver); Handle<String> name_handle(name); bool pending_exception; - LoadLazy(Handle<JSFunction>(JSFunction::cast(result->GetValue())), + LoadLazy(Handle<JSObject>(JSObject::cast(result->GetLazyValue())), &pending_exception); if (pending_exception) return Failure::Exception(); return this_handle->GetPropertyWithReceiver(*receiver_handle, @@ -393,7 +377,7 @@ Object* JSObject::SetLazyProperty(LookupResult* result, Handle<String> name_handle(name); Handle<Object> value_handle(value); bool pending_exception; - LoadLazy(Handle<JSFunction>(JSFunction::cast(result->GetValue())), + LoadLazy(Handle<JSObject>(JSObject::cast(result->GetLazyValue())), &pending_exception); if (pending_exception) return Failure::Exception(); return this_handle->SetProperty(*name_handle, *value_handle, attributes); @@ -405,7 +389,7 @@ Object* JSObject::DeleteLazyProperty(LookupResult* result, String* name) { Handle<JSObject> this_handle(this); Handle<String> name_handle(name); bool pending_exception; - LoadLazy(Handle<JSFunction>(JSFunction::cast(result->GetValue())), + LoadLazy(Handle<JSObject>(JSObject::cast(result->GetLazyValue())), &pending_exception); if (pending_exception) return Failure::Exception(); return this_handle->DeleteProperty(*name_handle); @@ -618,8 +602,6 @@ Object* String::TryFlatten() { if (StringShape(String::cast(ok)).IsCons()) { ss->set_buffer(ConsString::cast(ok)->first()); } - ASSERT(StringShape(this).IsAsciiRepresentation() == - StringShape(ss->buffer()).IsAsciiRepresentation()); return this; } case kConsStringTag: { @@ -634,7 +616,7 @@ Object* String::TryFlatten() { int len = length(); Object* object; String* result; - if (StringShape(this).IsAsciiRepresentation()) { + if (IsAsciiRepresentation()) { object = Heap::AllocateRawAsciiString(len, tenure); if (object->IsFailure()) return object; result = String::cast(object); @@ -972,10 +954,11 @@ int HeapObject::SlowSizeFromMap(Map* map) { // Avoid calling functions such as FixedArray::cast during GC, which // read map pointer of this object again. InstanceType instance_type = map->instance_type(); + uint32_t type = static_cast<uint32_t>(instance_type); if (instance_type < FIRST_NONSTRING_TYPE && (StringShape(instance_type).IsSequential())) { - if (StringShape(instance_type).IsAsciiRepresentation()) { + if ((type & kStringEncodingMask) == kAsciiStringTag) { SeqAsciiString* seq_ascii_this = reinterpret_cast<SeqAsciiString*>(this); return seq_ascii_this->SeqAsciiStringSize(instance_type); } else { @@ -1174,7 +1157,7 @@ Object* JSObject::AddFastProperty(String* name, (index - map()->inobject_properties()) < properties()->length() || map()->unused_property_fields() == 0); // Allocate a new map for the object. - Object* r = map()->Copy(); + Object* r = map()->CopyDropDescriptors(); if (r->IsFailure()) return r; Map* new_map = Map::cast(r); if (allow_map_transition) { @@ -1219,7 +1202,7 @@ Object* JSObject::AddConstantFunctionProperty(String* name, if (new_descriptors->IsFailure()) return new_descriptors; // Allocate a new map for the object. - Object* new_map = map()->Copy(); + Object* new_map = map()->CopyDropDescriptors(); if (new_map->IsFailure()) return new_map; DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors); @@ -1377,7 +1360,7 @@ Object* JSObject::ConvertDescriptorToField(String* name, DescriptorArray::cast(descriptors_unchecked); // Make a new map for the object. - Object* new_map_unchecked = map()->Copy(); + Object* new_map_unchecked = map()->CopyDropDescriptors(); if (new_map_unchecked->IsFailure()) return new_map_unchecked; Map* new_map = Map::cast(new_map_unchecked); new_map->set_instance_descriptors(new_descriptors); @@ -1800,6 +1783,17 @@ Object* JSObject::IgnoreAttributesAndSetLocalProperty( && !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { return SetPropertyWithFailedAccessCheck(result, name, value); } + + if (IsJSGlobalProxy()) { + Object* proto = GetPrototype(); + if (proto->IsNull()) return value; + ASSERT(proto->IsJSGlobalObject()); + return JSObject::cast(proto)->IgnoreAttributesAndSetLocalProperty( + name, + value, + attributes); + } + // Check for accessor in prototype chain removed here in clone. if (result->IsNotFound()) { return AddProperty(name, value, attributes); @@ -1820,20 +1814,16 @@ Object* JSObject::IgnoreAttributesAndSetLocalProperty( return AddFastPropertyUsingMap(result->GetTransitionMap(), name, value); - } else { - return ConvertDescriptorToField(name, value, attributes); } + return ConvertDescriptorToField(name, value, attributes); case CONSTANT_FUNCTION: if (value == result->GetConstantFunction()) return value; // Only replace the function if necessary. return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); case CALLBACKS: - return SetPropertyWithCallback(result->GetCallbackObject(), - name, - value, - result->holder()); case INTERCEPTOR: - return SetPropertyWithInterceptor(name, value, attributes); + // Override callback in clone + return ConvertDescriptorToField(name, value, attributes); case CONSTANT_TRANSITION: // Replace with a MAP_TRANSITION to a new map with a FIELD, even // if the value is a function. @@ -2041,7 +2031,7 @@ Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) { dictionary->SetNextEnumerationIndex(index); // Allocate new map. - obj = map()->Copy(); + obj = map()->CopyDropDescriptors(); if (obj->IsFailure()) return obj; Map* new_map = Map::cast(obj); @@ -2713,24 +2703,29 @@ Object* JSObject::SlowReverseLookup(Object* value) { } -Object* Map::Copy() { +Object* Map::CopyDropDescriptors() { Object* result = Heap::AllocateMap(instance_type(), instance_size()); if (result->IsFailure()) return result; Map::cast(result)->set_prototype(prototype()); Map::cast(result)->set_constructor(constructor()); // Don't copy descriptors, so map transitions always remain a forest. + // If we retained the same descriptors we would have two maps + // pointing to the same transition which is bad because the garbage + // collector relies on being able to reverse pointers from transitions + // to maps. If properties need to be retained use CopyDropTransitions. Map::cast(result)->set_instance_descriptors(Heap::empty_descriptor_array()); // Please note instance_type and instance_size are set when allocated. Map::cast(result)->set_inobject_properties(inobject_properties()); Map::cast(result)->set_unused_property_fields(unused_property_fields()); Map::cast(result)->set_bit_field(bit_field()); + Map::cast(result)->set_bit_field2(bit_field2()); Map::cast(result)->ClearCodeCache(); return result; } Object* Map::CopyDropTransitions() { - Object* new_map = Copy(); + Object* new_map = CopyDropDescriptors(); if (new_map->IsFailure()) return new_map; Object* descriptors = instance_descriptors()->RemoveTransitions(); if (descriptors->IsFailure()) return descriptors; @@ -2854,22 +2849,26 @@ static bool HasKey(FixedArray* array, Object* key) { Object* FixedArray::AddKeysFromJSArray(JSArray* array) { - // Remove array holes from array if any. - Object* object = array->RemoveHoles(); - if (object->IsFailure()) return object; - JSArray* compacted_array = JSArray::cast(object); + if (array->HasFastElements()) { + return UnionOfKeys(array->elements()); + } + ASSERT(!array->HasFastElements()); + Dictionary* dict = array->element_dictionary(); + int size = dict->NumberOfElements(); // Allocate a temporary fixed array. - int compacted_array_length = Smi::cast(compacted_array->length())->value(); - object = Heap::AllocateFixedArray(compacted_array_length); + Object* object = Heap::AllocateFixedArray(size); if (object->IsFailure()) return object; FixedArray* key_array = FixedArray::cast(object); + int capacity = dict->Capacity(); + int pos = 0; // Copy the elements from the JSArray to the temporary fixed array. - for (int i = 0; i < compacted_array_length; i++) { - key_array->set(i, compacted_array->GetElement(i)); + for (int i = 0; i < capacity; i++) { + if (dict->IsKey(dict->KeyAt(i))) { + key_array->set(pos++, dict->ValueAt(i)); + } } - // Compute the union of this and the temporary fixed array. return UnionOfKeys(key_array); } @@ -2885,9 +2884,12 @@ Object* FixedArray::UnionOfKeys(FixedArray* other) { // Compute how many elements are not in this. int extra = 0; for (int y = 0; y < len1; y++) { - if (!HasKey(this, other->get(y))) extra++; + Object* value = other->get(y); + if (!value->IsTheHole() && !HasKey(this, value)) extra++; } + if (extra == 0) return this; + // Allocate the result Object* obj = Heap::AllocateFixedArray(len0 + extra); if (obj->IsFailure()) return obj; @@ -2900,7 +2902,8 @@ Object* FixedArray::UnionOfKeys(FixedArray* other) { // Fill in the extra keys. int index = 0; for (int y = 0; y < len1; y++) { - if (!HasKey(this, other->get(y))) { + Object* value = other->get(y); + if (!value->IsTheHole() && !HasKey(this, value)) { result->set(len0 + index, other->get(y), mode); index++; } @@ -3231,7 +3234,7 @@ bool String::LooksValid() { int String::Utf8Length() { - if (StringShape(this).IsAsciiRepresentation()) return length(); + if (IsAsciiRepresentation()) return length(); // Attempt to flatten before accessing the string. It probably // doesn't make Utf8Length faster, but it is very likely that // the string will be accessed later (for example by WriteUtf8) @@ -3247,7 +3250,7 @@ int String::Utf8Length() { Vector<const char> String::ToAsciiVector() { - ASSERT(StringShape(this).IsAsciiRepresentation()); + ASSERT(IsAsciiRepresentation()); ASSERT(IsFlat()); int offset = 0; @@ -3278,7 +3281,7 @@ Vector<const char> String::ToAsciiVector() { Vector<const uc16> String::ToUC16Vector() { - ASSERT(StringShape(this).IsTwoByteRepresentation()); + ASSERT(IsTwoByteRepresentation()); ASSERT(IsFlat()); int offset = 0; @@ -3302,13 +3305,6 @@ Vector<const uc16> String::ToUC16Vector() { } ASSERT(string_tag == kExternalStringTag); ExternalTwoByteString* ext = ExternalTwoByteString::cast(string); - // This is a workaround for Chromium bug 9746: http://crbug.com/9746 - // For external strings with a deleted resource we return a special - // Vector which will not compare to any string when doing SymbolTable - // lookups. - if (ext->resource() == NULL) { - return Vector<const uc16>(NULL, length); - } const uc16* start = reinterpret_cast<const uc16*>(ext->resource()->data()); return Vector<const uc16>(start + offset, length); @@ -3381,7 +3377,7 @@ const uc16* String::GetTwoByteData() { const uc16* String::GetTwoByteData(unsigned start) { - ASSERT(!StringShape(this).IsAsciiRepresentation()); + ASSERT(!IsAsciiRepresentation()); switch (StringShape(this).representation_tag()) { case kSeqStringTag: return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); @@ -3676,7 +3672,7 @@ const unibrow::byte* String::ReadBlock(String* input, } switch (StringShape(input).representation_tag()) { case kSeqStringTag: - if (StringShape(input).IsAsciiRepresentation()) { + if (input->IsAsciiRepresentation()) { SeqAsciiString* str = SeqAsciiString::cast(input); return str->SeqAsciiStringReadBlock(&rbb->remaining, offset_ptr, @@ -3697,7 +3693,7 @@ const unibrow::byte* String::ReadBlock(String* input, offset_ptr, max_chars); case kExternalStringTag: - if (StringShape(input).IsAsciiRepresentation()) { + if (input->IsAsciiRepresentation()) { return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock( &rbb->remaining, offset_ptr, @@ -3750,7 +3746,7 @@ void FlatStringReader::RefreshState() { if (str_ == NULL) return; Handle<String> str(str_); ASSERT(str->IsFlat()); - is_ascii_ = StringShape(*str).IsAsciiRepresentation(); + is_ascii_ = str->IsAsciiRepresentation(); if (is_ascii_) { start_ = str->ToAsciiVector().start(); } else { @@ -3791,7 +3787,7 @@ void String::ReadBlockIntoBuffer(String* input, switch (StringShape(input).representation_tag()) { case kSeqStringTag: - if (StringShape(input).IsAsciiRepresentation()) { + if (input->IsAsciiRepresentation()) { SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars); @@ -3813,7 +3809,7 @@ void String::ReadBlockIntoBuffer(String* input, max_chars); return; case kExternalStringTag: - if (StringShape(input).IsAsciiRepresentation()) { + if (input->IsAsciiRepresentation()) { ExternalAsciiString::cast(input)-> ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars); } else { @@ -4093,7 +4089,7 @@ static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) { const Char* pa = a.start(); const Char* pb = b.start(); int i = 0; -#ifndef CAN_READ_UNALIGNED +#ifndef V8_HOST_CAN_READ_UNALIGNED // If this architecture isn't comfortable reading unaligned ints // then we have to check that the strings are aligned before // comparing them blockwise. @@ -4112,7 +4108,7 @@ static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) { return false; } } -#ifndef CAN_READ_UNALIGNED +#ifndef V8_HOST_CAN_READ_UNALIGNED } #endif // Compare the remaining characters that didn't fit into a block. @@ -4125,31 +4121,17 @@ static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) { } -// This is a workaround for Chromium bug 9746: http://crbug.com/9746 -// Returns true if this Vector matches the problem exposed in the bug. -template <typename T> -static bool CheckVectorForBug9746(Vector<T> vec) { - // The problem is that somehow external string entries in the symbol - // table can have their resources collected while they are still in the - // table. This should not happen according to the test in the function - // DisposeExternalString in api.cc, but we have evidence that it does. - return (vec.start() == NULL) ? true : false; -} - - static StringInputBuffer string_compare_buffer_b; template <typename IteratorA> static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) { if (b->IsFlat()) { - if (StringShape(b).IsAsciiRepresentation()) { + if (b->IsAsciiRepresentation()) { VectorIterator<char> ib(b->ToAsciiVector()); return CompareStringContents(ia, &ib); } else { - Vector<const uc16> vb = b->ToUC16Vector(); - if (CheckVectorForBug9746(vb)) return false; - VectorIterator<uc16> ib(vb); + VectorIterator<uc16> ib(b->ToUC16Vector()); return CompareStringContents(ia, &ib); } } else { @@ -4183,17 +4165,15 @@ bool String::SlowEquals(String* other) { } if (this->IsFlat()) { - if (StringShape(this).IsAsciiRepresentation()) { + if (IsAsciiRepresentation()) { Vector<const char> vec1 = this->ToAsciiVector(); if (other->IsFlat()) { - if (StringShape(other).IsAsciiRepresentation()) { + if (other->IsAsciiRepresentation()) { Vector<const char> vec2 = other->ToAsciiVector(); return CompareRawStringContents(vec1, vec2); } else { VectorIterator<char> buf1(vec1); - Vector<const uc16> vec2 = other->ToUC16Vector(); - if (CheckVectorForBug9746(vec2)) return false; - VectorIterator<uc16> ib(vec2); + VectorIterator<uc16> ib(other->ToUC16Vector()); return CompareStringContents(&buf1, &ib); } } else { @@ -4203,15 +4183,13 @@ bool String::SlowEquals(String* other) { } } else { Vector<const uc16> vec1 = this->ToUC16Vector(); - if (CheckVectorForBug9746(vec1)) return false; if (other->IsFlat()) { - if (StringShape(other).IsAsciiRepresentation()) { + if (other->IsAsciiRepresentation()) { VectorIterator<uc16> buf1(vec1); VectorIterator<char> ib(other->ToAsciiVector()); return CompareStringContents(&buf1, &ib); } else { - Vector<const uc16> vec2 = other->ToUC16Vector(); - if (CheckVectorForBug9746(vec2)) return false; + Vector<const uc16> vec2(other->ToUC16Vector()); return CompareRawStringContents(vec1, vec2); } } else { @@ -4256,18 +4234,6 @@ bool String::MarkAsUndetectable() { bool String::IsEqualTo(Vector<const char> str) { - // This is a workaround for Chromium bug 9746: http://crbug.com/9746 - // The problem is that somehow external string entries in the symbol - // table can have their resources deleted while they are still in the - // table. This should not happen according to the test in the function - // DisposeExternalString in api.cc but we have evidence that it does. - // Thus we add this bailout here. - StringShape shape(this); - if (shape.IsExternalTwoByte()) { - ExternalTwoByteString* ext = ExternalTwoByteString::cast(this); - if (ext->resource() == NULL) return false; - } - int slen = length(); Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder()); decoder->Reset(str.start(), str.length()); @@ -4678,6 +4644,7 @@ void Code::ConvertICTargetsFromAddressToObject() { it.rinfo()->set_target_object(code); } +#ifdef ENABLE_DEBUGGER_SUPPORT if (Debug::has_break_points()) { for (RelocIterator it(this, RelocInfo::ModeMask(RelocInfo::JS_RETURN)); !it.done(); @@ -4691,6 +4658,7 @@ void Code::ConvertICTargetsFromAddressToObject() { } } } +#endif set_ic_flag(IC_TARGET_IS_OBJECT); } @@ -4712,10 +4680,12 @@ void Code::CodeIterateBody(ObjectVisitor* v) { v->VisitCodeTarget(it.rinfo()); } else if (rmode == RelocInfo::EXTERNAL_REFERENCE) { v->VisitExternalReference(it.rinfo()->target_reference_address()); +#ifdef ENABLE_DEBUGGER_SUPPORT } else if (Debug::has_break_points() && RelocInfo::IsJSReturn(rmode) && it.rinfo()->IsCallInstruction()) { v->VisitDebugTarget(it.rinfo()); +#endif } else if (rmode == RelocInfo::RUNTIME_ENTRY) { v->VisitRuntimeEntry(it.rinfo()); } @@ -4740,6 +4710,7 @@ void Code::ConvertICTargetsFromObjectToAddress() { it.rinfo()->set_target_address(code->instruction_start()); } +#ifdef ENABLE_DEBUGGER_SUPPORT if (Debug::has_break_points()) { for (RelocIterator it(this, RelocInfo::ModeMask(RelocInfo::JS_RETURN)); !it.done(); @@ -4751,6 +4722,7 @@ void Code::ConvertICTargetsFromObjectToAddress() { } } } +#endif set_ic_flag(IC_TARGET_IS_ADDRESS); } @@ -5138,7 +5110,7 @@ bool JSObject::HasElementWithInterceptor(JSObject* receiver, uint32_t index) { VMState state(EXTERNAL); result = getter(index, info); } - if (!result.IsEmpty()) return !result->IsUndefined(); + if (!result.IsEmpty()) return true; } return holder_handle->HasElementPostInterceptor(*receiver_handle, index); } @@ -5189,7 +5161,8 @@ Object* JSObject::GetHiddenProperties(bool create_if_needed) { } // Only attempt to find the hidden properties in the local object and not - // in the prototype chain. + // in the prototype chain. Note that HasLocalProperty() can cause a GC in + // the general case, but in this case we know it won't hit an interceptor. if (!this->HasLocalProperty(key)) { // Hidden properties object not found. Allocate a new hidden properties // object if requested. Otherwise return the undefined value. @@ -5626,75 +5599,18 @@ bool JSObject::ShouldConvertToFastElements() { } -Object* Dictionary::RemoveHoles() { - int capacity = Capacity(); - Object* obj = Allocate(NumberOfElements()); - if (obj->IsFailure()) return obj; - Dictionary* dict = Dictionary::cast(obj); - uint32_t pos = 0; - for (int i = 0; i < capacity; i++) { - Object* k = KeyAt(i); - if (IsKey(k)) { - dict->AddNumberEntry(pos++, ValueAt(i), DetailsAt(i)); - } - } - return dict; -} - - void Dictionary::CopyValuesTo(FixedArray* elements) { int pos = 0; int capacity = Capacity(); + WriteBarrierMode mode = elements->GetWriteBarrierMode(); for (int i = 0; i < capacity; i++) { Object* k = KeyAt(i); - if (IsKey(k)) elements->set(pos++, ValueAt(i)); + if (IsKey(k)) elements->set(pos++, ValueAt(i), mode); } ASSERT(pos == elements->length()); } -Object* JSArray::RemoveHoles() { - if (HasFastElements()) { - int len = Smi::cast(length())->value(); - int pos = 0; - FixedArray* elms = FixedArray::cast(elements()); - for (int index = 0; index < len; index++) { - Object* e = elms->get(index); - if (!e->IsTheHole()) { - if (index != pos) elms->set(pos, e); - pos++; - } - } - set_length(Smi::FromInt(pos), SKIP_WRITE_BARRIER); - for (int index = pos; index < len; index++) { - elms->set_the_hole(index); - } - return this; - } - - // Compact the sparse array if possible. - Dictionary* dict = element_dictionary(); - int length = dict->NumberOfElements(); - - // Try to make this a fast array again. - if (length <= kMaxFastElementsLength) { - Object* obj = Heap::AllocateFixedArray(length); - if (obj->IsFailure()) return obj; - dict->CopyValuesTo(FixedArray::cast(obj)); - set_length(Smi::FromInt(length), SKIP_WRITE_BARRIER); - set_elements(FixedArray::cast(obj)); - return this; - } - - // Make another dictionary with smaller indices. - Object* obj = dict->RemoveHoles(); - if (obj->IsFailure()) return obj; - set_length(Smi::FromInt(length), SKIP_WRITE_BARRIER); - set_elements(Dictionary::cast(obj)); - return this; -} - - InterceptorInfo* JSObject::GetNamedInterceptor() { ASSERT(map()->has_named_interceptor()); JSFunction* constructor = JSFunction::cast(map()->constructor()); @@ -5861,43 +5777,46 @@ int JSObject::NumberOfEnumProperties() { } -void FixedArray::Swap(int i, int j) { +void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) { Object* temp = get(i); set(i, get(j)); set(j, temp); + if (this != numbers) { + temp = numbers->get(i); + numbers->set(i, numbers->get(j)); + numbers->set(j, temp); + } } -static void InsertionSortPairs(FixedArray* content, FixedArray* smis) { - int len = smis->length(); +static void InsertionSortPairs(FixedArray* content, + FixedArray* numbers, + int len) { for (int i = 1; i < len; i++) { int j = i; while (j > 0 && - Smi::cast(smis->get(j-1))->value() > - Smi::cast(smis->get(j))->value()) { - smis->Swap(j-1, j); - content->Swap(j-1, j); + (NumberToUint32(numbers->get(j - 1)) > + NumberToUint32(numbers->get(j)))) { + content->SwapPairs(numbers, j - 1, j); j--; } } } -void HeapSortPairs(FixedArray* content, FixedArray* smis) { +void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) { // In-place heap sort. - ASSERT(content->length() == smis->length()); - int len = smis->length(); + ASSERT(content->length() == numbers->length()); // Bottom-up max-heap construction. for (int i = 1; i < len; ++i) { int child_index = i; while (child_index > 0) { int parent_index = ((child_index + 1) >> 1) - 1; - int parent_value = Smi::cast(smis->get(parent_index))->value(); - int child_value = Smi::cast(smis->get(child_index))->value(); + uint32_t parent_value = NumberToUint32(numbers->get(parent_index)); + uint32_t child_value = NumberToUint32(numbers->get(child_index)); if (parent_value < child_value) { - content->Swap(parent_index, child_index); - smis->Swap(parent_index, child_index); + content->SwapPairs(numbers, parent_index, child_index); } else { break; } @@ -5908,25 +5827,22 @@ void HeapSortPairs(FixedArray* content, FixedArray* smis) { // Extract elements and create sorted array. for (int i = len - 1; i > 0; --i) { // Put max element at the back of the array. - content->Swap(0, i); - smis->Swap(0, i); + content->SwapPairs(numbers, 0, i); // Sift down the new top element. int parent_index = 0; while (true) { int child_index = ((parent_index + 1) << 1) - 1; if (child_index >= i) break; - uint32_t child1_value = Smi::cast(smis->get(child_index))->value(); - uint32_t child2_value = Smi::cast(smis->get(child_index + 1))->value(); - uint32_t parent_value = Smi::cast(smis->get(parent_index))->value(); + uint32_t child1_value = NumberToUint32(numbers->get(child_index)); + uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1)); + uint32_t parent_value = NumberToUint32(numbers->get(parent_index)); if (child_index + 1 >= i || child1_value > child2_value) { if (parent_value > child1_value) break; - content->Swap(parent_index, child_index); - smis->Swap(parent_index, child_index); + content->SwapPairs(numbers, parent_index, child_index); parent_index = child_index; } else { if (parent_value > child2_value) break; - content->Swap(parent_index, child_index + 1); - smis->Swap(parent_index, child_index + 1); + content->SwapPairs(numbers, parent_index, child_index + 1); parent_index = child_index + 1; } } @@ -5934,43 +5850,41 @@ void HeapSortPairs(FixedArray* content, FixedArray* smis) { } -// Sort this array and the smis as pairs wrt. the (distinct) smis. -void FixedArray::SortPairs(FixedArray* smis) { - ASSERT(this->length() == smis->length()); - int len = smis->length(); +// Sort this array and the numbers as pairs wrt. the (distinct) numbers. +void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) { + ASSERT(this->length() == numbers->length()); // For small arrays, simply use insertion sort. if (len <= 10) { - InsertionSortPairs(this, smis); + InsertionSortPairs(this, numbers, len); return; } // Check the range of indices. - int min_index = Smi::cast(smis->get(0))->value(); - int max_index = min_index; - int i; + uint32_t min_index = NumberToUint32(numbers->get(0)); + uint32_t max_index = min_index; + uint32_t i; for (i = 1; i < len; i++) { - if (Smi::cast(smis->get(i))->value() < min_index) { - min_index = Smi::cast(smis->get(i))->value(); - } else if (Smi::cast(smis->get(i))->value() > max_index) { - max_index = Smi::cast(smis->get(i))->value(); + if (NumberToUint32(numbers->get(i)) < min_index) { + min_index = NumberToUint32(numbers->get(i)); + } else if (NumberToUint32(numbers->get(i)) > max_index) { + max_index = NumberToUint32(numbers->get(i)); } } if (max_index - min_index + 1 == len) { // Indices form a contiguous range, unless there are duplicates. - // Do an in-place linear time sort assuming distinct smis, but + // Do an in-place linear time sort assuming distinct numbers, but // avoid hanging in case they are not. for (i = 0; i < len; i++) { - int p; - int j = 0; + uint32_t p; + uint32_t j = 0; // While the current element at i is not at its correct position p, // swap the elements at these two positions. - while ((p = Smi::cast(smis->get(i))->value() - min_index) != i && + while ((p = NumberToUint32(numbers->get(i)) - min_index) != i && j++ < len) { - this->Swap(i, p); - smis->Swap(i, p); + SwapPairs(numbers, i, p); } } } else { - HeapSortPairs(this, smis); + HeapSortPairs(this, numbers, len); return; } } @@ -6448,6 +6362,176 @@ template class HashTable<2, 3>; template class HashTable<0, 2>; +// Collates undefined and unexisting elements below limit from position +// zero of the elements. The object stays in Dictionary mode. +Object* JSObject::PrepareSlowElementsForSort(uint32_t limit) { + ASSERT(!HasFastElements()); + // Must stay in dictionary mode, either because of requires_slow_elements, + // or because we are not going to sort (and therefore compact) all of the + // elements. + Dictionary* dict = element_dictionary(); + HeapNumber* result_double = NULL; + if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { + // Allocate space for result before we start mutating the object. + Object* new_double = Heap::AllocateHeapNumber(0.0); + if (new_double->IsFailure()) return new_double; + result_double = HeapNumber::cast(new_double); + } + + int capacity = dict->Capacity(); + Object* obj = Dictionary::Allocate(dict->Capacity()); + if (obj->IsFailure()) return obj; + Dictionary* new_dict = Dictionary::cast(obj); + + AssertNoAllocation no_alloc; + + // Loose all details on properties when moving them around. + // Elements do not have special details like properties. + PropertyDetails no_details = PropertyDetails(NONE, NORMAL); + + uint32_t pos = 0; + uint32_t undefs = 0; + for (int i = 0; i < capacity; i++) { + Object* k = dict->KeyAt(i); + if (dict->IsKey(k)) { + ASSERT(k->IsNumber()); + ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0); + ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0); + ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32); + Object* value = dict->ValueAt(i); + uint32_t key = NumberToUint32(k); + if (key < limit) { + if (value->IsUndefined()) { + undefs++; + } else { + new_dict->AddNumberEntry(pos, value, no_details); + pos++; + } + } else { + new_dict->AddNumberEntry(key, value, no_details); + } + } + } + + uint32_t result = pos; + while (undefs > 0) { + new_dict->AddNumberEntry(pos, Heap::undefined_value(), no_details); + pos++; + undefs--; + } + + set_elements(new_dict); + + if (result <= static_cast<uint32_t>(Smi::kMaxValue)) { + return Smi::FromInt(static_cast<int>(result)); + } + + ASSERT_NE(NULL, result_double); + result_double->set_value(static_cast<double>(result)); + return result_double; +} + + +// Collects all defined (non-hole) and non-undefined (array) elements at +// the start of the elements array. +// If the object is in dictionary mode, it is converted to fast elements +// mode. +Object* JSObject::PrepareElementsForSort(uint32_t limit) { + if (!HasFastElements()) { + // Convert to fast elements containing only the existing properties. + // Ordering is irrelevant, since we are going to sort anyway. + Dictionary* dict = element_dictionary(); + if (IsJSArray() || dict->requires_slow_elements() || + dict->max_number_key() >= limit) { + return PrepareSlowElementsForSort(limit); + } + // Convert to fast elements. + + PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED: TENURED; + Object* new_array = + Heap::AllocateFixedArray(dict->NumberOfElements(), tenure); + if (new_array->IsFailure()) { + return new_array; + } + FixedArray* fast_elements = FixedArray::cast(new_array); + dict->CopyValuesTo(fast_elements); + set_elements(fast_elements); + } + ASSERT(HasFastElements()); + + // Collect holes at the end, undefined before that and the rest at the + // start, and return the number of non-hole, non-undefined values. + + FixedArray* elements = this->elements(); + uint32_t elements_length = static_cast<uint32_t>(elements->length()); + if (limit > elements_length) { + limit = elements_length ; + } + if (limit == 0) { + return Smi::FromInt(0); + } + + HeapNumber* result_double = NULL; + if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { + // Pessimistically allocate space for return value before + // we start mutating the array. + Object* new_double = Heap::AllocateHeapNumber(0.0); + if (new_double->IsFailure()) return new_double; + result_double = HeapNumber::cast(new_double); + } + + AssertNoAllocation no_alloc; + + // Split elements into defined, undefined and the_hole, in that order. + // Only count locations for undefined and the hole, and fill them afterwards. + WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(); + unsigned int undefs = limit; + unsigned int holes = limit; + // Assume most arrays contain no holes and undefined values, so minimize the + // number of stores of non-undefined, non-the-hole values. + for (unsigned int i = 0; i < undefs; i++) { + Object* current = elements->get(i); + if (current->IsTheHole()) { + holes--; + undefs--; + } else if (current->IsUndefined()) { + undefs--; + } else { + continue; + } + // Position i needs to be filled. + while (undefs > i) { + current = elements->get(undefs); + if (current->IsTheHole()) { + holes--; + undefs--; + } else if (current->IsUndefined()) { + undefs--; + } else { + elements->set(i, current, write_barrier); + break; + } + } + } + uint32_t result = undefs; + while (undefs < holes) { + elements->set_undefined(undefs); + undefs++; + } + while (holes < limit) { + elements->set_the_hole(holes); + holes++; + } + + if (result <= static_cast<uint32_t>(Smi::kMaxValue)) { + return Smi::FromInt(static_cast<int>(result)); + } + ASSERT_NE(NULL, result_double); + result_double->set_value(static_cast<double>(result)); + return result_double; +} + + Object* SymbolTable::LookupString(String* string, Object** s) { SymbolKey key(string); return LookupKey(&key, s); @@ -6758,7 +6842,7 @@ Object* Dictionary::GenerateNewEnumerationIndices() { } // Sort the arrays wrt. enumeration order. - iteration_order->SortPairs(enumeration_order); + iteration_order->SortPairs(enumeration_order, enumeration_order->length()); // Overwrite the enumeration_order with the enumeration indices. for (int i = 0; i < length; i++) { @@ -7010,6 +7094,7 @@ void Dictionary::CopyKeysTo(FixedArray* storage, PropertyAttributes filter) { if ((attr & filter) == 0) storage->set(index++, k); } } + storage->SortPairs(storage, index); ASSERT(storage->length() >= index); } @@ -7031,7 +7116,7 @@ void Dictionary::CopyEnumKeysTo(FixedArray* storage, FixedArray* sort_array) { } } } - storage->SortPairs(sort_array); + storage->SortPairs(sort_array, sort_array->length()); ASSERT(storage->length() >= index); } @@ -7157,7 +7242,7 @@ Object* Dictionary::TransformPropertiesToFastFor(JSObject* obj, descriptors->Sort(); // Allocate new map. - Object* new_map = obj->map()->Copy(); + Object* new_map = obj->map()->CopyDropDescriptors(); if (new_map->IsFailure()) return new_map; // Transform the object. @@ -7176,6 +7261,7 @@ Object* Dictionary::TransformPropertiesToFastFor(JSObject* obj, } +#ifdef ENABLE_DEBUGGER_SUPPORT // Check if there is a break point at this code position. bool DebugInfo::HasBreakPoint(int code_position) { // Get the break point info object for this code position. @@ -7419,6 +7505,6 @@ int BreakPointInfo::GetBreakPointCount() { // Multiple break points. return FixedArray::cast(break_point_objects())->length(); } - +#endif } } // namespace v8::internal diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index ade282be6..3e132ff19 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -389,7 +389,7 @@ enum PropertyNormalizationMode { // Note that for subtle reasons related to the ordering or numerical values of // type tags, elements in this list have to be added to the INSTANCE_TYPE_LIST // manually. -#define STRUCT_LIST(V) \ +#define STRUCT_LIST_ALL(V) \ V(ACCESSOR_INFO, AccessorInfo, accessor_info) \ V(ACCESS_CHECK_INFO, AccessCheckInfo, access_check_info) \ V(INTERCEPTOR_INFO, InterceptorInfo, interceptor_info) \ @@ -398,10 +398,19 @@ enum PropertyNormalizationMode { V(OBJECT_TEMPLATE_INFO, ObjectTemplateInfo, object_template_info) \ V(SIGNATURE_INFO, SignatureInfo, signature_info) \ V(TYPE_SWITCH_INFO, TypeSwitchInfo, type_switch_info) \ - V(DEBUG_INFO, DebugInfo, debug_info) \ - V(BREAK_POINT_INFO, BreakPointInfo, break_point_info) \ V(SCRIPT, Script, script) +#ifdef ENABLE_DEBUGGER_SUPPORT +#define STRUCT_LIST_DEBUGGER(V) \ + V(DEBUG_INFO, DebugInfo, debug_info) \ + V(BREAK_POINT_INFO, BreakPointInfo, break_point_info) +#else +#define STRUCT_LIST_DEBUGGER(V) +#endif + +#define STRUCT_LIST(V) \ + STRUCT_LIST_ALL(V) \ + STRUCT_LIST_DEBUGGER(V) // We use the full 8 bits of the instance_type field to encode heap object // instance types. The high-order bit (bit 7) is set if the object is not a @@ -773,9 +782,13 @@ class Smi: public Object { // Convert a value to a Smi object. static inline Smi* FromInt(int value); + static inline Smi* FromIntptr(intptr_t value); + // Returns whether value can be represented in a Smi. static inline bool IsValid(int value); + static inline bool IsIntptrValid(intptr_t); + // Casting. static inline Smi* cast(Object* object); @@ -786,9 +799,10 @@ class Smi: public Object { void SmiVerify(); #endif + static const int kSmiNumBits = 31; // Min and max limits for Smi values. - static const int kMinValue = -(1 << (kBitsPerPointer - (kSmiTagSize + 1))); - static const int kMaxValue = (1 << (kBitsPerPointer - (kSmiTagSize + 1))) - 1; + static const int kMinValue = -(1 << (kSmiNumBits - 1)); + static const int kMaxValue = (1 << (kSmiNumBits - 1)) - 1; private: DISALLOW_IMPLICIT_CONSTRUCTORS(Smi); @@ -1169,6 +1183,14 @@ class JSObject: public HeapObject { inline bool HasFastElements(); inline Dictionary* element_dictionary(); // Gets slow elements. + // Collects elements starting at index 0. + // Undefined values are placed after non-undefined values. + // Returns the number of non-undefined values. + Object* PrepareElementsForSort(uint32_t limit); + // As PrepareElementsForSort, but only on objects where elements is + // a dictionary, and it will stay a dictionary. + Object* PrepareSlowElementsForSort(uint32_t limit); + Object* SetProperty(String* key, Object* value, PropertyAttributes attributes); @@ -1233,10 +1255,14 @@ class JSObject: public HeapObject { String* name, PropertyAttributes* attributes); + // Tells whether this object needs to be loaded. + inline bool IsLoaded(); + bool HasProperty(String* name) { return GetPropertyAttribute(name) != ABSENT; } + // Can cause a GC if it hits an interceptor. bool HasLocalProperty(String* name) { return GetLocalPropertyAttribute(name) != ABSENT; } @@ -1585,11 +1611,15 @@ class FixedArray: public Array { bool IsEqualTo(FixedArray* other); #endif - // Swap two elements. - void Swap(int i, int j); + // Swap two elements in a pair of arrays. If this array and the + // numbers array are the same object, the elements are only swapped + // once. + void SwapPairs(FixedArray* numbers, int i, int j); - // Sort this array and the smis as pairs wrt. the smis. - void SortPairs(FixedArray* smis); + // Sort prefix of this array and the numbers array as pairs wrt. the + // numbers. If the numbers array and the this array are the same + // object, the prefix of this array is sorted. + void SortPairs(FixedArray* numbers, uint32_t len); protected: // Set operation on FixedArray without using write barriers. @@ -1992,7 +2022,6 @@ class Dictionary: public DictionaryBase { void RemoveNumberEntries(uint32_t from, uint32_t to); // Sorting support - Object* RemoveHoles(); void CopyValuesTo(FixedArray* elements); // Casting. @@ -2301,8 +2330,7 @@ class Code: public HeapObject { // the layout of the code object into account. int ExecutableSize() { // Check that the assumptions about the layout of the code object holds. - ASSERT_EQ(reinterpret_cast<unsigned int>(instruction_start()) - - reinterpret_cast<unsigned int>(address()), + ASSERT_EQ(instruction_start() - address(), Code::kHeaderSize); return instruction_size() + Code::kHeaderSize; } @@ -2384,6 +2412,10 @@ class Map: public HeapObject { inline byte bit_field(); inline void set_bit_field(byte value); + // Bit field 2. + inline byte bit_field2(); + inline void set_bit_field2(byte value); + // Tells whether the object in the prototype property will be used // for instances created from this function. If the prototype // property is set to a value that is not a JSObject, the prototype @@ -2434,6 +2466,20 @@ class Map: public HeapObject { return ((1 << kIsUndetectable) & bit_field()) != 0; } + inline void set_needs_loading(bool value) { + if (value) { + set_bit_field2(bit_field2() | (1 << kNeedsLoading)); + } else { + set_bit_field2(bit_field2() & ~(1 << kNeedsLoading)); + } + } + + // Does this object or function require a lazily loaded script to be + // run before being used? + inline bool needs_loading() { + return ((1 << kNeedsLoading) & bit_field2()) != 0; + } + // Tells whether the instance has a call-as-function handler. inline void set_has_instance_call_handler() { set_bit_field(bit_field() | (1 << kHasInstanceCallHandler)); @@ -2461,7 +2507,7 @@ class Map: public HeapObject { DECL_ACCESSORS(code_cache, FixedArray) // Returns a copy of the map. - Object* Copy(); + Object* CopyDropDescriptors(); // Returns a copy of the map, with all transitions dropped from the // instance descriptors. @@ -2537,7 +2583,7 @@ class Map: public HeapObject { static const int kInstanceTypeOffset = kInstanceAttributesOffset + 0; static const int kUnusedPropertyFieldsOffset = kInstanceAttributesOffset + 1; static const int kBitFieldOffset = kInstanceAttributesOffset + 2; - // The byte at position 3 is not in use at the moment. + static const int kBitField2Offset = kInstanceAttributesOffset + 3; // Bit positions for bit field. static const int kUnused = 0; // To be used for marking recently used maps. @@ -2548,6 +2594,10 @@ class Map: public HeapObject { static const int kIsUndetectable = 5; static const int kHasInstanceCallHandler = 6; static const int kIsAccessCheckNeeded = 7; + + // Bit positions for but field 2 + static const int kNeedsLoading = 0; + private: DISALLOW_IMPLICIT_CONSTRUCTORS(Map); }; @@ -2590,6 +2640,12 @@ class Script: public Struct { // extracted. DECL_ACCESSORS(column_offset, Smi) + // [data]: additional data associated with this script. + DECL_ACCESSORS(data, Object) + + // [context_data]: context data for the context this script was compiled in. + DECL_ACCESSORS(context_data, Object) + // [wrapper]: the wrapper cache. DECL_ACCESSORS(wrapper, Proxy) @@ -2610,7 +2666,9 @@ class Script: public Struct { static const int kNameOffset = kSourceOffset + kPointerSize; static const int kLineOffsetOffset = kNameOffset + kPointerSize; static const int kColumnOffsetOffset = kLineOffsetOffset + kPointerSize; - static const int kWrapperOffset = kColumnOffsetOffset + kPointerSize; + static const int kDataOffset = kColumnOffsetOffset + kPointerSize; + static const int kContextOffset = kDataOffset + kPointerSize; + static const int kWrapperOffset = kContextOffset + kPointerSize; static const int kTypeOffset = kWrapperOffset + kPointerSize; static const int kLineEndsOffset = kTypeOffset + kPointerSize; static const int kIdOffset = kLineEndsOffset + kPointerSize; @@ -2660,10 +2718,6 @@ class SharedFunctionInfo: public HeapObject { // on objects. DECL_ACCESSORS(function_data, Object) - // [lazy load data]: If the function has lazy loading, this field - // contains contexts and other data needed to load it. - DECL_ACCESSORS(lazy_load_data, Object) - // [script info]: Script from which the function originates. DECL_ACCESSORS(script, Object) @@ -2737,9 +2791,7 @@ class SharedFunctionInfo: public HeapObject { kExpectedNofPropertiesOffset + kIntSize; static const int kExternalReferenceDataOffset = kInstanceClassNameOffset + kPointerSize; - static const int kLazyLoadDataOffset = - kExternalReferenceDataOffset + kPointerSize; - static const int kScriptOffset = kLazyLoadDataOffset + kPointerSize; + static const int kScriptOffset = kExternalReferenceDataOffset + kPointerSize; static const int kStartPositionAndTypeOffset = kScriptOffset + kPointerSize; static const int kEndPositionOffset = kStartPositionAndTypeOffset + kIntSize; static const int kFunctionTokenPositionOffset = kEndPositionOffset + kIntSize; @@ -2792,9 +2844,6 @@ class JSFunction: public JSObject { // function. inline bool IsBoilerplate(); - // Tells whether this function needs to be loaded. - inline bool IsLoaded(); - // [literals]: Fixed array holding the materialized literals. // // If the function contains object, regexp or array literals, the @@ -3167,8 +3216,6 @@ class StringShape BASE_EMBEDDED { inline explicit StringShape(String* s); inline explicit StringShape(Map* s); inline explicit StringShape(InstanceType t); - inline bool IsAsciiRepresentation(); - inline bool IsTwoByteRepresentation(); inline bool IsSequential(); inline bool IsExternal(); inline bool IsCons(); @@ -3220,6 +3267,9 @@ class String: public HeapObject { inline uint32_t length_field(); inline void set_length_field(uint32_t value); + inline bool IsAsciiRepresentation(); + inline bool IsTwoByteRepresentation(); + // Get and set individual two byte chars in the string. inline void Set(int index, uint16_t value); // Get individual two byte char in the string. Repeated calls @@ -3859,9 +3909,6 @@ class JSArray: public JSObject { // Set the content of the array to the content of storage. inline void SetContent(FixedArray* storage); - // Support for sorting - Object* RemoveHoles(); - // Casting. static inline JSArray* cast(Object* obj); @@ -4147,6 +4194,7 @@ class TypeSwitchInfo: public Struct { }; +#ifdef ENABLE_DEBUGGER_SUPPORT // The DebugInfo class holds additional information for a function being // debugged. class DebugInfo: public Struct { @@ -4252,6 +4300,7 @@ class BreakPointInfo: public Struct { private: DISALLOW_IMPLICIT_CONSTRUCTORS(BreakPointInfo); }; +#endif // ENABLE_DEBUGGER_SUPPORT #undef DECL_BOOLEAN_ACCESSORS diff --git a/deps/v8/src/platform-freebsd.cc b/deps/v8/src/platform-freebsd.cc index 92099907b..82208f1a3 100644 --- a/deps/v8/src/platform-freebsd.cc +++ b/deps/v8/src/platform-freebsd.cc @@ -171,7 +171,7 @@ void OS::Abort() { void OS::DebugBreak() { -#if defined (__arm__) || defined(__thumb__) +#if defined(__arm__) || defined(__thumb__) asm("bkpt 0"); #else asm("int $3"); @@ -262,7 +262,8 @@ void OS::LogSharedLibraryAddresses() { } -int OS::StackWalk(OS::StackFrame* frames, int frames_size) { +int OS::StackWalk(Vector<OS::StackFrame> frames) { + int frames_size = frames.length(); void** addresses = NewArray<void*>(frames_size); int frames_count = backtrace(addresses, frames_size); @@ -502,27 +503,24 @@ void FreeBSDSemaphore::Wait() { bool FreeBSDSemaphore::Wait(int timeout) { const long kOneSecondMicros = 1000000; // NOLINT - const long kOneSecondNanos = 1000000000; // NOLINT // Split timeout into second and nanosecond parts. - long nanos = (timeout % kOneSecondMicros) * 1000; // NOLINT - time_t secs = timeout / kOneSecondMicros; + struct timeval delta; + delta.tv_usec = timeout % kOneSecondMicros; + delta.tv_sec = timeout / kOneSecondMicros; - // Get the current real time clock. - struct timespec ts; - if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { + struct timeval current_time; + // Get the current time. + if (gettimeofday(¤t_time, NULL) == -1) { return false; } - // Calculate realtime for end of timeout. - ts.tv_nsec += nanos; - if (ts.tv_nsec >= kOneSecondNanos) { - ts.tv_nsec -= kOneSecondNanos; - ts.tv_nsec++; - } - ts.tv_sec += secs; + // Calculate time for end of timeout. + struct timeval end_time; + timeradd(¤t_time, &delta, &end_time); - // Wait for semaphore signalled or timeout. + struct timespec ts; + TIMEVAL_TO_TIMESPEC(&end_time, &ts); while (true) { int result = sem_timedwait(&sem_, &ts); if (result == 0) return true; // Successfully got semaphore. diff --git a/deps/v8/src/platform-linux.cc b/deps/v8/src/platform-linux.cc index f9a5deacb..c02eebc3b 100644 --- a/deps/v8/src/platform-linux.cc +++ b/deps/v8/src/platform-linux.cc @@ -171,6 +171,8 @@ void OS::Abort() { void OS::DebugBreak() { +// TODO(lrn): Introduce processor define for runtime system (!= V8_ARCH_x, +// which is the architecture of generated code). #if defined(__arm__) || defined(__thumb__) asm("bkpt 0"); #else @@ -262,9 +264,10 @@ void OS::LogSharedLibraryAddresses() { } -int OS::StackWalk(OS::StackFrame* frames, int frames_size) { +int OS::StackWalk(Vector<OS::StackFrame> frames) { // backtrace is a glibc extension. #ifdef __GLIBC__ + int frames_size = frames.length(); void** addresses = NewArray<void*>(frames_size); int frames_count = backtrace(addresses, frames_size); @@ -506,28 +509,34 @@ void LinuxSemaphore::Wait() { } +#ifndef TIMEVAL_TO_TIMESPEC +#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \ + (ts)->tv_sec = (tv)->tv_sec; \ + (ts)->tv_nsec = (tv)->tv_usec * 1000; \ +} while (false) +#endif + + bool LinuxSemaphore::Wait(int timeout) { const long kOneSecondMicros = 1000000; // NOLINT - const long kOneSecondNanos = 1000000000; // NOLINT // Split timeout into second and nanosecond parts. - long nanos = (timeout % kOneSecondMicros) * 1000; // NOLINT - time_t secs = timeout / kOneSecondMicros; + struct timeval delta; + delta.tv_usec = timeout % kOneSecondMicros; + delta.tv_sec = timeout / kOneSecondMicros; - // Get the current realtime clock. - struct timespec ts; - if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { + struct timeval current_time; + // Get the current time. + if (gettimeofday(¤t_time, NULL) == -1) { return false; } - // Calculate real time for end of timeout. - ts.tv_nsec += nanos; - if (ts.tv_nsec >= kOneSecondNanos) { - ts.tv_nsec -= kOneSecondNanos; - ts.tv_nsec++; - } - ts.tv_sec += secs; + // Calculate time for end of timeout. + struct timeval end_time; + timeradd(¤t_time, &delta, &end_time); + struct timespec ts; + TIMEVAL_TO_TIMESPEC(&end_time, &ts); // Wait for semaphore signalled or timeout. while (true) { int result = sem_timedwait(&sem_, &ts); @@ -591,14 +600,18 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { // Extracting the sample from the context is extremely machine dependent. ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); mcontext_t& mcontext = ucontext->uc_mcontext; -#if defined (__arm__) || defined(__thumb__) - sample.pc = mcontext.gregs[R15]; - sample.sp = mcontext.gregs[R13]; - sample.fp = mcontext.gregs[R11]; -#else +#if V8_HOST_ARCH_IA32 sample.pc = mcontext.gregs[REG_EIP]; sample.sp = mcontext.gregs[REG_ESP]; sample.fp = mcontext.gregs[REG_EBP]; +#elif V8_HOST_ARCH_X64 + sample.pc = mcontext.gregs[REG_RIP]; + sample.sp = mcontext.gregs[REG_RSP]; + sample.fp = mcontext.gregs[REG_RBP]; +#elif V8_HOST_ARCH_ARM + sample.pc = mcontext.gregs[R15]; + sample.sp = mcontext.gregs[R13]; + sample.fp = mcontext.gregs[R11]; #endif } diff --git a/deps/v8/src/platform-macos.cc b/deps/v8/src/platform-macos.cc index b13122fae..79515434e 100644 --- a/deps/v8/src/platform-macos.cc +++ b/deps/v8/src/platform-macos.cc @@ -212,10 +212,11 @@ int OS::ActivationFrameAlignment() { } -int OS::StackWalk(StackFrame* frames, int frames_size) { +int OS::StackWalk(Vector<StackFrame> frames) { #ifndef MAC_OS_X_VERSION_10_5 return 0; #else + int frames_size = frames.length(); void** addresses = NewArray<void*>(frames_size); int frames_count = backtrace(addresses, frames_size); diff --git a/deps/v8/src/platform-nullos.cc b/deps/v8/src/platform-nullos.cc index 3a50b9ddd..42583f17f 100644 --- a/deps/v8/src/platform-nullos.cc +++ b/deps/v8/src/platform-nullos.cc @@ -215,7 +215,7 @@ void OS::LogSharedLibraryAddresses() { } -int OS::StackWalk(OS::StackFrame* frames, int frames_size) { +int OS::StackWalk(Vector<OS::StackFrame> frames) { UNIMPLEMENTED(); return 0; } diff --git a/deps/v8/src/platform-win32.cc b/deps/v8/src/platform-win32.cc index 717787022..6c4e67a7f 100644 --- a/deps/v8/src/platform-win32.cc +++ b/deps/v8/src/platform-win32.cc @@ -1161,7 +1161,7 @@ void OS::LogSharedLibraryAddresses() { // it is triggered by the use of inline assembler. #pragma warning(push) #pragma warning(disable : 4748) -int OS::StackWalk(OS::StackFrame* frames, int frames_size) { +int OS::StackWalk(Vector<OS::StackFrame> frames) { BOOL ok; // Load the required functions from DLL's. @@ -1201,6 +1201,7 @@ int OS::StackWalk(OS::StackFrame* frames, int frames_size) { int frames_count = 0; // Collect stack frames. + int frames_size = frames.length(); while (frames_count < frames_size) { ok = _StackWalk64( IMAGE_FILE_MACHINE_I386, // MachineType @@ -1284,7 +1285,7 @@ int OS::StackWalk(OS::StackFrame* frames, int frames_size) { #else // __MINGW32__ void OS::LogSharedLibraryAddresses() { } -int OS::StackWalk(OS::StackFrame* frames, int frames_size) { return 0; } +int OS::StackWalk(Vector<OS::StackFrame> frames) { return 0; } #endif // __MINGW32__ @@ -1774,9 +1775,16 @@ class Sampler::PlatformData : public Malloced { context.ContextFlags = CONTEXT_FULL; GetThreadContext(profiled_thread_, &context); // Invoke tick handler with program counter and stack pointer. +#if V8_HOST_ARCH_X64 + UNIMPLEMENTED(); + sample.pc = context.Rip; + sample.sp = context.Rsp; + sample.fp = context.Rbp; +#else sample.pc = context.Eip; sample.sp = context.Esp; sample.fp = context.Ebp; +#endif } // We always sample the VM state. diff --git a/deps/v8/src/platform.h b/deps/v8/src/platform.h index db4f2fdab..e23abfc37 100644 --- a/deps/v8/src/platform.h +++ b/deps/v8/src/platform.h @@ -207,7 +207,7 @@ class OS { char text[kStackWalkMaxTextLen]; }; - static int StackWalk(StackFrame* frames, int frames_size); + static int StackWalk(Vector<StackFrame> frames); // Factory method for creating platform dependent Mutex. // Please use delete to reclaim the storage for the returned Mutex. @@ -350,7 +350,16 @@ class Thread: public ThreadHandle { static LocalStorageKey CreateThreadLocalKey(); static void DeleteThreadLocalKey(LocalStorageKey key); static void* GetThreadLocal(LocalStorageKey key); + static int GetThreadLocalInt(LocalStorageKey key) { + return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key))); + } static void SetThreadLocal(LocalStorageKey key, void* value); + static void SetThreadLocalInt(LocalStorageKey key, int value) { + SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value))); + } + static bool HasThreadLocal(LocalStorageKey key) { + return GetThreadLocal(key) != NULL; + } // A hint to the scheduler to let another thread run. static void YieldCPU(); @@ -483,9 +492,9 @@ class Socket { class TickSample { public: TickSample() : pc(0), sp(0), fp(0), state(OTHER) {} - unsigned int pc; // Instruction pointer. - unsigned int sp; // Stack pointer. - unsigned int fp; // Frame pointer. + uintptr_t pc; // Instruction pointer. + uintptr_t sp; // Stack pointer. + uintptr_t fp; // Frame pointer. StateTag state; // The state of the VM. static const int kMaxFramesCount = 100; EmbeddedVector<Address, kMaxFramesCount> stack; // Call stack. diff --git a/deps/v8/src/property.h b/deps/v8/src/property.h index 65d4a0d6d..60a9b544d 100644 --- a/deps/v8/src/property.h +++ b/deps/v8/src/property.h @@ -245,14 +245,25 @@ class LookupResult BASE_EMBEDDED { // Tells whether the value needs to be loaded. bool IsLoaded() { if (lookup_type_ == DESCRIPTOR_TYPE || lookup_type_ == DICTIONARY_TYPE) { - Object* value = GetValue(); - if (value->IsJSFunction()) { - return JSFunction::cast(value)->IsLoaded(); - } + Object* target = GetLazyValue(); + return !target->IsJSObject() || JSObject::cast(target)->IsLoaded(); } return true; } + Object* GetLazyValue() { + switch (type()) { + case FIELD: + return holder()->FastPropertyAt(GetFieldIndex()); + case NORMAL: + return holder()->property_dictionary()->ValueAt(GetDictionaryEntry()); + case CONSTANT_FUNCTION: + return GetConstantFunction(); + default: + return Smi::FromInt(0); + } + } + Map* GetTransitionMap() { ASSERT(lookup_type_ == DESCRIPTOR_TYPE); ASSERT(type() == MAP_TRANSITION); diff --git a/deps/v8/src/regexp-macro-assembler-irregexp-inl.h b/deps/v8/src/regexp-macro-assembler-irregexp-inl.h index 378529108..fa4c3d16b 100644 --- a/deps/v8/src/regexp-macro-assembler-irregexp-inl.h +++ b/deps/v8/src/regexp-macro-assembler-irregexp-inl.h @@ -32,6 +32,8 @@ #include "ast.h" #include "bytecodes-irregexp.h" +#ifndef V8_REGEXP_MACRO_ASSEMBLER_IRREGEXP_INL_H_ +#define V8_REGEXP_MACRO_ASSEMBLER_IRREGEXP_INL_H_ namespace v8 { namespace internal { @@ -69,3 +71,5 @@ void RegExpMacroAssemblerIrregexp::Emit32(uint32_t word) { } } // namespace v8::internal + +#endif // V8_REGEXP_MACRO_ASSEMBLER_IRREGEXP_INL_H_ diff --git a/deps/v8/src/regexp-macro-assembler-tracer.h b/deps/v8/src/regexp-macro-assembler-tracer.h index d3aeff73a..f25289e6e 100644 --- a/deps/v8/src/regexp-macro-assembler-tracer.h +++ b/deps/v8/src/regexp-macro-assembler-tracer.h @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef REGEXP_MACRO_ASSEMBLER_TRACER_H_ -#define REGEXP_MACRO_ASSEMBLER_TRACER_H_ +#ifndef V8_REGEXP_MACRO_ASSEMBLER_TRACER_H_ +#define V8_REGEXP_MACRO_ASSEMBLER_TRACER_H_ namespace v8 { namespace internal { @@ -115,4 +115,4 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler { }} // namespace v8::internal -#endif // REGEXP_MACRO_ASSEMBLER_TRACER_H_ +#endif // V8_REGEXP_MACRO_ASSEMBLER_TRACER_H_ diff --git a/deps/v8/src/regexp-stack.h b/deps/v8/src/regexp-stack.h index e47462ffd..b955e76a0 100644 --- a/deps/v8/src/regexp-stack.h +++ b/deps/v8/src/regexp-stack.h @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef REGEXP_STACK_H_ -#define REGEXP_STACK_H_ +#ifndef V8_REGEXP_STACK_H_ +#define V8_REGEXP_STACK_H_ namespace v8 { namespace internal { @@ -103,4 +103,4 @@ class RegExpStack { }} // namespace v8::internal -#endif /* REGEXP_STACK_H_ */ +#endif // V8_REGEXP_STACK_H_ diff --git a/deps/v8/src/register-allocator.h b/deps/v8/src/register-allocator.h index dcc2eb7ee..f79d6cfdf 100644 --- a/deps/v8/src/register-allocator.h +++ b/deps/v8/src/register-allocator.h @@ -275,6 +275,11 @@ class RegisterAllocator BASE_EMBEDDED { // Unuse all the reserved registers in a register file. static void UnuseReserved(RegisterFile* register_file); + // True if the register is reserved by the code generator, false if it + // can be freely used by the allocator. + static bool IsReserved(int reg_code); + static bool IsReserved(Register reg) { return IsReserved(reg); } + // Predicates and accessors for the registers' reference counts. bool is_used(int reg_code) const { return registers_.is_used(reg_code); } bool is_used(Register reg) const { return registers_.is_used(reg.code()); } diff --git a/deps/v8/src/rewriter.cc b/deps/v8/src/rewriter.cc index 6641f2615..4e3676b7d 100644 --- a/deps/v8/src/rewriter.cc +++ b/deps/v8/src/rewriter.cc @@ -194,7 +194,7 @@ void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) { if (node->name()->length() == 0) { // Anonymous function. - func_name_inferrer_.SetFuncToInfer(node); + func_name_inferrer_.AddFunction(node); } } @@ -282,10 +282,7 @@ void AstOptimizer::VisitAssignment(Assignment* node) { case Token::ASSIGN: // No type can be infered from the general assignment. - if (node->value()->AsFunctionLiteral() != NULL || - node->value()->AsObjectLiteral() != NULL) { - scoped_fni.Enter(); - } + scoped_fni.Enter(); break; case Token::ASSIGN_BIT_OR: case Token::ASSIGN_BIT_XOR: diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index ab25c9ec3..bf6286fe3 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -474,6 +474,42 @@ static Object* Runtime_IsInPrototypeChain(Arguments args) { } +// Inserts an object as the hidden prototype of another object. +static Object* Runtime_SetHiddenPrototype(Arguments args) { + NoHandleAllocation ha; + ASSERT(args.length() == 2); + CONVERT_CHECKED(JSObject, jsobject, args[0]); + CONVERT_CHECKED(JSObject, proto, args[1]); + + // Sanity checks. The old prototype (that we are replacing) could + // theoretically be null, but if it is not null then check that we + // didn't already install a hidden prototype here. + RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() || + !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype()); + RUNTIME_ASSERT(!proto->map()->is_hidden_prototype()); + + // Allocate up front before we start altering state in case we get a GC. + Object* map_or_failure = proto->map()->CopyDropTransitions(); + if (map_or_failure->IsFailure()) return map_or_failure; + Map* new_proto_map = Map::cast(map_or_failure); + + map_or_failure = jsobject->map()->CopyDropTransitions(); + if (map_or_failure->IsFailure()) return map_or_failure; + Map* new_map = Map::cast(map_or_failure); + + // Set proto's prototype to be the old prototype of the object. + new_proto_map->set_prototype(jsobject->GetPrototype()); + proto->set_map(new_proto_map); + new_proto_map->set_is_hidden_prototype(); + + // Set the object's prototype to proto. + new_map->set_prototype(proto); + jsobject->set_map(new_map); + + return Heap::undefined_value(); +} + + static Object* Runtime_IsConstructCall(Arguments args) { NoHandleAllocation ha; ASSERT(args.length() == 0); @@ -1282,7 +1318,7 @@ class ReplacementStringBuilder { parts_(Factory::NewFixedArray(estimated_part_count)), part_count_(0), character_count_(0), - is_ascii_(StringShape(*subject).IsAsciiRepresentation()) { + is_ascii_(subject->IsAsciiRepresentation()) { // Require a non-zero initial size. Ensures that doubling the size to // extend the array will work. ASSERT(estimated_part_count > 0); @@ -1326,7 +1362,7 @@ class ReplacementStringBuilder { int length = string->length(); ASSERT(length > 0); AddElement(*string); - if (!StringShape(*string).IsAsciiRepresentation()) { + if (!string->IsAsciiRepresentation()) { is_ascii_ = false; } IncrementCharacterCount(length); @@ -1583,14 +1619,14 @@ void CompiledReplacement::Compile(Handle<String> replacement, int capture_count, int subject_length) { ASSERT(replacement->IsFlat()); - if (StringShape(*replacement).IsAsciiRepresentation()) { + if (replacement->IsAsciiRepresentation()) { AssertNoAllocation no_alloc; ParseReplacementPattern(&parts_, replacement->ToAsciiVector(), capture_count, subject_length); } else { - ASSERT(StringShape(*replacement).IsTwoByteRepresentation()); + ASSERT(replacement->IsTwoByteRepresentation()); AssertNoAllocation no_alloc; ParseReplacementPattern(&parts_, @@ -2165,7 +2201,7 @@ int Runtime::StringMatch(Handle<String> sub, // algorithm is unnecessary overhead. if (pattern_length == 1) { AssertNoAllocation no_heap_allocation; // ensure vectors stay valid - if (StringShape(*sub).IsAsciiRepresentation()) { + if (sub->IsAsciiRepresentation()) { uc16 pchar = pat->Get(0); if (pchar > String::kMaxAsciiCharCode) { return -1; @@ -2190,15 +2226,15 @@ int Runtime::StringMatch(Handle<String> sub, AssertNoAllocation no_heap_allocation; // ensure vectors stay valid // dispatch on type of strings - if (StringShape(*pat).IsAsciiRepresentation()) { + if (pat->IsAsciiRepresentation()) { Vector<const char> pat_vector = pat->ToAsciiVector(); - if (StringShape(*sub).IsAsciiRepresentation()) { + if (sub->IsAsciiRepresentation()) { return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); } return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); } Vector<const uc16> pat_vector = pat->ToUC16Vector(); - if (StringShape(*sub).IsAsciiRepresentation()) { + if (sub->IsAsciiRepresentation()) { return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); } return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); @@ -2688,6 +2724,59 @@ Object* Runtime::SetObjectProperty(Handle<Object> object, } +Object* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object, + Handle<Object> key, + Handle<Object> value, + PropertyAttributes attr) { + HandleScope scope; + + // Check if the given key is an array index. + uint32_t index; + if (Array::IndexFromObject(*key, &index)) { + ASSERT(attr == NONE); + + // In Firefox/SpiderMonkey, Safari and Opera you can access the characters + // of a string using [] notation. We need to support this too in + // JavaScript. + // In the case of a String object we just need to redirect the assignment to + // the underlying string if the index is in range. Since the underlying + // string does nothing with the assignment then we can ignore such + // assignments. + if (js_object->IsStringObjectWithCharacterAt(index)) { + return *value; + } + + return js_object->SetElement(index, *value); + } + + if (key->IsString()) { + if (Handle<String>::cast(key)->AsArrayIndex(&index)) { + ASSERT(attr == NONE); + return js_object->SetElement(index, *value); + } else { + Handle<String> key_string = Handle<String>::cast(key); + key_string->TryFlattenIfNotFlat(); + return js_object->IgnoreAttributesAndSetLocalProperty(*key_string, + *value, + attr); + } + } + + // Call-back into JavaScript to convert the key to a string. + bool has_pending_exception = false; + Handle<Object> converted = Execution::ToString(key, &has_pending_exception); + if (has_pending_exception) return Failure::Exception(); + Handle<String> name = Handle<String>::cast(converted); + + if (name->AsArrayIndex(&index)) { + ASSERT(attr == NONE); + return js_object->SetElement(index, *value); + } else { + return js_object->IgnoreAttributesAndSetLocalProperty(*name, *value, attr); + } +} + + static Object* Runtime_SetProperty(Arguments args) { NoHandleAllocation ha; RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); @@ -2743,20 +2832,42 @@ static Object* Runtime_DeleteProperty(Arguments args) { } +static Object* HasLocalPropertyImplementation(Handle<JSObject> object, + Handle<String> key) { + if (object->HasLocalProperty(*key)) return Heap::true_value(); + // Handle hidden prototypes. If there's a hidden prototype above this thing + // then we have to check it for properties, because they are supposed to + // look like they are on this object. + Handle<Object> proto(object->GetPrototype()); + if (proto->IsJSObject() && + Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) { + return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key); + } + return Heap::false_value(); +} + + static Object* Runtime_HasLocalProperty(Arguments args) { NoHandleAllocation ha; ASSERT(args.length() == 2); CONVERT_CHECKED(String, key, args[1]); + Object* obj = args[0]; // Only JS objects can have properties. - if (args[0]->IsJSObject()) { - JSObject* object = JSObject::cast(args[0]); - if (object->HasLocalProperty(key)) return Heap::true_value(); - } else if (args[0]->IsString()) { + if (obj->IsJSObject()) { + JSObject* object = JSObject::cast(obj); + // Fast case - no interceptors. + if (object->HasRealNamedProperty(key)) return Heap::true_value(); + // Slow case. Either it's not there or we have an interceptor. We should + // have handles for this kind of deal. + HandleScope scope; + return HasLocalPropertyImplementation(Handle<JSObject>(object), + Handle<String>(key)); + } else if (obj->IsString()) { // Well, there is one exception: Handle [] on strings. uint32_t index; if (key->AsArrayIndex(&index)) { - String* string = String::cast(args[0]); + String* string = String::cast(obj); if (index < static_cast<uint32_t>(string->length())) return Heap::true_value(); } @@ -3276,7 +3387,7 @@ static Object* ConvertCaseHelper(String* s, // character is also ascii. This is currently the case, but it // might break in the future if we implement more context and locale // dependent upper/lower conversions. - Object* o = StringShape(s).IsAsciiRepresentation() + Object* o = s->IsAsciiRepresentation() ? Heap::AllocateRawAsciiString(length) : Heap::AllocateRawTwoByteString(length); if (o->IsFailure()) return o; @@ -3482,6 +3593,7 @@ static Object* Runtime_NumberToSmi(Arguments args) { return Heap::nan_value(); } + static Object* Runtime_NumberAdd(Arguments args) { NoHandleAllocation ha; ASSERT(args.length() == 2); @@ -3626,7 +3738,7 @@ static Object* Runtime_StringBuilderConcat(Arguments args) { if (first->IsString()) return first; } - bool ascii = StringShape(special).IsAsciiRepresentation(); + bool ascii = special->IsAsciiRepresentation(); int position = 0; for (int i = 0; i < array_length; i++) { Object* elt = fixed_array->get(i); @@ -3646,7 +3758,7 @@ static Object* Runtime_StringBuilderConcat(Arguments args) { return Failure::OutOfMemoryException(); } position += element_length; - if (ascii && !StringShape(element).IsAsciiRepresentation()) { + if (ascii && !element->IsAsciiRepresentation()) { ascii = false; } } else { @@ -4158,10 +4270,12 @@ static Object* Runtime_NewObject(Arguments args) { JSFunction* function = JSFunction::cast(constructor); // Handle stepping into constructors if step into is active. +#ifdef ENABLE_DEBUGGER_SUPPORT if (Debug::StepInActive()) { HandleScope scope; Debug::HandleStepIn(Handle<JSFunction>(function), 0, true); } +#endif if (function->has_initial_map() && function->initial_map()->instance_type() == JS_FUNCTION_TYPE) { @@ -4525,12 +4639,6 @@ static Object* Runtime_StackOverflow(Arguments args) { } -static Object* Runtime_DebugBreak(Arguments args) { - ASSERT(args.length() == 0); - return Execution::DebugBreakHelper(); -} - - static Object* Runtime_StackGuard(Arguments args) { ASSERT(args.length() == 1); @@ -4707,10 +4815,10 @@ static Object* Runtime_DateParseString(Arguments args) { FixedArray* output_array = output->elements(); RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE); bool result; - if (StringShape(*str).IsAsciiRepresentation()) { + if (str->IsAsciiRepresentation()) { result = DateParser::Parse(str->ToAsciiVector(), output_array); } else { - ASSERT(StringShape(*str).IsTwoByteRepresentation()); + ASSERT(str->IsTwoByteRepresentation()); result = DateParser::Parse(str->ToUC16Vector(), output_array); } @@ -4774,14 +4882,18 @@ static Object* Runtime_GlobalReceiver(Arguments args) { static Object* Runtime_CompileString(Arguments args) { HandleScope scope; - ASSERT(args.length() == 2); + ASSERT_EQ(3, args.length()); CONVERT_ARG_CHECKED(String, source, 0); CONVERT_ARG_CHECKED(Smi, line_offset, 1); + CONVERT_ARG_CHECKED(Oddball, is_json, 2) // Compile source string in the global context. Handle<Context> context(Top::context()->global_context()); - Handle<JSFunction> boilerplate = - Compiler::CompileEval(source, context, line_offset->value(), true); + Handle<JSFunction> boilerplate = Compiler::CompileEval(source, + context, + line_offset->value(), + true, + is_json->IsTrue()); if (boilerplate.is_null()) return Failure::Exception(); Handle<JSFunction> fun = Factory::NewFunctionFromBoilerplate(boilerplate, context); @@ -4806,7 +4918,7 @@ static Object* CompileDirectEval(Handle<String> source) { // Compile source string in the current context. Handle<JSFunction> boilerplate = - Compiler::CompileEval(source, context, 0, is_global); + Compiler::CompileEval(source, context, 0, is_global, false); if (boilerplate.is_null()) return Failure::Exception(); Handle<JSFunction> fun = Factory::NewFunctionFromBoilerplate(boilerplate, context); @@ -4892,26 +5004,6 @@ static Object* Runtime_ResolvePossiblyDirectEval(Arguments args) { } -static Object* Runtime_CompileScript(Arguments args) { - HandleScope scope; - ASSERT(args.length() == 4); - - CONVERT_ARG_CHECKED(String, source, 0); - CONVERT_ARG_CHECKED(String, script, 1); - CONVERT_CHECKED(Smi, line_attrs, args[2]); - int line = line_attrs->value(); - CONVERT_CHECKED(Smi, col_attrs, args[3]); - int col = col_attrs->value(); - Handle<JSFunction> boilerplate = - Compiler::Compile(source, script, line, col, NULL, NULL); - if (boilerplate.is_null()) return Failure::Exception(); - Handle<JSFunction> fun = - Factory::NewFunctionFromBoilerplate(boilerplate, - Handle<Context>(Top::context())); - return *fun; -} - - static Object* Runtime_SetNewFunctionAttributes(Arguments args) { // This utility adjusts the property attributes for newly created Function // object ("new Function(...)") by changing the map. @@ -5210,12 +5302,16 @@ static Object* Runtime_GlobalPrint(Arguments args) { return string; } - +// Moves all own elements of an object, that are below a limit, to positions +// starting at zero. All undefined values are placed after non-undefined values, +// and are followed by non-existing element. Does not change the length +// property. +// Returns the number of non-undefined elements collected. static Object* Runtime_RemoveArrayHoles(Arguments args) { - ASSERT(args.length() == 1); - // Ignore the case if this is not a JSArray. - if (!args[0]->IsJSArray()) return args[0]; - return JSArray::cast(args[0])->RemoveHoles(); + ASSERT(args.length() == 2); + CONVERT_CHECKED(JSObject, object, args[0]); + CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); + return object->PrepareElementsForSort(limit); } @@ -5251,8 +5347,7 @@ static Object* Runtime_EstimateNumberOfElements(Arguments args) { static Object* Runtime_GetArrayKeys(Arguments args) { ASSERT(args.length() == 2); HandleScope scope; - CONVERT_CHECKED(JSArray, raw_array, args[0]); - Handle<JSArray> array(raw_array); + CONVERT_ARG_CHECKED(JSObject, array, 0); CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]); if (array->elements()->IsDictionary()) { // Create an array and get all the keys into it, then remove all the @@ -5274,8 +5369,10 @@ static Object* Runtime_GetArrayKeys(Arguments args) { single_interval->set(0, Smi::FromInt(-1), SKIP_WRITE_BARRIER); + uint32_t actual_length = static_cast<uint32_t>(array->elements()->length()); + uint32_t min_length = actual_length < length ? actual_length : length; Handle<Object> length_object = - Factory::NewNumber(static_cast<double>(length)); + Factory::NewNumber(static_cast<double>(min_length)); single_interval->set(1, *length_object); return *Factory::NewJSArrayWithElements(single_interval); } @@ -5316,6 +5413,13 @@ static Object* Runtime_LookupAccessor(Arguments args) { } +#ifdef ENABLE_DEBUGGER_SUPPORT +static Object* Runtime_DebugBreak(Arguments args) { + ASSERT(args.length() == 0); + return Execution::DebugBreakHelper(); +} + + // Helper functions for wrapping and unwrapping stack frame ids. static Smi* WrapFrameId(StackFrame::Id id) { ASSERT(IsAligned(OffsetFrom(id), 4)); @@ -5928,8 +6032,8 @@ static Object* Runtime_GetCFrames(Arguments args) { if (result->IsFailure()) return result; static const int kMaxCFramesSize = 200; - OS::StackFrame frames[kMaxCFramesSize]; - int frames_count = OS::StackWalk(frames, kMaxCFramesSize); + ScopedVector<OS::StackFrame> frames(kMaxCFramesSize); + int frames_count = OS::StackWalk(frames); if (frames_count == OS::kStackWalkError) { return Heap::undefined_value(); } @@ -6442,7 +6546,8 @@ static Object* Runtime_DebugEvaluate(Arguments args) { Compiler::CompileEval(function_source, context, 0, - context->IsGlobalContext()); + context->IsGlobalContext(), + false); if (boilerplate.is_null()) return Failure::Exception(); Handle<JSFunction> compiled_function = Factory::NewFunctionFromBoilerplate(boilerplate, context); @@ -6500,7 +6605,11 @@ static Object* Runtime_DebugEvaluateGlobal(Arguments args) { // Compile the source to be evaluated. Handle<JSFunction> boilerplate = - Handle<JSFunction>(Compiler::CompileEval(source, context, 0, true)); + Handle<JSFunction>(Compiler::CompileEval(source, + context, + 0, + true, + false)); if (boilerplate.is_null()) return Failure::Exception(); Handle<JSFunction> compiled_function = Handle<JSFunction>(Factory::NewFunctionFromBoilerplate(boilerplate, @@ -6523,9 +6632,9 @@ static bool IsExternalStringValid(Object* str) { if (!str->IsString() || !StringShape(String::cast(str)).IsExternal()) { return true; } - if (StringShape(String::cast(str)).IsAsciiRepresentation()) { + if (String::cast(str)->IsAsciiRepresentation()) { return ExternalAsciiString::cast(str)->resource() != NULL; - } else if (StringShape(String::cast(str)).IsTwoByteRepresentation()) { + } else if (String::cast(str)->IsTwoByteRepresentation()) { return ExternalTwoByteString::cast(str)->resource() != NULL; } else { return true; @@ -6796,6 +6905,31 @@ static Object* Runtime_SystemBreak(Arguments args) { } +static Object* Runtime_FunctionGetAssemblerCode(Arguments args) { +#ifdef DEBUG + HandleScope scope; + ASSERT(args.length() == 1); + // Get the function and make sure it is compiled. + CONVERT_ARG_CHECKED(JSFunction, func, 0); + if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) { + return Failure::Exception(); + } + func->code()->PrintLn(); +#endif // DEBUG + return Heap::undefined_value(); +} + + +static Object* Runtime_FunctionGetInferredName(Arguments args) { + NoHandleAllocation ha; + ASSERT(args.length() == 1); + + CONVERT_CHECKED(JSFunction, f, args[0]); + return f->shared()->inferred_name(); +} +#endif // ENABLE_DEBUGGER_SUPPORT + + // Finds the script object from the script data. NOTE: This operation uses // heap traversal to find the function generated for the source position // for the requested break point. For lazily compiled functions several heap @@ -6845,21 +6979,6 @@ static Object* Runtime_GetScript(Arguments args) { } -static Object* Runtime_FunctionGetAssemblerCode(Arguments args) { -#ifdef DEBUG - HandleScope scope; - ASSERT(args.length() == 1); - // Get the function and make sure it is compiled. - CONVERT_ARG_CHECKED(JSFunction, func, 0); - if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) { - return Failure::Exception(); - } - func->code()->PrintLn(); -#endif // DEBUG - return Heap::undefined_value(); -} - - static Object* Runtime_Abort(Arguments args) { ASSERT(args.length() == 2); OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) + diff --git a/deps/v8/src/runtime.h b/deps/v8/src/runtime.h index 657e5c5d9..204129515 100644 --- a/deps/v8/src/runtime.h +++ b/deps/v8/src/runtime.h @@ -53,6 +53,7 @@ namespace v8 { namespace internal { F(ToSlowProperties, 1) \ \ F(IsInPrototypeChain, 2) \ + F(SetHiddenPrototype, 2) \ \ F(IsConstructCall, 0) \ \ @@ -194,8 +195,7 @@ namespace v8 { namespace internal { F(NumberIsFinite, 1) \ \ /* Globals */ \ - F(CompileString, 2) \ - F(CompileScript, 4) \ + F(CompileString, 3) \ F(GlobalPrint, 1) \ \ /* Eval */ \ @@ -206,7 +206,7 @@ namespace v8 { namespace internal { F(IgnoreAttributesAndSetProperty, -1 /* 3 or 4 */) \ \ /* Arrays */ \ - F(RemoveArrayHoles, 1) \ + F(RemoveArrayHoles, 2) \ F(GetArrayKeys, 2) \ F(MoveArrayContents, 2) \ F(EstimateNumberOfElements, 1) \ @@ -215,42 +215,6 @@ namespace v8 { namespace internal { F(DefineAccessor, -1 /* 4 or 5 */) \ F(LookupAccessor, 3) \ \ - /* Debugging */ \ - F(SetDebugEventListener, 2) \ - F(Break, 0) \ - F(DebugGetPropertyDetails, 2) \ - F(DebugGetProperty, 2) \ - F(DebugLocalPropertyNames, 1) \ - F(DebugLocalElementNames, 1) \ - F(DebugPropertyTypeFromDetails, 1) \ - F(DebugPropertyAttributesFromDetails, 1) \ - F(DebugPropertyIndexFromDetails, 1) \ - F(DebugInterceptorInfo, 1) \ - F(DebugNamedInterceptorPropertyNames, 1) \ - F(DebugIndexedInterceptorElementNames, 1) \ - F(DebugNamedInterceptorPropertyValue, 2) \ - F(DebugIndexedInterceptorElementValue, 2) \ - F(CheckExecutionState, 1) \ - F(GetFrameCount, 1) \ - F(GetFrameDetails, 2) \ - F(GetCFrames, 1) \ - F(GetThreadCount, 1) \ - F(GetThreadDetails, 2) \ - F(GetBreakLocations, 1) \ - F(SetFunctionBreakPoint, 3) \ - F(SetScriptBreakPoint, 3) \ - F(ClearBreakPoint, 1) \ - F(ChangeBreakOnException, 2) \ - F(PrepareStep, 3) \ - F(ClearStepping, 0) \ - F(DebugEvaluate, 4) \ - F(DebugEvaluateGlobal, 3) \ - F(DebugGetLoadedScripts, 0) \ - F(DebugReferencedBy, 3) \ - F(DebugConstructedBy, 2) \ - F(DebugGetPrototype, 1) \ - F(SystemBreak, 0) \ - \ /* Literals */ \ F(MaterializeRegExpLiteral, 4)\ F(CreateArrayLiteralBoilerplate, 3) \ @@ -290,8 +254,6 @@ namespace v8 { namespace internal { F(DebugTrace, 0) \ F(TraceEnter, 0) \ F(TraceExit, 1) \ - F(DebugBreak, 0) \ - F(FunctionGetAssemblerCode, 1) \ F(Abort, 2) \ /* Logging */ \ F(Log, 2) \ @@ -299,6 +261,49 @@ namespace v8 { namespace internal { /* Pseudo functions - handled as macros by parser */ \ F(IS_VAR, 1) +#ifdef ENABLE_DEBUGGER_SUPPORT +#define RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F) \ + /* Debugger support*/ \ + F(DebugBreak, 0) \ + F(SetDebugEventListener, 2) \ + F(Break, 0) \ + F(DebugGetPropertyDetails, 2) \ + F(DebugGetProperty, 2) \ + F(DebugLocalPropertyNames, 1) \ + F(DebugLocalElementNames, 1) \ + F(DebugPropertyTypeFromDetails, 1) \ + F(DebugPropertyAttributesFromDetails, 1) \ + F(DebugPropertyIndexFromDetails, 1) \ + F(DebugInterceptorInfo, 1) \ + F(DebugNamedInterceptorPropertyNames, 1) \ + F(DebugIndexedInterceptorElementNames, 1) \ + F(DebugNamedInterceptorPropertyValue, 2) \ + F(DebugIndexedInterceptorElementValue, 2) \ + F(CheckExecutionState, 1) \ + F(GetFrameCount, 1) \ + F(GetFrameDetails, 2) \ + F(GetCFrames, 1) \ + F(GetThreadCount, 1) \ + F(GetThreadDetails, 2) \ + F(GetBreakLocations, 1) \ + F(SetFunctionBreakPoint, 3) \ + F(SetScriptBreakPoint, 3) \ + F(ClearBreakPoint, 1) \ + F(ChangeBreakOnException, 2) \ + F(PrepareStep, 3) \ + F(ClearStepping, 0) \ + F(DebugEvaluate, 4) \ + F(DebugEvaluateGlobal, 3) \ + F(DebugGetLoadedScripts, 0) \ + F(DebugReferencedBy, 3) \ + F(DebugConstructedBy, 2) \ + F(DebugGetPrototype, 1) \ + F(SystemBreak, 0) \ + F(FunctionGetAssemblerCode, 1) \ + F(FunctionGetInferredName, 1) +#else +#define RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F) +#endif #ifdef DEBUG #define RUNTIME_FUNCTION_LIST_DEBUG(F) \ @@ -316,7 +321,8 @@ namespace v8 { namespace internal { #define RUNTIME_FUNCTION_LIST(F) \ RUNTIME_FUNCTION_LIST_ALWAYS(F) \ - RUNTIME_FUNCTION_LIST_DEBUG(F) + RUNTIME_FUNCTION_LIST_DEBUG(F) \ + RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F) // ---------------------------------------------------------------------------- // Runtime provides access to all C++ runtime functions. @@ -369,6 +375,11 @@ class Runtime : public AllStatic { Handle<Object> value, PropertyAttributes attr); + static Object* ForceSetObjectProperty(Handle<JSObject> object, + Handle<Object> key, + Handle<Object> value, + PropertyAttributes attr); + static Object* GetObjectProperty(Handle<Object> object, Handle<Object> key); // This function is used in FunctionNameUsing* tests. diff --git a/deps/v8/src/serialize.cc b/deps/v8/src/serialize.cc index 9a2be23e5..62287bc0d 100644 --- a/deps/v8/src/serialize.cc +++ b/deps/v8/src/serialize.cc @@ -78,8 +78,8 @@ const int kPageAndOffsetMask = (1 << kPageAndOffsetBits) - 1; static inline AllocationSpace GetSpace(Address addr) { - const int encoded = reinterpret_cast<int>(addr); - int space_number = ((encoded >> kSpaceShift) & kSpaceMask); + const intptr_t encoded = reinterpret_cast<intptr_t>(addr); + int space_number = (static_cast<int>(encoded >> kSpaceShift) & kSpaceMask); if (space_number == kLOSpaceExecutable) space_number = LO_SPACE; else if (space_number == kLOSpacePointer) space_number = LO_SPACE; return static_cast<AllocationSpace>(space_number); @@ -87,43 +87,45 @@ static inline AllocationSpace GetSpace(Address addr) { static inline bool IsLargeExecutableObject(Address addr) { - const int encoded = reinterpret_cast<int>(addr); - const int space_number = ((encoded >> kSpaceShift) & kSpaceMask); - if (space_number == kLOSpaceExecutable) return true; - return false; + const intptr_t encoded = reinterpret_cast<intptr_t>(addr); + const int space_number = + (static_cast<int>(encoded >> kSpaceShift) & kSpaceMask); + return (space_number == kLOSpaceExecutable); } static inline bool IsLargeFixedArray(Address addr) { - const int encoded = reinterpret_cast<int>(addr); - const int space_number = ((encoded >> kSpaceShift) & kSpaceMask); - if (space_number == kLOSpacePointer) return true; - return false; + const intptr_t encoded = reinterpret_cast<intptr_t>(addr); + const int space_number = + (static_cast<int>(encoded >> kSpaceShift) & kSpaceMask); + return (space_number == kLOSpacePointer); } static inline int PageIndex(Address addr) { - const int encoded = reinterpret_cast<int>(addr); - return (encoded >> kPageShift) & kPageMask; + const intptr_t encoded = reinterpret_cast<intptr_t>(addr); + return static_cast<int>(encoded >> kPageShift) & kPageMask; } static inline int PageOffset(Address addr) { - const int encoded = reinterpret_cast<int>(addr); - return ((encoded >> kOffsetShift) & kOffsetMask) << kObjectAlignmentBits; + const intptr_t encoded = reinterpret_cast<intptr_t>(addr); + const int offset = static_cast<int>(encoded >> kOffsetShift) & kOffsetMask; + return offset << kObjectAlignmentBits; } static inline int NewSpaceOffset(Address addr) { - const int encoded = reinterpret_cast<int>(addr); - return ((encoded >> kPageAndOffsetShift) & kPageAndOffsetMask) << - kObjectAlignmentBits; + const intptr_t encoded = reinterpret_cast<intptr_t>(addr); + const int page_offset = + static_cast<int>(encoded >> kPageAndOffsetShift) & kPageAndOffsetMask; + return page_offset << kObjectAlignmentBits; } static inline int LargeObjectIndex(Address addr) { - const int encoded = reinterpret_cast<int>(addr); - return (encoded >> kPageAndOffsetShift) & kPageAndOffsetMask; + const intptr_t encoded = reinterpret_cast<intptr_t>(addr); + return static_cast<int>(encoded >> kPageAndOffsetShift) & kPageAndOffsetMask; } @@ -548,6 +550,7 @@ void ExternalReferenceTable::PopulateTable() { AddFromId(ref_table[i].type, ref_table[i].id, ref_table[i].name); } +#ifdef ENABLE_DEBUGGER_SUPPORT // Debug addresses Add(Debug_Address(Debug::k_after_break_target_address).address(), DEBUG_ADDRESS, @@ -567,6 +570,7 @@ void ExternalReferenceTable::PopulateTable() { Debug::k_register_address << kDebugIdShift | i, name.start()); } +#endif // Stat counters struct StatsRefTableEntry { @@ -659,10 +663,6 @@ void ExternalReferenceTable::PopulateTable() { UNCLASSIFIED, 4, "RegExpStack::limit_address()"); - Add(ExternalReference::debug_break().address(), - UNCLASSIFIED, - 5, - "Debug::Break()"); Add(ExternalReference::new_space_start().address(), UNCLASSIFIED, 6, @@ -679,10 +679,28 @@ void ExternalReferenceTable::PopulateTable() { UNCLASSIFIED, 9, "Heap::NewSpaceAllocationTopAddress()"); +#ifdef ENABLE_DEBUGGER_SUPPORT + Add(ExternalReference::debug_break().address(), + UNCLASSIFIED, + 5, + "Debug::Break()"); Add(ExternalReference::debug_step_in_fp_address().address(), UNCLASSIFIED, 10, "Debug::step_in_fp_addr()"); + Add(ExternalReference::double_fp_operation(Token::ADD).address(), + UNCLASSIFIED, + 11, + "add_two_doubles"); + Add(ExternalReference::double_fp_operation(Token::SUB).address(), + UNCLASSIFIED, + 12, + "sub_two_doubles"); + Add(ExternalReference::double_fp_operation(Token::MUL).address(), + UNCLASSIFIED, + 13, + "mul_two_doubles"); +#endif } @@ -712,7 +730,9 @@ int ExternalReferenceEncoder::IndexOf(Address key) const { if (key == NULL) return -1; HashMap::Entry* entry = const_cast<HashMap &>(encodings_).Lookup(key, Hash(key), false); - return entry == NULL ? -1 : reinterpret_cast<int>(entry->value); + return entry == NULL + ? -1 + : static_cast<int>(reinterpret_cast<intptr_t>(entry->value)); } @@ -778,6 +798,10 @@ class SnapshotWriter { InsertInt(i, len_); } + void PutAddress(Address p) { + PutBytes(reinterpret_cast<byte*>(&p), sizeof(p)); + } + void PutBytes(const byte* a, int size) { InsertBytes(a, len_, size); } @@ -898,7 +922,8 @@ class ReferenceUpdater: public ObjectVisitor { // Helper functions for a map of encoded heap object addresses. static uint32_t HeapObjectHash(HeapObject* key) { - return reinterpret_cast<uint32_t>(key) >> 2; + uint32_t low32bits = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)); + return low32bits >> 2; } @@ -1137,7 +1162,7 @@ void Serializer::PutContextStack() { void Serializer::PutEncodedAddress(Address addr) { writer_->PutC('P'); - writer_->PutInt(reinterpret_cast<int>(addr)); + writer_->PutAddress(addr); } @@ -1320,7 +1345,7 @@ void Deserializer::VisitPointers(Object** start, Object** end) { *p = GetObject(); // embedded object } else { ASSERT(c == 'P'); // pointer to previously serialized object - *p = Resolve(reinterpret_cast<Address>(reader_.GetInt())); + *p = Resolve(reader_.GetAddress()); } } else { // A pointer internal to a HeapObject that we've already @@ -1334,7 +1359,7 @@ void Deserializer::VisitPointers(Object** start, Object** end) { void Deserializer::VisitExternalReferences(Address* start, Address* end) { for (Address* p = start; p < end; ++p) { - uint32_t code = reinterpret_cast<uint32_t>(*p); + uint32_t code = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(*p)); *p = reference_decoder_->Decode(code); } } @@ -1460,7 +1485,7 @@ void Deserializer::GetContextStack() { Address Deserializer::GetEncodedAddress() { reader_.ExpectC('P'); - return reinterpret_cast<Address>(reader_.GetInt()); + return reader_.GetAddress(); } diff --git a/deps/v8/src/serialize.h b/deps/v8/src/serialize.h index ce7d94784..f6594aca8 100644 --- a/deps/v8/src/serialize.h +++ b/deps/v8/src/serialize.h @@ -70,7 +70,7 @@ class ExternalReferenceEncoder { private: HashMap encodings_; static uint32_t Hash(Address key) { - return reinterpret_cast<uint32_t>(key) >> 2; + return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key) >> 2); } int IndexOf(Address key) const; @@ -231,6 +231,12 @@ class SnapshotReader { return result; } + Address GetAddress() { + Address result; + GetBytes(reinterpret_cast<Address>(&result), sizeof(result)); + return result; + } + void GetBytes(Address a, int size) { ASSERT(str_ + size <= end_); memcpy(a, str_, size); diff --git a/deps/v8/src/shell.h b/deps/v8/src/shell.h index 4042c07ca..671245128 100644 --- a/deps/v8/src/shell.h +++ b/deps/v8/src/shell.h @@ -27,6 +27,9 @@ // // A simple interactive shell. Enable with --shell. +#ifndef V8_SHELL_H_ +#define V8_SHELL_H_ + #include "../public/debug.h" namespace v8 { namespace internal { @@ -47,3 +50,5 @@ class Shell { }; } } // namespace v8::internal + +#endif // V8_SHELL_H_ diff --git a/deps/v8/src/spaces-inl.h b/deps/v8/src/spaces-inl.h index d7cddb4fd..397365847 100644 --- a/deps/v8/src/spaces-inl.h +++ b/deps/v8/src/spaces-inl.h @@ -64,15 +64,16 @@ HeapObject* HeapObjectIterator::next() { // PageIterator bool PageIterator::has_next() { - return cur_page_ != stop_page_; + return prev_page_ != stop_page_; } Page* PageIterator::next() { ASSERT(has_next()); - Page* result = cur_page_; - cur_page_ = cur_page_->next_page(); - return result; + prev_page_ = (prev_page_ == NULL) + ? space_->first_page_ + : prev_page_->next_page(); + return prev_page_; } diff --git a/deps/v8/src/spaces.cc b/deps/v8/src/spaces.cc index ea40d5211..f15af9e72 100644 --- a/deps/v8/src/spaces.cc +++ b/deps/v8/src/spaces.cc @@ -111,17 +111,17 @@ void HeapObjectIterator::Verify() { // ----------------------------------------------------------------------------- // PageIterator -PageIterator::PageIterator(PagedSpace* space, Mode mode) { - cur_page_ = space->first_page_; +PageIterator::PageIterator(PagedSpace* space, Mode mode) : space_(space) { + prev_page_ = NULL; switch (mode) { case PAGES_IN_USE: - stop_page_ = space->AllocationTopPage()->next_page(); + stop_page_ = space->AllocationTopPage(); break; case PAGES_USED_BY_MC: - stop_page_ = space->MCRelocationTopPage()->next_page(); + stop_page_ = space->MCRelocationTopPage(); break; case ALL_PAGES: - stop_page_ = Page::FromAddress(NULL); + stop_page_ = space->last_page_; break; default: UNREACHABLE(); @@ -496,8 +496,11 @@ bool PagedSpace::Setup(Address start, size_t size) { accounting_stats_.ExpandSpace(num_pages * Page::kObjectAreaSize); ASSERT(Capacity() <= max_capacity_); + // Sequentially initialize remembered sets in the newly allocated + // pages and cache the current last page in the space. for (Page* p = first_page_; p->is_valid(); p = p->next_page()) { p->ClearRSet(); + last_page_ = p; } // Use first_page_ for allocation. @@ -676,9 +679,11 @@ bool PagedSpace::Expand(Page* last_page) { MemoryAllocator::SetNextPage(last_page, p); - // Clear remembered set of new pages. + // Sequentially clear remembered set of new pages and and cache the + // new last page in the space. while (p->is_valid()) { p->ClearRSet(); + last_page_ = p; p = p->next_page(); } @@ -723,10 +728,12 @@ void PagedSpace::Shrink() { Page* p = MemoryAllocator::FreePages(last_page_to_keep->next_page()); MemoryAllocator::SetNextPage(last_page_to_keep, p); - // Since pages are only freed in whole chunks, we may have kept more than - // pages_to_keep. + // Since pages are only freed in whole chunks, we may have kept more + // than pages_to_keep. Count the extra pages and cache the new last + // page in the space. while (p->is_valid()) { pages_to_keep++; + last_page_ = p; p = p->next_page(); } @@ -811,7 +818,7 @@ bool NewSpace::Setup(Address start, int size) { start_ = start; address_mask_ = ~(size - 1); object_mask_ = address_mask_ | kHeapObjectTag; - object_expected_ = reinterpret_cast<uint32_t>(start) | kHeapObjectTag; + object_expected_ = reinterpret_cast<uintptr_t>(start) | kHeapObjectTag; allocation_info_.top = to_space_.low(); allocation_info_.limit = to_space_.high(); @@ -970,7 +977,7 @@ bool SemiSpace::Setup(Address start, start_ = start; address_mask_ = ~(maximum_capacity - 1); object_mask_ = address_mask_ | kHeapObjectTag; - object_expected_ = reinterpret_cast<uint32_t>(start) | kHeapObjectTag; + object_expected_ = reinterpret_cast<uintptr_t>(start) | kHeapObjectTag; age_mark_ = start_; return true; @@ -1890,7 +1897,7 @@ static void PrintRSetRange(Address start, Address end, Object** object_p, // If the range starts on on odd numbered word (eg, for large object extra // remembered set ranges), print some spaces. - if ((reinterpret_cast<uint32_t>(start) / kIntSize) % 2 == 1) { + if ((reinterpret_cast<uintptr_t>(start) / kIntSize) % 2 == 1) { PrintF(" "); } @@ -1929,7 +1936,7 @@ static void PrintRSetRange(Address start, Address end, Object** object_p, } // Print a newline after every odd numbered word, otherwise a space. - if ((reinterpret_cast<uint32_t>(rset_address) / kIntSize) % 2 == 1) { + if ((reinterpret_cast<uintptr_t>(rset_address) / kIntSize) % 2 == 1) { PrintF("\n"); } else { PrintF(" "); diff --git a/deps/v8/src/spaces.h b/deps/v8/src/spaces.h index 3138cc360..e8504a427 100644 --- a/deps/v8/src/spaces.h +++ b/deps/v8/src/spaces.h @@ -511,11 +511,22 @@ class ObjectIterator : public Malloced { // // A HeapObjectIterator iterates objects from a given address to the // top of a space. The given address must be below the current -// allocation pointer (space top). If the space top changes during -// iteration (because of allocating new objects), the iterator does -// not iterate new objects. The caller function must create a new -// iterator starting from the old top in order to visit these new -// objects. Heap::Scavenage() is such an example. +// allocation pointer (space top). There are some caveats. +// +// (1) If the space top changes upward during iteration (because of +// allocating new objects), the iterator does not iterate objects +// above the original space top. The caller must create a new +// iterator starting from the old top in order to visit these new +// objects. +// +// (2) If new objects are allocated below the original allocation top +// (e.g., free-list allocation in paged spaces), the new objects +// may or may not be iterated depending on their position with +// respect to the current point of iteration. +// +// (3) The space top should not change downward during iteration, +// otherwise the iterator will return not-necessarily-valid +// objects. class HeapObjectIterator: public ObjectIterator { public: @@ -559,17 +570,35 @@ class HeapObjectIterator: public ObjectIterator { // ----------------------------------------------------------------------------- -// A PageIterator iterates pages in a space. +// A PageIterator iterates the pages in a paged space. // // The PageIterator class provides three modes for iterating pages in a space: -// PAGES_IN_USE iterates pages that are in use by the allocator; -// PAGES_USED_BY_GC iterates pages that hold relocated objects during a -// mark-compact collection; +// PAGES_IN_USE iterates pages containing allocated objects. +// PAGES_USED_BY_MC iterates pages that hold relocated objects during a +// mark-compact collection. // ALL_PAGES iterates all pages in the space. +// +// There are some caveats. +// +// (1) If the space expands during iteration, new pages will not be +// returned by the iterator in any mode. +// +// (2) If new objects are allocated during iteration, they will appear +// in pages returned by the iterator. Allocation may cause the +// allocation pointer or MC allocation pointer in the last page to +// change between constructing the iterator and iterating the last +// page. +// +// (3) The space should not shrink during iteration, otherwise the +// iterator will return deallocated pages. class PageIterator BASE_EMBEDDED { public: - enum Mode {PAGES_IN_USE, PAGES_USED_BY_MC, ALL_PAGES}; + enum Mode { + PAGES_IN_USE, + PAGES_USED_BY_MC, + ALL_PAGES + }; PageIterator(PagedSpace* space, Mode mode); @@ -577,8 +606,9 @@ class PageIterator BASE_EMBEDDED { inline Page* next(); private: - Page* cur_page_; // next page to return - Page* stop_page_; // page where to stop + PagedSpace* space_; + Page* prev_page_; // Previous page returned. + Page* stop_page_; // Page to stop at (last page returned by the iterator). }; @@ -809,6 +839,10 @@ class PagedSpace : public Space { // The first page in this space. Page* first_page_; + // The last page in this space. Initially set in Setup, updated in + // Expand and Shrink. + Page* last_page_; + // Normal allocation information. AllocationInfo allocation_info_; @@ -939,14 +973,14 @@ class SemiSpace : public Space { // True if the address is in the address range of this semispace (not // necessarily below the allocation pointer). bool Contains(Address a) { - return (reinterpret_cast<uint32_t>(a) & address_mask_) - == reinterpret_cast<uint32_t>(start_); + return (reinterpret_cast<uintptr_t>(a) & address_mask_) + == reinterpret_cast<uintptr_t>(start_); } // True if the object is a heap object in the address range of this // semispace (not necessarily below the allocation pointer). bool Contains(Object* o) { - return (reinterpret_cast<uint32_t>(o) & object_mask_) == object_expected_; + return (reinterpret_cast<uintptr_t>(o) & object_mask_) == object_expected_; } // The offset of an address from the beginning of the space. @@ -975,9 +1009,9 @@ class SemiSpace : public Space { Address age_mark_; // Masks and comparison values to test for containment in this semispace. - uint32_t address_mask_; - uint32_t object_mask_; - uint32_t object_expected_; + uintptr_t address_mask_; + uintptr_t object_mask_; + uintptr_t object_expected_; public: TRACK_MEMORY("SemiSpace") @@ -1063,11 +1097,11 @@ class NewSpace : public Space { // True if the address or object lies in the address range of either // semispace (not necessarily below the allocation pointer). bool Contains(Address a) { - return (reinterpret_cast<uint32_t>(a) & address_mask_) - == reinterpret_cast<uint32_t>(start_); + return (reinterpret_cast<uintptr_t>(a) & address_mask_) + == reinterpret_cast<uintptr_t>(start_); } bool Contains(Object* o) { - return (reinterpret_cast<uint32_t>(o) & object_mask_) == object_expected_; + return (reinterpret_cast<uintptr_t>(o) & object_mask_) == object_expected_; } // Return the allocated bytes in the active semispace. @@ -1183,9 +1217,9 @@ class NewSpace : public Space { // Start address and bit mask for containment testing. Address start_; - uint32_t address_mask_; - uint32_t object_mask_; - uint32_t object_expected_; + uintptr_t address_mask_; + uintptr_t object_mask_; + uintptr_t object_expected_; // Allocation pointer and limit for normal allocation and allocation during // mark-compact collection. diff --git a/deps/v8/src/string-stream.cc b/deps/v8/src/string-stream.cc index f311e20bd..2e0912fbd 100644 --- a/deps/v8/src/string-stream.cc +++ b/deps/v8/src/string-stream.cc @@ -57,19 +57,26 @@ NoAllocationStringAllocator::NoAllocationStringAllocator(char* memory, bool StringStream::Put(char c) { - if (space() == 0) return false; - if (length_ >= capacity_ - 1) { + if (full()) return false; + ASSERT(length_ < capacity_); + // Since the trailing '\0' is not accounted for in length_ fullness is + // indicated by a difference of 1 between length_ and capacity_. Thus when + // reaching a difference of 2 we need to grow the buffer. + if (length_ == capacity_ - 2) { unsigned new_capacity = capacity_; char* new_buffer = allocator_->grow(&new_capacity); if (new_capacity > capacity_) { capacity_ = new_capacity; buffer_ = new_buffer; } else { - // Indicate truncation with dots. - memset(cursor(), '.', space()); - length_ = capacity_; - buffer_[length_ - 2] = '\n'; - buffer_[length_ - 1] = '\0'; + // Reached the end of the available buffer. + ASSERT(capacity_ >= 5); + length_ = capacity_ - 1; // Indicate fullness of the stream. + buffer_[length_ - 4] = '.'; + buffer_[length_ - 3] = '.'; + buffer_[length_ - 2] = '.'; + buffer_[length_ - 1] = '\n'; + buffer_[length_] = '\0'; return false; } } @@ -95,8 +102,7 @@ static bool IsControlChar(char c) { void StringStream::Add(Vector<const char> format, Vector<FmtElm> elms) { // If we already ran out of space then return immediately. - if (space() == 0) - return; + if (full()) return; int offset = 0; int elm = 0; while (offset < format.length()) { @@ -564,12 +570,10 @@ char* HeapStringAllocator::grow(unsigned* bytes) { } +// Only grow once to the maximum allowable size. char* NoAllocationStringAllocator::grow(unsigned* bytes) { - unsigned new_bytes = *bytes * 2; - if (new_bytes > size_) { - new_bytes = size_; - } - *bytes = new_bytes; + ASSERT(size_ >= *bytes); + *bytes = size_; return space_; } diff --git a/deps/v8/src/string-stream.h b/deps/v8/src/string-stream.h index 37ae93e2c..fa20064e4 100644 --- a/deps/v8/src/string-stream.h +++ b/deps/v8/src/string-stream.h @@ -72,13 +72,36 @@ class NoAllocationStringAllocator: public StringAllocator { class FmtElm { public: - FmtElm(int value) : type_(INT) { data_.u_int_ = value; } // NOLINT - explicit FmtElm(double value) : type_(DOUBLE) { data_.u_double_ = value; } // NOLINT - FmtElm(const char* value) : type_(C_STR) { data_.u_c_str_ = value; } // NOLINT - FmtElm(const Vector<const uc16>& value) : type_(LC_STR) { data_.u_lc_str_ = &value; } // NOLINT - FmtElm(Object* value) : type_(OBJ) { data_.u_obj_ = value; } // NOLINT - FmtElm(Handle<Object> value) : type_(HANDLE) { data_.u_handle_ = value.location(); } // NOLINT - FmtElm(void* value) : type_(INT) { data_.u_int_ = reinterpret_cast<int>(value); } // NOLINT + FmtElm(int value) : type_(INT) { // NOLINT + data_.u_int_ = value; + } + explicit FmtElm(double value) : type_(DOUBLE) { + data_.u_double_ = value; + } + FmtElm(const char* value) : type_(C_STR) { // NOLINT + data_.u_c_str_ = value; + } + FmtElm(const Vector<const uc16>& value) : type_(LC_STR) { // NOLINT + data_.u_lc_str_ = &value; + } + FmtElm(Object* value) : type_(OBJ) { // NOLINT + data_.u_obj_ = value; + } + FmtElm(Handle<Object> value) : type_(HANDLE) { // NOLINT + data_.u_handle_ = value.location(); + } + FmtElm(void* value) : type_(INT) { // NOLINT +#if V8_HOST_ARCH_64_BIT + // TODO(x64): FmtElm needs to treat pointers as pointers, and not as + // ints. This will require adding a pointer type, etc. For now just + // hack it and truncate the pointer. + // http://code.google.com/p/v8/issues/detail?id=335 + data_.u_int_ = 0; + UNIMPLEMENTED(); +#else + data_.u_int_ = reinterpret_cast<int>(value); +#endif + } private: friend class StringStream; enum Type { INT, DOUBLE, C_STR, LC_STR, OBJ, HANDLE }; @@ -162,8 +185,8 @@ class StringStream { unsigned length_; // does not include terminating 0-character char* buffer_; + bool full() const { return (capacity_ - length_) == 1; } int space() const { return capacity_ - length_; } - char* cursor() const { return buffer_ + length_; } DISALLOW_IMPLICIT_CONSTRUCTORS(StringStream); }; diff --git a/deps/v8/src/string.js b/deps/v8/src/string.js index 3ccad9a21..0bcabc943 100644 --- a/deps/v8/src/string.js +++ b/deps/v8/src/string.js @@ -812,6 +812,11 @@ ReplaceResultBuilder.prototype.generate = function() { } +function StringToJSON(key) { + return CheckJSONPrimitive(this.valueOf()); +} + + // ------------------------------------------------------------------- function SetupString() { @@ -826,7 +831,7 @@ function SetupString() { // Setup the non-enumerable functions on the String prototype object. - InstallFunctions($String.prototype, DONT_ENUM, $Array( + InstallFunctionsOnHiddenPrototype($String.prototype, DONT_ENUM, $Array( "valueOf", StringValueOf, "toString", StringToString, "charAt", StringCharAt, @@ -858,7 +863,8 @@ function SetupString() { "small", StringSmall, "strike", StringStrike, "sub", StringSub, - "sup", StringSup + "sup", StringSup, + "toJSON", StringToJSON )); } diff --git a/deps/v8/src/stub-cache.cc b/deps/v8/src/stub-cache.cc index 35e3d42a5..6811fd2e7 100644 --- a/deps/v8/src/stub-cache.cc +++ b/deps/v8/src/stub-cache.cc @@ -594,6 +594,7 @@ Object* StubCache::ComputeCallMiss(int argc) { } +#ifdef ENABLE_DEBUGGER_SUPPORT Object* StubCache::ComputeCallDebugBreak(int argc) { Code::Flags flags = Code::ComputeFlags(Code::CALL_IC, DEBUG_BREAK, NORMAL, argc); @@ -612,6 +613,7 @@ Object* StubCache::ComputeCallDebugPrepareStepIn(int argc) { StubCompiler compiler; return FillCache(compiler.CompileCallDebugPrepareStepIn(flags)); } +#endif Object* StubCache::ComputeLazyCompile(int argc) { @@ -836,6 +838,7 @@ Object* StubCompiler::CompileCallMiss(Code::Flags flags) { } +#ifdef ENABLE_DEBUGGER_SUPPORT Object* StubCompiler::CompileCallDebugBreak(Code::Flags flags) { HandleScope scope; Debug::GenerateCallICDebugBreak(masm()); @@ -864,6 +867,7 @@ Object* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) { } return result; } +#endif Object* StubCompiler::GetCodeWithFlags(Code::Flags flags, const char* name) { diff --git a/deps/v8/src/stub-cache.h b/deps/v8/src/stub-cache.h index 05845e596..369b15da9 100644 --- a/deps/v8/src/stub-cache.h +++ b/deps/v8/src/stub-cache.h @@ -157,8 +157,10 @@ class StubCache : public AllStatic { // Finds the Code object stored in the Heap::non_monomorphic_cache(). static Code* FindCallInitialize(int argc); +#ifdef ENABLE_DEBUGGER_SUPPORT static Object* ComputeCallDebugBreak(int argc); static Object* ComputeCallDebugPrepareStepIn(int argc); +#endif static Object* ComputeLazyCompile(int argc); @@ -201,14 +203,21 @@ class StubCache : public AllStatic { // Compute the hash of the name (use entire length field). ASSERT(name->HasHashCode()); uint32_t field = name->length_field(); + // Using only the low bits in 64-bit mode is unlikely to increase the + // risk of collision even if the heap is spread over an area larger than + // 4Gb (and not at all if it isn't). + uint32_t map_low32bits = + static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)); // Base the offset on a simple combination of name, flags, and map. - uint32_t key = (reinterpret_cast<uint32_t>(map) + field) ^ flags; + uint32_t key = (map_low32bits + field) ^ flags; return key & ((kPrimaryTableSize - 1) << kHeapObjectTagSize); } static int SecondaryOffset(String* name, Code::Flags flags, int seed) { // Use the seed from the primary cache in the secondary cache. - uint32_t key = seed - reinterpret_cast<uint32_t>(name) + flags; + uint32_t string_low32bits = + static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name)); + uint32_t key = seed - string_low32bits + flags; return key & ((kSecondaryTableSize - 1) << kHeapObjectTagSize); } @@ -288,8 +297,10 @@ class StubCompiler BASE_EMBEDDED { Object* CompileCallNormal(Code::Flags flags); Object* CompileCallMegamorphic(Code::Flags flags); Object* CompileCallMiss(Code::Flags flags); +#ifdef ENABLE_DEBUGGER_SUPPORT Object* CompileCallDebugBreak(Code::Flags flags); Object* CompileCallDebugPrepareStepIn(Code::Flags flags); +#endif Object* CompileLazyCompile(Code::Flags flags); // Static functions for generating parts of stubs. diff --git a/deps/v8/src/top.cc b/deps/v8/src/top.cc index a99e9fff8..96f98a5a2 100644 --- a/deps/v8/src/top.cc +++ b/deps/v8/src/top.cc @@ -116,15 +116,15 @@ class PreallocatedMemoryThread: public Thread { // When the thread starts running it will allocate a fixed number of bytes // on the stack and publish the location of this memory for others to use. void Run() { - EmbeddedVector<char, 32 * 1024> local_buffer; + EmbeddedVector<char, 15 * 1024> local_buffer; // Initialize the buffer with a known good value. OS::StrNCpy(local_buffer, "Trace data was not generated.\n", local_buffer.length()); // Publish the local buffer and signal its availability. - data_ = &local_buffer[0]; - length_ = sizeof(local_buffer); + data_ = local_buffer.start(); + length_ = local_buffer.length(); data_ready_semaphore_->Signal(); while (keep_running_) { @@ -728,8 +728,10 @@ void Top::DoThrow(Object* exception, bool should_return_exception = ShouldReportException(&is_caught_externally); bool report_exception = !is_out_of_memory && should_return_exception; +#ifdef ENABLE_DEBUGGER_SUPPORT // Notify debugger of exception. Debugger::OnException(exception_handle, report_exception); +#endif // Generate the message. Handle<Object> message_obj; diff --git a/deps/v8/src/unicode-inl.h b/deps/v8/src/unicode-inl.h index 9737c2736..0ee03bd96 100644 --- a/deps/v8/src/unicode-inl.h +++ b/deps/v8/src/unicode-inl.h @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef __UNIBROW_INL_H__ -#define __UNIBROW_INL_H__ +#ifndef V8_UNICODE_INL_H_ +#define V8_UNICODE_INL_H_ #include "unicode.h" @@ -235,4 +235,4 @@ Utf8InputBuffer<s>::Utf8InputBuffer(const char* data, unsigned length) } // namespace unibrow -#endif // __UNIBROW_INL_H__ +#endif // V8_UNICODE_INL_H_ diff --git a/deps/v8/src/unicode.h b/deps/v8/src/unicode.h index 86fd49885..f5e4210cb 100644 --- a/deps/v8/src/unicode.h +++ b/deps/v8/src/unicode.h @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef __UNIBROW_H__ -#define __UNIBROW_H__ +#ifndef V8_UNICODE_H_ +#define V8_UNICODE_H_ #include <sys/types.h> @@ -276,4 +276,4 @@ struct CanonicalizationRange { } // namespace unibrow -#endif // __UNIBROW_H__ +#endif // V8_UNICODE_H_ diff --git a/deps/v8/src/usage-analyzer.h b/deps/v8/src/usage-analyzer.h index 2732dd576..2369422b9 100644 --- a/deps/v8/src/usage-analyzer.h +++ b/deps/v8/src/usage-analyzer.h @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef V8_USAGE_ANALYSER_H_ -#define V8_USAGE_ANALYSER_H_ +#ifndef V8_USAGE_ANALYZER_H_ +#define V8_USAGE_ANALYZER_H_ namespace v8 { namespace internal { @@ -36,4 +36,4 @@ bool AnalyzeVariableUsage(FunctionLiteral* lit); } } // namespace v8::internal -#endif // V8_USAGE_ANALYSER_H_ +#endif // V8_USAGE_ANALYZER_H_ diff --git a/deps/v8/src/utils.h b/deps/v8/src/utils.h index f62b47a54..0febe4a8d 100644 --- a/deps/v8/src/utils.h +++ b/deps/v8/src/utils.h @@ -406,6 +406,16 @@ class EmbeddedVector : public Vector<T> { }; +template <typename T> +class ScopedVector : public Vector<T> { + public: + explicit ScopedVector(int length) : Vector<T>(NewArray<T>(length), length) { } + ~ScopedVector() { + DeleteArray(this->start()); + } +}; + + inline Vector<const char> CStrVector(const char* data) { return Vector<const char>(data, strlen(data)); } @@ -517,7 +527,7 @@ class StringBuilder { template <typename sourcechar, typename sinkchar> static inline void CopyChars(sinkchar* dest, const sourcechar* src, int chars) { sinkchar* limit = dest + chars; -#ifdef CAN_READ_UNALIGNED +#ifdef V8_HOST_CAN_READ_UNALIGNED if (sizeof(*dest) == sizeof(*src)) { // Number of characters in a uint32_t. static const int kStepSize = sizeof(uint32_t) / sizeof(*dest); // NOLINT diff --git a/deps/v8/src/v8-counters.h b/deps/v8/src/v8-counters.h index 6596dbf47..34156ea6f 100644 --- a/deps/v8/src/v8-counters.h +++ b/deps/v8/src/v8-counters.h @@ -116,6 +116,8 @@ namespace v8 { namespace internal { SC(keyed_load_interceptor, V8.KeyedLoadInterceptor) \ SC(keyed_load_inline, V8.KeyedLoadInline) \ SC(keyed_load_inline_miss, V8.KeyedLoadInlineMiss) \ + SC(named_load_inline, V8.NamedLoadInline) \ + SC(named_load_inline_miss, V8.NamedLoadInlineMiss) \ SC(keyed_store_field, V8.KeyedStoreField) \ SC(for_in, V8.ForIn) \ SC(enum_cache_hits, V8.EnumCacheHits) \ @@ -159,4 +161,4 @@ class Counters : AllStatic { } } // namespace v8::internal -#endif // V8_COUNTERS_H_ +#endif // V8_V8_COUNTERS_H_ diff --git a/deps/v8/src/v8.cc b/deps/v8/src/v8.cc index 9158b5269..c0124e4de 100644 --- a/deps/v8/src/v8.cc +++ b/deps/v8/src/v8.cc @@ -72,7 +72,9 @@ bool V8::Initialize(Deserializer *des) { v8::Locker::StartPreemption(100); } +#ifdef ENABLE_DEBUGGER_SUPPORT Debug::Setup(create_heap_objects); +#endif StubCache::Initialize(create_heap_objects); // If we are deserializing, read the state into the now-empty heap. @@ -111,8 +113,6 @@ void V8::TearDown() { Heap::TearDown(); Logger::TearDown(); - Debugger::TearDown(); - has_been_setup_ = false; has_been_disposed_ = true; } diff --git a/deps/v8/src/v8.h b/deps/v8/src/v8.h index 4cf0b70e4..4ced0d2b4 100644 --- a/deps/v8/src/v8.h +++ b/deps/v8/src/v8.h @@ -51,6 +51,11 @@ #error both DEBUG and NDEBUG are set #endif +// Enable debugger support by default, unless it is in ANDROID +#if !defined(ENABLE_DEBUGGER_SUPPORT) && !defined(ANDROID) +#define ENABLE_DEBUGGER_SUPPORT +#endif + // Basic includes #include "../include/v8.h" #include "globals.h" diff --git a/deps/v8/src/v8natives.js b/deps/v8/src/v8natives.js index 9772e2f0c..55bc9f8ff 100644 --- a/deps/v8/src/v8natives.js +++ b/deps/v8/src/v8natives.js @@ -54,6 +54,16 @@ function InstallFunctions(object, attributes, functions) { } } +// Emulates JSC by installing functions on a hidden prototype that +// lies above the current object/prototype. This lets you override +// functions on String.prototype etc. and then restore the old function +// with delete. See http://code.google.com/p/chromium/issues/detail?id=1717 +function InstallFunctionsOnHiddenPrototype(object, attributes, functions) { + var hidden_prototype = new $Object(); + %SetHiddenPrototype(object, hidden_prototype); + InstallFunctions(hidden_prototype, attributes, functions); +} + // ---------------------------------------------------------------------------- @@ -110,7 +120,7 @@ function GlobalEval(x) { 'be the global object from which eval originated'); } - var f = %CompileString(x, 0); + var f = %CompileString(x, 0, false); if (!IS_FUNCTION(f)) return f; return f.call(this); @@ -121,7 +131,7 @@ function GlobalEval(x) { function GlobalExecScript(expr, lang) { // NOTE: We don't care about the character casing. if (!lang || /javascript/i.test(lang)) { - var f = %CompileString(ToString(expr), 0); + var f = %CompileString(ToString(expr), 0, false); f.call(%GlobalReceiver(global)); } return null; @@ -312,13 +322,19 @@ function BooleanValueOf() { } +function BooleanToJSON(key) { + return CheckJSONPrimitive(this.valueOf()); +} + + // ---------------------------------------------------------------------------- function SetupBoolean() { InstallFunctions($Boolean.prototype, DONT_ENUM, $Array( "toString", BooleanToString, - "valueOf", BooleanValueOf + "valueOf", BooleanValueOf, + "toJSON", BooleanToJSON )); } @@ -418,6 +434,18 @@ function NumberToPrecision(precision) { } +function CheckJSONPrimitive(val) { + if (!IsPrimitive(val)) + throw MakeTypeError('result_not_primitive', ['toJSON', val]); + return val; +} + + +function NumberToJSON(key) { + return CheckJSONPrimitive(this.valueOf()); +} + + // ---------------------------------------------------------------------------- function SetupNumber() { @@ -455,7 +483,8 @@ function SetupNumber() { "valueOf", NumberValueOf, "toFixed", NumberToFixed, "toExponential", NumberToExponential, - "toPrecision", NumberToPrecision + "toPrecision", NumberToPrecision, + "toJSON", NumberToJSON )); } @@ -521,7 +550,7 @@ function NewFunction(arg1) { // length == 1 // The call to SetNewFunctionAttributes will ensure the prototype // property of the resulting function is enumerable (ECMA262, 15.3.5.2). - var f = %CompileString(source, -1)(); + var f = %CompileString(source, -1, false)(); %FunctionSetName(f, "anonymous"); return %SetNewFunctionAttributes(f); } diff --git a/deps/v8/src/v8threads.cc b/deps/v8/src/v8threads.cc index e8f6f9b22..838cae772 100644 --- a/deps/v8/src/v8threads.cc +++ b/deps/v8/src/v8threads.cc @@ -144,7 +144,9 @@ bool ThreadManager::RestoreThread() { char* from = state->data(); from = HandleScopeImplementer::RestoreThread(from); from = Top::RestoreThread(from); +#ifdef ENABLE_DEBUGGER_SUPPORT from = Debug::RestoreDebug(from); +#endif from = StackGuard::RestoreStackGuard(from); from = RegExpStack::RestoreStack(from); from = Bootstrapper::RestoreState(from); @@ -172,7 +174,9 @@ void ThreadManager::Unlock() { static int ArchiveSpacePerThread() { return HandleScopeImplementer::ArchiveSpacePerThread() + Top::ArchiveSpacePerThread() + +#ifdef ENABLE_DEBUGGER_SUPPORT Debug::ArchiveSpacePerThread() + +#endif StackGuard::ArchiveSpacePerThread() + RegExpStack::ArchiveSpacePerThread() + Bootstrapper::ArchiveSpacePerThread(); @@ -259,7 +263,9 @@ void ThreadManager::EagerlyArchiveThread() { char* to = state->data(); to = HandleScopeImplementer::ArchiveThread(to); to = Top::ArchiveThread(to); +#ifdef ENABLE_DEBUGGER_SUPPORT to = Debug::ArchiveDebug(to); +#endif to = StackGuard::ArchiveStackGuard(to); to = RegExpStack::ArchiveStack(to); to = Bootstrapper::ArchiveState(to); @@ -303,13 +309,13 @@ void ThreadManager::MarkCompactEpilogue(bool is_compacting) { int ThreadManager::CurrentId() { - return bit_cast<int, void*>(Thread::GetThreadLocal(thread_id_key)); + return Thread::GetThreadLocalInt(thread_id_key); } void ThreadManager::AssignId() { - if (Thread::GetThreadLocal(thread_id_key) == NULL) { - Thread::SetThreadLocal(thread_id_key, bit_cast<void*, int>(next_id_++)); + if (!Thread::HasThreadLocal(thread_id_key)) { + Thread::SetThreadLocalInt(thread_id_key, next_id_++); } } diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc new file mode 100644 index 000000000..0d2840d44 --- /dev/null +++ b/deps/v8/src/version.cc @@ -0,0 +1,87 @@ +// Copyright 2008 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. + +#include "v8.h" + +#include "version.h" + +// These macros define the version number for the current version. +// NOTE these macros are used by the SCons build script so their names +// cannot be changed without changing the SCons build script. +#define MAJOR_VERSION 1 +#define MINOR_VERSION 2 +#define BUILD_NUMBER 3 +#define PATCH_LEVEL 0 +#define CANDIDATE_VERSION false + +// Define SONAME to have the SCons build the put a specific SONAME into the +// shared library instead the generic SONAME generated from the V8 version +// number. This define is mainly used by the SCons build script. +#define SONAME "" + +namespace v8 { namespace internal { + +int Version::major_ = MAJOR_VERSION; +int Version::minor_ = MINOR_VERSION; +int Version::build_ = BUILD_NUMBER; +int Version::patch_ = PATCH_LEVEL; +bool Version::candidate_ = CANDIDATE_VERSION; +const char* Version::soname_ = SONAME; + + +// Calculate the V8 version string. +void Version::GetString(Vector<char> str) { + const char* candidate = IsCandidate() ? " (candidate)" : ""; + if (GetPatch() > 0) { + OS::SNPrintF(str, "%d.%d.%d.%d%s", + GetMajor(), GetMinor(), GetBuild(), GetPatch(), candidate); + } else { + OS::SNPrintF(str, "%d.%d.%d%s", + GetMajor(), GetMinor(), GetBuild(), candidate); + } +} + + +// Calculate the SONAME for the V8 shared library. +void Version::GetSONAME(Vector<char> str) { + if (soname_ == NULL || *soname_ == '\0') { + // Generate generic SONAME if no specific SONAME is defined. + const char* candidate = IsCandidate() ? "-candidate" : ""; + if (GetPatch() > 0) { + OS::SNPrintF(str, "libv8-%d.%d.%d.%d%s.so", + GetMajor(), GetMinor(), GetBuild(), GetPatch(), candidate); + } else { + OS::SNPrintF(str, "libv8-%d.%d.%d%s.so", + GetMajor(), GetMinor(), GetBuild(), candidate); + } + } else { + // Use specific SONAME. + OS::SNPrintF(str, "%s", soname_); + } +} + +} } // namespace v8::internal diff --git a/deps/v8/src/version.h b/deps/v8/src/version.h new file mode 100644 index 000000000..423b5f7a1 --- /dev/null +++ b/deps/v8/src/version.h @@ -0,0 +1,63 @@ +// Copyright 2009 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. + +#ifndef V8_VERSION_H_ +#define V8_VERSION_H_ + +namespace v8 { namespace internal { + +class Version { + public: + // Return the various version components. + static int GetMajor() { return major_; } + static int GetMinor() { return minor_; } + static int GetBuild() { return build_; } + static int GetPatch() { return patch_; } + static bool IsCandidate() { return candidate_; } + + // Calculate the V8 version string. + static void GetString(Vector<char> str); + + // Calculate the SONAME for the V8 shared library. + static void GetSONAME(Vector<char> str); + + private: + static int major_; + static int minor_; + static int build_; + static int patch_; + static bool candidate_; + static const char* soname_; + + // In test-version.cc. + friend void SetVersion(int major, int minor, int build, int patch, + bool candidate, const char* soname); +}; + +} } // namespace v8::internal + +#endif // V8_VERSION_H_ diff --git a/deps/v8/src/virtual-frame.cc b/deps/v8/src/virtual-frame.cc index a03e31a35..566fcdbc0 100644 --- a/deps/v8/src/virtual-frame.cc +++ b/deps/v8/src/virtual-frame.cc @@ -213,40 +213,14 @@ void VirtualFrame::SpillElementAt(int index) { } -// Clear the dirty bits for the range of elements in -// [min(stack_pointer_ + 1,begin), end). -void VirtualFrame::SyncRange(int begin, int end) { - ASSERT(begin >= 0); - ASSERT(end <= elements_.length()); - if (begin > stack_pointer_) { - // Elements between stack_pointer_ + 1 and begin must also be synced. - for (int i = stack_pointer_ + 1; i < end; i++) { - SyncElementByPushing(i); - } - } else if (end <= stack_pointer_ + 1) { - for (int i = begin; i < end; i++) { - if (!elements_[i].is_synced()) { - SyncElementBelowStackPointer(i); - } - } - } else { - // Split into two ranges that each satisfy a condition above. - SyncRange(begin, stack_pointer_ + 1); - SyncRange(stack_pointer_ + 1, end); - } -} - - // Clear the dirty bit for the element at a given index. void VirtualFrame::SyncElementAt(int index) { if (index <= stack_pointer_) { - if (!elements_[index].is_synced()) { - SyncElementBelowStackPointer(index); - } + if (!elements_[index].is_synced()) SyncElementBelowStackPointer(index); + } else if (index == stack_pointer_ + 1) { + SyncElementByPushing(index); } else { - for (int i = stack_pointer_ + 1; i <= index; i++) { - SyncElementByPushing(i); - } + SyncRange(stack_pointer_ + 1, index); } } @@ -310,7 +284,7 @@ void VirtualFrame::PrepareForCall(int spilled_args, int dropped_args) { ASSERT(height() >= spilled_args); ASSERT(dropped_args <= spilled_args); - SyncRange(0, elements_.length()); + SyncRange(0, elements_.length() - 1); // Spill registers. for (int i = 0; i < kNumRegisters; i++) { if (is_used(i)) { @@ -533,4 +507,14 @@ bool VirtualFrame::Equals(VirtualFrame* other) { return true; } + +// Specialization of List::ResizeAdd to non-inlined version for FrameElements. +// The function ResizeAdd becomes a real function, whose implementation is the +// inlined ResizeAddInternal. +template <> +void List<FrameElement, + FreeStoreAllocationPolicy>::ResizeAdd(const FrameElement& element) { + ResizeAddInternal(element); +} + } } // namespace v8::internal diff --git a/deps/v8/src/virtual-frame.h b/deps/v8/src/virtual-frame.h index 99b4f7672..794f1567c 100644 --- a/deps/v8/src/virtual-frame.h +++ b/deps/v8/src/virtual-frame.h @@ -191,16 +191,23 @@ class FrameElement BASE_EMBEDDED { data_.index_ = new_index; } + void set_reg(Register new_reg) { + ASSERT(is_register()); + data_.reg_ = new_reg; + } + friend class VirtualFrame; }; } } // namespace v8::internal -#ifdef ARM -#include "virtual-frame-arm.h" -#else // ia32 -#include "virtual-frame-ia32.h" +#if V8_TARGET_ARCH_IA32 +#include "ia32/virtual-frame-ia32.h" +#elif V8_TARGET_ARCH_X64 +#include "x64/virtual-frame-x64.h" +#elif V8_TARGET_ARCH_ARM +#include "arm/virtual-frame-arm.h" #endif #endif // V8_VIRTUAL_FRAME_H_ diff --git a/deps/v8/src/x64/assembler-x64-inl.h b/deps/v8/src/x64/assembler-x64-inl.h new file mode 100644 index 000000000..0b018490d --- /dev/null +++ b/deps/v8/src/x64/assembler-x64-inl.h @@ -0,0 +1,68 @@ +// Copyright 2009 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. + +#ifndef V8_X64_ASSEMBLER_X64_INL_H_ +#define V8_X64_ASSEMBLER_X64_INL_H_ + +namespace v8 { namespace internal { + +Condition NegateCondition(Condition cc) { + return static_cast<Condition>(cc ^ 1); +} + + +Address RelocInfo::target_address() { + ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY); + return Assembler::target_address_at(pc_); +} + + +Address RelocInfo::target_address_address() { + ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY); + return reinterpret_cast<Address>(pc_); +} + + +void RelocInfo::set_target_address(Address target) { + ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY); + Assembler::set_target_address_at(pc_, target); +} + + +void Assembler::set_target_address_at(byte* location, byte* value) { + UNIMPLEMENTED(); +} + + +byte* Assembler::target_address_at(byte* location) { + UNIMPLEMENTED(); + return NULL; +} + +} } // namespace v8::internal + +#endif // V8_X64_ASSEMBLER_X64_INL_H_ diff --git a/deps/v8/src/x64/assembler-x64.cc b/deps/v8/src/x64/assembler-x64.cc new file mode 100644 index 000000000..6e2c42a12 --- /dev/null +++ b/deps/v8/src/x64/assembler-x64.cc @@ -0,0 +1,36 @@ +// Copyright 2009 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. + +#include "v8.h" + +#include "macro-assembler.h" + +namespace v8 { namespace internal { + +Register no_reg = { -1 }; + +} } // namespace v8::internal diff --git a/deps/v8/src/x64/assembler-x64.h b/deps/v8/src/x64/assembler-x64.h new file mode 100644 index 000000000..40fcdd32b --- /dev/null +++ b/deps/v8/src/x64/assembler-x64.h @@ -0,0 +1,925 @@ +// Copyright (c) 1994-2006 Sun Microsystems Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// - Redistribution 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 Sun Microsystems or the names of 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. + +// The original source code covered by the above license above has been +// modified significantly by Google Inc. +// Copyright 2006-2009 the V8 project authors. All rights reserved. + +// A lightweight X64 Assembler. + +#ifndef V8_X64_ASSEMBLER_X64_H_ +#define V8_X64_ASSEMBLER_X64_H_ + +namespace v8 { namespace internal { + +// CPU Registers. +// +// 1) We would prefer to use an enum, but enum values are assignment- +// compatible with int, which has caused code-generation bugs. +// +// 2) We would prefer to use a class instead of a struct but we don't like +// the register initialization to depend on the particular initialization +// order (which appears to be different on OS X, Linux, and Windows for the +// installed versions of C++ we tried). Using a struct permits C-style +// "initialization". Also, the Register objects cannot be const as this +// forces initialization stubs in MSVC, making us dependent on initialization +// order. +// +// 3) By not using an enum, we are possibly preventing the compiler from +// doing certain constant folds, which may significantly reduce the +// code generated for some assembly instructions (because they boil down +// to a few constants). If this is a problem, we could change the code +// such that we use an enum in optimized mode, and the struct in debug +// mode. This way we get the compile-time error checking in debug mode +// and best performance in optimized code. +// +const int kNumRegisters = 16; + +struct Register { + bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; } + bool is(Register reg) const { return code_ == reg.code_; } + // The byte-register distinction of ai32 has dissapeared. + bool is_byte_register() const { return false; } + int code() const { + ASSERT(is_valid()); + return code_; + } + int bit() const { + UNIMPLEMENTED(); + return 0; + } + + // (unfortunately we can't make this private in a struct) + int code_; +}; + +extern Register rax; +extern Register rcx; +extern Register rdx; +extern Register rbx; +extern Register rsp; +extern Register rbp; +extern Register rsi; +extern Register rdi; +extern Register r8; +extern Register r9; +extern Register r10; +extern Register r11; +extern Register r12; +extern Register r13; +extern Register r14; +extern Register r15; +extern Register no_reg; + + +struct XMMRegister { + bool is_valid() const { return 0 <= code_ && code_ < 2; } + int code() const { + ASSERT(is_valid()); + return code_; + } + + int code_; +}; + +extern XMMRegister xmm0; +extern XMMRegister xmm1; +extern XMMRegister xmm2; +extern XMMRegister xmm3; +extern XMMRegister xmm4; +extern XMMRegister xmm5; +extern XMMRegister xmm6; +extern XMMRegister xmm7; + +enum Condition { + // any value < 0 is considered no_condition + no_condition = -1, + + overflow = 0, + no_overflow = 1, + below = 2, + above_equal = 3, + equal = 4, + not_equal = 5, + below_equal = 6, + above = 7, + negative = 8, + positive = 9, + parity_even = 10, + parity_odd = 11, + less = 12, + greater_equal = 13, + less_equal = 14, + greater = 15, + + // aliases + carry = below, + not_carry = above_equal, + zero = equal, + not_zero = not_equal, + sign = negative, + not_sign = positive +}; + + +// Returns the equivalent of !cc. +// Negation of the default no_condition (-1) results in a non-default +// no_condition value (-2). As long as tests for no_condition check +// for condition < 0, this will work as expected. +inline Condition NegateCondition(Condition cc); + +// Corresponds to transposing the operands of a comparison. +inline Condition ReverseCondition(Condition cc) { + switch (cc) { + case below: + return above; + case above: + return below; + case above_equal: + return below_equal; + case below_equal: + return above_equal; + case less: + return greater; + case greater: + return less; + case greater_equal: + return less_equal; + case less_equal: + return greater_equal; + default: + return cc; + }; +} + +enum Hint { + no_hint = 0, + not_taken = 0x2e, + taken = 0x3e +}; + +// The result of negating a hint is as if the corresponding condition +// were negated by NegateCondition. That is, no_hint is mapped to +// itself and not_taken and taken are mapped to each other. +inline Hint NegateHint(Hint hint) { + return (hint == no_hint) + ? no_hint + : ((hint == not_taken) ? taken : not_taken); +} + + +// ----------------------------------------------------------------------------- +// Machine instruction Immediates + +class Immediate BASE_EMBEDDED { + public: + inline explicit Immediate(int64_t x); + inline explicit Immediate(const char* s); + inline explicit Immediate(const ExternalReference& ext); + inline explicit Immediate(Handle<Object> handle); + inline explicit Immediate(Smi* value); + + static Immediate CodeRelativeOffset(Label* label) { + return Immediate(label); + } + + bool is_zero() const { return x_ == 0 && rmode_ == RelocInfo::NONE; } + bool is_int8() const { + return -128 <= x_ && x_ < 128 && rmode_ == RelocInfo::NONE; + } + bool is_int16() const { + return -32768 <= x_ && x_ < 32768 && rmode_ == RelocInfo::NONE; + } + bool is_int32() const { + return V8_INT64_C(-2147483648) <= x_ + && x_ < V8_INT64_C(2147483648) + && rmode_ == RelocInfo::NONE; + } + + private: + inline explicit Immediate(Label* value) { UNIMPLEMENTED(); } + + int64_t x_; + RelocInfo::Mode rmode_; + + friend class Assembler; +}; + + +// ----------------------------------------------------------------------------- +// Machine instruction Operands + +enum ScaleFactor { + times_1 = 0, + times_2 = 1, + times_4 = 2, + times_8 = 3 +}; + + +class Operand BASE_EMBEDDED { + public: + // reg + INLINE(explicit Operand(Register reg)); + + // MemoryOperand + INLINE(explicit Operand()) { UNIMPLEMENTED(); } + + // Returns true if this Operand is a wrapper for the specified register. + bool is_reg(Register reg) const; + + // These constructors have been moved to MemOperand, and should + // be removed from Operand as soon as all their uses use MemOperands instead. + // [disp/r] + INLINE(explicit Operand(intptr_t disp, RelocInfo::Mode rmode)) { + UNIMPLEMENTED(); + } + // disp only must always be relocated + + // [base + disp/r] + explicit Operand(Register base, intptr_t disp, + RelocInfo::Mode rmode = RelocInfo::NONE); + + // [base + index*scale + disp/r] + explicit Operand(Register base, + Register index, + ScaleFactor scale, + intptr_t disp, + RelocInfo::Mode rmode = RelocInfo::NONE); + + // [index*scale + disp/r] + explicit Operand(Register index, + ScaleFactor scale, + intptr_t disp, + RelocInfo::Mode rmode = RelocInfo::NONE); + + static Operand StaticVariable(const ExternalReference& ext) { + return Operand(reinterpret_cast<intptr_t>(ext.address()), + RelocInfo::EXTERNAL_REFERENCE); + } + + static Operand StaticArray(Register index, + ScaleFactor scale, + const ExternalReference& arr) { + return Operand(index, scale, reinterpret_cast<intptr_t>(arr.address()), + RelocInfo::EXTERNAL_REFERENCE); + } + + // End of constructors and methods that have been moved to MemOperand. + + private: + byte rex_; + byte buf_[10]; + // The number of bytes in buf_. + unsigned int len_; + // Only valid if len_ > 4. + RelocInfo::Mode rmode_; + + // Set the ModRM byte without an encoded 'reg' register. The + // register is encoded later as part of the emit_operand operation. + inline void set_modrm(int mod, Register rm); + + inline void set_sib(ScaleFactor scale, Register index, Register base); + inline void set_disp8(int8_t disp); + inline void set_disp32(int32_t disp); + inline void set_dispr(intptr_t disp, RelocInfo::Mode rmode); + + friend class Assembler; +}; + +class MemOperand : public Operand { + public: + // [disp/r] + INLINE(explicit MemOperand(intptr_t disp, RelocInfo::Mode rmode)) : + Operand() { + UNIMPLEMENTED(); + } + // disp only must always be relocated + + // [base + disp/r] + explicit MemOperand(Register base, intptr_t disp, + RelocInfo::Mode rmode = RelocInfo::NONE); + + // [base + index*scale + disp/r] + explicit MemOperand(Register base, + Register index, + ScaleFactor scale, + intptr_t disp, + RelocInfo::Mode rmode = RelocInfo::NONE); + + // [index*scale + disp/r] + explicit MemOperand(Register index, + ScaleFactor scale, + intptr_t disp, + RelocInfo::Mode rmode = RelocInfo::NONE); + + static MemOperand StaticVariable(const ExternalReference& ext) { + return MemOperand(reinterpret_cast<intptr_t>(ext.address()), + RelocInfo::EXTERNAL_REFERENCE); + } + + static MemOperand StaticArray(Register index, + ScaleFactor scale, + const ExternalReference& arr) { + return MemOperand(index, scale, reinterpret_cast<intptr_t>(arr.address()), + RelocInfo::EXTERNAL_REFERENCE); + } +}; + +// ----------------------------------------------------------------------------- +// A Displacement describes the 32bit immediate field of an instruction which +// may be used together with a Label in order to refer to a yet unknown code +// position. Displacements stored in the instruction stream are used to describe +// the instruction and to chain a list of instructions using the same Label. +// A Displacement contains 2 different fields: +// +// next field: position of next displacement in the chain (0 = end of list) +// type field: instruction type +// +// A next value of null (0) indicates the end of a chain (note that there can +// be no displacement at position zero, because there is always at least one +// instruction byte before the displacement). +// +// Displacement _data field layout +// +// |31.....2|1......0| +// [ next | type | + +class Displacement BASE_EMBEDDED { + public: + enum Type { + UNCONDITIONAL_JUMP, + CODE_RELATIVE, + OTHER + }; + + int data() const { return data_; } + Type type() const { return TypeField::decode(data_); } + void next(Label* L) const { + int n = NextField::decode(data_); + n > 0 ? L->link_to(n) : L->Unuse(); + } + void link_to(Label* L) { init(L, type()); } + + explicit Displacement(int data) { data_ = data; } + + Displacement(Label* L, Type type) { init(L, type); } + + void print() { + PrintF("%s (%x) ", (type() == UNCONDITIONAL_JUMP ? "jmp" : "[other]"), + NextField::decode(data_)); + } + + private: + int data_; + + class TypeField: public BitField<Type, 0, 2> {}; + class NextField: public BitField<int, 2, 32-2> {}; + + void init(Label* L, Type type); +}; + + + +// CpuFeatures keeps track of which features are supported by the target CPU. +// Supported features must be enabled by a Scope before use. +// Example: +// if (CpuFeatures::IsSupported(SSE2)) { +// CpuFeatures::Scope fscope(SSE2); +// // Generate SSE2 floating point code. +// } else { +// // Generate standard x87 floating point code. +// } +class CpuFeatures : public AllStatic { + public: + // Feature flags bit positions. They are mostly based on the CPUID spec. + // (We assign CPUID itself to one of the currently reserved bits -- + // feel free to change this if needed.) + enum Feature { SSE3 = 32, SSE2 = 26, CMOV = 15, RDTSC = 4, CPUID = 10 }; + // Detect features of the target CPU. Set safe defaults if the serializer + // is enabled (snapshots must be portable). + static void Probe(); + // Check whether a feature is supported by the target CPU. + static bool IsSupported(Feature f) { + return (supported_ & (static_cast<uint64_t>(1) << f)) != 0; + } + // Check whether a feature is currently enabled. + static bool IsEnabled(Feature f) { + return (enabled_ & (static_cast<uint64_t>(1) << f)) != 0; + } + // Enable a specified feature within a scope. + class Scope BASE_EMBEDDED { +#ifdef DEBUG + public: + explicit Scope(Feature f) { + ASSERT(CpuFeatures::IsSupported(f)); + old_enabled_ = CpuFeatures::enabled_; + CpuFeatures::enabled_ |= (static_cast<uint64_t>(1) << f); + } + ~Scope() { CpuFeatures::enabled_ = old_enabled_; } + private: + uint64_t old_enabled_; +#else + public: + explicit Scope(Feature f) {} +#endif + }; + private: + static uint64_t supported_; + static uint64_t enabled_; +}; + + +class Assembler : public Malloced { + private: + // The relocation writer's position is kGap bytes below the end of + // the generated instructions. This leaves enough space for the + // longest possible ia32 instruction (17 bytes as of 9/26/06) and + // allows for a single, fast space check per instruction. + static const int kGap = 32; + + public: + // Create an assembler. Instructions and relocation information are emitted + // into a buffer, with the instructions starting from the beginning and the + // relocation information starting from the end of the buffer. See CodeDesc + // for a detailed comment on the layout (globals.h). + // + // If the provided buffer is NULL, the assembler allocates and grows its own + // buffer, and buffer_size determines the initial buffer size. The buffer is + // owned by the assembler and deallocated upon destruction of the assembler. + // + // If the provided buffer is not NULL, the assembler uses the provided buffer + // for code generation and assumes its size to be buffer_size. If the buffer + // is too small, a fatal error occurs. No deallocation of the buffer is done + // upon destruction of the assembler. + Assembler(void* buffer, int buffer_size); + ~Assembler(); + + // GetCode emits any pending (non-emitted) code and fills the descriptor + // desc. GetCode() is idempotent; it returns the same result if no other + // Assembler functions are invoked in between GetCode() calls. + void GetCode(CodeDesc* desc); + + // Read/Modify the code target in the branch/call instruction at pc. + inline static Address target_address_at(Address pc); + inline static void set_target_address_at(Address pc, Address target); + + // Distance between the address of the code target in the call instruction + // and the return address + static const int kTargetAddrToReturnAddrDist = kPointerSize; + + + // --------------------------------------------------------------------------- + // Code generation + // + // - function names correspond one-to-one to ia32 instruction mnemonics + // - unless specified otherwise, instructions operate on 32bit operands + // - instructions on 8bit (byte) operands/registers have a trailing '_b' + // - instructions on 16bit (word) operands/registers have a trailing '_w' + // - naming conflicts with C++ keywords are resolved via a trailing '_' + + // NOTE ON INTERFACE: Currently, the interface is not very consistent + // in the sense that some operations (e.g. mov()) can be called in more + // the one way to generate the same instruction: The Register argument + // can in some cases be replaced with an Operand(Register) argument. + // This should be cleaned up and made more orthogonal. The questions + // is: should we always use Operands instead of Registers where an + // Operand is possible, or should we have a Register (overloaded) form + // instead? We must be careful to make sure that the selected instruction + // is obvious from the parameters to avoid hard-to-find code generation + // bugs. + + // Insert the smallest number of nop instructions + // possible to align the pc offset to a multiple + // of m. m must be a power of 2. + void Align(int m); + + // Stack + void pushad(); + void popad(); + + void pushfd(); + void popfd(); + + void push(const Immediate& x); + void push(Register src); + void push(const Operand& src); + void push(Label* label, RelocInfo::Mode relocation_mode); + + void pop(Register dst); + void pop(const Operand& dst); + + void enter(const Immediate& size); + void leave(); + + // Moves + void mov_b(Register dst, const Operand& src); + void mov_b(const Operand& dst, int8_t imm8); + void mov_b(const Operand& dst, Register src); + + void mov_w(Register dst, const Operand& src); + void mov_w(const Operand& dst, Register src); + + void mov(Register dst, int32_t imm32); + void mov(Register dst, const Immediate& x); + void mov(Register dst, Handle<Object> handle); + void mov(Register dst, const Operand& src); + void mov(Register dst, Register src); + void mov(const Operand& dst, const Immediate& x); + void mov(const Operand& dst, Handle<Object> handle); + void mov(const Operand& dst, Register src); + + void movsx_b(Register dst, const Operand& src); + + void movsx_w(Register dst, const Operand& src); + + void movzx_b(Register dst, const Operand& src); + + void movzx_w(Register dst, const Operand& src); + + // Conditional moves + void cmov(Condition cc, Register dst, int32_t imm32); + void cmov(Condition cc, Register dst, Handle<Object> handle); + void cmov(Condition cc, Register dst, const Operand& src); + + // Exchange two registers + void xchg(Register dst, Register src); + + // Arithmetics + void adc(Register dst, int32_t imm32); + void adc(Register dst, const Operand& src); + + void add(Register dst, const Operand& src); + void add(const Operand& dst, const Immediate& x); + + void and_(Register dst, int32_t imm32); + void and_(Register dst, const Operand& src); + void and_(const Operand& src, Register dst); + void and_(const Operand& dst, const Immediate& x); + + void cmpb(const Operand& op, int8_t imm8); + void cmpb_al(const Operand& op); + void cmpw_ax(const Operand& op); + void cmpw(const Operand& op, Immediate imm16); + void cmp(Register reg, int32_t imm32); + void cmp(Register reg, Handle<Object> handle); + void cmp(Register reg, const Operand& op); + void cmp(const Operand& op, const Immediate& imm); + + void dec_b(Register dst); + + void dec(Register dst); + void dec(const Operand& dst); + + void cdq(); + + void idiv(Register src); + + void imul(Register dst, const Operand& src); + void imul(Register dst, Register src, int32_t imm32); + + void inc(Register dst); + void inc(const Operand& dst); + + void lea(Register dst, const Operand& src); + + void mul(Register src); + + void neg(Register dst); + + void not_(Register dst); + + void or_(Register dst, int32_t imm32); + void or_(Register dst, const Operand& src); + void or_(const Operand& dst, Register src); + void or_(const Operand& dst, const Immediate& x); + + void rcl(Register dst, uint8_t imm8); + + void sar(Register dst, uint8_t imm8); + void sar(Register dst); + + void sbb(Register dst, const Operand& src); + + void shld(Register dst, const Operand& src); + + void shl(Register dst, uint8_t imm8); + void shl(Register dst); + + void shrd(Register dst, const Operand& src); + + void shr(Register dst, uint8_t imm8); + void shr(Register dst); + void shr_cl(Register dst); + + void sub(const Operand& dst, const Immediate& x); + void sub(Register dst, const Operand& src); + void sub(const Operand& dst, Register src); + + void test(Register reg, const Immediate& imm); + void test(Register reg, const Operand& op); + void test(const Operand& op, const Immediate& imm); + + void xor_(Register dst, int32_t imm32); + void xor_(Register dst, const Operand& src); + void xor_(const Operand& src, Register dst); + void xor_(const Operand& dst, const Immediate& x); + + // Bit operations. + void bt(const Operand& dst, Register src); + void bts(const Operand& dst, Register src); + + // Miscellaneous + void hlt(); + void int3(); + void nop(); + void rdtsc(); + void ret(int imm16); + + // Label operations & relative jumps (PPUM Appendix D) + // + // Takes a branch opcode (cc) and a label (L) and generates + // either a backward branch or a forward branch and links it + // to the label fixup chain. Usage: + // + // Label L; // unbound label + // j(cc, &L); // forward branch to unbound label + // bind(&L); // bind label to the current pc + // j(cc, &L); // backward branch to bound label + // bind(&L); // illegal: a label may be bound only once + // + // Note: The same Label can be used for forward and backward branches + // but it may be bound only once. + + void bind(Label* L); // binds an unbound label L to the current code position + + // Calls + void call(Label* L); + void call(byte* entry, RelocInfo::Mode rmode); + void call(const Operand& adr); + void call(Handle<Code> code, RelocInfo::Mode rmode); + + // Jumps + void jmp(Label* L); // unconditional jump to L + void jmp(byte* entry, RelocInfo::Mode rmode); + void jmp(const Operand& adr); + void jmp(Handle<Code> code, RelocInfo::Mode rmode); + + // Conditional jumps + void j(Condition cc, Label* L, Hint hint = no_hint); + void j(Condition cc, byte* entry, RelocInfo::Mode rmode, Hint hint = no_hint); + void j(Condition cc, Handle<Code> code, Hint hint = no_hint); + + // Floating-point operations + void fld(int i); + + void fld1(); + void fldz(); + + void fld_s(const Operand& adr); + void fld_d(const Operand& adr); + + void fstp_s(const Operand& adr); + void fstp_d(const Operand& adr); + + void fild_s(const Operand& adr); + void fild_d(const Operand& adr); + + void fist_s(const Operand& adr); + + void fistp_s(const Operand& adr); + void fistp_d(const Operand& adr); + + void fisttp_s(const Operand& adr); + + void fabs(); + void fchs(); + + void fadd(int i); + void fsub(int i); + void fmul(int i); + void fdiv(int i); + + void fisub_s(const Operand& adr); + + void faddp(int i = 1); + void fsubp(int i = 1); + void fsubrp(int i = 1); + void fmulp(int i = 1); + void fdivp(int i = 1); + void fprem(); + void fprem1(); + + void fxch(int i = 1); + void fincstp(); + void ffree(int i = 0); + + void ftst(); + void fucomp(int i); + void fucompp(); + void fcompp(); + void fnstsw_ax(); + void fwait(); + void fnclex(); + + void frndint(); + + void sahf(); + void setcc(Condition cc, Register reg); + + void cpuid(); + + // SSE2 instructions + void cvttss2si(Register dst, const Operand& src); + void cvttsd2si(Register dst, const Operand& src); + + void cvtsi2sd(XMMRegister dst, const Operand& src); + + void addsd(XMMRegister dst, XMMRegister src); + void subsd(XMMRegister dst, XMMRegister src); + void mulsd(XMMRegister dst, XMMRegister src); + void divsd(XMMRegister dst, XMMRegister src); + + // Use either movsd or movlpd. + void movdbl(XMMRegister dst, const Operand& src); + void movdbl(const Operand& dst, XMMRegister src); + + // Debugging + void Print(); + + // Check the code size generated from label to here. + int SizeOfCodeGeneratedSince(Label* l) { return pc_offset() - l->pos(); } + + // Mark address of the ExitJSFrame code. + void RecordJSReturn(); + + // Record a comment relocation entry that can be used by a disassembler. + // Use --debug_code to enable. + void RecordComment(const char* msg); + + void RecordPosition(int pos); + void RecordStatementPosition(int pos); + void WriteRecordedPositions(); + + // Writes a single word of data in the code stream. + // Used for inline tables, e.g., jump-tables. + void dd(uint32_t data, RelocInfo::Mode reloc_info); + + // Writes the absolute address of a bound label at the given position in + // the generated code. That positions should have the relocation mode + // internal_reference! + void WriteInternalReference(int position, const Label& bound_label); + + int pc_offset() const { return pc_ - buffer_; } + int current_statement_position() const { return current_statement_position_; } + int current_position() const { return current_position_; } + + // Check if there is less than kGap bytes available in the buffer. + // If this is the case, we need to grow the buffer before emitting + // an instruction or relocation information. + inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; } + + // Get the number of bytes available in the buffer. + inline int available_space() const { return reloc_info_writer.pos() - pc_; } + + // Avoid overflows for displacements etc. + static const int kMaximalBufferSize = 512*MB; + static const int kMinimalBufferSize = 4*KB; + + protected: + void movsd(XMMRegister dst, const Operand& src); + void movsd(const Operand& dst, XMMRegister src); + + void emit_sse_operand(XMMRegister reg, const Operand& adr); + void emit_sse_operand(XMMRegister dst, XMMRegister src); + + + private: + byte* addr_at(int pos) { return buffer_ + pos; } + byte byte_at(int pos) { return buffer_[pos]; } + uint32_t long_at(int pos) { + return *reinterpret_cast<uint32_t*>(addr_at(pos)); + } + void long_at_put(int pos, uint32_t x) { + *reinterpret_cast<uint32_t*>(addr_at(pos)) = x; + } + + // code emission + void GrowBuffer(); + inline void emit(uint32_t x); + inline void emit(Handle<Object> handle); + inline void emit(uint32_t x, RelocInfo::Mode rmode); + inline void emit(const Immediate& x); + inline void emit_w(const Immediate& x); + + // Emit the code-object-relative offset of the label's position + inline void emit_code_relative_offset(Label* label); + + // instruction generation + void emit_arith_b(int op1, int op2, Register dst, int imm8); + + // Emit a basic arithmetic instruction (i.e. first byte of the family is 0x81) + // with a given destination expression and an immediate operand. It attempts + // to use the shortest encoding possible. + // sel specifies the /n in the modrm byte (see the Intel PRM). + void emit_arith(int sel, Operand dst, const Immediate& x); + + void emit_operand(Register reg, const Operand& adr); + + void emit_farith(int b1, int b2, int i); + + // labels + void print(Label* L); + void bind_to(Label* L, int pos); + void link_to(Label* L, Label* appendix); + + // displacements + inline Displacement disp_at(Label* L); + inline void disp_at_put(Label* L, Displacement disp); + inline void emit_disp(Label* L, Displacement::Type type); + + // record reloc info for current pc_ + void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); + + friend class CodePatcher; + friend class EnsureSpace; + + // Code buffer: + // The buffer into which code and relocation info are generated. + byte* buffer_; + int buffer_size_; + // True if the assembler owns the buffer, false if buffer is external. + bool own_buffer_; + + // code generation + byte* pc_; // the program counter; moves forward + RelocInfoWriter reloc_info_writer; + + // push-pop elimination + byte* last_pc_; + + // source position information + int current_statement_position_; + int current_position_; + int written_statement_position_; + int written_position_; +}; + + +// Helper class that ensures that there is enough space for generating +// instructions and relocation information. The constructor makes +// sure that there is enough space and (in debug mode) the destructor +// checks that we did not generate too much. +class EnsureSpace BASE_EMBEDDED { + public: + explicit EnsureSpace(Assembler* assembler) : assembler_(assembler) { + if (assembler_->overflow()) assembler_->GrowBuffer(); +#ifdef DEBUG + space_before_ = assembler_->available_space(); +#endif + } + +#ifdef DEBUG + ~EnsureSpace() { + int bytes_generated = space_before_ - assembler_->available_space(); + ASSERT(bytes_generated < assembler_->kGap); + } +#endif + + private: + Assembler* assembler_; +#ifdef DEBUG + int space_before_; +#endif +}; + +} } // namespace v8::internal + +#endif // V8_X64_ASSEMBLER_X64_H_ diff --git a/deps/v8/src/x64/builtins-x64.cc b/deps/v8/src/x64/builtins-x64.cc new file mode 100644 index 000000000..209aa2d30 --- /dev/null +++ b/deps/v8/src/x64/builtins-x64.cc @@ -0,0 +1,27 @@ +// Copyright 2009 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. + diff --git a/deps/v8/src/x64/codegen-x64.cc b/deps/v8/src/x64/codegen-x64.cc new file mode 100644 index 000000000..209aa2d30 --- /dev/null +++ b/deps/v8/src/x64/codegen-x64.cc @@ -0,0 +1,27 @@ +// Copyright 2009 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. + diff --git a/deps/v8/src/codegen-ia32.h b/deps/v8/src/x64/codegen-x64.h index 24a57a074..4acb0cb7f 100644 --- a/deps/v8/src/codegen-ia32.h +++ b/deps/v8/src/x64/codegen-x64.h @@ -1,4 +1,4 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// Copyright 2009 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: @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef V8_CODEGEN_IA32_H_ -#define V8_CODEGEN_IA32_H_ +#ifndef V8_X64_CODEGEN_X64_H_ +#define V8_X64_CODEGEN_X64_H_ namespace v8 { namespace internal { @@ -35,9 +35,6 @@ class DeferredCode; class RegisterAllocator; class RegisterFile; -// Mode to overwrite BinaryExpression values. -enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT }; - enum InitState { CONST_INIT, NOT_CONST_INIT }; enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; @@ -393,7 +390,7 @@ class CodeGenerator: public AstVisitor { // Expressions Operand GlobalObject() const { - return ContextOperand(esi, Context::GLOBAL_INDEX); + return ContextOperand(rsi, Context::GLOBAL_INDEX); } void LoadCondition(Expression* x, @@ -435,7 +432,7 @@ class CodeGenerator: public AstVisitor { void GenericBinaryOperation( Token::Value op, SmiAnalysis* type, - const OverwriteMode overwrite_mode = NO_OVERWRITE); + OverwriteMode overwrite_mode); // If possible, combine two constant smi values using op to produce // a smi result, and push it on the virtual frame, all at compile time. @@ -618,4 +615,4 @@ class CodeGenerator: public AstVisitor { } } // namespace v8::internal -#endif // V8_CODEGEN_IA32_H_ +#endif // V8_X64_CODEGEN_X64_H_ diff --git a/deps/v8/src/x64/cpu-x64.cc b/deps/v8/src/x64/cpu-x64.cc new file mode 100644 index 000000000..209aa2d30 --- /dev/null +++ b/deps/v8/src/x64/cpu-x64.cc @@ -0,0 +1,27 @@ +// Copyright 2009 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. + diff --git a/deps/v8/src/x64/debug-x64.cc b/deps/v8/src/x64/debug-x64.cc new file mode 100644 index 000000000..209aa2d30 --- /dev/null +++ b/deps/v8/src/x64/debug-x64.cc @@ -0,0 +1,27 @@ +// Copyright 2009 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. + diff --git a/deps/v8/src/x64/disasm-x64.cc b/deps/v8/src/x64/disasm-x64.cc new file mode 100644 index 000000000..209aa2d30 --- /dev/null +++ b/deps/v8/src/x64/disasm-x64.cc @@ -0,0 +1,27 @@ +// Copyright 2009 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. + diff --git a/deps/v8/src/x64/frames-x64.cc b/deps/v8/src/x64/frames-x64.cc new file mode 100644 index 000000000..209aa2d30 --- /dev/null +++ b/deps/v8/src/x64/frames-x64.cc @@ -0,0 +1,27 @@ +// Copyright 2009 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. + diff --git a/deps/v8/src/x64/frames-x64.h b/deps/v8/src/x64/frames-x64.h new file mode 100644 index 000000000..f4468f6a2 --- /dev/null +++ b/deps/v8/src/x64/frames-x64.h @@ -0,0 +1,121 @@ +// Copyright 2009 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. + +#ifndef V8_X64_FRAMES_X64_H_ +#define V8_X64_FRAMES_X64_H_ + +namespace v8 { namespace internal { + +// TODO(x64): This is a stub, mostly just a copy of the ia32 bit version. +// This will all need to change to be correct for x64. + +static const int kNumRegs = 8; +static const RegList kJSCallerSaved = 0; +static const int kNumJSCallerSaved = 5; +typedef Object* JSCallerSavedBuffer[kNumJSCallerSaved]; + +class StackHandlerConstants : public AllStatic { + public: + static const int kNextOffset = -1 * kPointerSize; + static const int kPPOffset = -1 * kPointerSize; + static const int kFPOffset = -1 * kPointerSize; + + static const int kCodeOffset = -1 * kPointerSize; + + static const int kStateOffset = -1 * kPointerSize; + static const int kPCOffset = -1 * kPointerSize; + + static const int kAddressDisplacement = -1 * kPointerSize; + static const int kSize = kPCOffset + kPointerSize; +}; + + +class EntryFrameConstants : public AllStatic { + public: + static const int kCallerFPOffset = -1 * kPointerSize; + + static const int kFunctionArgOffset = -1 * kPointerSize; + static const int kReceiverArgOffset = -1 * kPointerSize; + static const int kArgcOffset = -1 * kPointerSize; + static const int kArgvOffset = -1 * kPointerSize; +}; + + +class ExitFrameConstants : public AllStatic { + public: + static const int kDebugMarkOffset = -1 * kPointerSize; + static const int kSPOffset = -1 * kPointerSize; + + static const int kPPDisplacement = -1 * kPointerSize; + + static const int kCallerFPOffset = -1 * kPointerSize; + static const int kCallerPCOffset = -1 * kPointerSize; +}; + + +class StandardFrameConstants : public AllStatic { + public: + static const int kExpressionsOffset = -1 * kPointerSize; + static const int kMarkerOffset = -1 * kPointerSize; + static const int kContextOffset = -1 * kPointerSize; + static const int kCallerFPOffset = -1 * kPointerSize; + static const int kCallerPCOffset = -1 * kPointerSize; + static const int kCallerSPOffset = -1 * kPointerSize; +}; + + +class JavaScriptFrameConstants : public AllStatic { + public: + static const int kLocal0Offset = StandardFrameConstants::kExpressionsOffset; + static const int kSavedRegistersOffset = -1 * kPointerSize; + static const int kFunctionOffset = StandardFrameConstants::kMarkerOffset; + + static const int kParam0Offset = -1 * kPointerSize; + static const int kReceiverOffset = -1 * kPointerSize; +}; + + +class ArgumentsAdaptorFrameConstants : public AllStatic { + public: + static const int kLengthOffset = StandardFrameConstants::kExpressionsOffset; +}; + + +class InternalFrameConstants : public AllStatic { + public: + static const int kCodeOffset = StandardFrameConstants::kExpressionsOffset; +}; + + +inline Object* JavaScriptFrame::function_slot_object() const { + const int offset = JavaScriptFrameConstants::kFunctionOffset; + return Memory::Object_at(fp() + offset); +} + +} } // namespace v8::internal + +#endif // V8_X64_FRAMES_X64_H_ diff --git a/deps/v8/src/x64/ic-x64.cc b/deps/v8/src/x64/ic-x64.cc new file mode 100644 index 000000000..209aa2d30 --- /dev/null +++ b/deps/v8/src/x64/ic-x64.cc @@ -0,0 +1,27 @@ +// Copyright 2009 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. + diff --git a/deps/v8/src/x64/jump-target-x64.cc b/deps/v8/src/x64/jump-target-x64.cc new file mode 100644 index 000000000..209aa2d30 --- /dev/null +++ b/deps/v8/src/x64/jump-target-x64.cc @@ -0,0 +1,27 @@ +// Copyright 2009 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. + diff --git a/deps/v8/src/x64/macro-assembler-x64.cc b/deps/v8/src/x64/macro-assembler-x64.cc new file mode 100644 index 000000000..209aa2d30 --- /dev/null +++ b/deps/v8/src/x64/macro-assembler-x64.cc @@ -0,0 +1,27 @@ +// Copyright 2009 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. + diff --git a/deps/v8/src/macro-assembler-ia32.h b/deps/v8/src/x64/macro-assembler-x64.h index 40aa84a0a..159d0c4f3 100644 --- a/deps/v8/src/macro-assembler-ia32.h +++ b/deps/v8/src/x64/macro-assembler-x64.h @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef V8_MACRO_ASSEMBLER_IA32_H_ -#define V8_MACRO_ASSEMBLER_IA32_H_ +#ifndef V8_X64_MACRO_ASSEMBLER_X64_H_ +#define V8_X64_MACRO_ASSEMBLER_X64_H_ #include "assembler.h" @@ -73,7 +73,7 @@ class MacroAssembler: public Assembler { Register value, Register scratch); - +#ifdef ENABLE_DEBUGGER_SUPPORT // --------------------------------------------------------------------------- // Debugger Support @@ -84,7 +84,7 @@ class MacroAssembler: public Assembler { void CopyRegistersFromStackToMemory(Register base, Register scratch, RegList regs); - +#endif // --------------------------------------------------------------------------- // Activation frames @@ -343,6 +343,29 @@ static inline Operand FieldOperand(Register object, return Operand(object, index, scale, offset - kHeapObjectTag); } + +#ifdef GENERATED_CODE_COVERAGE +extern void LogGeneratedCodeCoverage(const char* file_line); +#define CODE_COVERAGE_STRINGIFY(x) #x +#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x) +#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__) +#define ACCESS_MASM(masm) { \ + byte* x64_coverage_function = \ + reinterpret_cast<byte*>(FUNCTION_ADDR(LogGeneratedCodeCoverage)); \ + masm->pushfd(); \ + masm->pushad(); \ + masm->push(Immediate(reinterpret_cast<int>(&__FILE_LINE__))); \ + masm->call(x64_coverage_function, RelocInfo::RUNTIME_ENTRY); \ + masm->pop(rax); \ + masm->popad(); \ + masm->popfd(); \ + } \ + masm-> +#else +#define ACCESS_MASM(masm) masm-> +#endif + + } } // namespace v8::internal -#endif // V8_MACRO_ASSEMBLER_IA32_H_ +#endif // V8_X64_MACRO_ASSEMBLER_X64_H_ diff --git a/deps/v8/src/x64/regexp-macro-assembler-x64.cc b/deps/v8/src/x64/regexp-macro-assembler-x64.cc new file mode 100644 index 000000000..209aa2d30 --- /dev/null +++ b/deps/v8/src/x64/regexp-macro-assembler-x64.cc @@ -0,0 +1,27 @@ +// Copyright 2009 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. + diff --git a/deps/v8/src/x64/regexp-macro-assembler-x64.h b/deps/v8/src/x64/regexp-macro-assembler-x64.h new file mode 100644 index 000000000..209aa2d30 --- /dev/null +++ b/deps/v8/src/x64/regexp-macro-assembler-x64.h @@ -0,0 +1,27 @@ +// Copyright 2009 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. + diff --git a/deps/v8/src/x64/register-allocator-x64.cc b/deps/v8/src/x64/register-allocator-x64.cc new file mode 100644 index 000000000..209aa2d30 --- /dev/null +++ b/deps/v8/src/x64/register-allocator-x64.cc @@ -0,0 +1,27 @@ +// Copyright 2009 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. + diff --git a/deps/v8/src/x64/simulator-x64.cc b/deps/v8/src/x64/simulator-x64.cc new file mode 100644 index 000000000..209aa2d30 --- /dev/null +++ b/deps/v8/src/x64/simulator-x64.cc @@ -0,0 +1,27 @@ +// Copyright 2009 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. + diff --git a/deps/v8/src/x64/simulator-x64.h b/deps/v8/src/x64/simulator-x64.h new file mode 100644 index 000000000..8160e5364 --- /dev/null +++ b/deps/v8/src/x64/simulator-x64.h @@ -0,0 +1,47 @@ +// Copyright 2009 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. + +#ifndef V8_X64_SIMULATOR_X64_H_ +#define V8_X64_SIMULATOR_X64_H_ + + +// Since there is no simulator for the ia32 architecture the only thing we can +// do is to call the entry directly. +#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ + entry(p0, p1, p2, p3, p4); + +// Calculated the stack limit beyond which we will throw stack overflow errors. +// This macro must be called from a C++ method. It relies on being able to take +// the address of "this" to get a value on the current execution stack and then +// calculates the stack limit based on that value. +// NOTE: The check for overflow is not safe as there is no guarantee that the +// running thread has its stack in all memory up to address 0x00000000. +#define GENERATED_CODE_STACK_LIMIT(limit) \ + (reinterpret_cast<uintptr_t>(this) >= limit ? \ + reinterpret_cast<uintptr_t>(this) - limit : 0) + +#endif // V8_X64_SIMULATOR_X64_H_ diff --git a/deps/v8/src/x64/stub-cache-x64.cc b/deps/v8/src/x64/stub-cache-x64.cc new file mode 100644 index 000000000..209aa2d30 --- /dev/null +++ b/deps/v8/src/x64/stub-cache-x64.cc @@ -0,0 +1,27 @@ +// Copyright 2009 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. + diff --git a/deps/v8/src/x64/virtual-frame-x64.cc b/deps/v8/src/x64/virtual-frame-x64.cc new file mode 100644 index 000000000..209aa2d30 --- /dev/null +++ b/deps/v8/src/x64/virtual-frame-x64.cc @@ -0,0 +1,27 @@ +// Copyright 2009 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. + diff --git a/deps/v8/src/x64/virtual-frame-x64.h b/deps/v8/src/x64/virtual-frame-x64.h new file mode 100644 index 000000000..f71766d03 --- /dev/null +++ b/deps/v8/src/x64/virtual-frame-x64.h @@ -0,0 +1,493 @@ +// Copyright 2009 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. + +#ifndef V8_X64_VIRTUAL_FRAME_X64_H_ +#define V8_X64_VIRTUAL_FRAME_X64_H_ + +#include "register-allocator.h" + +namespace v8 { namespace internal { + +// ------------------------------------------------------------------------- +// Virtual frames +// +// The virtual frame is an abstraction of the physical stack frame. It +// encapsulates the parameters, frame-allocated locals, and the expression +// stack. It supports push/pop operations on the expression stack, as well +// as random access to the expression stack elements, locals, and +// parameters. + +class VirtualFrame : public Malloced { + public: + // A utility class to introduce a scope where the virtual frame is + // expected to remain spilled. The constructor spills the code + // generator's current frame, but no attempt is made to require it + // to stay spilled. It is intended as documentation while the code + // generator is being transformed. + class SpilledScope BASE_EMBEDDED { + public: + explicit SpilledScope(CodeGenerator* cgen); + + ~SpilledScope(); + + private: + CodeGenerator* cgen_; + bool previous_state_; + }; + + // An illegal index into the virtual frame. + static const int kIllegalIndex = -1; + + // Construct an initial virtual frame on entry to a JS function. + explicit VirtualFrame(CodeGenerator* cgen); + + // Construct a virtual frame as a clone of an existing one. + explicit VirtualFrame(VirtualFrame* original); + + // Create a duplicate of an existing valid frame element. + FrameElement CopyElementAt(int index); + + // The height of the virtual expression stack. + int height() const { + return elements_.length() - expression_base_index(); + } + + int register_index(Register reg) { + return register_locations_[reg.code()]; + } + + bool is_used(int reg_code) { + return register_locations_[reg_code] != kIllegalIndex; + } + + bool is_used(Register reg) { + return is_used(reg.code()); + } + + // Add extra in-memory elements to the top of the frame to match an actual + // frame (eg, the frame after an exception handler is pushed). No code is + // emitted. + void Adjust(int count); + + // Forget count elements from the top of the frame all in-memory + // (including synced) and adjust the stack pointer downward, to + // match an external frame effect (examples include a call removing + // its arguments, and exiting a try/catch removing an exception + // handler). No code will be emitted. + void Forget(int count); + + // Forget count elements from the top of the frame without adjusting + // the stack pointer downward. This is used, for example, before + // merging frames at break, continue, and return targets. + void ForgetElements(int count); + + // Spill all values from the frame to memory. + void SpillAll(); + + // Spill all occurrences of a specific register from the frame. + void Spill(Register reg); + + // Spill all occurrences of an arbitrary register if possible. Return the + // register spilled or no_reg if it was not possible to free any register + // (ie, they all have frame-external references). + Register SpillAnyRegister(); + + // Prepare this virtual frame for merging to an expected frame by + // performing some state changes that do not require generating + // code. It is guaranteed that no code will be generated. + void PrepareMergeTo(VirtualFrame* expected); + + // Make this virtual frame have a state identical to an expected virtual + // frame. As a side effect, code may be emitted to make this frame match + // the expected one. + void MergeTo(VirtualFrame* expected); + + // Detach a frame from its code generator, perhaps temporarily. This + // tells the register allocator that it is free to use frame-internal + // registers. Used when the code generator's frame is switched from this + // one to NULL by an unconditional jump. + void DetachFromCodeGenerator(); + + // (Re)attach a frame to its code generator. This informs the register + // allocator that the frame-internal register references are active again. + // Used when a code generator's frame is switched from NULL to this one by + // binding a label. + void AttachToCodeGenerator(); + + // Emit code for the physical JS entry and exit frame sequences. After + // calling Enter, the virtual frame is ready for use; and after calling + // Exit it should not be used. Note that Enter does not allocate space in + // the physical frame for storing frame-allocated locals. + void Enter(); + void Exit(); + + // Prepare for returning from the frame by spilling locals. This + // avoids generating unnecessary merge code when jumping to the + // shared return site. Emits code for spills. + void PrepareForReturn(); + + // Allocate and initialize the frame-allocated locals. + void AllocateStackSlots(int count); + + // An element of the expression stack as an assembly operand. + Operand ElementAt(int index) const { + return Operand(rsp, index * kPointerSize); + } + + // Random-access store to a frame-top relative frame element. The result + // becomes owned by the frame and is invalidated. + void SetElementAt(int index, Result* value); + + // Set a frame element to a constant. The index is frame-top relative. + void SetElementAt(int index, Handle<Object> value) { + Result temp(value, cgen_); + SetElementAt(index, &temp); + } + + void PushElementAt(int index) { + PushFrameSlotAt(elements_.length() - index - 1); + } + + void StoreToElementAt(int index) { + StoreToFrameSlotAt(elements_.length() - index - 1); + } + + // A frame-allocated local as an assembly operand. + Operand LocalAt(int index) const { + ASSERT(0 <= index); + ASSERT(index < local_count_); + return Operand(rbp, kLocal0Offset - index * kPointerSize); + } + + // Push a copy of the value of a local frame slot on top of the frame. + void PushLocalAt(int index) { + PushFrameSlotAt(local0_index() + index); + } + + // Push the value of a local frame slot on top of the frame and invalidate + // the local slot. The slot should be written to before trying to read + // from it again. + void TakeLocalAt(int index) { + TakeFrameSlotAt(local0_index() + index); + } + + // Store the top value on the virtual frame into a local frame slot. The + // value is left in place on top of the frame. + void StoreToLocalAt(int index) { + StoreToFrameSlotAt(local0_index() + index); + } + + // Push the address of the receiver slot on the frame. + void PushReceiverSlotAddress(); + + // Push the function on top of the frame. + void PushFunction() { PushFrameSlotAt(function_index()); } + + // Save the value of the esi register to the context frame slot. + void SaveContextRegister(); + + // Restore the esi register from the value of the context frame + // slot. + void RestoreContextRegister(); + + // A parameter as an assembly operand. + Operand ParameterAt(int index) const { + ASSERT(-1 <= index); // -1 is the receiver. + ASSERT(index < parameter_count_); + return Operand(rbp, (1 + parameter_count_ - index) * kPointerSize); + } + + // Push a copy of the value of a parameter frame slot on top of the frame. + void PushParameterAt(int index) { + PushFrameSlotAt(param0_index() + index); + } + + // Push the value of a paramter frame slot on top of the frame and + // invalidate the parameter slot. The slot should be written to before + // trying to read from it again. + void TakeParameterAt(int index) { + TakeFrameSlotAt(param0_index() + index); + } + + // Store the top value on the virtual frame into a parameter frame slot. + // The value is left in place on top of the frame. + void StoreToParameterAt(int index) { + StoreToFrameSlotAt(param0_index() + index); + } + + // The receiver frame slot. + Operand Receiver() const { return ParameterAt(-1); } + + // Push a try-catch or try-finally handler on top of the virtual frame. + void PushTryHandler(HandlerType type); + + // Call stub given the number of arguments it expects on (and + // removes from) the stack. + Result CallStub(CodeStub* stub, int arg_count); + + // Call stub that takes a single argument passed in eax. The + // argument is given as a result which does not have to be eax or + // even a register. The argument is consumed by the call. + Result CallStub(CodeStub* stub, Result* arg); + + // Call stub that takes a pair of arguments passed in edx (arg0) and + // eax (arg1). The arguments are given as results which do not have + // to be in the proper registers or even in registers. The + // arguments are consumed by the call. + Result CallStub(CodeStub* stub, Result* arg0, Result* arg1); + + // Call runtime given the number of arguments expected on (and + // removed from) the stack. + Result CallRuntime(Runtime::Function* f, int arg_count); + Result CallRuntime(Runtime::FunctionId id, int arg_count); + + // Invoke builtin given the number of arguments it expects on (and + // removes from) the stack. + Result InvokeBuiltin(Builtins::JavaScript id, + InvokeFlag flag, + int arg_count); + + // Call load IC. Name and receiver are found on top of the frame. + // Receiver is not dropped. + Result CallLoadIC(RelocInfo::Mode mode); + + // Call keyed load IC. Key and receiver are found on top of the + // frame. They are not dropped. + Result CallKeyedLoadIC(RelocInfo::Mode mode); + + // Call store IC. Name, value, and receiver are found on top of the + // frame. Receiver is not dropped. + Result CallStoreIC(); + + // Call keyed store IC. Value, key, and receiver are found on top + // of the frame. Key and receiver are not dropped. + Result CallKeyedStoreIC(); + + // Call call IC. Arguments, reciever, and function name are found + // on top of the frame. Function name slot is not dropped. The + // argument count does not include the receiver. + Result CallCallIC(RelocInfo::Mode mode, int arg_count, int loop_nesting); + + // Allocate and call JS function as constructor. Arguments, + // receiver (global object), and function are found on top of the + // frame. Function is not dropped. The argument count does not + // include the receiver. + Result CallConstructor(int arg_count); + + // Drop a number of elements from the top of the expression stack. May + // emit code to affect the physical frame. Does not clobber any registers + // excepting possibly the stack pointer. + void Drop(int count); + + // Drop one element. + void Drop() { Drop(1); } + + // Duplicate the top element of the frame. + void Dup() { PushFrameSlotAt(elements_.length() - 1); } + + // Pop an element from the top of the expression stack. Returns a + // Result, which may be a constant or a register. + Result Pop(); + + // Pop and save an element from the top of the expression stack and + // emit a corresponding pop instruction. + void EmitPop(Register reg); + void EmitPop(Operand operand); + + // Push an element on top of the expression stack and emit a + // corresponding push instruction. + void EmitPush(Register reg); + void EmitPush(Operand operand); + void EmitPush(Immediate immediate); + + // Push an element on the virtual frame. + void Push(Register reg, StaticType static_type = StaticType()); + void Push(Handle<Object> value); + void Push(Smi* value) { Push(Handle<Object>(value)); } + + // Pushing a result invalidates it (its contents become owned by the + // frame). + void Push(Result* result); + + // Nip removes zero or more elements from immediately below the top + // of the frame, leaving the previous top-of-frame value on top of + // the frame. Nip(k) is equivalent to x = Pop(), Drop(k), Push(x). + void Nip(int num_dropped); + + private: + static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset; + static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset; + static const int kContextOffset = StandardFrameConstants::kContextOffset; + + static const int kHandlerSize = StackHandlerConstants::kSize / kPointerSize; + static const int kPreallocatedElements = 5 + 8; // 8 expression stack slots. + + CodeGenerator* cgen_; + MacroAssembler* masm_; + + List<FrameElement> elements_; + + // The number of frame-allocated locals and parameters respectively. + int parameter_count_; + int local_count_; + + // The index of the element that is at the processor's stack pointer + // (the esp register). + int stack_pointer_; + + // The index of the element that is at the processor's frame pointer + // (the ebp register). + int frame_pointer_; + + // The index of the register frame element using each register, or + // kIllegalIndex if a register is not on the frame. + int register_locations_[kNumRegisters]; + + // The index of the first parameter. The receiver lies below the first + // parameter. + int param0_index() const { return 1; } + + // The index of the context slot in the frame. + int context_index() const { + ASSERT(frame_pointer_ != kIllegalIndex); + return frame_pointer_ + 1; + } + + // The index of the function slot in the frame. It lies above the context + // slot. + int function_index() const { + ASSERT(frame_pointer_ != kIllegalIndex); + return frame_pointer_ + 2; + } + + // The index of the first local. Between the parameters and the locals + // lie the return address, the saved frame pointer, the context, and the + // function. + int local0_index() const { + ASSERT(frame_pointer_ != kIllegalIndex); + return frame_pointer_ + 3; + } + + // The index of the base of the expression stack. + int expression_base_index() const { return local0_index() + local_count_; } + + // Convert a frame index into a frame pointer relative offset into the + // actual stack. + int fp_relative(int index) const { + return (frame_pointer_ - index) * kPointerSize; + } + + // Record an occurrence of a register in the virtual frame. This has the + // effect of incrementing the register's external reference count and + // of updating the index of the register's location in the frame. + void Use(Register reg, int index); + + // Record that a register reference has been dropped from the frame. This + // decrements the register's external reference count and invalidates the + // index of the register's location in the frame. + void Unuse(Register reg); + + // Spill the element at a particular index---write it to memory if + // necessary, free any associated register, and forget its value if + // constant. + void SpillElementAt(int index); + + // Sync the element at a particular index. If it is a register or + // constant that disagrees with the value on the stack, write it to memory. + // Keep the element type as register or constant, and clear the dirty bit. + void SyncElementAt(int index); + + // Sync the range of elements in [begin, end). + void SyncRange(int begin, int end); + + // Sync a single unsynced element that lies beneath or at the stack pointer. + void SyncElementBelowStackPointer(int index); + + // Sync a single unsynced element that lies just above the stack pointer. + void SyncElementByPushing(int index); + + // Push a copy of a frame slot (typically a local or parameter) on top of + // the frame. + void PushFrameSlotAt(int index); + + // Push a the value of a frame slot (typically a local or parameter) on + // top of the frame and invalidate the slot. + void TakeFrameSlotAt(int index); + + // Store the value on top of the frame to a frame slot (typically a local + // or parameter). + void StoreToFrameSlotAt(int index); + + // Spill all elements in registers. Spill the top spilled_args elements + // on the frame. Sync all other frame elements. + // Then drop dropped_args elements from the virtual frame, to match + // the effect of an upcoming call that will drop them from the stack. + void PrepareForCall(int spilled_args, int dropped_args); + + // Move frame elements currently in registers or constants, that + // should be in memory in the expected frame, to memory. + void MergeMoveRegistersToMemory(VirtualFrame* expected); + + // Make the register-to-register moves necessary to + // merge this frame with the expected frame. + // Register to memory moves must already have been made, + // and memory to register moves must follow this call. + // This is because some new memory-to-register moves are + // created in order to break cycles of register moves. + // Used in the implementation of MergeTo(). + void MergeMoveRegistersToRegisters(VirtualFrame* expected); + + // Make the memory-to-register and constant-to-register moves + // needed to make this frame equal the expected frame. + // Called after all register-to-memory and register-to-register + // moves have been made. After this function returns, the frames + // should be equal. + void MergeMoveMemoryToRegisters(VirtualFrame* expected); + + // Invalidates a frame slot (puts an invalid frame element in it). + // Copies on the frame are correctly handled, and if this slot was + // the backing store of copies, the index of the new backing store + // is returned. Otherwise, returns kIllegalIndex. + // Register counts are correctly updated. + int InvalidateFrameSlotAt(int index); + + // Call a code stub that has already been prepared for calling (via + // PrepareForCall). + Result RawCallStub(CodeStub* stub); + + // Calls a code object which has already been prepared for calling + // (via PrepareForCall). + Result RawCallCodeObject(Handle<Code> code, RelocInfo::Mode rmode); + + bool Equals(VirtualFrame* other); + + friend class JumpTarget; +}; + +} } // namespace v8::internal + +#endif // V8_X64_VIRTUAL_FRAME_X64_H_ diff --git a/deps/v8/test/cctest/SConscript b/deps/v8/test/cctest/SConscript index f66f72b0e..740acbaa6 100644 --- a/deps/v8/test/cctest/SConscript +++ b/deps/v8/test/cctest/SConscript @@ -47,6 +47,7 @@ SOURCES = { 'test-heap.cc', 'test-list.cc', 'test-lock.cc', + 'test-log.cc', 'test-mark-compact.cc', 'test-regexp.cc', 'test-serialize.cc', @@ -54,7 +55,8 @@ SOURCES = { 'test-spaces.cc', 'test-strings.cc', 'test-threads.cc', - 'test-utils.cc' + 'test-utils.cc', + 'test-version.cc' ], 'arch:arm': ['test-assembler-arm.cc', 'test-disasm-arm.cc'], 'arch:ia32': [ diff --git a/deps/v8/test/cctest/cctest.cc b/deps/v8/test/cctest/cctest.cc index 2807c8b47..82a33e6da 100644 --- a/deps/v8/test/cctest/cctest.cc +++ b/deps/v8/test/cctest/cctest.cc @@ -26,9 +26,6 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <v8.h> -#include <cstdlib> -#include <cstring> -#include <cstdio> #include "cctest.h" #include "debug.h" diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status index 9a3f819e4..7b43c8de9 100644 --- a/deps/v8/test/cctest/cctest.status +++ b/deps/v8/test/cctest/cctest.status @@ -27,9 +27,6 @@ prefix cctest -# BUG(96): Fix this flaky test. -test-debug/ThreadedDebugging: PASS || FAIL - # BUG(281): This test fails on some Linuxes. test-debug/DebuggerAgent: PASS, (PASS || FAIL) if $system == linux @@ -43,8 +40,10 @@ test-spaces/LargeObjectSpace: PASS || FAIL # BUG(240): Test seems flaky on ARM. test-api/RegExpInterruption: SKIP +[ $simulator == arm ] + # BUG(271): During exception propagation, we compare pointers into the # stack. These tests fail on the ARM simulator because the C++ and # the JavaScript stacks are separate. -test-api/ExceptionOrder: PASS || FAIL -test-api/TryCatchInTryFinally: PASS || FAIL +test-api/ExceptionOrder: FAIL +test-api/TryCatchInTryFinally: FAIL diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 23e57d548..4b55b6be0 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -27,9 +27,6 @@ #include <stdlib.h> -#include <map> -#include <string> - #include "v8.h" #include "api.h" @@ -161,7 +158,7 @@ class RegisterThreadedTest { } static int count() { return count_; } static RegisterThreadedTest* nth(int i) { - ASSERT(i < count()); + CHECK(i < count()); RegisterThreadedTest* current = first_; while (i > 0) { i--; @@ -295,13 +292,13 @@ THREADED_TEST(ArgumentSignature) { env->Global()->Set(v8_str("Fun1"), fun->GetFunction()); v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';"); - ASSERT(value1->IsTrue()); + CHECK(value1->IsTrue()); v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';"); - ASSERT(value2->IsTrue()); + CHECK(value2->IsTrue()); v8::Handle<Value> value3 = CompileRun("Fun1() == '';"); - ASSERT(value3->IsTrue()); + CHECK(value3->IsTrue()); v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(); cons1->SetClassName(v8_str("Cons1")); @@ -323,24 +320,24 @@ THREADED_TEST(ArgumentSignature) { v8::Handle<Value> value4 = CompileRun( "Fun2(new Cons1(), new Cons2(), new Cons3()) ==" "'[object Cons1],[object Cons2],[object Cons3]'"); - ASSERT(value4->IsTrue()); + CHECK(value4->IsTrue()); v8::Handle<Value> value5 = CompileRun( "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'"); - ASSERT(value5->IsTrue()); + CHECK(value5->IsTrue()); v8::Handle<Value> value6 = CompileRun( "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'"); - ASSERT(value6->IsTrue()); + CHECK(value6->IsTrue()); v8::Handle<Value> value7 = CompileRun( "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == " "'[object Cons1],[object Cons2],[object Cons3],d';"); - ASSERT(value7->IsTrue()); + CHECK(value7->IsTrue()); v8::Handle<Value> value8 = CompileRun( "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'"); - ASSERT(value8->IsTrue()); + CHECK(value8->IsTrue()); } @@ -423,7 +420,7 @@ class TestAsciiResource: public String::ExternalAsciiStringResource { public: static int dispose_count; - explicit TestAsciiResource(char* data) + explicit TestAsciiResource(const char* data) : data_(data), length_(strlen(data)) { } @@ -440,7 +437,7 @@ class TestAsciiResource: public String::ExternalAsciiStringResource { return length_; } private: - char* data_; + const char* data_; size_t length_; }; @@ -1394,6 +1391,7 @@ static void check_message(v8::Handle<v8::Message> message, v8::Handle<Value> data) { CHECK_EQ(5.76, data->NumberValue()); CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); + CHECK_EQ(7.56, message->GetScriptData()->NumberValue()); message_received = true; } @@ -1406,7 +1404,10 @@ THREADED_TEST(MessageHandlerData) { LocalContext context; v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("6.75")); - Script::Compile(v8_str("throw 'error'"), &origin)->Run(); + v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"), + &origin); + script->SetData(v8_str("7.56")); + script->Run(); CHECK(message_received); // clear out the message listener v8::V8::RemoveMessageListeners(check_message); @@ -2925,7 +2926,19 @@ THREADED_TEST(Deleter) { static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) { ApiTestFuzzer::Fuzz(); - return v8::Undefined(); + if (name->Equals(v8_str("foo")) || + name->Equals(v8_str("bar")) || + name->Equals(v8_str("baz"))) { + return v8::Undefined(); + } + return v8::Handle<Value>(); +} + + +static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) { + ApiTestFuzzer::Fuzz(); + if (index == 0 || index == 1) return v8::Undefined(); + return v8::Handle<Value>(); } @@ -2942,8 +2955,8 @@ static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) { static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) { ApiTestFuzzer::Fuzz(); v8::Handle<v8::Array> result = v8::Array::New(2); - result->Set(v8::Integer::New(0), v8_str("hat")); - result->Set(v8::Integer::New(1), v8_str("gyt")); + result->Set(v8::Integer::New(0), v8_str("0")); + result->Set(v8::Integer::New(1), v8_str("1")); return result; } @@ -2952,21 +2965,56 @@ THREADED_TEST(Enumerators) { v8::HandleScope scope; v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum); - obj->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL, IndexedEnum); + obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum); LocalContext context; context->Global()->Set(v8_str("k"), obj->NewInstance()); v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun( + "k[10] = 0;" + "k.a = 0;" + "k[5] = 0;" + "k.b = 0;" + "k[4294967295] = 0;" + "k.c = 0;" + "k[4294967296] = 0;" + "k.d = 0;" + "k[140000] = 0;" + "k.e = 0;" + "k[30000000000] = 0;" + "k.f = 0;" "var result = [];" "for (var prop in k) {" " result.push(prop);" "}" "result")); - CHECK_EQ(5, result->Length()); - CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(0))); - CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(1))); - CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(2))); - CHECK_EQ(v8_str("hat"), result->Get(v8::Integer::New(3))); - CHECK_EQ(v8_str("gyt"), result->Get(v8::Integer::New(4))); + // Check that we get all the property names returned including the + // ones from the enumerators in the right order: indexed properties + // in numerical order, indexed interceptor properties, named + // properties in insertion order, named interceptor properties. + // This order is not mandated by the spec, so this test is just + // documenting our behavior. + CHECK_EQ(17, result->Length()); + // Indexed properties in numerical order. + CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0))); + CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1))); + CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2))); + CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3))); + // Indexed interceptor properties in the order they are returned + // from the enumerator interceptor. + CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4))); + CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5))); + // Named properties in insertion order. + CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6))); + CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7))); + CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8))); + CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9))); + CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10))); + CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11))); + CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12))); + CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13))); + // Named interceptor properties. + CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14))); + CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15))); + CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16))); } @@ -4579,40 +4627,42 @@ THREADED_TEST(CallAsFunction) { Local<Value> value; CHECK(!try_catch.HasCaught()); - value = Script::Compile(v8_str("obj(42)"))->Run(); + value = CompileRun("obj(42)"); CHECK(!try_catch.HasCaught()); CHECK_EQ(42, value->Int32Value()); - value = Script::Compile(v8_str("(function(o){return o(49)})(obj)"))->Run(); + value = CompileRun("(function(o){return o(49)})(obj)"); CHECK(!try_catch.HasCaught()); CHECK_EQ(49, value->Int32Value()); // test special case of call as function - value = Script::Compile(v8_str("[obj]['0'](45)"))->Run(); + value = CompileRun("[obj]['0'](45)"); CHECK(!try_catch.HasCaught()); CHECK_EQ(45, value->Int32Value()); - value = Script::Compile(v8_str("obj.call = Function.prototype.call;" - "obj.call(null, 87)"))->Run(); + value = CompileRun("obj.call = Function.prototype.call;" + "obj.call(null, 87)"); CHECK(!try_catch.HasCaught()); CHECK_EQ(87, value->Int32Value()); // Regression tests for bug #1116356: Calling call through call/apply // must work for non-function receivers. const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])"; - value = Script::Compile(v8_str(apply_99))->Run(); + value = CompileRun(apply_99); CHECK(!try_catch.HasCaught()); CHECK_EQ(99, value->Int32Value()); const char* call_17 = "Function.prototype.call.call(obj, this, 17)"; - value = Script::Compile(v8_str(call_17))->Run(); + value = CompileRun(call_17); CHECK(!try_catch.HasCaught()); CHECK_EQ(17, value->Int32Value()); - // Try something that will cause an exception: Call the object as a - // constructor. This should be the last test. - value = Script::Compile(v8_str("new obj(42)"))->Run(); - CHECK(try_catch.HasCaught()); + // Check that the call-as-function handler can be called through + // new. Currently, there is no way to check in the call-as-function + // handler if it has been called through new or not. + value = CompileRun("new obj(42)"); + CHECK(!try_catch.HasCaught()); + CHECK_EQ(42, value->Int32Value()); } @@ -4689,6 +4739,44 @@ THREADED_TEST(InterceptorHasOwnProperty) { } +static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC( + Local<String> name, + const AccessorInfo& info) { + ApiTestFuzzer::Fuzz(); + i::Heap::CollectAllGarbage(); + return v8::Handle<Value>(); +} + + +THREADED_TEST(InterceptorHasOwnPropertyCausingGC) { + v8::HandleScope scope; + LocalContext context; + Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); + Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate(); + instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC); + Local<Function> function = fun_templ->GetFunction(); + context->Global()->Set(v8_str("constructor"), function); + // Let's first make some stuff so we can be sure to get a good GC. + CompileRun( + "function makestr(size) {" + " switch (size) {" + " case 1: return 'f';" + " case 2: return 'fo';" + " case 3: return 'foo';" + " }" + " return makestr(size >> 1) + makestr((size + 1) >> 1);" + "}" + "var x = makestr(12345);" + "x = makestr(31415);" + "x = makestr(23456);"); + v8::Handle<Value> value = CompileRun( + "var o = new constructor();" + "o.__proto__ = new String(x);" + "o.hasOwnProperty('ostehaps');"); + CHECK_EQ(false, value->BooleanValue()); +} + + static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name, const AccessorInfo& info) { ApiTestFuzzer::Fuzz(); @@ -5963,6 +6051,114 @@ TEST(RegExpInterruption) { } +class ApplyInterruptTest { + public: + ApplyInterruptTest() : block_(NULL) {} + ~ApplyInterruptTest() { delete block_; } + void RunTest() { + block_ = i::OS::CreateSemaphore(0); + gc_count_ = 0; + gc_during_apply_ = 0; + apply_success_ = false; + gc_success_ = false; + GCThread gc_thread(this); + gc_thread.Start(); + v8::Locker::StartPreemption(1); + + LongRunningApply(); + { + v8::Unlocker unlock; + gc_thread.Join(); + } + v8::Locker::StopPreemption(); + CHECK(apply_success_); + CHECK(gc_success_); + } + private: + // Number of garbage collections required. + static const int kRequiredGCs = 2; + + class GCThread : public i::Thread { + public: + explicit GCThread(ApplyInterruptTest* test) + : test_(test) {} + virtual void Run() { + test_->CollectGarbage(); + } + private: + ApplyInterruptTest* test_; + }; + + void CollectGarbage() { + block_->Wait(); + while (gc_during_apply_ < kRequiredGCs) { + { + v8::Locker lock; + i::Heap::CollectAllGarbage(); + gc_count_++; + } + i::OS::Sleep(1); + } + gc_success_ = true; + } + + void LongRunningApply() { + block_->Signal(); + int rounds = 0; + while (gc_during_apply_ < kRequiredGCs) { + int gc_before = gc_count_; + { + const char* c_source = + "function do_very_little(bar) {" + " this.foo = bar;" + "}" + "for (var i = 0; i < 100000; i++) {" + " do_very_little.apply(this, ['bar']);" + "}"; + Local<String> source = String::New(c_source); + Local<Script> script = Script::Compile(source); + Local<Value> result = script->Run(); + // Check that no exception was thrown. + CHECK(!result.IsEmpty()); + } + int gc_after = gc_count_; + gc_during_apply_ += gc_after - gc_before; + rounds++; + } + apply_success_ = true; + } + + i::Semaphore* block_; + int gc_count_; + int gc_during_apply_; + bool apply_success_; + bool gc_success_; +}; + + +// Test that nothing bad happens if we get a preemption just when we were +// about to do an apply(). +TEST(ApplyInterruption) { + v8::Locker lock; + v8::V8::Initialize(); + v8::HandleScope scope; + Local<Context> local_env; + { + LocalContext env; + local_env = env.local(); + } + + // Local context should still be live. + CHECK(!local_env.IsEmpty()); + local_env->Enter(); + + // Should complete without problems. + ApplyInterruptTest().RunTest(); + + local_env->Exit(); +} + + // Verify that we can clone an object TEST(ObjectClone) { v8::HandleScope scope; @@ -5997,6 +6193,117 @@ TEST(ObjectClone) { } +class AsciiVectorResource : public v8::String::ExternalAsciiStringResource { + public: + explicit AsciiVectorResource(i::Vector<const char> vector) + : data_(vector) {} + virtual ~AsciiVectorResource() {} + virtual size_t length() const { return data_.length(); } + virtual const char* data() const { return data_.start(); } + private: + i::Vector<const char> data_; +}; + + +class UC16VectorResource : public v8::String::ExternalStringResource { + public: + explicit UC16VectorResource(i::Vector<const i::uc16> vector) + : data_(vector) {} + virtual ~UC16VectorResource() {} + virtual size_t length() const { return data_.length(); } + virtual const i::uc16* data() const { return data_.start(); } + private: + i::Vector<const i::uc16> data_; +}; + + +static void MorphAString(i::String* string, + AsciiVectorResource* ascii_resource, + UC16VectorResource* uc16_resource) { + CHECK(i::StringShape(string).IsExternal()); + if (string->IsAsciiRepresentation()) { + // Check old map is not symbol or long. + CHECK(string->map() == i::Heap::short_external_ascii_string_map() || + string->map() == i::Heap::medium_external_ascii_string_map()); + // Morph external string to be TwoByte string. + if (string->length() <= i::String::kMaxShortStringSize) { + string->set_map(i::Heap::short_external_string_map()); + } else { + string->set_map(i::Heap::medium_external_string_map()); + } + i::ExternalTwoByteString* morphed = + i::ExternalTwoByteString::cast(string); + morphed->set_resource(uc16_resource); + } else { + // Check old map is not symbol or long. + CHECK(string->map() == i::Heap::short_external_string_map() || + string->map() == i::Heap::medium_external_string_map()); + // Morph external string to be ASCII string. + if (string->length() <= i::String::kMaxShortStringSize) { + string->set_map(i::Heap::short_external_ascii_string_map()); + } else { + string->set_map(i::Heap::medium_external_ascii_string_map()); + } + i::ExternalAsciiString* morphed = + i::ExternalAsciiString::cast(string); + morphed->set_resource(ascii_resource); + } +} + + +// Test that we can still flatten a string if the components it is built up +// from have been turned into 16 bit strings in the mean time. +THREADED_TEST(MorphCompositeStringTest) { + const char* c_string = "Now is the time for all good men" + " to come to the aid of the party"; + uint16_t* two_byte_string = AsciiToTwoByteString(c_string); + { + v8::HandleScope scope; + LocalContext env; + AsciiVectorResource ascii_resource( + i::Vector<const char>(c_string, strlen(c_string))); + UC16VectorResource uc16_resource( + i::Vector<const uint16_t>(two_byte_string, strlen(c_string))); + + Local<String> lhs(v8::Utils::ToLocal( + i::Factory::NewExternalStringFromAscii(&ascii_resource))); + Local<String> rhs(v8::Utils::ToLocal( + i::Factory::NewExternalStringFromAscii(&ascii_resource))); + + env->Global()->Set(v8_str("lhs"), lhs); + env->Global()->Set(v8_str("rhs"), rhs); + + CompileRun( + "var cons = lhs + rhs;" + "var slice = lhs.substring(1, lhs.length - 1);" + "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);"); + + MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource); + MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource); + + // Now do some stuff to make sure the strings are flattened, etc. + CompileRun( + "/[^a-z]/.test(cons);" + "/[^a-z]/.test(slice);" + "/[^a-z]/.test(slice_on_cons);"); + const char* expected_cons = + "Now is the time for all good men to come to the aid of the party" + "Now is the time for all good men to come to the aid of the party"; + const char* expected_slice = + "ow is the time for all good men to come to the aid of the part"; + const char* expected_slice_on_cons = + "ow is the time for all good men to come to the aid of the party" + "Now is the time for all good men to come to the aid of the part"; + CHECK_EQ(String::New(expected_cons), + env->Global()->Get(v8_str("cons"))); + CHECK_EQ(String::New(expected_slice), + env->Global()->Get(v8_str("slice"))); + CHECK_EQ(String::New(expected_slice_on_cons), + env->Global()->Get(v8_str("slice_on_cons"))); + } +} + + class RegExpStringModificationTest { public: RegExpStringModificationTest() @@ -6041,26 +6348,6 @@ class RegExpStringModificationTest { } private: - class AsciiVectorResource : public v8::String::ExternalAsciiStringResource { - public: - explicit AsciiVectorResource(i::Vector<const char> vector) - : data_(vector) {} - virtual ~AsciiVectorResource() {} - virtual size_t length() const { return data_.length(); } - virtual const char* data() const { return data_.start(); } - private: - i::Vector<const char> data_; - }; - class UC16VectorResource : public v8::String::ExternalStringResource { - public: - explicit UC16VectorResource(i::Vector<const i::uc16> vector) - : data_(vector) {} - virtual ~UC16VectorResource() {} - virtual size_t length() const { return data_.length(); } - virtual const i::uc16* data() const { return data_.start(); } - private: - i::Vector<const i::uc16> data_; - }; // Number of string modifications required. static const int kRequiredModifications = 5; static const int kMaxModifications = 100; @@ -6084,25 +6371,7 @@ class RegExpStringModificationTest { v8::Locker lock; // Swap string between ascii and two-byte representation. i::String* string = *input_; - CHECK(i::StringShape(string).IsExternal()); - if (i::StringShape(string).IsAsciiRepresentation()) { - // Morph external string to be TwoByte string. - i::ExternalAsciiString* ext_string = - i::ExternalAsciiString::cast(string); - i::ExternalTwoByteString* morphed = - reinterpret_cast<i::ExternalTwoByteString*>(ext_string); - morphed->map()->set_instance_type(i::SHORT_EXTERNAL_STRING_TYPE); - morphed->set_resource(&uc16_resource_); - } else { - // Morph external string to be ASCII string. - i::ExternalTwoByteString* ext_string = - i::ExternalTwoByteString::cast(string); - i::ExternalAsciiString* morphed = - reinterpret_cast<i::ExternalAsciiString*>(ext_string); - morphed->map()->set_instance_type( - i::SHORT_EXTERNAL_ASCII_STRING_TYPE); - morphed->set_resource(&ascii_resource_); - } + MorphAString(string, &ascii_resource_, &uc16_resource_); morphs_++; } i::OS::Sleep(1); @@ -6187,3 +6456,118 @@ TEST(ReadOnlyPropertyInGlobalProto) { res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()"); CHECK_EQ(v8::Integer::New(42), res); } + +static int force_set_set_count = 0; +static int force_set_get_count = 0; +bool pass_on_get = false; + +static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name, + const v8::AccessorInfo& info) { + force_set_get_count++; + if (pass_on_get) { + return v8::Handle<v8::Value>(); + } else { + return v8::Int32::New(3); + } +} + +static void ForceSetSetter(v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::AccessorInfo& info) { + force_set_set_count++; +} + +static v8::Handle<v8::Value> ForceSetInterceptSetter( + v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::AccessorInfo& info) { + force_set_set_count++; + return v8::Undefined(); +} + +TEST(ForceSet) { + force_set_get_count = 0; + force_set_set_count = 0; + pass_on_get = false; + + v8::HandleScope scope; + v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); + v8::Handle<v8::String> access_property = v8::String::New("a"); + templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter); + LocalContext context(NULL, templ); + v8::Handle<v8::Object> global = context->Global(); + + // Ordinary properties + v8::Handle<v8::String> simple_property = v8::String::New("p"); + global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly); + CHECK_EQ(4, global->Get(simple_property)->Int32Value()); + // This should fail because the property is read-only + global->Set(simple_property, v8::Int32::New(5)); + CHECK_EQ(4, global->Get(simple_property)->Int32Value()); + // This should succeed even though the property is read-only + global->ForceSet(simple_property, v8::Int32::New(6)); + CHECK_EQ(6, global->Get(simple_property)->Int32Value()); + + // Accessors + CHECK_EQ(0, force_set_set_count); + CHECK_EQ(0, force_set_get_count); + CHECK_EQ(3, global->Get(access_property)->Int32Value()); + // CHECK_EQ the property shouldn't override it, just call the setter + // which in this case does nothing. + global->Set(access_property, v8::Int32::New(7)); + CHECK_EQ(3, global->Get(access_property)->Int32Value()); + CHECK_EQ(1, force_set_set_count); + CHECK_EQ(2, force_set_get_count); + // Forcing the property to be set should override the accessor without + // calling it + global->ForceSet(access_property, v8::Int32::New(8)); + CHECK_EQ(8, global->Get(access_property)->Int32Value()); + CHECK_EQ(1, force_set_set_count); + CHECK_EQ(2, force_set_get_count); +} + +TEST(ForceSetWithInterceptor) { + force_set_get_count = 0; + force_set_set_count = 0; + pass_on_get = false; + + v8::HandleScope scope; + v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); + templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter); + LocalContext context(NULL, templ); + v8::Handle<v8::Object> global = context->Global(); + + v8::Handle<v8::String> some_property = v8::String::New("a"); + CHECK_EQ(0, force_set_set_count); + CHECK_EQ(0, force_set_get_count); + CHECK_EQ(3, global->Get(some_property)->Int32Value()); + // Setting the property shouldn't override it, just call the setter + // which in this case does nothing. + global->Set(some_property, v8::Int32::New(7)); + CHECK_EQ(3, global->Get(some_property)->Int32Value()); + CHECK_EQ(1, force_set_set_count); + CHECK_EQ(2, force_set_get_count); + // Getting the property when the interceptor returns an empty handle + // should yield undefined, since the property isn't present on the + // object itself yet. + pass_on_get = true; + CHECK(global->Get(some_property)->IsUndefined()); + CHECK_EQ(1, force_set_set_count); + CHECK_EQ(3, force_set_get_count); + // Forcing the property to be set should cause the value to be + // set locally without calling the interceptor. + global->ForceSet(some_property, v8::Int32::New(8)); + CHECK_EQ(8, global->Get(some_property)->Int32Value()); + CHECK_EQ(1, force_set_set_count); + CHECK_EQ(4, force_set_get_count); + // Reenabling the interceptor should cause it to take precedence over + // the property + pass_on_get = false; + CHECK_EQ(3, global->Get(some_property)->Int32Value()); + CHECK_EQ(1, force_set_set_count); + CHECK_EQ(5, force_set_get_count); + // The interceptor should also work for other properties + CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value()); + CHECK_EQ(1, force_set_set_count); + CHECK_EQ(6, force_set_get_count); +} diff --git a/deps/v8/test/cctest/test-assembler-arm.cc b/deps/v8/test/cctest/test-assembler-arm.cc index bd75a04cc..fe1621c2a 100644 --- a/deps/v8/test/cctest/test-assembler-arm.cc +++ b/deps/v8/test/cctest/test-assembler-arm.cc @@ -29,8 +29,8 @@ #include "disassembler.h" #include "factory.h" -#include "simulator-arm.h" -#include "assembler-arm-inl.h" +#include "arm/simulator-arm.h" +#include "arm/assembler-arm-inl.h" #include "cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-debug.cc b/deps/v8/test/cctest/test-debug.cc index e482c7f1c..288efbaed 100644 --- a/deps/v8/test/cctest/test-debug.cc +++ b/deps/v8/test/cctest/test-debug.cc @@ -45,10 +45,13 @@ using ::v8::internal::JSGlobalProxy; using ::v8::internal::Code; using ::v8::internal::Debug; using ::v8::internal::Debugger; +using ::v8::internal::CommandMessage; +using ::v8::internal::CommandMessageQueue; using ::v8::internal::StepAction; using ::v8::internal::StepIn; // From StepAction enum using ::v8::internal::StepNext; // From StepAction enum using ::v8::internal::StepOut; // From StepAction enum +using ::v8::internal::Vector; // Size of temp buffer for formatting small strings. @@ -164,11 +167,22 @@ static v8::Local<v8::Function> CompileFunction(DebugLocalContext* env, (*env)->Global()->Get(v8::String::New(function_name))); } + +// Compile and run the supplied source and return the requested function. +static v8::Local<v8::Function> CompileFunction(const char* source, + const char* function_name) { + v8::Script::Compile(v8::String::New(source))->Run(); + return v8::Local<v8::Function>::Cast( + v8::Context::GetCurrent()->Global()->Get(v8::String::New(function_name))); +} + + // Helper function that compiles and runs the source. static v8::Local<v8::Value> CompileRun(const char* source) { return v8::Script::Compile(v8::String::New(source))->Run(); } + // Is there any debug info for the function? static bool HasDebugInfo(v8::Handle<v8::Function> fun) { Handle<v8::internal::JSFunction> f = v8::Utils::OpenHandle(*fun); @@ -229,7 +243,7 @@ static int SetScriptBreakPointByIdFromJS(int script_id, int line, int column) { v8::TryCatch try_catch; v8::Handle<v8::String> str = v8::String::New(buffer.start()); v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run(); - ASSERT(!try_catch.HasCaught()); + CHECK(!try_catch.HasCaught()); return value->Int32Value(); } } @@ -256,7 +270,7 @@ static int SetScriptBreakPointByNameFromJS(const char* script_name, v8::TryCatch try_catch; v8::Handle<v8::String> str = v8::String::New(buffer.start()); v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run(); - ASSERT(!try_catch.HasCaught()); + CHECK(!try_catch.HasCaught()); return value->Int32Value(); } } @@ -525,6 +539,24 @@ const char* frame_source_column_source = v8::Local<v8::Function> frame_source_column; +// Source for The JavaScript function which picks out the script name for the +// top frame. +const char* frame_script_name_source = + "function frame_script_name(exec_state) {" + " return exec_state.frame(0).func().script().name();" + "}"; +v8::Local<v8::Function> frame_script_name; + + +// Source for The JavaScript function which picks out the script data for the +// top frame. +const char* frame_script_data_source = + "function frame_script_data(exec_state) {" + " return exec_state.frame(0).func().script().data();" + "}"; +v8::Local<v8::Function> frame_script_data; + + // Source for The JavaScript function which returns the number of frames. static const char* frame_count_source = "function frame_count(exec_state) {" @@ -536,6 +568,11 @@ v8::Handle<v8::Function> frame_count; // Global variable to store the last function hit - used by some tests. char last_function_hit[80]; +// Global variable to store the name and data for last script hit - used by some +// tests. +char last_script_name_hit[80]; +char last_script_data_hit[80]; + // Global variables to store the last source position - used by some tests. int last_source_line = -1; int last_source_column = -1; @@ -586,6 +623,37 @@ static void DebugEventBreakPointHitCount(v8::DebugEvent event, CHECK(result->IsNumber()); last_source_column = result->Int32Value(); } + + if (!frame_script_name.IsEmpty()) { + // Get the script name of the function script. + const int argc = 1; + v8::Handle<v8::Value> argv[argc] = { exec_state }; + v8::Handle<v8::Value> result = frame_script_name->Call(exec_state, + argc, argv); + if (result->IsUndefined()) { + last_script_name_hit[0] = '\0'; + } else { + CHECK(result->IsString()); + v8::Handle<v8::String> script_name(result->ToString()); + script_name->WriteAscii(last_script_name_hit); + } + } + + if (!frame_script_data.IsEmpty()) { + // Get the script data of the function script. + const int argc = 1; + v8::Handle<v8::Value> argv[argc] = { exec_state }; + v8::Handle<v8::Value> result = frame_script_data->Call(exec_state, + argc, argv); + if (result->IsUndefined()) { + last_script_data_hit[0] = '\0'; + } else { + result = result->ToString(); + CHECK(result->IsString()); + v8::Handle<v8::String> script_data(result->ToString()); + script_data->WriteAscii(last_script_data_hit); + } + } } } @@ -2120,6 +2188,53 @@ TEST(DebugStepLinear) { } +// Test of the stepping mechanism for keyed load in a loop. +TEST(DebugStepKeyedLoadLoop) { + v8::HandleScope scope; + DebugLocalContext env; + + // Create a function for testing stepping of keyed load. The statement 'y=1' + // is there to have more than one breakable statement in the loop, TODO(315). + v8::Local<v8::Function> foo = CompileFunction( + &env, + "function foo(a) {\n" + " var x;\n" + " var len = a.length;\n" + " for (var i = 0; i < len; i++) {\n" + " y = 1;\n" + " x = a[i];\n" + " }\n" + "}\n", + "foo"); + + // Create array [0,1,2,3,4,5,6,7,8,9] + v8::Local<v8::Array> a = v8::Array::New(10); + for (int i = 0; i < 10; i++) { + a->Set(v8::Number::New(i), v8::Number::New(i)); + } + + // Call function without any break points to ensure inlining is in place. + const int kArgc = 1; + v8::Handle<v8::Value> args[kArgc] = { a }; + foo->Call(env->Global(), kArgc, args); + + // Register a debug event listener which steps and counts. + v8::Debug::SetDebugEventListener(DebugEventStep); + + // Setup break point and step through the function. + SetBreakPoint(foo, 3); + step_action = StepNext; + break_point_hit_count = 0; + foo->Call(env->Global(), kArgc, args); + + // With stepping all break locations are hit. + CHECK_EQ(22, break_point_hit_count); + + v8::Debug::SetDebugEventListener(NULL); + CheckDebuggerUnloaded(); +} + + // Test the stepping mechanism with different ICs. TEST(DebugStepLinearMixedICs) { v8::HandleScope scope; @@ -2841,9 +2956,11 @@ TEST(DebugBreak) { v8::HandleScope scope; DebugLocalContext env; - // This test should be run with option --verify-heap. This is an ASSERT and - // not a CHECK as --verify-heap is only available in debug mode. - ASSERT(v8::internal::FLAG_verify_heap); + // This test should be run with option --verify-heap. As --verify-heap is + // only available in debug mode only check for it in that case. +#ifdef DEBUG + CHECK(v8::internal::FLAG_verify_heap); +#endif // Register a debug event listener which sets the break flag and counts. v8::Debug::SetDebugEventListener(DebugEventBreak); @@ -3257,7 +3374,7 @@ ThreadBarrier::~ThreadBarrier() { void ThreadBarrier::Wait() { lock_->Lock(); - ASSERT(!invalid_); + CHECK(!invalid_); if (num_blocked_ == num_threads_ - 1) { // Signal and unblock all waiting threads. for (int i = 0; i < num_threads_ - 1; ++i) { @@ -3321,7 +3438,8 @@ class MessageQueueDebuggerThread : public v8::internal::Thread { void Run(); }; -static void MessageHandler(const uint16_t* message, int length, void *data) { +static void MessageHandler(const uint16_t* message, int length, + v8::Debug::ClientData* client_data) { static char print_buffer[1000]; Utf16ToAscii(message, length, print_buffer); if (IsBreakEventMessage(print_buffer)) { @@ -3329,6 +3447,7 @@ static void MessageHandler(const uint16_t* message, int length, void *data) { // Signals when a break is reported. message_queue_barriers.semaphore_2->Signal(); } + // Allow message handler to block on a semaphore, to test queueing of // messages while blocked. message_queue_barriers.semaphore_1->Wait(); @@ -3336,7 +3455,6 @@ static void MessageHandler(const uint16_t* message, int length, void *data) { fflush(stdout); } - void MessageQueueDebuggerThread::Run() { const int kBufferSize = 1000; uint16_t buffer_1[kBufferSize]; @@ -3368,6 +3486,7 @@ void MessageQueueDebuggerThread::Run() { /* Interleaved sequence of actions by the two threads:*/ // Main thread compiles and runs source_1 + message_queue_barriers.semaphore_1->Signal(); message_queue_barriers.barrier_1.Wait(); // Post 6 commands, filling the command queue and making it expand. // These calls return immediately, but the commands stay on the queue @@ -3381,22 +3500,39 @@ void MessageQueueDebuggerThread::Run() { v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2)); message_queue_barriers.barrier_2.Wait(); // Main thread compiles and runs source_2. - // Queued commands are executed at the start of compilation of source_2. - message_queue_barriers.barrier_3.Wait(); - // Free the message handler to process all the messages from the queue. - for (int i = 0; i < 20 ; ++i) { + // Queued commands are executed at the start of compilation of source_2( + // beforeCompile event). + // Free the message handler to process all the messages from the queue. 7 + // messages are expected: 2 afterCompile events and 5 responses. + // All the commands added so far will fail to execute as long as call stack + // is empty on beforeCompile event. + for (int i = 0; i < 6 ; ++i) { message_queue_barriers.semaphore_1->Signal(); } + message_queue_barriers.barrier_3.Wait(); // Main thread compiles and runs source_3. + // Don't stop in the afterCompile handler. + message_queue_barriers.semaphore_1->Signal(); // source_3 includes a debugger statement, which causes a break event. // Wait on break event from hitting "debugger" statement message_queue_barriers.semaphore_2->Wait(); // These should execute after the "debugger" statement in source_2 + v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_1, buffer_1)); + v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_2, buffer_2)); + v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2)); v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_single_step, buffer_2)); + // Run after 2 break events, 4 responses. + for (int i = 0; i < 6 ; ++i) { + message_queue_barriers.semaphore_1->Signal(); + } // Wait on break event after a single step executes. message_queue_barriers.semaphore_2->Wait(); v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_2, buffer_1)); v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_continue, buffer_2)); + // Run after 2 responses. + for (int i = 0; i < 2 ; ++i) { + message_queue_barriers.semaphore_1->Signal(); + } // Main thread continues running source_3 to end, waits for this thread. } @@ -3427,6 +3563,117 @@ TEST(MessageQueues) { fflush(stdout); } + +class TestClientData : public v8::Debug::ClientData { + public: + TestClientData() { + constructor_call_counter++; + } + virtual ~TestClientData() { + destructor_call_counter++; + } + + static void ResetCounters() { + constructor_call_counter = 0; + destructor_call_counter = 0; + } + + static int constructor_call_counter; + static int destructor_call_counter; +}; + +int TestClientData::constructor_call_counter = 0; +int TestClientData::destructor_call_counter = 0; + + +// Tests that MessageQueue doesn't destroy client data when expands and +// does destroy when it dies. +TEST(MessageQueueExpandAndDestroy) { + TestClientData::ResetCounters(); + { // Create a scope for the queue. + CommandMessageQueue queue(1); + queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), + new TestClientData())); + queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), + new TestClientData())); + queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), + new TestClientData())); + CHECK_EQ(0, TestClientData::destructor_call_counter); + queue.Get().Dispose(); + CHECK_EQ(1, TestClientData::destructor_call_counter); + queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), + new TestClientData())); + queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), + new TestClientData())); + queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), + new TestClientData())); + queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), + new TestClientData())); + queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), + new TestClientData())); + CHECK_EQ(1, TestClientData::destructor_call_counter); + queue.Get().Dispose(); + CHECK_EQ(2, TestClientData::destructor_call_counter); + } + // All the client data should be destroyed when the queue is destroyed. + CHECK_EQ(TestClientData::destructor_call_counter, + TestClientData::destructor_call_counter); +} + + +static int handled_client_data_instances_count = 0; +static void MessageHandlerCountingClientData( + const v8::Debug::Message& message) { + if (message.GetClientData() != NULL) { + handled_client_data_instances_count++; + } +} + + +// Tests that all client data passed to the debugger are sent to the handler. +TEST(SendClientDataToHandler) { + // Create a V8 environment + v8::HandleScope scope; + DebugLocalContext env; + TestClientData::ResetCounters(); + handled_client_data_instances_count = 0; + v8::Debug::SetMessageHandler2(MessageHandlerCountingClientData); + const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;"; + const int kBufferSize = 1000; + uint16_t buffer[kBufferSize]; + const char* command_1 = + "{\"seq\":117," + "\"type\":\"request\"," + "\"command\":\"evaluate\"," + "\"arguments\":{\"expression\":\"1+2\"}}"; + const char* command_2 = + "{\"seq\":118," + "\"type\":\"request\"," + "\"command\":\"evaluate\"," + "\"arguments\":{\"expression\":\"1+a\"}}"; + const char* command_continue = + "{\"seq\":106," + "\"type\":\"request\"," + "\"command\":\"continue\"}"; + + v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer), + new TestClientData()); + v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer), NULL); + v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer), + new TestClientData()); + v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer), + new TestClientData()); + // All the messages will be processed on beforeCompile event. + CompileRun(source_1); + v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer)); + CHECK_EQ(3, TestClientData::constructor_call_counter); + CHECK_EQ(TestClientData::constructor_call_counter, + handled_client_data_instances_count); + CHECK_EQ(TestClientData::constructor_call_counter, + TestClientData::destructor_call_counter); +} + + /* Test ThreadedDebugging */ /* This test interrupts a running infinite loop that is * occupying the v8 thread by a break command from the @@ -3453,10 +3700,10 @@ static v8::Handle<v8::Value> ThreadedAtBarrier1(const v8::Arguments& args) { } -static void ThreadedMessageHandler(const uint16_t* message, int length, - void *data) { +static void ThreadedMessageHandler(const v8::Debug::Message& message) { static char print_buffer[1000]; - Utf16ToAscii(message, length, print_buffer); + v8::String::Value json(message.GetJSON()); + Utf16ToAscii(*json, json.length(), print_buffer); if (IsBreakEventMessage(print_buffer)) { threaded_debugging_barriers.barrier_2.Wait(); } @@ -3487,7 +3734,7 @@ void V8Thread::Run() { v8::HandleScope scope; DebugLocalContext env; - v8::Debug::SetMessageHandler(&ThreadedMessageHandler); + v8::Debug::SetMessageHandler2(&ThreadedMessageHandler); v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); global_template->Set(v8::String::New("ThreadedAtBarrier1"), v8::FunctionTemplate::New(ThreadedAtBarrier1)); @@ -3550,11 +3797,10 @@ class BreakpointsDebuggerThread : public v8::internal::Thread { Barriers* breakpoints_barriers; -static void BreakpointsMessageHandler(const uint16_t* message, - int length, - void *data) { +static void BreakpointsMessageHandler(const v8::Debug::Message& message) { static char print_buffer[1000]; - Utf16ToAscii(message, length, print_buffer); + v8::String::Value json(message.GetJSON()); + Utf16ToAscii(*json, json.length(), print_buffer); printf("%s\n", print_buffer); fflush(stdout); @@ -3588,7 +3834,7 @@ void BreakpointsV8Thread::Run() { v8::HandleScope scope; DebugLocalContext env; - v8::Debug::SetMessageHandler(&BreakpointsMessageHandler); + v8::Debug::SetMessageHandler2(&BreakpointsMessageHandler); CompileRun(source_1); breakpoints_barriers->barrier_1.Wait(); @@ -3697,13 +3943,12 @@ TEST(SetDebugEventListenerOnUninitializedVM) { } -static void DummyMessageHandler(const uint16_t* message, - int length, void *data) { +static void DummyMessageHandler(const v8::Debug::Message& message) { } TEST(SetMessageHandlerOnUninitializedVM) { - v8::Debug::SetMessageHandler(DummyMessageHandler); + v8::Debug::SetMessageHandler2(DummyMessageHandler); } @@ -3923,8 +4168,7 @@ TEST(DebuggerUnload) { // Debugger message handler which counts the number of times it is called. static int message_handler_hit_count = 0; -static void MessageHandlerHitCount(const uint16_t* message, - int length, void* data) { +static void MessageHandlerHitCount(const v8::Debug::Message& message) { message_handler_hit_count++; const int kBufferSize = 1000; @@ -3947,7 +4191,7 @@ TEST(DebuggerClearMessageHandler) { CheckDebuggerUnloaded(); // Set a debug message handler. - v8::Debug::SetMessageHandler(MessageHandlerHitCount); + v8::Debug::SetMessageHandler2(MessageHandlerHitCount); // Run code to throw a unhandled exception. This should end up in the message // handler. @@ -3972,9 +4216,8 @@ TEST(DebuggerClearMessageHandler) { // Debugger message handler which clears the message handler while active. -static void MessageHandlerClearingMessageHandler(const uint16_t* message, - int length, - void* data) { +static void MessageHandlerClearingMessageHandler( + const v8::Debug::Message& message) { message_handler_hit_count++; // Clear debug message handler. @@ -3991,7 +4234,7 @@ TEST(DebuggerClearMessageHandlerWhileActive) { CheckDebuggerUnloaded(); // Set a debug message handler. - v8::Debug::SetMessageHandler(MessageHandlerClearingMessageHandler); + v8::Debug::SetMessageHandler2(MessageHandlerClearingMessageHandler); // Run code to throw a unhandled exception. This should end up in the message // handler. @@ -4004,54 +4247,106 @@ TEST(DebuggerClearMessageHandlerWhileActive) { } -int host_dispatch_hit_count = 0; -static void HostDispatchHandlerHitCount(void* dispatch, void *data) { - host_dispatch_hit_count++; +/* Test DebuggerHostDispatch */ +/* In this test, the debugger waits for a command on a breakpoint + * and is dispatching host commands while in the infinite loop. + */ + +class HostDispatchV8Thread : public v8::internal::Thread { + public: + void Run(); +}; + +class HostDispatchDebuggerThread : public v8::internal::Thread { + public: + void Run(); +}; + +Barriers* host_dispatch_barriers; + +static void HostDispatchMessageHandler(const v8::Debug::Message& message) { + static char print_buffer[1000]; + v8::String::Value json(message.GetJSON()); + Utf16ToAscii(*json, json.length(), print_buffer); + printf("%s\n", print_buffer); + fflush(stdout); } -// Test that clearing the debug event listener actually clears all break points -// and related information. -TEST(DebuggerHostDispatch) { - i::FLAG_debugger_auto_break = true; +static void HostDispatchDispatchHandler() { + host_dispatch_barriers->semaphore_1->Signal(); +} + + +void HostDispatchV8Thread::Run() { + const char* source_1 = "var y_global = 3;\n" + "function cat( new_value ) {\n" + " var x = new_value;\n" + " y_global = 4;\n" + " x = 3 * x + 1;\n" + " y_global = 5;\n" + " return x;\n" + "}\n" + "\n"; + const char* source_2 = "cat(17);\n"; v8::HandleScope scope; DebugLocalContext env; - const int kBufferSize = 1000; - uint16_t buffer[kBufferSize]; - const char* command_continue = - "{\"seq\":0," - "\"type\":\"request\"," - "\"command\":\"continue\"}"; + // Setup message and host dispatch handlers. + v8::Debug::SetMessageHandler2(HostDispatchMessageHandler); + v8::Debug::SetHostDispatchHandler(HostDispatchDispatchHandler, 10 /* ms */); - // Create an empty function to call for processing debug commands - v8::Local<v8::Function> empty = - CompileFunction(&env, "function empty(){}", "empty"); + CompileRun(source_1); + host_dispatch_barriers->barrier_1.Wait(); + host_dispatch_barriers->barrier_2.Wait(); + CompileRun(source_2); +} - // Setup message and host dispatch handlers. - v8::Debug::SetMessageHandler(DummyMessageHandler); - v8::Debug::SetHostDispatchHandler(HostDispatchHandlerHitCount, - NULL); - // Send a host dispatch by itself. - v8::Debug::SendHostDispatch(NULL); - empty->Call(env->Global(), 0, NULL); // Run JavaScript to activate debugger. - CHECK_EQ(1, host_dispatch_hit_count); +void HostDispatchDebuggerThread::Run() { + const int kBufSize = 1000; + uint16_t buffer[kBufSize]; - // Fill a host dispatch and a continue command on the command queue. - v8::Debug::SendHostDispatch(NULL); - v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer)); - empty->Call(env->Global(), 0, NULL); // Run JavaScript to activate debugger. + const char* command_1 = "{\"seq\":101," + "\"type\":\"request\"," + "\"command\":\"setbreakpoint\"," + "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}"; + const char* command_2 = "{\"seq\":102," + "\"type\":\"request\"," + "\"command\":\"continue\"}"; - // Fill a continue command and a host dispatch on the command queue. - v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer)); - v8::Debug::SendHostDispatch(NULL); - empty->Call(env->Global(), 0, NULL); // Run JavaScript to activate debugger. - empty->Call(env->Global(), 0, NULL); // Run JavaScript to activate debugger. + // v8 thread initializes, runs source_1 + host_dispatch_barriers->barrier_1.Wait(); + // 1: Set breakpoint in cat(). + v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer)); + + host_dispatch_barriers->barrier_2.Wait(); + // v8 thread starts compiling source_2. + // Break happens, to run queued commands and host dispatches. + // Wait for host dispatch to be processed. + host_dispatch_barriers->semaphore_1->Wait(); + // 2: Continue evaluation + v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer)); +} + +HostDispatchDebuggerThread host_dispatch_debugger_thread; +HostDispatchV8Thread host_dispatch_v8_thread; + + +TEST(DebuggerHostDispatch) { + i::FLAG_debugger_auto_break = true; + + // Create a V8 environment + Barriers stack_allocated_host_dispatch_barriers; + stack_allocated_host_dispatch_barriers.Initialize(); + host_dispatch_barriers = &stack_allocated_host_dispatch_barriers; - // All the host dispatch callback should be called. - CHECK_EQ(3, host_dispatch_hit_count); + host_dispatch_v8_thread.Start(); + host_dispatch_debugger_thread.Start(); + + host_dispatch_v8_thread.Join(); + host_dispatch_debugger_thread.Join(); } @@ -4249,3 +4544,139 @@ TEST(DebugGetLoadedScripts) { // Must not crash while accessing line_ends. i::FLAG_allow_natives_syntax = allow_natives_syntax; } + + +// Test script break points set on lines. +TEST(ScriptNameAndData) { + v8::HandleScope scope; + DebugLocalContext env; + env.ExposeDebug(); + + // Create functions for retrieving script name and data for the function on + // the top frame when hitting a break point. + frame_script_name = CompileFunction(&env, + frame_script_name_source, + "frame_script_name"); + frame_script_data = CompileFunction(&env, + frame_script_data_source, + "frame_script_data"); + + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount, + v8::Undefined()); + + // Test function source. + v8::Local<v8::String> script = v8::String::New( + "function f() {\n" + " debugger;\n" + "}\n"); + + v8::ScriptOrigin origin1 = v8::ScriptOrigin(v8::String::New("name")); + v8::Handle<v8::Script> script1 = v8::Script::Compile(script, &origin1); + script1->SetData(v8::String::New("data")); + script1->Run(); + v8::Script::Compile(script, &origin1)->Run(); + v8::Local<v8::Function> f; + f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f"))); + + f->Call(env->Global(), 0, NULL); + CHECK_EQ(1, break_point_hit_count); + CHECK_EQ("name", last_script_name_hit); + CHECK_EQ("data", last_script_data_hit); + + v8::Local<v8::String> data_obj_source = v8::String::New( + "({ a: 'abc',\n" + " b: 123,\n" + " toString: function() { return this.a + ' ' + this.b; }\n" + "})\n"); + v8::Local<v8::Value> data_obj = v8::Script::Compile(data_obj_source)->Run(); + v8::ScriptOrigin origin2 = v8::ScriptOrigin(v8::String::New("new name")); + v8::Handle<v8::Script> script2 = v8::Script::Compile(script, &origin2); + script2->Run(); + script2->SetData(data_obj); + f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f"))); + f->Call(env->Global(), 0, NULL); + CHECK_EQ(2, break_point_hit_count); + CHECK_EQ("new name", last_script_name_hit); + CHECK_EQ("abc 123", last_script_data_hit); +} + + +static v8::Persistent<v8::Context> expected_context; +static v8::Handle<v8::Value> expected_context_data; + + +// Check that the expected context is the one generating the debug event. +static void ContextCheckMessageHandler(const v8::Debug::Message& message) { + CHECK(message.GetEventContext() == expected_context); + CHECK(message.GetEventContext()->GetData()->StrictEquals( + expected_context_data)); + message_handler_hit_count++; + + const int kBufferSize = 1000; + uint16_t buffer[kBufferSize]; + const char* command_continue = + "{\"seq\":0," + "\"type\":\"request\"," + "\"command\":\"continue\"}"; + + // Send a continue command for break events. + if (message.GetEvent() == v8::Break) { + v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer)); + } +} + + +// Test which creates two contexts and sets different embedder data on each. +// Checks that this data is set correctly and that when the debug message +// handler is called the expected context is the one active. +TEST(ContextData) { + v8::HandleScope scope; + + v8::Debug::SetMessageHandler2(ContextCheckMessageHandler); + + // Create two contexts. + v8::Persistent<v8::Context> context_1; + v8::Persistent<v8::Context> context_2; + v8::Handle<v8::ObjectTemplate> global_template = + v8::Handle<v8::ObjectTemplate>(); + v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>(); + context_1 = v8::Context::New(NULL, global_template, global_object); + context_2 = v8::Context::New(NULL, global_template, global_object); + + // Default data value is undefined. + CHECK(context_1->GetData()->IsUndefined()); + CHECK(context_2->GetData()->IsUndefined()); + + // Set and check different data values. + v8::Handle<v8::Value> data_1 = v8::Number::New(1); + v8::Handle<v8::Value> data_2 = v8::String::New("2"); + context_1->SetData(data_1); + context_2->SetData(data_2); + CHECK(context_1->GetData()->StrictEquals(data_1)); + CHECK(context_2->GetData()->StrictEquals(data_2)); + + // Simple test function which causes a break. + const char* source = "function f() { debugger; }"; + + // Enter and run function in the first context. + { + v8::Context::Scope context_scope(context_1); + expected_context = context_1; + expected_context_data = data_1; + v8::Local<v8::Function> f = CompileFunction(source, "f"); + f->Call(context_1->Global(), 0, NULL); + } + + + // Enter and run function in the second context. + { + v8::Context::Scope context_scope(context_2); + expected_context = context_2; + expected_context_data = data_2; + v8::Local<v8::Function> f = CompileFunction(source, "f"); + f->Call(context_2->Global(), 0, NULL); + } + + // Two times compile event and two times break event. + CHECK_GT(message_handler_hit_count, 4); +} diff --git a/deps/v8/test/cctest/test-decls.cc b/deps/v8/test/cctest/test-decls.cc index e798fee9b..ecdad2e7d 100644 --- a/deps/v8/test/cctest/test-decls.cc +++ b/deps/v8/test/cctest/test-decls.cc @@ -389,7 +389,7 @@ class AppearingPropertyContext: public DeclarationContext { state_ = UNKNOWN; return True(); default: - ASSERT(state_ == UNKNOWN); + CHECK(state_ == UNKNOWN); break; } // Do the lookup in the object. @@ -479,7 +479,7 @@ class ReappearingPropertyContext: public DeclarationContext { state_ = UNKNOWN; return False(); default: - ASSERT(state_ == UNKNOWN); + CHECK(state_ == UNKNOWN); break; } // Do the lookup in the object. diff --git a/deps/v8/test/cctest/test-func-name-inference.cc b/deps/v8/test/cctest/test-func-name-inference.cc index 505862984..d91f75fa0 100644 --- a/deps/v8/test/cctest/test-func-name-inference.cc +++ b/deps/v8/test/cctest/test-func-name-inference.cc @@ -221,3 +221,30 @@ TEST(AsParameter) { CheckFunctionName(script, "return 2", ""); CheckFunctionName(script, "return 3", ""); } + + +TEST(MultipleFuncsConditional) { + InitializeVM(); + v8::HandleScope scope; + + v8::Handle<v8::Script> script = Compile( + "fun1 = 0 ?\n" + " function() { return 1; } :\n" + " function() { return 2; }"); + CheckFunctionName(script, "return 1", "fun1"); + CheckFunctionName(script, "return 2", "fun1"); +} + + +TEST(MultipleFuncsInLiteral) { + InitializeVM(); + v8::HandleScope scope; + + v8::Handle<v8::Script> script = Compile( + "function MyClass() {}\n" + "MyClass.prototype = {\n" + " method1: 0 ? function() { return 1; } :\n" + " function() { return 2; } }"); + CheckFunctionName(script, "return 1", "MyClass.method1"); + CheckFunctionName(script, "return 2", "MyClass.method1"); +} diff --git a/deps/v8/test/cctest/test-hashmap.cc b/deps/v8/test/cctest/test-hashmap.cc index 4918d5d52..954dbe103 100644 --- a/deps/v8/test/cctest/test-hashmap.cc +++ b/deps/v8/test/cctest/test-hashmap.cc @@ -43,7 +43,7 @@ class IntSet { IntSet() : map_(DefaultMatchFun) {} void Insert(int x) { - ASSERT(x != 0); // 0 corresponds to (void*)NULL - illegal key value + CHECK_NE(0, x); // 0 corresponds to (void*)NULL - illegal key value HashMap::Entry* p = map_.Lookup(reinterpret_cast<void*>(x), Hash(x), true); CHECK(p != NULL); // insert is set! CHECK_EQ(reinterpret_cast<void*>(x), p->key); diff --git a/deps/v8/test/cctest/test-list.cc b/deps/v8/test/cctest/test-list.cc index d10cdd7de..838a45d0d 100644 --- a/deps/v8/test/cctest/test-list.cc +++ b/deps/v8/test/cctest/test-list.cc @@ -63,5 +63,5 @@ TEST(ListAdd) { // Add an existing element, the backing store should have to grow. list.Add(list[0]); - ASSERT(list[4] == 1); + CHECK_EQ(1, list[4]); } diff --git a/deps/v8/test/cctest/test-log-ia32.cc b/deps/v8/test/cctest/test-log-ia32.cc index b171339c2..43cb294b1 100644 --- a/deps/v8/test/cctest/test-log-ia32.cc +++ b/deps/v8/test/cctest/test-log-ia32.cc @@ -8,9 +8,11 @@ #include "v8.h" +#include "codegen.h" #include "log.h" #include "top.h" #include "cctest.h" +#include "disassembler.h" using v8::Function; using v8::Local; @@ -20,12 +22,15 @@ using v8::String; using v8::Value; using v8::internal::byte; +using v8::internal::Address; using v8::internal::Handle; using v8::internal::JSFunction; using v8::internal::StackTracer; using v8::internal::TickSample; using v8::internal::Top; +namespace i = v8::internal; + static v8::Persistent<v8::Context> env; @@ -42,8 +47,8 @@ static void InitTraceEnv(StackTracer* tracer, TickSample* sample) { } -static void DoTrace(unsigned int fp) { - trace_env.sample->fp = fp; +static void DoTrace(Address fp) { + trace_env.sample->fp = reinterpret_cast<uintptr_t>(fp); // sp is only used to define stack high bound trace_env.sample->sp = reinterpret_cast<unsigned int>(trace_env.sample) - 10240; @@ -53,7 +58,7 @@ static void DoTrace(unsigned int fp) { // Hide c_entry_fp to emulate situation when sampling is done while // pure JS code is being executed -static void DoTraceHideCEntryFPAddress(unsigned int fp) { +static void DoTraceHideCEntryFPAddress(Address fp) { v8::internal::Address saved_c_frame_fp = *(Top::c_entry_fp_address()); CHECK(saved_c_frame_fp); *(Top::c_entry_fp_address()) = 0; @@ -63,10 +68,10 @@ static void DoTraceHideCEntryFPAddress(unsigned int fp) { static void CheckRetAddrIsInFunction(const char* func_name, - unsigned int ret_addr, - unsigned int func_start_addr, + Address ret_addr, + Address func_start_addr, unsigned int func_len) { - printf("CheckRetAddrIsInFunction \"%s\": %08x %08x %08x\n", + printf("CheckRetAddrIsInFunction \"%s\": %p %p %p\n", func_name, func_start_addr, ret_addr, func_start_addr + func_len); CHECK_GE(ret_addr, func_start_addr); CHECK_GE(func_start_addr + func_len, ret_addr); @@ -74,12 +79,12 @@ static void CheckRetAddrIsInFunction(const char* func_name, static void CheckRetAddrIsInJSFunction(const char* func_name, - unsigned int ret_addr, + Address ret_addr, Handle<JSFunction> func) { v8::internal::Code* func_code = func->code(); CheckRetAddrIsInFunction( func_name, ret_addr, - reinterpret_cast<unsigned int>(func_code->instruction_start()), + func_code->instruction_start(), func_code->ExecutableSize()); } @@ -94,7 +99,7 @@ class TraceExtension : public v8::Extension { static v8::Handle<v8::Value> Trace(const v8::Arguments& args); static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args); private: - static unsigned int GetFP(const v8::Arguments& args); + static Address GetFP(const v8::Arguments& args); static const char* kSource; }; @@ -117,10 +122,10 @@ v8::Handle<v8::FunctionTemplate> TraceExtension::GetNativeFunction( } -unsigned int TraceExtension::GetFP(const v8::Arguments& args) { +Address TraceExtension::GetFP(const v8::Arguments& args) { CHECK_EQ(1, args.Length()); - unsigned int fp = args[0]->Int32Value() << 2; - printf("Trace: %08x\n", fp); + Address fp = reinterpret_cast<Address>(args[0]->Int32Value() << 2); + printf("Trace: %p\n", fp); return fp; } @@ -177,7 +182,7 @@ static Handle<JSFunction> GetGlobalJSFunction(const char* name) { static void CheckRetAddrIsInJSFunction(const char* func_name, - unsigned int ret_addr) { + Address ret_addr) { CheckRetAddrIsInJSFunction(func_name, ret_addr, GetGlobalJSFunction(func_name)); } @@ -188,47 +193,59 @@ static void SetGlobalProperty(const char* name, Local<Value> value) { } -static bool Patch(byte* from, - size_t num, - byte* original, - byte* patch, - size_t patch_len) { - byte* to = from + num; - do { - from = static_cast<byte*>(memchr(from, *original, to - from)); - CHECK(from != NULL); - if (memcmp(original, from, patch_len) == 0) { - memcpy(from, patch, patch_len); - return true; - } else { - from++; - } - } while (to - from > 0); - return false; +static Handle<v8::internal::String> NewString(const char* s) { + return i::Factory::NewStringFromAscii(i::CStrVector(s)); } +namespace v8 { namespace internal { + +class CodeGeneratorPatcher { + public: + CodeGeneratorPatcher() { + CodeGenerator::InlineRuntimeLUT genGetFramePointer = + {&CodeGenerator::GenerateGetFramePointer, "_GetFramePointer"}; + // _FastCharCodeAt is not used in our tests. + bool result = CodeGenerator::PatchInlineRuntimeEntry( + NewString("_FastCharCodeAt"), + genGetFramePointer, &oldInlineEntry); + CHECK(result); + } + + ~CodeGeneratorPatcher() { + CHECK(CodeGenerator::PatchInlineRuntimeEntry( + NewString("_GetFramePointer"), + oldInlineEntry, NULL)); + } + + private: + CodeGenerator::InlineRuntimeLUT oldInlineEntry; +}; + +} } // namespace v8::internal + + // Creates a global function named 'func_name' that calls the tracing // function 'trace_func_name' with an actual EBP register value, // shifted right to be presented as Smi. static void CreateTraceCallerFunction(const char* func_name, const char* trace_func_name) { - ::v8::internal::EmbeddedVector<char, 256> trace_call_buf; - ::v8::internal::OS::SNPrintF(trace_call_buf, "%s(0x6666);", trace_func_name); + i::EmbeddedVector<char, 256> trace_call_buf; + i::OS::SNPrintF(trace_call_buf, "%s(%%_GetFramePointer());", trace_func_name); + + // Compile the script. + i::CodeGeneratorPatcher patcher; + bool allow_natives_syntax = i::FLAG_allow_natives_syntax; + i::FLAG_allow_natives_syntax = true; Handle<JSFunction> func = CompileFunction(trace_call_buf.start()); CHECK(!func.is_null()); + i::FLAG_allow_natives_syntax = allow_natives_syntax; + +#ifdef DEBUG v8::internal::Code* func_code = func->code(); CHECK(func_code->IsCode()); - - // push 0xcccc (= 0x6666 << 1) - byte original[] = { 0x68, 0xcc, 0xcc, 0x00, 0x00 }; - // mov eax,ebp; shr eax; push eax; - byte patch[] = { 0x89, 0xe8, 0xd1, 0xe8, 0x50 }; - // Patch generated code to replace pushing of a constant with - // pushing of ebp contents in a Smi - CHECK(Patch(func_code->instruction_start(), - func_code->instruction_size(), - original, patch, sizeof(patch))); + func_code->Print(); +#endif SetGlobalProperty(func_name, v8::ToApi<Value>(func)); } @@ -236,7 +253,7 @@ static void CreateTraceCallerFunction(const char* func_name, TEST(CFromJSStackTrace) { TickSample sample; - StackTracer tracer(reinterpret_cast<unsigned int>(&sample)); + StackTracer tracer(reinterpret_cast<uintptr_t>(&sample)); InitTraceEnv(&tracer, &sample); InitializeVM(); @@ -244,21 +261,21 @@ TEST(CFromJSStackTrace) { CreateTraceCallerFunction("JSFuncDoTrace", "trace"); CompileRun( "function JSTrace() {" - " JSFuncDoTrace();" + " JSFuncDoTrace();" "};\n" "JSTrace();"); CHECK_GT(sample.frames_count, 1); // Stack sampling will start from the first JS function, i.e. "JSFuncDoTrace" CheckRetAddrIsInJSFunction("JSFuncDoTrace", - reinterpret_cast<unsigned int>(sample.stack[0])); + sample.stack[0]); CheckRetAddrIsInJSFunction("JSTrace", - reinterpret_cast<unsigned int>(sample.stack[1])); + sample.stack[1]); } TEST(PureJSStackTrace) { TickSample sample; - StackTracer tracer(reinterpret_cast<unsigned int>(&sample)); + StackTracer tracer(reinterpret_cast<uintptr_t>(&sample)); InitTraceEnv(&tracer, &sample); InitializeVM(); @@ -266,25 +283,25 @@ TEST(PureJSStackTrace) { CreateTraceCallerFunction("JSFuncDoTrace", "js_trace"); CompileRun( "function JSTrace() {" - " JSFuncDoTrace();" + " JSFuncDoTrace();" "};\n" "function OuterJSTrace() {" - " JSTrace();" + " JSTrace();" "};\n" "OuterJSTrace();"); CHECK_GT(sample.frames_count, 1); // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" CheckRetAddrIsInJSFunction("JSTrace", - reinterpret_cast<unsigned int>(sample.stack[0])); + sample.stack[0]); CheckRetAddrIsInJSFunction("OuterJSTrace", - reinterpret_cast<unsigned int>(sample.stack[1])); + sample.stack[1]); } static void CFuncDoTrace() { - unsigned int fp; + Address fp; #ifdef __GNUC__ - fp = reinterpret_cast<unsigned int>(__builtin_frame_address(0)); + fp = reinterpret_cast<Address>(__builtin_frame_address(0)); #elif defined _MSC_VER __asm mov [fp], ebp // NOLINT #endif @@ -304,7 +321,7 @@ static int CFunc(int depth) { TEST(PureCStackTrace) { TickSample sample; - StackTracer tracer(reinterpret_cast<unsigned int>(&sample)); + StackTracer tracer(reinterpret_cast<uintptr_t>(&sample)); InitTraceEnv(&tracer, &sample); // Check that sampler doesn't crash CHECK_EQ(10, CFunc(10)); diff --git a/deps/v8/test/cctest/test-log.cc b/deps/v8/test/cctest/test-log.cc new file mode 100644 index 000000000..6a7e54f1d --- /dev/null +++ b/deps/v8/test/cctest/test-log.cc @@ -0,0 +1,117 @@ +// Copyright 2006-2009 the V8 project authors. All rights reserved. +// +// Tests of logging functions from log.h + +#ifdef ENABLE_LOGGING_AND_PROFILING + +#include "v8.h" + +#include "log.h" + +#include "cctest.h" + +using v8::internal::Logger; + +static void SetUp() { + // Log to memory buffer. + v8::internal::FLAG_logfile = "*"; + v8::internal::FLAG_log = true; + Logger::Setup(); +} + +static void TearDown() { + Logger::TearDown(); +} + + +TEST(EmptyLog) { + SetUp(); + CHECK_EQ(0, Logger::GetLogLines(0, NULL, 0)); + CHECK_EQ(0, Logger::GetLogLines(100, NULL, 0)); + CHECK_EQ(0, Logger::GetLogLines(0, NULL, 100)); + CHECK_EQ(0, Logger::GetLogLines(100, NULL, 100)); + TearDown(); +} + + +TEST(GetMessages) { + SetUp(); + Logger::StringEvent("aaa", "bbb"); + Logger::StringEvent("cccc", "dddd"); + CHECK_EQ(0, Logger::GetLogLines(0, NULL, 0)); + char log_lines[100]; + memset(log_lines, 0, sizeof(log_lines)); + // Requesting data size which is smaller than first log message length. + CHECK_EQ(0, Logger::GetLogLines(0, log_lines, 3)); + // See Logger::StringEvent. + const char* line_1 = "aaa,\"bbb\"\n"; + const int line_1_len = strlen(line_1); + // Still smaller than log message length. + CHECK_EQ(0, Logger::GetLogLines(0, log_lines, line_1_len - 1)); + // The exact size. + CHECK_EQ(line_1_len, Logger::GetLogLines(0, log_lines, line_1_len)); + CHECK_EQ(line_1, log_lines); + memset(log_lines, 0, sizeof(log_lines)); + // A bit more than the first line length. + CHECK_EQ(line_1_len, Logger::GetLogLines(0, log_lines, line_1_len + 3)); + CHECK_EQ(line_1, log_lines); + memset(log_lines, 0, sizeof(log_lines)); + const char* line_2 = "cccc,\"dddd\"\n"; + const int line_2_len = strlen(line_2); + // Now start with line_2 beginning. + CHECK_EQ(0, Logger::GetLogLines(line_1_len, log_lines, 0)); + CHECK_EQ(0, Logger::GetLogLines(line_1_len, log_lines, 3)); + CHECK_EQ(0, Logger::GetLogLines(line_1_len, log_lines, line_2_len - 1)); + CHECK_EQ(line_2_len, Logger::GetLogLines(line_1_len, log_lines, line_2_len)); + CHECK_EQ(line_2, log_lines); + memset(log_lines, 0, sizeof(log_lines)); + CHECK_EQ(line_2_len, + Logger::GetLogLines(line_1_len, log_lines, line_2_len + 3)); + CHECK_EQ(line_2, log_lines); + memset(log_lines, 0, sizeof(log_lines)); + // Now get entire buffer contents. + const char* all_lines = "aaa,\"bbb\"\ncccc,\"dddd\"\n"; + const int all_lines_len = strlen(all_lines); + CHECK_EQ(all_lines_len, Logger::GetLogLines(0, log_lines, all_lines_len)); + CHECK_EQ(all_lines, log_lines); + memset(log_lines, 0, sizeof(log_lines)); + CHECK_EQ(all_lines_len, Logger::GetLogLines(0, log_lines, all_lines_len + 3)); + CHECK_EQ(all_lines, log_lines); + memset(log_lines, 0, sizeof(log_lines)); + TearDown(); +} + + +TEST(BeyondWritePosition) { + SetUp(); + Logger::StringEvent("aaa", "bbb"); + Logger::StringEvent("cccc", "dddd"); + // See Logger::StringEvent. + const char* all_lines = "aaa,\"bbb\"\ncccc,\"dddd\"\n"; + const int all_lines_len = strlen(all_lines); + CHECK_EQ(0, Logger::GetLogLines(all_lines_len, NULL, 1)); + CHECK_EQ(0, Logger::GetLogLines(all_lines_len, NULL, 100)); + CHECK_EQ(0, Logger::GetLogLines(all_lines_len + 1, NULL, 1)); + CHECK_EQ(0, Logger::GetLogLines(all_lines_len + 1, NULL, 100)); + CHECK_EQ(0, Logger::GetLogLines(all_lines_len + 100, NULL, 1)); + CHECK_EQ(0, Logger::GetLogLines(all_lines_len + 100, NULL, 100)); + CHECK_EQ(0, Logger::GetLogLines(10 * 1024 * 1024, NULL, 1)); + CHECK_EQ(0, Logger::GetLogLines(10 * 1024 * 1024, NULL, 100)); + TearDown(); +} + + +TEST(MemoryLoggingTurnedOff) { + // Log to stdout + v8::internal::FLAG_logfile = "-"; + v8::internal::FLAG_log = true; + Logger::Setup(); + CHECK_EQ(0, Logger::GetLogLines(0, NULL, 0)); + CHECK_EQ(0, Logger::GetLogLines(100, NULL, 0)); + CHECK_EQ(0, Logger::GetLogLines(0, NULL, 100)); + CHECK_EQ(0, Logger::GetLogLines(100, NULL, 100)); + Logger::TearDown(); +} + + +#endif // ENABLE_LOGGING_AND_PROFILING diff --git a/deps/v8/test/cctest/test-regexp.cc b/deps/v8/test/cctest/test-regexp.cc index afd967900..8761cf51b 100644 --- a/deps/v8/test/cctest/test-regexp.cc +++ b/deps/v8/test/cctest/test-regexp.cc @@ -27,7 +27,6 @@ #include <stdlib.h> -#include <set> #include "v8.h" @@ -39,11 +38,15 @@ #include "jsregexp-inl.h" #include "regexp-macro-assembler.h" #include "regexp-macro-assembler-irregexp.h" -#ifdef ARM -#include "regexp-macro-assembler-arm.h" -#else // IA32 -#include "macro-assembler-ia32.h" -#include "regexp-macro-assembler-ia32.h" +#ifdef V8_TARGET_ARCH_ARM +#include "arm/regexp-macro-assembler-arm.h" +#endif +#ifdef V8_TARGET_ARCH_X64 +// No X64-implementation yet. +#endif +#ifdef V8_TARGET_ARCH_IA32 +#include "ia32/macro-assembler-ia32.h" +#include "ia32/regexp-macro-assembler-ia32.h" #endif #include "interpreter-irregexp.h" @@ -499,24 +502,25 @@ const int TestConfig::kNoKey = 0; const int TestConfig::kNoValue = 0; -static int PseudoRandom(int i, int j) { +static unsigned PseudoRandom(int i, int j) { return ~(~((i * 781) ^ (j * 329))); } TEST(SplayTreeSimple) { - static const int kLimit = 1000; + static const unsigned kLimit = 1000; ZoneScope zone_scope(DELETE_ON_EXIT); ZoneSplayTree<TestConfig> tree; - std::set<int> seen; + bool seen[kLimit]; + for (unsigned i = 0; i < kLimit; i++) seen[i] = false; #define CHECK_MAPS_EQUAL() do { \ - for (int k = 0; k < kLimit; k++) \ - CHECK_EQ(seen.find(k) != seen.end(), tree.Find(k, &loc)); \ + for (unsigned k = 0; k < kLimit; k++) \ + CHECK_EQ(seen[k], tree.Find(k, &loc)); \ } while (false) for (int i = 0; i < 50; i++) { for (int j = 0; j < 50; j++) { - int next = PseudoRandom(i, j) % kLimit; - if (seen.find(next) != seen.end()) { + unsigned next = PseudoRandom(i, j) % kLimit; + if (seen[next]) { // We've already seen this one. Check the value and remove // it. ZoneSplayTree<TestConfig>::Locator loc; @@ -524,7 +528,7 @@ TEST(SplayTreeSimple) { CHECK_EQ(next, loc.key()); CHECK_EQ(3 * next, loc.value()); tree.Remove(next); - seen.erase(next); + seen[next] = false; CHECK_MAPS_EQUAL(); } else { // Check that it wasn't there already and then add it. @@ -533,26 +537,22 @@ TEST(SplayTreeSimple) { CHECK(tree.Insert(next, &loc)); CHECK_EQ(next, loc.key()); loc.set_value(3 * next); - seen.insert(next); + seen[next] = true; CHECK_MAPS_EQUAL(); } int val = PseudoRandom(j, i) % kLimit; - for (int k = val; k >= 0; k--) { - if (seen.find(val) != seen.end()) { - ZoneSplayTree<TestConfig>::Locator loc; - CHECK(tree.FindGreatestLessThan(val, &loc)); - CHECK_EQ(loc.key(), val); - break; - } + if (seen[val]) { + ZoneSplayTree<TestConfig>::Locator loc; + CHECK(tree.FindGreatestLessThan(val, &loc)); + CHECK_EQ(loc.key(), val); + break; } val = PseudoRandom(i + j, i - j) % kLimit; - for (int k = val; k < kLimit; k++) { - if (seen.find(val) != seen.end()) { - ZoneSplayTree<TestConfig>::Locator loc; - CHECK(tree.FindLeastGreaterThan(val, &loc)); - CHECK_EQ(loc.key(), val); - break; - } + if (seen[val]) { + ZoneSplayTree<TestConfig>::Locator loc; + CHECK(tree.FindLeastGreaterThan(val, &loc)); + CHECK_EQ(loc.key(), val); + break; } } } @@ -661,7 +661,7 @@ TEST(MacroAssembler) { } -#ifndef ARM // IA32 only tests. +#ifdef V8_TARGET_ARCH_IA32 // IA32 only tests. class ContextInitializer { public: diff --git a/deps/v8/test/cctest/test-serialize.cc b/deps/v8/test/cctest/test-serialize.cc index 56727dca4..36f051f57 100644 --- a/deps/v8/test/cctest/test-serialize.cc +++ b/deps/v8/test/cctest/test-serialize.cc @@ -26,8 +26,6 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <signal.h> -#include <map> -#include <string> #include "sys/stat.h" #include "v8.h" @@ -42,20 +40,40 @@ using namespace v8::internal; -static int local_counters[256]; -static int counter_count = 0; -static std::map<std::string, int> counter_table; +static const unsigned kCounters = 256; +static int local_counters[kCounters]; +static const char* local_counter_names[kCounters]; + + +static unsigned CounterHash(const char* s) { + unsigned hash = 0; + while (*++s) { + hash |= hash << 5; + hash += *s; + } + return hash; +} // Callback receiver to track counters in test. static int* counter_function(const char* name) { - std::string counter(name); - if (counter_table.find(counter) == counter_table.end()) { - local_counters[counter_count] = 0; - counter_table[counter] = counter_count++; + unsigned hash = CounterHash(name) % kCounters; + unsigned original_hash = hash; + USE(original_hash); + while (true) { + if (local_counter_names[hash] == name) { + return &local_counters[hash]; + } + if (local_counter_names[hash] == 0) { + local_counter_names[hash] = name; + return &local_counters[hash]; + } + if (strcmp(local_counter_names[hash], name) == 0) { + return &local_counters[hash]; + } + hash = (hash + 1) % kCounters; + ASSERT(hash != original_hash); // Hash table has been filled up. } - - return &local_counters[counter_table[counter]]; } diff --git a/deps/v8/test/cctest/test-strings.cc b/deps/v8/test/cctest/test-strings.cc index 3be5d6292..3065ba12b 100644 --- a/deps/v8/test/cctest/test-strings.cc +++ b/deps/v8/test/cctest/test-strings.cc @@ -9,6 +9,7 @@ #include "v8.h" +#include "api.h" #include "factory.h" #include "cctest.h" #include "zone-inl.h" @@ -154,7 +155,7 @@ static Handle<String> ConstructBalancedHelper( Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS], int from, int to) { - ASSERT(to > from); + CHECK(to > from); if (to - from == 1) { return building_blocks[from % NUMBER_OF_BUILDING_BLOCKS]; } @@ -279,7 +280,7 @@ static Handle<String> ConstructSliceTree( Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS], int from, int to) { - ASSERT(to > from); + CHECK(to > from); if (to - from <= 1) return SliceOf(building_blocks[from % NUMBER_OF_BUILDING_BLOCKS]); if (to - from == 2) { @@ -391,9 +392,17 @@ TEST(Utf8Conversion) { class TwoByteResource: public v8::String::ExternalStringResource { public: - explicit TwoByteResource(const uint16_t* data, size_t length) - : data_(data), length_(length) { } - virtual ~TwoByteResource() { } + TwoByteResource(const uint16_t* data, size_t length, bool* destructed) + : data_(data), length_(length), destructed_(destructed) { + CHECK_NE(destructed, NULL); + *destructed_ = false; + } + + virtual ~TwoByteResource() { + CHECK_NE(destructed_, NULL); + CHECK(!*destructed_); + *destructed_ = true; + } const uint16_t* data() const { return data_; } size_t length() const { return length_; } @@ -401,46 +410,107 @@ class TwoByteResource: public v8::String::ExternalStringResource { private: const uint16_t* data_; size_t length_; + bool* destructed_; }; -TEST(ExternalCrBug9746) { +// Regression test case for http://crbug.com/9746. The problem was +// that when we marked objects reachable only through weak pointers, +// we ended up keeping a sliced symbol alive, even though we already +// invoked the weak callback on the underlying external string thus +// deleting its resource. +TEST(Regress9746) { InitializeVM(); - v8::HandleScope handle_scope; - // This set of tests verifies that the workaround for Chromium bug 9746 - // works correctly. In certain situations the external resource of a symbol - // is collected while the symbol is still part of the symbol table. - static uint16_t two_byte_data[] = { - 't', 'w', 'o', '-', 'b', 'y', 't', 'e', ' ', 'd', 'a', 't', 'a' - }; - static size_t two_byte_length = - sizeof(two_byte_data) / sizeof(two_byte_data[0]); - static const char* one_byte_data = "two-byte data"; - - // Allocate an external string resource and external string. - TwoByteResource* resource = new TwoByteResource(two_byte_data, - two_byte_length); - Handle<String> string = Factory::NewExternalStringFromTwoByte(resource); - Vector<const char> one_byte_vec = CStrVector(one_byte_data); - Handle<String> compare = Factory::NewStringFromAscii(one_byte_vec); - - // Verify the correct behaviour before "collecting" the external resource. - CHECK(string->IsEqualTo(one_byte_vec)); - CHECK(string->Equals(*compare)); - - // "Collect" the external resource manually by setting the external resource - // pointer to NULL. Then redo the comparisons, they should not match AND - // not crash. - Handle<ExternalTwoByteString> external(ExternalTwoByteString::cast(*string)); - external->set_resource(NULL); - CHECK_EQ(false, string->IsEqualTo(one_byte_vec)); -#if !defined(DEBUG) - // These tests only work in non-debug as there are ASSERTs in the code that - // do prevent the ability to even get into the broken code when running the - // debug version of V8. - CHECK_EQ(false, string->Equals(*compare)); - CHECK_EQ(false, compare->Equals(*string)); - CHECK_EQ(false, string->Equals(Heap::empty_string())); -#endif // !defined(DEBUG) + // Setup lengths that guarantee we'll get slices instead of simple + // flat strings. + static const int kFullStringLength = String::kMinNonFlatLength * 2; + static const int kSliceStringLength = String::kMinNonFlatLength + 1; + + uint16_t* source = new uint16_t[kFullStringLength]; + for (int i = 0; i < kFullStringLength; i++) source[i] = '1'; + char* key = new char[kSliceStringLength]; + for (int i = 0; i < kSliceStringLength; i++) key[i] = '1'; + Vector<const char> key_vector(key, kSliceStringLength); + + // Allocate an external string resource that keeps track of when it + // is destructed. + bool resource_destructed = false; + TwoByteResource* resource = + new TwoByteResource(source, kFullStringLength, &resource_destructed); + + { + v8::HandleScope scope; + + // Allocate an external string resource and external string. We + // have to go through the API to get the weak handle and the + // automatic destruction going. + Handle<String> string = + v8::Utils::OpenHandle(*v8::String::NewExternal(resource)); + + // Create a slice of the external string. + Handle<String> slice = + Factory::NewStringSlice(string, 0, kSliceStringLength); + CHECK_EQ(kSliceStringLength, slice->length()); + CHECK(StringShape(*slice).IsSliced()); + + // Make sure the slice ends up in old space so we can morph it + // into a symbol. + while (Heap::InNewSpace(*slice)) { + Heap::PerformScavenge(); + } + + // Force the slice into the symbol table. + slice = Factory::SymbolFromString(slice); + CHECK(slice->IsSymbol()); + CHECK(StringShape(*slice).IsSliced()); + + Handle<String> buffer(Handle<SlicedString>::cast(slice)->buffer()); + CHECK(StringShape(*buffer).IsExternal()); + CHECK(buffer->IsTwoByteRepresentation()); + + // Finally, base a script on the slice of the external string and + // get its wrapper. This allocates yet another weak handle that + // indirectly refers to the external string. + Handle<Script> script = Factory::NewScript(slice); + Handle<JSObject> wrapper = GetScriptWrapper(script); + } + + // When we collect all garbage, we cannot get rid of the sliced + // symbol entry in the symbol table because it is used by the script + // kept alive by the weak wrapper. Make sure we don't destruct the + // external string. + Heap::CollectAllGarbage(); + CHECK(!resource_destructed); + + { + v8::HandleScope scope; + + // Make sure the sliced symbol is still in the table. + Handle<String> symbol = Factory::LookupSymbol(key_vector); + CHECK(StringShape(*symbol).IsSliced()); + + // Make sure the buffer is still a two-byte external string. + Handle<String> buffer(Handle<SlicedString>::cast(symbol)->buffer()); + CHECK(StringShape(*buffer).IsExternal()); + CHECK(buffer->IsTwoByteRepresentation()); + } + + // Forcing another garbage collection should let us get rid of the + // slice from the symbol table. The external string remains in the + // heap until the next GC. + Heap::CollectAllGarbage(); + CHECK(!resource_destructed); + v8::HandleScope scope; + Handle<String> key_string = Factory::NewStringFromAscii(key_vector); + String* out; + CHECK(!Heap::LookupSymbolIfExists(*key_string, &out)); + + // Forcing yet another garbage collection must allow us to finally + // get rid of the external string. + Heap::CollectAllGarbage(); + CHECK(resource_destructed); + + delete[] source; + delete[] key; } diff --git a/deps/v8/test/cctest/test-version.cc b/deps/v8/test/cctest/test-version.cc new file mode 100644 index 000000000..0b93fbf8c --- /dev/null +++ b/deps/v8/test/cctest/test-version.cc @@ -0,0 +1,88 @@ +// Copyright 2009 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. + +#include "v8.h" + +#include "version.h" +#include "cctest.h" + +using namespace v8::internal; + + +namespace v8 { namespace internal { + +void SetVersion(int major, int minor, int build, int patch, + bool candidate, const char* soname) { + Version::major_ = major; + Version::minor_ = minor; + Version::build_ = build; + Version::patch_ = patch; + Version::candidate_ = candidate; + Version::soname_ = soname; +} + +} } // namespace v8::internal + + +static void CheckVersion(int major, int minor, int build, + int patch, bool candidate, + const char* expected_version_string, + const char* expected_generic_soname) { + static v8::internal::EmbeddedVector<char, 128> version_str; + static v8::internal::EmbeddedVector<char, 128> soname_str; + + // Test version without specific SONAME. + SetVersion(major, minor, build, patch, candidate, ""); + Version::GetString(version_str); + CHECK_EQ(expected_version_string, version_str.start()); + Version::GetSONAME(soname_str); + CHECK_EQ(expected_generic_soname, soname_str.start()); + + // Test version with specific SONAME. + const char* soname = "libv8.so.1"; + SetVersion(major, minor, build, patch, candidate, soname); + Version::GetString(version_str); + CHECK_EQ(expected_version_string, version_str.start()); + Version::GetSONAME(soname_str); + CHECK_EQ(soname, soname_str.start()); +} + + +TEST(VersionString) { + CheckVersion(0, 0, 0, 0, false, "0.0.0", "libv8-0.0.0.so"); + CheckVersion(0, 0, 0, 0, true, + "0.0.0 (candidate)", "libv8-0.0.0-candidate.so"); + CheckVersion(1, 0, 0, 0, false, "1.0.0", "libv8-1.0.0.so"); + CheckVersion(1, 0, 0, 0, true, + "1.0.0 (candidate)", "libv8-1.0.0-candidate.so"); + CheckVersion(1, 0, 0, 1, false, "1.0.0.1", "libv8-1.0.0.1.so"); + CheckVersion(1, 0, 0, 1, true, + "1.0.0.1 (candidate)", "libv8-1.0.0.1-candidate.so"); + CheckVersion(2, 5, 10, 7, false, "2.5.10.7", "libv8-2.5.10.7.so"); + CheckVersion(2, 5, 10, 7, true, + "2.5.10.7 (candidate)", "libv8-2.5.10.7-candidate.so"); +} diff --git a/deps/v8/test/mjsunit/array-reduce.js b/deps/v8/test/mjsunit/array-reduce.js new file mode 100644 index 000000000..e476e1cb0 --- /dev/null +++ b/deps/v8/test/mjsunit/array-reduce.js @@ -0,0 +1,514 @@ +// Copyright 2009 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. + +/** + * @fileoverview Test reduce and reduceRight + */ + +function clone(v) { + // Shallow-copies arrays, returns everything else verbatim. + if (v instanceof Array) { + // Shallow-copy an array. + var newArray = new Array(v.length); + for (var i in v) { + newArray[i] = v[i]; + } + return newArray; + } + return v; +} + + +// Creates a callback function for reduce/reduceRight that tests the number +// of arguments and otherwise behaves as "func", but which also +// records all calls in an array on the function (as arrays of arguments +// followed by result). +function makeRecorder(func, testName) { + var record = []; + var f = function recorder(a, b, i, s) { + assertEquals(4, arguments.length, + testName + "(number of arguments: " + arguments.length + ")"); + assertEquals("number", typeof(i), testName + "(index must be number)"); + assertEquals(s[i], b, testName + "(current argument is at index)"); + if (record.length > 0) { + var prevRecord = record[record.length - 1]; + var prevResult = prevRecord[prevRecord.length - 1]; + assertEquals(prevResult, a, + testName + "(prev result -> current input)"); + } + var args = [clone(a), clone(b), i, clone(s)]; + var result = func.apply(this, arguments); + args.push(clone(result)); + record.push(args); + return result; + }; + f.record = record; + return f; +} + + +function testReduce(type, + testName, + expectedResult, + expectedCalls, + array, + combine, + init) { + var rec = makeRecorder(combine); + var result; + var performsCall; + if (arguments.length > 6) { + result = array[type](rec, init); + } else { + result = array[type](rec); + } + var calls = rec.record; + assertEquals(expectedCalls.length, calls.length, + testName + " (number of calls)"); + for (var i = 0; i < expectedCalls.length; i++) { + assertEquals(expectedCalls[i], calls[i], + testName + " (call " + (i + 1) + ")"); + } + assertEquals(expectedResult, result, testName + " (result)"); +} + + +function sum(a, b) { return a + b; } +function prod(a, b) { return a * b; } +function dec(a, b, i, arr) { return a + b * Math.pow(10, arr.length - i - 1); } +function accumulate(acc, elem, i) { acc[i] = elem; return acc; } + +// ---- Test Reduce[Left] + +var simpleArray = [2,4,6] + +testReduce("reduce", "SimpleReduceSum", 12, + [[0, 2, 0, simpleArray, 2], + [2, 4, 1, simpleArray, 6], + [6, 6, 2, simpleArray, 12]], + simpleArray, sum, 0); + +testReduce("reduce", "SimpleReduceProd", 48, + [[1, 2, 0, simpleArray, 2], + [2, 4, 1, simpleArray, 8], + [8, 6, 2, simpleArray, 48]], + simpleArray, prod, 1); + +testReduce("reduce", "SimpleReduceDec", 246, + [[0, 2, 0, simpleArray, 200], + [200, 4, 1, simpleArray, 240], + [240, 6, 2, simpleArray, 246]], + simpleArray, dec, 0); + +testReduce("reduce", "SimpleReduceAccumulate", simpleArray, + [[[], 2, 0, simpleArray, [2]], + [[2], 4, 1, simpleArray, [2, 4]], + [[2,4], 6, 2, simpleArray, simpleArray]], + simpleArray, accumulate, []); + + +testReduce("reduce", "EmptyReduceSum", 0, [], [], sum, 0); +testReduce("reduce", "EmptyReduceProd", 1, [], [], prod, 1); +testReduce("reduce", "EmptyReduceDec", 0, [], [], dec, 0); +testReduce("reduce", "EmptyReduceAccumulate", [], [], [], accumulate, []); + +testReduce("reduce", "EmptyReduceSumNoInit", 0, [], [0], sum); +testReduce("reduce", "EmptyReduceProdNoInit", 1, [], [1], prod); +testReduce("reduce", "EmptyReduceDecNoInit", 0, [], [0], dec); +testReduce("reduce", "EmptyReduceAccumulateNoInit", [], [], [[]], accumulate); + + +var simpleSparseArray = [,,,2,,4,,6,,]; +testReduce("reduce", "SimpleSparseReduceSum", 12, + [[0, 2, 3, simpleSparseArray, 2], + [2, 4, 5, simpleSparseArray, 6], + [6, 6, 7, simpleSparseArray, 12]], + simpleSparseArray, sum, 0); + +testReduce("reduce", "SimpleSparseReduceProd", 48, + [[1, 2, 3, simpleSparseArray, 2], + [2, 4, 5, simpleSparseArray, 8], + [8, 6, 7, simpleSparseArray, 48]], + simpleSparseArray, prod, 1); + +testReduce("reduce", "SimpleSparseReduceDec", 204060, + [[0, 2, 3, simpleSparseArray, 200000], + [200000, 4, 5, simpleSparseArray, 204000], + [204000, 6, 7, simpleSparseArray, 204060]], + simpleSparseArray, dec, 0); + +testReduce("reduce", "SimpleSparseReduceAccumulate", [,,,2,,4,,6], + [[[], 2, 3, simpleSparseArray, [,,,2]], + [[,,,2], 4, 5, simpleSparseArray, [,,,2,,4]], + [[,,,2,,4], 6, 7, simpleSparseArray, [,,,2,,4,,6]]], + simpleSparseArray, accumulate, []); + + +testReduce("reduce", "EmptySparseReduceSumNoInit", 0, [], [,,0,,], sum); +testReduce("reduce", "EmptySparseReduceProdNoInit", 1, [], [,,1,,], prod); +testReduce("reduce", "EmptySparseReduceDecNoInit", 0, [], [,,0,,], dec); +testReduce("reduce", "EmptySparseReduceAccumulateNoInit", + [], [], [,,[],,], accumulate); + + +var verySparseArray = []; +verySparseArray.length = 10000; +verySparseArray[2000] = 2; +verySparseArray[5000] = 4; +verySparseArray[9000] = 6; +var verySparseSlice2 = verySparseArray.slice(0, 2001); +var verySparseSlice4 = verySparseArray.slice(0, 5001); +var verySparseSlice6 = verySparseArray.slice(0, 9001); + +testReduce("reduce", "VerySparseReduceSum", 12, + [[0, 2, 2000, verySparseArray, 2], + [2, 4, 5000, verySparseArray, 6], + [6, 6, 9000, verySparseArray, 12]], + verySparseArray, sum, 0); + +testReduce("reduce", "VerySparseReduceProd", 48, + [[1, 2, 2000, verySparseArray, 2], + [2, 4, 5000, verySparseArray, 8], + [8, 6, 9000, verySparseArray, 48]], + verySparseArray, prod, 1); + +testReduce("reduce", "VerySparseReduceDec", Infinity, + [[0, 2, 2000, verySparseArray, Infinity], + [Infinity, 4, 5000, verySparseArray, Infinity], + [Infinity, 6, 9000, verySparseArray, Infinity]], + verySparseArray, dec, 0); + +testReduce("reduce", "VerySparseReduceAccumulate", + verySparseSlice6, + [[[], 2, 2000, verySparseArray, verySparseSlice2], + [verySparseSlice2, 4, 5000, verySparseArray, verySparseSlice4], + [verySparseSlice4, 6, 9000, verySparseArray, verySparseSlice6]], + verySparseArray, accumulate, []); + + +testReduce("reduce", "VerySparseReduceSumNoInit", 12, + [[2, 4, 5000, verySparseArray, 6], + [6, 6, 9000, verySparseArray, 12]], + verySparseArray, sum); + +testReduce("reduce", "VerySparseReduceProdNoInit", 48, + [[2, 4, 5000, verySparseArray, 8], + [8, 6, 9000, verySparseArray, 48]], + verySparseArray, prod); + +testReduce("reduce", "VerySparseReduceDecNoInit", Infinity, + [[2, 4, 5000, verySparseArray, Infinity], + [Infinity, 6, 9000, verySparseArray, Infinity]], + verySparseArray, dec); + +testReduce("reduce", "SimpleSparseReduceAccumulateNoInit", + 2, + [[2, 4, 5000, verySparseArray, 2], + [2, 6, 9000, verySparseArray, 2]], + verySparseArray, accumulate); + + +// ---- Test ReduceRight + +testReduce("reduceRight", "SimpleReduceRightSum", 12, + [[0, 6, 2, simpleArray, 6], + [6, 4, 1, simpleArray, 10], + [10, 2, 0, simpleArray, 12]], + simpleArray, sum, 0); + +testReduce("reduceRight", "SimpleReduceRightProd", 48, + [[1, 6, 2, simpleArray, 6], + [6, 4, 1, simpleArray, 24], + [24, 2, 0, simpleArray, 48]], + simpleArray, prod, 1); + +testReduce("reduceRight", "SimpleReduceRightDec", 246, + [[0, 6, 2, simpleArray, 6], + [6, 4, 1, simpleArray, 46], + [46, 2, 0, simpleArray, 246]], + simpleArray, dec, 0); + +testReduce("reduceRight", "SimpleReduceRightAccumulate", simpleArray, + [[[], 6, 2, simpleArray, [,,6]], + [[,,6], 4, 1, simpleArray, [,4,6]], + [[,4,6], 2, 0, simpleArray, simpleArray]], + simpleArray, accumulate, []); + + +testReduce("reduceRight", "EmptyReduceRightSum", 0, [], [], sum, 0); +testReduce("reduceRight", "EmptyReduceRightProd", 1, [], [], prod, 1); +testReduce("reduceRight", "EmptyReduceRightDec", 0, [], [], dec, 0); +testReduce("reduceRight", "EmptyReduceRightAccumulate", [], + [], [], accumulate, []); + +testReduce("reduceRight", "EmptyReduceRightSumNoInit", 0, [], [0], sum); +testReduce("reduceRight", "EmptyReduceRightProdNoInit", 1, [], [1], prod); +testReduce("reduceRight", "EmptyReduceRightDecNoInit", 0, [], [0], dec); +testReduce("reduceRight", "EmptyReduceRightAccumulateNoInit", + [], [], [[]], accumulate); + + +testReduce("reduceRight", "SimpleSparseReduceRightSum", 12, + [[0, 6, 7, simpleSparseArray, 6], + [6, 4, 5, simpleSparseArray, 10], + [10, 2, 3, simpleSparseArray, 12]], + simpleSparseArray, sum, 0); + +testReduce("reduceRight", "SimpleSparseReduceRightProd", 48, + [[1, 6, 7, simpleSparseArray, 6], + [6, 4, 5, simpleSparseArray, 24], + [24, 2, 3, simpleSparseArray, 48]], + simpleSparseArray, prod, 1); + +testReduce("reduceRight", "SimpleSparseReduceRightDec", 204060, + [[0, 6, 7, simpleSparseArray, 60], + [60, 4, 5, simpleSparseArray, 4060], + [4060, 2, 3, simpleSparseArray, 204060]], + simpleSparseArray, dec, 0); + +testReduce("reduceRight", "SimpleSparseReduceRightAccumulate", [,,,2,,4,,6], + [[[], 6, 7, simpleSparseArray, [,,,,,,,6]], + [[,,,,,,,6], 4, 5, simpleSparseArray, [,,,,,4,,6]], + [[,,,,,4,,6], 2, 3, simpleSparseArray, [,,,2,,4,,6]]], + simpleSparseArray, accumulate, []); + + +testReduce("reduceRight", "EmptySparseReduceRightSumNoInit", + 0, [], [,,0,,], sum); +testReduce("reduceRight", "EmptySparseReduceRightProdNoInit", + 1, [], [,,1,,], prod); +testReduce("reduceRight", "EmptySparseReduceRightDecNoInit", + 0, [], [,,0,,], dec); +testReduce("reduceRight", "EmptySparseReduceRightAccumulateNoInit", + [], [], [,,[],,], accumulate); + + +var verySparseSuffix6 = []; +verySparseSuffix6[9000] = 6; +var verySparseSuffix4 = []; +verySparseSuffix4[5000] = 4; +verySparseSuffix4[9000] = 6; +var verySparseSuffix2 = verySparseSlice6; + + +testReduce("reduceRight", "VerySparseReduceRightSum", 12, + [[0, 6, 9000, verySparseArray, 6], + [6, 4, 5000, verySparseArray, 10], + [10, 2, 2000, verySparseArray, 12]], + verySparseArray, sum, 0); + +testReduce("reduceRight", "VerySparseReduceRightProd", 48, + [[1, 6, 9000, verySparseArray, 6], + [6, 4, 5000, verySparseArray, 24], + [24, 2, 2000, verySparseArray, 48]], + verySparseArray, prod, 1); + +testReduce("reduceRight", "VerySparseReduceRightDec", Infinity, + [[0, 6, 9000, verySparseArray, Infinity], + [Infinity, 4, 5000, verySparseArray, Infinity], + [Infinity, 2, 2000, verySparseArray, Infinity]], + verySparseArray, dec, 0); + +testReduce("reduceRight", "VerySparseReduceRightAccumulate", + verySparseSuffix2, + [[[], 6, 9000, verySparseArray, verySparseSuffix6], + [verySparseSuffix6, 4, 5000, verySparseArray, verySparseSuffix4], + [verySparseSuffix4, 2, 2000, verySparseArray, verySparseSuffix2]], + verySparseArray, accumulate, []); + + +testReduce("reduceRight", "VerySparseReduceRightSumNoInit", 12, + [[6, 4, 5000, verySparseArray, 10], + [10, 2, 2000, verySparseArray, 12]], + verySparseArray, sum); + +testReduce("reduceRight", "VerySparseReduceRightProdNoInit", 48, + [[6, 4, 5000, verySparseArray, 24], + [24, 2, 2000, verySparseArray, 48]], + verySparseArray, prod); + +testReduce("reduceRight", "VerySparseReduceRightDecNoInit", Infinity, + [[6, 4, 5000, verySparseArray, Infinity], + [Infinity, 2, 2000, verySparseArray, Infinity]], + verySparseArray, dec); + +testReduce("reduceRight", "SimpleSparseReduceRightAccumulateNoInit", + 6, + [[6, 4, 5000, verySparseArray, 6], + [6, 2, 2000, verySparseArray, 6]], + verySparseArray, accumulate); + + +// undefined is an element +var undefArray = [,,undefined,,undefined,,]; + +testReduce("reduce", "SparseUndefinedReduceAdd", NaN, + [[0, undefined, 2, undefArray, NaN], + [NaN, undefined, 4, undefArray, NaN], + ], + undefArray, sum, 0); + +testReduce("reduceRight", "SparseUndefinedReduceRightAdd", NaN, + [[0, undefined, 4, undefArray, NaN], + [NaN, undefined, 2, undefArray, NaN], + ], undefArray, sum, 0); + +testReduce("reduce", "SparseUndefinedReduceAddNoInit", NaN, + [[undefined, undefined, 4, undefArray, NaN], + ], undefArray, sum); + +testReduce("reduceRight", "SparseUndefinedReduceRightAddNoInit", NaN, + [[undefined, undefined, 2, undefArray, NaN], + ], undefArray, sum); + + +// Ignore non-array properties: + +var arrayPlus = [1,2,,3]; +arrayPlus[-1] = NaN; +arrayPlus[Math.pow(2,32)] = NaN; +arrayPlus[NaN] = NaN; +arrayPlus["00"] = NaN; +arrayPlus["02"] = NaN; +arrayPlus["-0"] = NaN; + +testReduce("reduce", "ArrayWithNonElementPropertiesReduce", 6, + [[0, 1, 0, arrayPlus, 1], + [1, 2, 1, arrayPlus, 3], + [3, 3, 3, arrayPlus, 6], + ], arrayPlus, sum, 0); + +testReduce("reduceRight", "ArrayWithNonElementPropertiesReduceRight", 6, + [[0, 3, 3, arrayPlus, 3], + [3, 2, 1, arrayPlus, 5], + [5, 1, 0, arrayPlus, 6], + ], arrayPlus, sum, 0); + + +// Test error conditions: + +try { + [1].reduce("not a function"); + fail("Reduce callback not a function not throwing"); +} catch (e) { + assertTrue(e instanceof TypeError, + "reduce callback not a function not throwing TypeError"); + assertEquals("called_non_callable", e.type, + "reduce non function TypeError type"); +} + +try { + [1].reduceRight("not a function"); + fail("ReduceRight callback not a function not throwing"); +} catch (e) { + assertTrue(e instanceof TypeError, + "reduceRight callback not a function not throwing TypeError"); + assertEquals("called_non_callable", e.type, + "reduceRight non function TypeError type"); +} + + +try { + [].reduce(sum); + fail("Reduce no initial value not throwing"); +} catch (e) { + assertTrue(e instanceof TypeError, + "reduce no initial value not throwing TypeError"); + assertEquals("reduce_no_initial", e.type, + "reduce no initial TypeError type"); +} + +try { + [].reduceRight(sum); + fail("ReduceRight no initial value not throwing"); +} catch (e) { + assertTrue(e instanceof TypeError, + "reduceRight no initial value not throwing TypeError"); + assertEquals("reduce_no_initial", e.type, + "reduceRight no initial TypeError type"); +} + + +try { + [,,,].reduce(sum); + fail("Reduce sparse no initial value not throwing"); +} catch (e) { + assertTrue(e instanceof TypeError, + "reduce sparse no initial value not throwing TypeError"); + assertEquals("reduce_no_initial", e.type, + "reduce no initial TypeError type"); +} + +try { + [,,,].reduceRight(sum); + fail("ReduceRight sparse no initial value not throwing"); +} catch (e) { + assertTrue(e instanceof TypeError, + "reduceRight sparse no initial value not throwing TypeError"); + assertEquals("reduce_no_initial", e.type, + "reduceRight no initial TypeError type"); +} + + +// Array changing length + +function manipulator(a, b, i, s) { + if (s.length % 2) { + s[s.length * 3] = i; + } else { + s.length = s.length >> 1; + } + return a + b; +} + +var arr = [1, 2, 3, 4]; +testReduce("reduce", "ArrayManipulationShort", 3, + [[0, 1, 0, [1, 2, 3, 4], 1], + [1, 2, 1, [1, 2], 3], + ], arr, manipulator, 0); + +var arr = [1, 2, 3, 4, 5]; +testReduce("reduce", "ArrayManipulationLonger", 10, + [[0, 1, 0, [1, 2, 3, 4, 5], 1], + [1, 2, 1, [1, 2, 3, 4, 5,,,,,,,,,,, 0], 3], + [3, 3, 2, [1, 2, 3, 4, 5,,,,], 6], + [6, 4, 3, [1, 2, 3, 4], 10], + ], arr, manipulator, 0); + +function extender(a, b, i, s) { + s[s.length] = s.length; + return a + b; +} + +var arr = [1, 2, 3, 4]; +testReduce("reduce", "ArrayManipulationExtender", 10, + [[0, 1, 0, [1, 2, 3, 4], 1], + [1, 2, 1, [1, 2, 3, 4, 4], 3], + [3, 3, 2, [1, 2, 3, 4, 4, 5], 6], + [6, 4, 3, [1, 2, 3, 4, 4, 5, 6], 10], + ], arr, extender, 0); + diff --git a/deps/v8/test/mjsunit/array-sort.js b/deps/v8/test/mjsunit/array-sort.js index dfa45906e..ef75dcc29 100644 --- a/deps/v8/test/mjsunit/array-sort.js +++ b/deps/v8/test/mjsunit/array-sort.js @@ -152,3 +152,191 @@ function TestArraySortingWithUnsoundComparisonFunction() { } TestArraySortingWithUnsoundComparisonFunction(); + + +function TestSparseNonArraySorting(length) { + assertTrue(length > 101); + var obj = {length: length}; + obj[0] = 42; + obj[10] = 37; + obj[100] = undefined; + obj[length - 1] = null; + Array.prototype.sort.call(obj); + assertEquals(length, obj.length, "objsort length unaffected"); + assertEquals(37, obj[0], "objsort smallest number"); + assertEquals(42, obj[1], "objsort largest number"); + assertEquals(null, obj[2], "objsort null"); + assertEquals(undefined, obj[3], "objsort undefined"); + assertTrue(3 in obj, "objsort undefined retained"); + assertFalse(4 in obj, "objsort non-existing retained"); +} + +TestSparseNonArraySorting(5000); +TestSparseNonArraySorting(500000); +TestSparseNonArraySorting(Math.pow(2, 31) + 1); + + +function TestArrayLongerLength(length) { + var x = new Array(4); + x[0] = 42; + x[2] = 37; + x.length = length; + Array.prototype.sort.call(x); + assertEquals(length, x.length, "longlength length"); + assertEquals(37, x[0], "longlength first"); + assertEquals(42, x[1], "longlength second"); + assertFalse(2 in x,"longlength third"); +} + +TestArrayLongerLength(4); +TestArrayLongerLength(10); +TestArrayLongerLength(1000); +TestArrayLongerLength(500000); +TestArrayLongerLength(Math.pow(2,32) - 1); + + +function TestNonArrayLongerLength(length) { + var x = {}; + x[0] = 42; + x[2] = 37; + x.length = length; + Array.prototype.sort.call(x); + assertEquals(length, x.length, "longlength length"); + assertEquals(37, x[0], "longlength first"); + assertEquals(42, x[1], "longlength second"); + assertFalse(2 in x,"longlength third"); +} + +TestNonArrayLongerLength(4); +TestNonArrayLongerLength(10); +TestNonArrayLongerLength(1000); +TestNonArrayLongerLength(500000); +TestNonArrayLongerLength(Math.pow(2,32) - 1); + + +function TestInheritedElementSort(depth) { + var length = depth * 2 + 3; + var obj = {length: length}; + obj[depth * 2 + 1] = 0; + for (var i = 0; i < depth; i++) { + var newObj = {}; + newObj.__proto__ = obj; + obj[i] = undefined; + obj[i + depth + 1] = depth - i; + obj = newObj; + } + // expected (inherited) object: [undef1,...undefdepth,hole,1,...,depth,0,hole] + + Array.prototype.sort.call(obj, function(a,b) { return (b < a) - (a < b); }); + // expected result: [0,1,...,depth,undef1,...,undefdepth,undef,hole] + var name = "SortInherit("+depth+")-"; + + assertEquals(length, obj.length, name+"length"); + for (var i = 0; i <= depth; i++) { + assertTrue(obj.hasOwnProperty(i), name + "hasvalue" + i); + assertEquals(i, obj[i], name + "value" + i); + } + for (var i = depth + 1; i <= depth * 2 + 1; i++) { + assertEquals(undefined, obj[i], name + "undefined" + i); + assertTrue(obj.hasOwnProperty(i), name + "hasundefined" + i); + } + assertTrue(!obj.hasOwnProperty(depth * 2 + 2), name + "hashole"); +} + +TestInheritedElementSort(5); +TestInheritedElementSort(15); + +function TestSparseInheritedElementSort(scale) { + var length = scale * 10; + var x = {length: length}; + var y = {}; + y.__proto__ = x; + + for (var i = 0; i < 5; i++) { + x[i * 2 * scale] = 2 * (4 - i); + y[(i * 2 + 1) * scale] = 2 * (4 - i) + 1; + } + + var name = "SparseSortInherit(" + scale + ")-"; + + Array.prototype.sort.call(y); + + assertEquals(length, y.length, name +"length"); + + for (var i = 0; i < 10; i++) { + assertTrue(y.hasOwnProperty(i), name + "hasvalue" + i); + assertEquals(i, y[i], name + "value" + i); + } + for (var i = 10; i < length; i++) { + assertEquals(x.hasOwnProperty(i), y.hasOwnProperty(i), + name + "hasundef" + i); + assertEquals(undefined, y[i], name+"undefined"+i); + if (x.hasOwnProperty(i)) { + assertTrue(0 == i % (2 * scale), name + "new_x" + i); + } + } +} + +TestSparseInheritedElementSort(10); +TestSparseInheritedElementSort(100); +TestSparseInheritedElementSort(1000); + +function TestSpecialCasesInheritedElementSort() { + + var x = { + 1:"d1", + 2:"c1", + 3:"b1", + 4: undefined, + __proto__: { + length: 10000, + 1: "e2", + 10: "a2", + 100: "b2", + 1000: "c2", + 2000: undefined, + 8000: "d2", + 12000: "XX", + __proto__: { + 0: "e3", + 1: "d3", + 2: "c3", + 3: "b3", + 4: "f3", + 5: "a3", + 6: undefined, + } + } + }; + Array.prototype.sort.call(x); + + var name = "SpecialInherit-"; + + assertEquals(10000, x.length, name + "length"); + var sorted = ["a2", "a3", "b1", "b2", "c1", "c2", "d1", "d2", "e3", + undefined, undefined, undefined]; + for (var i = 0; i < sorted.length; i++) { + assertTrue(x.hasOwnProperty(i), name + "has" + i) + assertEquals(sorted[i], x[i], name + i); + } + assertFalse(x.hasOwnProperty(sorted.length), name + "haspost"); + assertFalse(sorted.length in x, name + "haspost2"); + + assertTrue(x.hasOwnProperty(10), name + "hasundefined10"); + assertEquals(undefined, x[10], name + "undefined10"); + assertTrue(x.hasOwnProperty(100), name + "hasundefined100"); + assertEquals(undefined, x[100], name + "undefined100"); + assertTrue(x.hasOwnProperty(1000), name + "hasundefined1000"); + assertEquals(undefined, x[1000], name + "undefined1000"); + assertTrue(x.hasOwnProperty(2000), name + "hasundefined2000"); + assertEquals(undefined, x[2000], name + "undefined2000"); + assertTrue(x.hasOwnProperty(8000), name + "hasundefined8000"); + assertEquals(undefined, x[8000], name + "undefined8000"); + + assertFalse(x.hasOwnProperty(12000), name + "has12000"); + assertEquals("XX", x[12000], name + "XX12000"); + +} + +TestSpecialCasesInheritedElementSort(); + diff --git a/deps/v8/test/mjsunit/bugs/bug-334.js b/deps/v8/test/mjsunit/bugs/bug-334.js new file mode 100644 index 000000000..024fc9e85 --- /dev/null +++ b/deps/v8/test/mjsunit/bugs/bug-334.js @@ -0,0 +1,90 @@ +// Copyright 2008 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. + +// Flags: --allow-natives-syntax + +// Test for http://code.google.com/p/v8/issues/detail?id=334 + +var READ_ONLY = 1; +var DONT_ENUM = 2; +var DONT_DELETE = 4; + +function func1(){} +function func2(){} + +var object = {__proto__:{}}; +%SetProperty(object, "foo", func1, DONT_ENUM | DONT_DELETE); +%SetProperty(object, "bar", func1, DONT_ENUM | READ_ONLY); +%SetProperty(object, "baz", func1, DONT_DELETE | READ_ONLY); +%SetProperty(object.__proto__, "bif", func1, DONT_ENUM | DONT_DELETE | READ_ONLY); +object.bif = func2; + +function enumerable(obj) { + var res = []; + for (var i in obj) { + res.push(i); + } + res.sort(); + return res; +} + +// Sanity check: expected initial state. +assertArrayEquals(["baz", "bif"], enumerable(object), "enum0"); +assertFalse(delete object.foo, "delete foo"); +assertFalse(delete object.baz, "delete baz"); +assertEquals(func1, object.foo, "read foo"); +assertEquals(func1, object.bar, "read bar"); +assertEquals(func1, object.baz, "read baz"); +assertEquals(func2, object.bif, "read bif"); + +// Can't assign to READ_ONLY. +object.bar = "NO WAY"; +assertEquals(func1, object.bar, "read bar 2"); +assertArrayEquals(["baz", "bif"], enumerable(object), "enum1"); + +// Assignment to non-readonly. Assignment shouldn't change attributes! +object.foo = func2; +assertArrayEquals(["baz", "bif"], enumerable(object), "enum2"); +assertFalse(delete object.foo, "delete foo 2"); + +// Delete should erase attributes if value set again. +assertTrue(delete object.bar, "delete bar"); +assertFalse("bar" in object, "has bar"); +object.bar = func2; +assertTrue("bar" in object, "has bar 2"); +assertEquals(func2, object.bar, "read bar 3"); + +assertArrayEquals(["bar", "baz", "bif"], enumerable(object), "enum3"); + +// Unshadowing a prototype property exposes its attributes. +assertTrue(delete object.bif, "delete bif"); +assertArrayEquals(["bar", "baz"], enumerable(object), "enum4"); +assertEquals(func1, object.bif, "read bif 2"); +// Can't delete prototype property. +assertTrue(delete object.bif, "delete bif 2"); +assertArrayEquals(["bar", "baz"], enumerable(object), "enum5"); +assertEquals(func1, object.bif, "read bif3"); diff --git a/deps/v8/test/mjsunit/codegen_coverage.js b/deps/v8/test/mjsunit/codegen_coverage.js new file mode 100644 index 000000000..d5e7769d7 --- /dev/null +++ b/deps/v8/test/mjsunit/codegen_coverage.js @@ -0,0 +1,91 @@ +// Copyright 2009 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 the paths in the code generator where values in specific +// registers get moved around so that the shift operation can use +// register ECX on ia32 for the shift amount. Other codegen coverage +// tests should go here too. + + + +function identity(x) { + return x; +} + +function cover_codegen_paths() { + var x = 1; + var a; // Register EAX + var b; // Register EBX + var c; // Register ECX + var d; // Register EDX + // Register ESI is already used. + var di; // Register EDI + + while (x == 1) { + x = identity(1); + a = x + 1; + c = x + 1; + d = x + 1; + b = x + 1; + di = x + 1; + // Locals are in the corresponding registers here. + assertEquals(c << a, 8); + + x = identity(1); + a = x + 1; + c = x + 1; + d = x + 1; + b = x + 1; + di = x + 1; + // Locals are in the corresponding registers here. + assertEquals(a << c, 8); + + x = identity(1); + a = x + 1; + c = x + 1; + d = x + 1; + b = x + 1; + di = x + 1; + // Locals are in the corresponding registers here. + c = 0; // Free register ecx. + assertEquals(a << d, 8); + + x = identity(1); + a = x + 1; + c = x + 1; + d = x + 1; + b = x + 1; + di = x + 1; + // Locals are in the corresponding registers here. + b = 0; // Free register ebx. + assertEquals(a << d, 8); + + x = 3; + } +} + +cover_codegen_paths(); diff --git a/deps/v8/test/mjsunit/constant-folding.js b/deps/v8/test/mjsunit/constant-folding.js index 41b632f7f..4deb43cd3 100644 --- a/deps/v8/test/mjsunit/constant-folding.js +++ b/deps/v8/test/mjsunit/constant-folding.js @@ -168,4 +168,65 @@ function test() { assertEquals(17, j, "switch with constant value"); } + +function TrueToString() { + return true.toString(); +} + + +function FalseToString() { + return false.toString(); +} + + +function BoolTest() { + assertEquals("true", TrueToString()); + assertEquals("true", TrueToString()); + assertEquals("true", TrueToString()); + assertEquals("false", FalseToString()); + assertEquals("false", FalseToString()); + assertEquals("false", FalseToString()); + Boolean.prototype.toString = function() { return "foo"; } + assertEquals("foo", TrueToString()); + assertEquals("foo", FalseToString()); +} + + +// Some tests of shifts that get into the corners in terms of coverage. +// We generate different code for the case where the operand is a constant. +function ShiftTest() { + var x = 123; + assertEquals(x, x >> 0); + assertEquals(x, x << 0); + assertEquals(x, x >>> 0); + assertEquals(61, x >> 1); + assertEquals(246, x << 1); + assertEquals(61, x >>> 1); + x = -123; + assertEquals(x, x >> 0); + assertEquals(x, x << 0); + assertEquals(0x10000 * 0x10000 + x, x >>> 0); + assertEquals(-62, x >> 1); + assertEquals(-246, x << 1); + assertEquals(0x10000 * 0x8000 - 62, x >>> 1); + // Answer is non-Smi so the subtraction is not folded in the code + // generator. + assertEquals(-0x40000001, -0x3fffffff - 2); + + x = 123; + assertEquals(0, x & 0); + + // Answer is non-smi and lhs of << is a temporary heap number that we can + // overwrite. + x = 123.0001; + assertEquals(1073741824, (x * x) << 30); + x = 123; + // Answer is non-smi and lhs of << is a temporary heap number that we think + // we can overwrite (but we can't because it's a Smi). + assertEquals(1073741824, (x * x) << 30); +} + + test(); +BoolTest(); +ShiftTest(); diff --git a/deps/v8/test/mjsunit/debug-backtrace.js b/deps/v8/test/mjsunit/debug-backtrace.js index 940c4cb4b..f08f6390e 100644 --- a/deps/v8/test/mjsunit/debug-backtrace.js +++ b/deps/v8/test/mjsunit/debug-backtrace.js @@ -32,10 +32,14 @@ function f(x, y) { a=1; }; -function g() { +var m = function() { new f(1); }; +function g() { + m(); +}; + // Get the Debug object exposed from the debug context global object. Debug = debug.Debug @@ -90,22 +94,26 @@ function listener(event, exec_state, event_data, data) { // Get the backtrace. var json; json = '{"seq":0,"type":"request","command":"backtrace"}' - response = new ParsedResponse(dcp.processDebugJSONRequest(json)); + var resp = dcp.processDebugJSONRequest(json); + response = new ParsedResponse(resp); backtrace = response.body(); assertEquals(0, backtrace.fromFrame); - assertEquals(3, backtrace.toFrame); - assertEquals(3, backtrace.totalFrames); + assertEquals(4, backtrace.toFrame); + assertEquals(4, backtrace.totalFrames); var frames = backtrace.frames; - assertEquals(3, frames.length); + assertEquals(4, frames.length); for (var i = 0; i < frames.length; i++) { assertEquals('frame', frames[i].type); } assertEquals(0, frames[0].index); assertEquals("f", response.lookup(frames[0].func.ref).name); assertEquals(1, frames[1].index); - assertEquals("g", response.lookup(frames[1].func.ref).name); + assertEquals("", response.lookup(frames[1].func.ref).name); + assertEquals("m", response.lookup(frames[1].func.ref).inferredName); assertEquals(2, frames[2].index); - assertEquals("", response.lookup(frames[2].func.ref).name); + assertEquals("g", response.lookup(frames[2].func.ref).name); + assertEquals(3, frames[3].index); + assertEquals("", response.lookup(frames[3].func.ref).name); // Get backtrace with two frames. json = '{"seq":0,"type":"request","command":"backtrace","arguments":{"fromFrame":1,"toFrame":3}}' @@ -113,16 +121,17 @@ function listener(event, exec_state, event_data, data) { backtrace = response.body(); assertEquals(1, backtrace.fromFrame); assertEquals(3, backtrace.toFrame); - assertEquals(3, backtrace.totalFrames); + assertEquals(4, backtrace.totalFrames); var frames = backtrace.frames; assertEquals(2, frames.length); for (var i = 0; i < frames.length; i++) { assertEquals('frame', frames[i].type); } assertEquals(1, frames[0].index); - assertEquals("g", response.lookup(frames[0].func.ref).name); + assertEquals("", response.lookup(frames[0].func.ref).name); + assertEquals("m", response.lookup(frames[0].func.ref).inferredName); assertEquals(2, frames[1].index); - assertEquals("", response.lookup(frames[1].func.ref).name); + assertEquals("g", response.lookup(frames[1].func.ref).name); // Get the individual frames. json = '{"seq":0,"type":"request","command":"frame"}' @@ -158,16 +167,17 @@ function listener(event, exec_state, event_data, data) { response = new ParsedResponse(dcp.processDebugJSONRequest(json)); frame = response.body(); assertEquals(1, frame.index); - assertEquals("g", response.lookup(frame.func.ref).name); + assertEquals("", response.lookup(frame.func.ref).name); + assertEquals("m", response.lookup(frame.func.ref).inferredName); assertFalse(frame.constructCall); assertEquals(35, frame.line); assertEquals(2, frame.column); assertEquals(0, frame.arguments.length); - json = '{"seq":0,"type":"request","command":"frame","arguments":{"number":2}}' + json = '{"seq":0,"type":"request","command":"frame","arguments":{"number":3}}' response = new ParsedResponse(dcp.processDebugJSONRequest(json)); frame = response.body(); - assertEquals(2, frame.index); + assertEquals(3, frame.index); assertEquals("", response.lookup(frame.func.ref).name); // Source slices for the individual frames (they all refer to this script). diff --git a/deps/v8/test/mjsunit/debug-handle.js b/deps/v8/test/mjsunit/debug-handle.js index 64a68a86e..c7ab76af4 100644 --- a/deps/v8/test/mjsunit/debug-handle.js +++ b/deps/v8/test/mjsunit/debug-handle.js @@ -95,8 +95,8 @@ function listener(event, exec_state, event_data, data) { // Test some illegal lookup requests. lookupRequest(dcp, void 0, false); - lookupRequest(dcp, '{"handle":"a"}', false); - lookupRequest(dcp, '{"handle":-1}', false); + lookupRequest(dcp, '{"handles":["a"]}', false); + lookupRequest(dcp, '{"handles":[-1]}', false); // Evaluate and get some handles. var handle_o = evaluateRequest(dcp, '{"expression":"o"}'); @@ -109,24 +109,28 @@ function listener(event, exec_state, event_data, data) { var response; var count; - response = lookupRequest(dcp, '{"handle":' + handle_o + '}', true); - assertEquals(handle_o, response.body.handle); + response = lookupRequest(dcp, '{"handles":[' + handle_o + ']}', true); + var obj = response.body[handle_o]; + assertTrue(!!obj, 'Object not found: ' + handle_o); + assertEquals(handle_o, obj.handle); count = 0; - for (i in response.body.properties) { - switch (response.body.properties[i].name) { + for (i in obj.properties) { + switch (obj.properties[i].name) { case 'o': - response.body.properties[i].ref = handle_o; + obj.properties[i].ref = handle_o; count++; break; case 'p': - response.body.properties[i].ref = handle_p; + obj.properties[i].ref = handle_p; count++; break; } } assertEquals(2, count, 'Either "o" or "p" not found'); - response = lookupRequest(dcp, '{"handle":' + handle_p + '}', true); - assertEquals(handle_p, response.body.handle); + response = lookupRequest(dcp, '{"handles":[' + handle_p + ']}', true); + obj = response.body[handle_p]; + assertTrue(!!obj, 'Object not found: ' + handle_p); + assertEquals(handle_p, obj.handle); // Check handles for functions on the stack. var handle_f = evaluateRequest(dcp, '{"expression":"f"}'); @@ -136,28 +140,31 @@ function listener(event, exec_state, event_data, data) { assertFalse(handle_f == handle_g, "f and g have he same handle"); assertEquals(handle_g, handle_caller, "caller for f should be g"); - response = lookupRequest(dcp, '{"handle":' + handle_f + '}', true); - assertEquals(handle_f, response.body.handle); + response = lookupRequest(dcp, '{"handles":[' + handle_f + ']}', true); + obj = response.body[handle_f]; + assertEquals(handle_f, obj.handle); + count = 0; - for (i in response.body.properties) { - var arguments = '{"handle":' + response.body.properties[i].ref + '}' - switch (response.body.properties[i].name) { + for (i in obj.properties) { + var ref = obj.properties[i].ref; + var arguments = '{"handles":[' + ref + ']}'; + switch (obj.properties[i].name) { case 'name': var response_name; response_name = lookupRequest(dcp, arguments, true); - assertEquals('string', response_name.body.type); - assertEquals("f", response_name.body.value); + assertEquals('string', response_name.body[ref].type); + assertEquals("f", response_name.body[ref].value); count++; break; case 'length': var response_length; response_length = lookupRequest(dcp, arguments, true); - assertEquals('number', response_length.body.type); - assertEquals(1, response_length.body.value); + assertEquals('number', response_length.body[ref].type); + assertEquals(1, response_length.body[ref].value); count++; break; case 'caller': - assertEquals(handle_g, response.body.properties[i].ref); + assertEquals(handle_g, obj.properties[i].ref); count++; break; } @@ -165,6 +172,49 @@ function listener(event, exec_state, event_data, data) { assertEquals(3, count, 'Either "name", "length" or "caller" not found'); + // Resolve all at once. + var refs = []; + for (i in obj.properties) { + refs.push(obj.properties[i].ref); + } + + var arguments = '{"handles":[' + refs.join(',') + ']}'; + response = lookupRequest(dcp, arguments, true); + count = 0; + for (i in obj.properties) { + var ref = obj.properties[i].ref; + var val = response.body[ref]; + assertTrue(!!val, 'Failed to lookup "' + obj.properties[i].name + '"'); + switch (obj.properties[i].name) { + case 'name': + assertEquals('string', val.type); + assertEquals("f", val.value); + count++; + break; + case 'length': + assertEquals('number', val.type); + assertEquals(1, val.value); + count++; + break; + case 'caller': + assertEquals('function', val.type); + assertEquals(handle_g, ref); + count++; + break; + } + } + assertEquals(3, count, 'Either "name", "length" or "caller" not found'); + + count = 0; + for (var handle in response.body) { + assertTrue(refs.indexOf(parseInt(handle)) != -1, + 'Handle not in the request: ' + handle); + count++; + } + assertEquals(count, obj.properties.length, + 'Unexpected number of resolved objects'); + + // Indicate that all was processed. listenerComplete = true; } @@ -195,5 +245,5 @@ p.p = p; g(o); // Make sure that the debug event listener vas invoked. -assertTrue(listenerComplete, "listener did not run to completion"); +assertTrue(listenerComplete, "listener did not run to completion: " + exception); assertFalse(exception, "exception in listener") diff --git a/deps/v8/test/mjsunit/debug-setbreakpoint.js b/deps/v8/test/mjsunit/debug-setbreakpoint.js index 904ec187f..f8d9b157b 100644 --- a/deps/v8/test/mjsunit/debug-setbreakpoint.js +++ b/deps/v8/test/mjsunit/debug-setbreakpoint.js @@ -54,14 +54,14 @@ function testArguments(dcp, arguments, success, is_script) { var json_response = dcp.processDebugJSONRequest(request); var response = safeEval(json_response); if (success) { - assertTrue(response.success, json_response); + assertTrue(response.success, request + ' -> ' + json_response); if (is_script) { - assertEquals('scriptName', response.body.type, json_response); + assertEquals('scriptName', response.body.type, request + ' -> ' + json_response); } else { - assertEquals('scriptId', response.body.type, json_response); + assertEquals('scriptId', response.body.type, request + ' -> ' + json_response); } } else { - assertFalse(response.success, json_response); + assertFalse(response.success, request + ' -> ' + json_response); } } @@ -75,6 +75,8 @@ function listener(event, exec_state, event_data, data) { var request = '{' + base_request + '}' var response = safeEval(dcp.processDebugJSONRequest(request)); assertFalse(response.success); + + var mirror; testArguments(dcp, '{}', false); testArguments(dcp, '{"type":"xx"}', false); @@ -86,6 +88,9 @@ function listener(event, exec_state, event_data, data) { testArguments(dcp, '{"type":"function","target":"f","line":-1}', false); testArguments(dcp, '{"type":"function","target":"f","column":-1}', false); testArguments(dcp, '{"type":"function","target":"f","ignoreCount":-1}', false); + testArguments(dcp, '{"type":"handle","target":"-1"}', false); + mirror = debug.MakeMirror(o); + testArguments(dcp, '{"type":"handle","target":' + mirror.handle() + '}', false); // Test some legal setbreakpoint requests. testArguments(dcp, '{"type":"function","target":"f"}', true, false); @@ -106,6 +111,11 @@ function listener(event, exec_state, event_data, data) { testArguments(dcp, '{"type":"scriptId","target":' + g_script_id + ',"line":' + g_line + '}', true, false); testArguments(dcp, '{"type":"scriptId","target":' + h_script_id + ',"line":' + h_line + '}', true, false); + mirror = debug.MakeMirror(f); + testArguments(dcp, '{"type":"handle","target":' + mirror.handle() + '}', true, false); + mirror = debug.MakeMirror(o.a); + testArguments(dcp, '{"type":"handle","target":' + mirror.handle() + '}', true, false); + // Indicate that all was processed. listenerComplete = true; } @@ -127,6 +137,8 @@ function g() { eval('function h(){}'); +o = {a:function(){},b:function(){}} + // Check the script ids for the test functions. f_script_id = Debug.findScript(f).id; g_script_id = Debug.findScript(g).id; diff --git a/deps/v8/test/mjsunit/enumeration-order.js b/deps/v8/test/mjsunit/enumeration-order.js index 699a636cc..a328121d7 100644 --- a/deps/v8/test/mjsunit/enumeration-order.js +++ b/deps/v8/test/mjsunit/enumeration-order.js @@ -26,17 +26,17 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. function check_enumeration_order(obj) { - var value = 0; + var value = 0; for (var name in obj) assertTrue(value < obj[name]); value = obj[name]; } function make_object(size) { var a = new Object(); - + for (var i = 0; i < size; i++) a["a_" + i] = i + 1; check_enumeration_order(a); - + for (var i = 0; i < size; i +=3) delete a["a_" + i]; check_enumeration_order(a); } @@ -51,9 +51,59 @@ function make_literal_object(size) { code += "a_" + (size - 1) + " : " + size; code += " }"; eval("var a = " + code); - check_enumeration_order(a); + check_enumeration_order(a); } -// Validate the enumeration order for object literals up to 100 named properties. +// Validate the enumeration order for object literals up to 100 named +// properties. for (var j = 1; j< 100; j++) make_literal_object(j); +// We enumerate indexed properties in numerical order followed by +// named properties in insertion order, followed by indexed properties +// of the prototype object in numerical order, followed by named +// properties of the prototype object in insertion order, and so on. +// +// This enumeration order is not required by the specification, so +// this just documents our choice. +var proto2 = {}; +proto2[140000] = 0; +proto2.a = 0; +proto2[2] = 0; +proto2[3] = 0; // also on the 'proto1' object +proto2.b = 0; +proto2[4294967295] = 0; +proto2.c = 0; +proto2[4294967296] = 0; + +var proto1 = {}; +proto1[5] = 0; +proto1.d = 0; +proto1[3] = 0; +proto1.e = 0; +proto1.f = 0; // also on the 'o' object + +var o = {}; +o[-23] = 0; +o[300000000000] = 0; +o[23] = 0; +o.f = 0; +o.g = 0; +o[-4] = 0; +o[42] = 0; + +o.__proto__ = proto1; +proto1.__proto__ = proto2; + +var expected = ['23', '42', // indexed from 'o' + '-23', '300000000000', 'f', 'g', '-4', // named from 'o' + '3', '5', // indexed from 'proto1' + 'd', 'e', // named from 'proto1' + '2', '140000', '4294967295', // indexed from 'proto2' + 'a', 'b', 'c', '4294967296']; // named from 'proto2' +var actual = []; +for (var p in o) actual.push(p); +assertArrayEquals(expected, actual); + + + + diff --git a/deps/v8/test/mjsunit/eval-enclosing-function-name.js b/deps/v8/test/mjsunit/eval-enclosing-function-name.js new file mode 100644 index 000000000..422f03f37 --- /dev/null +++ b/deps/v8/test/mjsunit/eval-enclosing-function-name.js @@ -0,0 +1,76 @@ +// Copyright 2009 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. + +// From within 'eval', the name of the enclosing function should be +// visible. + +var f = function y() { return typeof y; }; +assertEquals("function", f()); + + +f = function y() { return eval('typeof y'); }; +assertEquals("function", f()); + + +f = function y() { y = 3; return typeof y; }; +assertEquals("function", f()); + + +f = function y() { y += 3; return typeof y; }; +assertEquals("function", f()); + + +f = function y() { y &= y; return typeof y; }; +assertEquals("function", f()); + + +f = function y() { y = 3; return eval('typeof y'); } +assertEquals("function", f()); + + +f = function y() { var y = 3; return typeof y; } +assertEquals("number", f()); + + +f = function y() { var y = 3; return eval('typeof y'); } +assertEquals("number", f()); + + +f = function y() { eval('y = 3'); return typeof y; } +assertEquals("function", f()); + + +f = function y() { eval('y = 3'); return eval('typeof y'); } +assertEquals("function", f()); + + +f = function y() { eval('var y = 3'); return typeof y; } +assertEquals("number", f()); + + +f = function y() { eval('var y = 3'); return eval('typeof y'); } +assertEquals("number", f()); diff --git a/deps/v8/test/mjsunit/json.js b/deps/v8/test/mjsunit/json.js new file mode 100644 index 000000000..47582643c --- /dev/null +++ b/deps/v8/test/mjsunit/json.js @@ -0,0 +1,197 @@ +// Copyright 2009 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. + +function GenericToJSONChecks(Constructor, value, alternative) { + var n1 = new Constructor(value); + n1.valueOf = function () { return alternative; }; + assertEquals(alternative, n1.toJSON()); + var n2 = new Constructor(value); + n2.valueOf = null; + assertThrows(function () { n2.toJSON(); }, TypeError); + var n3 = new Constructor(value); + n3.valueOf = function () { return {}; }; + assertThrows(function () { n3.toJSON(); }, TypeError, 'result_not_primitive'); + var n4 = new Constructor(value); + n4.valueOf = function () { + assertEquals(0, arguments.length); + assertEquals(this, n4); + return null; + }; + assertEquals(null, n4.toJSON()); +} + +// Number toJSON +assertEquals(3, (3).toJSON()); +assertEquals(3, (3).toJSON(true)); +assertEquals(4, (new Number(4)).toJSON()); +GenericToJSONChecks(Number, 5, 6); + +// Boolean toJSON +assertEquals(true, (true).toJSON()); +assertEquals(true, (true).toJSON(false)); +assertEquals(false, (false).toJSON()); +assertEquals(true, (new Boolean(true)).toJSON()); +GenericToJSONChecks(Boolean, true, false); +GenericToJSONChecks(Boolean, false, true); + +// String toJSON +assertEquals("flot", "flot".toJSON()); +assertEquals("flot", "flot".toJSON(3)); +assertEquals("tolf", (new String("tolf")).toJSON()); +GenericToJSONChecks(String, "x", "y"); + +// Date toJSON +assertEquals("1970-01-01T00:00:00Z", new Date(0).toJSON()); +assertEquals("1979-01-11T08:00:00Z", new Date("1979-01-11 08:00 GMT").toJSON()); +assertEquals("2005-05-05T05:05:05Z", new Date("2005-05-05 05:05:05 GMT").toJSON()); +var n1 = new Date(10000); +n1.toISOString = function () { return "foo"; }; +assertEquals("foo", n1.toJSON()); +var n2 = new Date(10001); +n2.toISOString = null; +assertThrows(function () { n2.toJSON(); }, TypeError); +var n3 = new Date(10002); +n3.toISOString = function () { return {}; }; +assertThrows(function () { n3.toJSON(); }, TypeError, "result_not_primitive"); +var n4 = new Date(10003); +n4.toISOString = function () { + assertEquals(0, arguments.length); + assertEquals(this, n4); + return null; +}; +assertEquals(null, n4.toJSON()); + +assertEquals(Object.prototype, JSON.__proto__); +assertEquals("[object JSON]", Object.prototype.toString.call(JSON)); + +// DontEnum +for (var p in this) + assertFalse(p == "JSON"); + +// Parse + +assertEquals({}, JSON.parse("{}")); +assertEquals(null, JSON.parse("null")); +assertEquals(true, JSON.parse("true")); +assertEquals(false, JSON.parse("false")); +assertEquals("foo", JSON.parse('"foo"')); +assertEquals("f\no", JSON.parse('"f\\no"')); +assertEquals(1.1, JSON.parse("1.1")); +assertEquals(1, JSON.parse("1.0")); +assertEquals(0.0000000003, JSON.parse("3e-10")); +assertEquals([], JSON.parse("[]")); +assertEquals([1], JSON.parse("[1]")); +assertEquals([1, "2", true, null], JSON.parse('[1, "2", true, null]')); + +function GetFilter(name) { + function Filter(key, value) { + return (key == name) ? undefined : value; + } + return Filter; +} + +var pointJson = '{"x": 1, "y": 2}'; +assertEquals({'x': 1, 'y': 2}, JSON.parse(pointJson)); +assertEquals({'x': 1}, JSON.parse(pointJson, GetFilter('y'))); +assertEquals({'y': 2}, JSON.parse(pointJson, GetFilter('x'))); +assertEquals([1, 2, 3], JSON.parse("[1, 2, 3]")); +assertEquals([1, undefined, 3], JSON.parse("[1, 2, 3]", GetFilter(1))); +assertEquals([1, 2, undefined], JSON.parse("[1, 2, 3]", GetFilter(2))); + +function DoubleNumbers(key, value) { + return (typeof value == 'number') ? 2 * value : value; +} + +var deepObject = '{"a": {"b": 1, "c": 2}, "d": {"e": {"f": 3}}}'; +assertEquals({"a": {"b": 1, "c": 2}, "d": {"e": {"f": 3}}}, + JSON.parse(deepObject)); +assertEquals({"a": {"b": 2, "c": 4}, "d": {"e": {"f": 6}}}, + JSON.parse(deepObject, DoubleNumbers)); + +function TestInvalid(str) { + assertThrows(function () { JSON.parse(str); }, SyntaxError); +} + +TestInvalid('abcdef'); +TestInvalid('isNaN()'); +TestInvalid('{"x": [1, 2, deepObject]}'); +TestInvalid('[1, [2, [deepObject], 3], 4]'); +TestInvalid('function () { return 0; }'); + +TestInvalid("[1, 2"); +TestInvalid('{"x": 3'); + +// Stringify + +assertEquals("true", JSON.stringify(true)); +assertEquals("false", JSON.stringify(false)); +assertEquals("null", JSON.stringify(null)); +assertEquals("false", JSON.stringify({toJSON: function () { return false; }})); +assertEquals("4", JSON.stringify(4)); +assertEquals('"foo"', JSON.stringify("foo")); +assertEquals("null", JSON.stringify(Infinity)); +assertEquals("null", JSON.stringify(-Infinity)); +assertEquals("null", JSON.stringify(NaN)); +assertEquals("4", JSON.stringify(new Number(4))); +assertEquals('"bar"', JSON.stringify(new String("bar"))); + +assertEquals('"foo\\u0000bar"', JSON.stringify("foo\0bar")); +assertEquals('"f\\"o\'o\\\\b\\ba\\fr\\nb\\ra\\tz"', + JSON.stringify("f\"o\'o\\b\ba\fr\nb\ra\tz")); + +assertEquals("[1,2,3]", JSON.stringify([1, 2, 3])); +assertEquals("[\n 1,\n 2,\n 3\n]", JSON.stringify([1, 2, 3], null, 1)); +assertEquals("[\n 1,\n 2,\n 3\n]", JSON.stringify([1, 2, 3], null, 2)); +assertEquals("[\n 1,\n 2,\n 3\n]", + JSON.stringify([1, 2, 3], null, new Number(2))); +assertEquals("[\n^1,\n^2,\n^3\n]", JSON.stringify([1, 2, 3], null, "^")); +assertEquals("[\n^1,\n^2,\n^3\n]", + JSON.stringify([1, 2, 3], null, new String("^"))); +assertEquals("[\n 1,\n 2,\n [\n 3,\n [\n 4\n ],\n 5\n ],\n 6,\n 7\n]", + JSON.stringify([1, 2, [3, [4], 5], 6, 7], null, 1)); +assertEquals("[]", JSON.stringify([], null, 1)); +assertEquals("[1,2,[3,[4],5],6,7]", + JSON.stringify([1, 2, [3, [4], 5], 6, 7], null)); +assertEquals("[2,4,[6,[8],10],12,14]", + JSON.stringify([1, 2, [3, [4], 5], 6, 7], DoubleNumbers)); + +var circular = [1, 2, 3]; +circular[2] = circular; +assertThrows(function () { JSON.stringify(circular); }, TypeError); + +var singleton = []; +var multiOccurrence = [singleton, singleton, singleton]; +assertEquals("[[],[],[]]", JSON.stringify(multiOccurrence)); + +assertEquals('{"x":5,"y":6}', JSON.stringify({x:5,y:6})); +assertEquals('{"x":5}', JSON.stringify({x:5,y:6}, ['x'])); +assertEquals('{\n "a": "b",\n "c": "d"\n}', + JSON.stringify({a:"b",c:"d"}, null, 1)); +assertEquals('{"y":6,"x":5}', JSON.stringify({x:5,y:6}, ['y', 'x'])); + +assertEquals(undefined, JSON.stringify(undefined)); +assertEquals(undefined, JSON.stringify(function () { })); diff --git a/deps/v8/test/mjsunit/keyed-ic.js b/deps/v8/test/mjsunit/keyed-ic.js index d37bd034c..a6726ed49 100644 --- a/deps/v8/test/mjsunit/keyed-ic.js +++ b/deps/v8/test/mjsunit/keyed-ic.js @@ -145,6 +145,35 @@ runTest(); // ---------------------------------------------------------------------- +// Indexed access. +// ---------------------------------------------------------------------- +runTest = function() { + var o = [ 42, 43 ]; + + var initial_X = 0; + var X = initial_X; + var Y = 1; + + function fieldTest(change_index) { + for (var i = 0; i < 10; i++) { + var property = o[X]; + if (i <= change_index) { + assertEquals(42, property); + } else { + assertEquals(43, property); + } + if (i == change_index) X = Y; + } + X = initial_X; + }; + + for (var i = 0; i < 10; i++) fieldTest(i); +} + +runTest(); + + +// ---------------------------------------------------------------------- // Constant function access. // ---------------------------------------------------------------------- runTest = function() { diff --git a/deps/v8/test/mjsunit/mirror-unresolved-function.js b/deps/v8/test/mjsunit/mirror-unresolved-function.js index 21d0e561b..8d8ca37f8 100644 --- a/deps/v8/test/mjsunit/mirror-unresolved-function.js +++ b/deps/v8/test/mjsunit/mirror-unresolved-function.js @@ -57,6 +57,7 @@ assertEquals('function', mirror.type()); assertFalse(mirror.isPrimitive()); assertEquals("Function", mirror.className()); assertEquals("f", mirror.name()); +assertEquals('undefined', typeof mirror.inferredName()); assertFalse(mirror.resolved()); assertEquals(void 0, mirror.source()); assertEquals('undefined', mirror.constructorFunction().type()); @@ -75,4 +76,5 @@ assertEquals(mirror.prototypeObject().handle(), fromJSON.prototypeObject.ref, 'U assertEquals('undefined', refs.lookup(fromJSON.prototypeObject.ref).type, 'Unexpected prototype object type in JSON'); assertFalse(fromJSON.resolved); assertEquals("f", fromJSON.name); +assertFalse('inferredName' in fromJSON); assertEquals(void 0, fromJSON.source); diff --git a/deps/v8/test/mjsunit/mjsunit.js b/deps/v8/test/mjsunit/mjsunit.js index 3570d689c..2c52a31e6 100644 --- a/deps/v8/test/mjsunit/mjsunit.js +++ b/deps/v8/test/mjsunit/mjsunit.js @@ -51,8 +51,30 @@ function fail(expected, found, name_opt) { } +function deepObjectEquals(a, b) { + var aProps = []; + for (var key in a) + aProps.push(key); + var bProps = []; + for (var key in b) + bProps.push(key); + aProps.sort(); + bProps.sort(); + if (!deepEquals(aProps, bProps)) + return false; + for (var i = 0; i < aProps.length; i++) { + if (!deepEquals(a[aProps[i]], b[aProps[i]])) + return false; + } + return true; +} + + function deepEquals(a, b) { if (a == b) return true; + if (typeof a == "number" && typeof b == "number" && isNaN(a) && isNaN(b)) { + return true; + } if ((typeof a) !== 'object' || (typeof b) !== 'object' || (a === null) || (b === null)) return false; @@ -70,8 +92,9 @@ function deepEquals(a, b) { } } return true; + } else { + return deepObjectEquals(a, b); } - return false; } @@ -113,12 +136,34 @@ function assertNaN(value, name_opt) { } -function assertThrows(code) { +function assertNull(value, name_opt) { + if (value !== null) { + fail("null", value, name_opt); + } +} + + +function assertNotNull(value, name_opt) { + if (value === null) { + fail("not null", value, name_opt); + } +} + + +function assertThrows(code, type_opt, cause_opt) { var threwException = true; try { - eval(code); + if (typeof code == 'function') { + code(); + } else { + eval(code); + } threwException = false; } catch (e) { + if (typeof type_opt == 'function') + assertInstanceof(e, type_opt); + if (arguments.length >= 3) + assertEquals(e.type, cause_opt); // Do nothing. } if (!threwException) assertTrue(false, "did not throw exception"); diff --git a/deps/v8/test/mjsunit/mjsunit.status b/deps/v8/test/mjsunit/mjsunit.status index 5a7607872..4bb7c1652 100644 --- a/deps/v8/test/mjsunit/mjsunit.status +++ b/deps/v8/test/mjsunit/mjsunit.status @@ -48,19 +48,19 @@ unicode-test: PASS, (PASS || FAIL) if $mode == debug # Bug number 1020483: Debug tests fail on ARM. debug-constructor: CRASH, FAIL debug-continue: SKIP -debug-evaluate-recursive: CRASH, FAIL if $mode == debug -debug-changebreakpoint: CRASH, FAIL if $mode == debug -debug-clearbreakpoint: CRASH, FAIL if $mode == debug -debug-conditional-breakpoints: CRASH, FAIL if $mode == debug -debug-evaluate: CRASH, FAIL if $mode == debug -debug-ignore-breakpoints: CRASH, FAIL if $mode == debug -debug-multiple-breakpoints: CRASH, FAIL if $mode == debug -debug-setbreakpoint: CRASH, FAIL if $mode == debug +debug-evaluate-recursive: CRASH || FAIL +debug-changebreakpoint: CRASH || FAIL +debug-clearbreakpoint: CRASH || FAIL +debug-conditional-breakpoints: FAIL +debug-evaluate: CRASH || FAIL +debug-ignore-breakpoints: CRASH || FAIL +debug-multiple-breakpoints: CRASH || FAIL +debug-setbreakpoint: CRASH || FAIL || PASS debug-step-stub-callfunction: SKIP debug-stepin-constructor: CRASH, FAIL debug-step: SKIP debug-breakpoints: PASS || FAIL -debug-handle: CRASH, FAIL if $mode == debug +debug-handle: CRASH || FAIL || PASS regress/regress-269: SKIP # Bug number 130 http://code.google.com/p/v8/issues/detail?id=130 diff --git a/deps/v8/test/mjsunit/negate.js b/deps/v8/test/mjsunit/negate.js index 3bf411156..70daf2435 100644 --- a/deps/v8/test/mjsunit/negate.js +++ b/deps/v8/test/mjsunit/negate.js @@ -30,9 +30,9 @@ const SMI_MIN = -(1 << 30); function testmulneg(a, b) { var base = a * b; - assertEquals(-base, a * -b); - assertEquals(-base, -a * b); - assertEquals(base, -a * -b); + assertEquals(-base, a * -b, "a * -b where a = " + a + ", b = " + b); + assertEquals(-base, -a * b, "-a * b where a = " + a + ", b = " + b); + assertEquals(base, -a * -b, "*-a * -b where a = " + a + ", b = " + b); } testmulneg(2, 3); diff --git a/deps/v8/test/mjsunit/number-limits.js b/deps/v8/test/mjsunit/number-limits.js index 1d9a1e558..99ed4e1b4 100644 --- a/deps/v8/test/mjsunit/number-limits.js +++ b/deps/v8/test/mjsunit/number-limits.js @@ -33,10 +33,14 @@ function testLimits() { var addAboveMax = Number.MAX_VALUE + 1/eps; var mulBelowMin = Number.MIN_VALUE * (1 - eps); var addBelowMin = Number.MIN_VALUE - eps; - assertTrue(mulAboveMax == Number.MAX_VALUE || mulAboveMax == Infinity); - assertTrue(addAboveMax == Number.MAX_VALUE || addAboveMax == Infinity); - assertTrue(mulBelowMin == Number.MIN_VALUE || mulBelowMin <= 0); - assertTrue(addBelowMin == Number.MIN_VALUE || addBelowMin <= 0); + assertTrue(mulAboveMax == Number.MAX_VALUE || + mulAboveMax == Infinity, "mul" + i); + assertTrue(addAboveMax == Number.MAX_VALUE || + addAboveMax == Infinity, "add" + i); + assertTrue(mulBelowMin == Number.MIN_VALUE || + mulBelowMin <= 0, "mul2" + i); + assertTrue(addBelowMin == Number.MIN_VALUE || + addBelowMin <= 0, "add2" + i); } } diff --git a/deps/v8/test/mjsunit/receiver-in-with-calls.js b/deps/v8/test/mjsunit/receiver-in-with-calls.js new file mode 100644 index 000000000..5f2bdac20 --- /dev/null +++ b/deps/v8/test/mjsunit/receiver-in-with-calls.js @@ -0,0 +1,47 @@ +// Copyright 2009 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. + +// When invoking functions from within a 'with' statement, we must set +// the receiver to the object where we found the function. + +(function () { + var x = { get_this: function() { return this; } }; + assertTrue(x === x.get_this()); + with (x) assertTrue(x === get_this()); +})(); + + +assertTrue({ f: function() { + function g() { return this; }; + return eval("g")(); +} }.f() == this); + + +assertTrue({ f: function() { + function g() { return this; }; + return eval("g()"); +} }.f() == this); diff --git a/deps/v8/test/mjsunit/regexp-multiline-stack-trace.js b/deps/v8/test/mjsunit/regexp-multiline-stack-trace.js index aa2de8875..fc248ef6a 100644 --- a/deps/v8/test/mjsunit/regexp-multiline-stack-trace.js +++ b/deps/v8/test/mjsunit/regexp-multiline-stack-trace.js @@ -25,6 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// The flags below are to test the trace-calls functionality and the +// preallocated meessage memory. // Flags: --trace-calls --preallocate-message-memory /** diff --git a/deps/v8/test/mjsunit/regress/regress-318.js b/deps/v8/test/mjsunit/regress/regress-318.js index 9e00b5fba..e94f1cba1 100644 --- a/deps/v8/test/mjsunit/regress/regress-318.js +++ b/deps/v8/test/mjsunit/regress/regress-318.js @@ -25,11 +25,11 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Should not raise an exception. +// Should not crash or raise an exception. function test(value) { if (typeof(value) == 'boolean') value = value + ''; if (typeof(value) == 'number') value = value + ''; } -assertDoesNotThrow(test(0)); +assertDoesNotThrow('test(0)'); diff --git a/deps/v8/test/mjsunit/regress/regress-326.js b/deps/v8/test/mjsunit/regress/regress-326.js new file mode 100644 index 000000000..fcd102e13 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-326.js @@ -0,0 +1,40 @@ +// Copyright 2009 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. + +// Should not crash or raise an exception. +// Should sort non-array into equivalent of [37,42,undefined,,0] + +var nonArray = { length: 4, 0: 42, 2: 37, 3: undefined, 4: 0 }; +Array.prototype.sort.call(nonArray); + +assertEquals(4, nonArray.length, "preserve length"); +assertEquals(37, nonArray[0], "sort smallest first"); +assertEquals(42, nonArray[1], "sort largest last"); +assertTrue(2 in nonArray, "don't delete undefined"); +assertEquals(undefined, nonArray[2], "sort undefined after largest"); +assertFalse(3 in nonArray, "don't create non-existing"); +assertEquals(0, nonArray[4], "don't affect after length."); diff --git a/deps/v8/test/mjsunit/smi-ops.js b/deps/v8/test/mjsunit/smi-ops.js index bdd7509c9..7e571369b 100644 --- a/deps/v8/test/mjsunit/smi-ops.js +++ b/deps/v8/test/mjsunit/smi-ops.js @@ -34,7 +34,7 @@ const OBJ_42 = new (function() { this.valueOf = function() { return 42; }; })(); -assertEquals(42, OBJ_42.valueOf()); +assertEquals(42, OBJ_42.valueOf()); function Add1(x) { @@ -100,3 +100,488 @@ assertEquals(SMI_MIN - ONE_HUNDRED, Sub100(SMI_MIN)); // overflow assertEquals(ONE_HUNDRED - SMI_MIN, Sub100Reversed(SMI_MIN)); // overflow assertEquals(42 - ONE_HUNDRED, Sub100(OBJ_42)); // non-smi assertEquals(ONE_HUNDRED - 42, Sub100Reversed(OBJ_42)); // non-smi + + +function Shr1(x) { + return x >>> 1; +} + +function Shr100(x) { + return x >>> 100; +} + +function Shr1Reversed(x) { + return 1 >>> x; +} + +function Shr100Reversed(x) { + return 100 >>> x; +} + +function Sar1(x) { + return x >> 1; +} + +function Sar100(x) { + return x >> 100; +} + +function Sar1Reversed(x) { + return 1 >> x; +} + +function Sar100Reversed(x) { + return 100 >> x; +} + + +assertEquals(0, Shr1(1)); +assertEquals(0, Sar1(1)); +assertEquals(0, Shr1Reversed(2)); +assertEquals(0, Sar1Reversed(2)); +assertEquals(1610612736, Shr1(SMI_MIN)); +assertEquals(-536870912, Sar1(SMI_MIN)); +assertEquals(1, Shr1Reversed(SMI_MIN)); +assertEquals(1, Sar1Reversed(SMI_MIN)); +assertEquals(21, Shr1(OBJ_42)); +assertEquals(21, Sar1(OBJ_42)); +assertEquals(0, Shr1Reversed(OBJ_42)); +assertEquals(0, Sar1Reversed(OBJ_42)); + +assertEquals(6, Shr100(100)); +assertEquals(6, Sar100(100)); +assertEquals(12, Shr100Reversed(99)); +assertEquals(12, Sar100Reversed(99)); +assertEquals(201326592, Shr100(SMI_MIN)); +assertEquals(-67108864, Sar100(SMI_MIN)); +assertEquals(100, Shr100Reversed(SMI_MIN)); +assertEquals(100, Sar100Reversed(SMI_MIN)); +assertEquals(2, Shr100(OBJ_42)); +assertEquals(2, Sar100(OBJ_42)); +assertEquals(0, Shr100Reversed(OBJ_42)); +assertEquals(0, Sar100Reversed(OBJ_42)); + + +function Xor1(x) { + return x ^ 1; +} + +function Xor100(x) { + return x ^ 100; +} + +function Xor1Reversed(x) { + return 1 ^ x; +} + +function Xor100Reversed(x) { + return 100 ^ x; +} + + +assertEquals(0, Xor1(1)); +assertEquals(3, Xor1Reversed(2)); +assertEquals(SMI_MIN + 1, Xor1(SMI_MIN)); +assertEquals(SMI_MIN + 1, Xor1Reversed(SMI_MIN)); +assertEquals(43, Xor1(OBJ_42)); +assertEquals(43, Xor1Reversed(OBJ_42)); + +assertEquals(0, Xor100(100)); +assertEquals(7, Xor100Reversed(99)); +assertEquals(-1073741724, Xor100(SMI_MIN)); +assertEquals(-1073741724, Xor100Reversed(SMI_MIN)); +assertEquals(78, Xor100(OBJ_42)); +assertEquals(78, Xor100Reversed(OBJ_42)); + +var x = 0x23; var y = 0x35; +assertEquals(0x16, x ^ y); + +// Test shift operators on non-smi inputs, giving smi and non-smi results. +function testShiftNonSmis() { + var pos_non_smi = 2000000000; + var neg_non_smi = -pos_non_smi; + var pos_smi = 1000000000; + var neg_smi = -pos_smi; + + // Begin block A + assertEquals(pos_non_smi, (pos_non_smi) >> 0); + assertEquals(pos_non_smi, (pos_non_smi) >>> 0); + assertEquals(pos_non_smi, (pos_non_smi) << 0); + assertEquals(neg_non_smi, (neg_non_smi) >> 0); + assertEquals(neg_non_smi + 0x100000000, (neg_non_smi) >>> 0); + assertEquals(neg_non_smi, (neg_non_smi) << 0); + assertEquals(pos_smi, (pos_smi) >> 0); + assertEquals(pos_smi, (pos_smi) >>> 0); + assertEquals(pos_smi, (pos_smi) << 0); + assertEquals(neg_smi, (neg_smi) >> 0); + assertEquals(neg_smi + 0x100000000, (neg_smi) >>> 0); + assertEquals(neg_smi, (neg_smi) << 0); + + assertEquals(pos_non_smi / 2, (pos_non_smi) >> 1); + assertEquals(pos_non_smi / 2, (pos_non_smi) >>> 1); + assertEquals(-0x1194D800, (pos_non_smi) << 1); + assertEquals(pos_non_smi / 8, (pos_non_smi) >> 3); + assertEquals(pos_non_smi / 8, (pos_non_smi) >>> 3); + assertEquals(-0x46536000, (pos_non_smi) << 3); + assertEquals(0x73594000, (pos_non_smi) << 4); + assertEquals(pos_non_smi, (pos_non_smi + 0.5) >> 0); + assertEquals(pos_non_smi, (pos_non_smi + 0.5) >>> 0); + assertEquals(pos_non_smi, (pos_non_smi + 0.5) << 0); + assertEquals(pos_non_smi / 2, (pos_non_smi + 0.5) >> 1); + assertEquals(pos_non_smi / 2, (pos_non_smi + 0.5) >>> 1); + assertEquals(-0x1194D800, (pos_non_smi + 0.5) << 1); + assertEquals(pos_non_smi / 8, (pos_non_smi + 0.5) >> 3); + assertEquals(pos_non_smi / 8, (pos_non_smi + 0.5) >>> 3); + assertEquals(-0x46536000, (pos_non_smi + 0.5) << 3); + assertEquals(0x73594000, (pos_non_smi + 0.5) << 4); + + assertEquals(neg_non_smi / 2, (neg_non_smi) >> 1); + assertEquals(neg_non_smi / 2 + 0x100000000 / 2, (neg_non_smi) >>> 1); + assertEquals(0x1194D800, (neg_non_smi) << 1); + assertEquals(neg_non_smi / 8, (neg_non_smi) >> 3); + assertEquals(neg_non_smi / 8 + 0x100000000 / 8, (neg_non_smi) >>> 3); + assertEquals(0x46536000, (neg_non_smi) << 3); + assertEquals(-0x73594000, (neg_non_smi) << 4); + assertEquals(neg_non_smi, (neg_non_smi - 0.5) >> 0); + assertEquals(neg_non_smi + 0x100000000, (neg_non_smi - 0.5) >>> 0); + assertEquals(neg_non_smi, (neg_non_smi - 0.5) << 0); + assertEquals(neg_non_smi / 2, (neg_non_smi - 0.5) >> 1); + assertEquals(neg_non_smi / 2 + 0x100000000 / 2, (neg_non_smi - 0.5) >>> 1); + assertEquals(0x1194D800, (neg_non_smi - 0.5) << 1); + assertEquals(neg_non_smi / 8, (neg_non_smi - 0.5) >> 3); + assertEquals(neg_non_smi / 8 + 0x100000000 / 8, (neg_non_smi - 0.5) >>> 3); + assertEquals(0x46536000, (neg_non_smi - 0.5) << 3); + assertEquals(-0x73594000, (neg_non_smi - 0.5) << 4); + + assertEquals(pos_smi / 2, (pos_smi) >> 1); + assertEquals(pos_smi / 2, (pos_smi) >>> 1); + assertEquals(pos_non_smi, (pos_smi) << 1); + assertEquals(pos_smi / 8, (pos_smi) >> 3); + assertEquals(pos_smi / 8, (pos_smi) >>> 3); + assertEquals(-0x2329b000, (pos_smi) << 3); + assertEquals(0x73594000, (pos_smi) << 5); + assertEquals(pos_smi, (pos_smi + 0.5) >> 0); + assertEquals(pos_smi, (pos_smi + 0.5) >>> 0); + assertEquals(pos_smi, (pos_smi + 0.5) << 0); + assertEquals(pos_smi / 2, (pos_smi + 0.5) >> 1); + assertEquals(pos_smi / 2, (pos_smi + 0.5) >>> 1); + assertEquals(pos_non_smi, (pos_smi + 0.5) << 1); + assertEquals(pos_smi / 8, (pos_smi + 0.5) >> 3); + assertEquals(pos_smi / 8, (pos_smi + 0.5) >>> 3); + assertEquals(-0x2329b000, (pos_smi + 0.5) << 3); + assertEquals(0x73594000, (pos_smi + 0.5) << 5); + + assertEquals(neg_smi / 2, (neg_smi) >> 1); + assertEquals(neg_smi / 2 + 0x100000000 / 2, (neg_smi) >>> 1); + assertEquals(neg_non_smi, (neg_smi) << 1); + assertEquals(neg_smi / 8, (neg_smi) >> 3); + assertEquals(neg_smi / 8 + 0x100000000 / 8, (neg_smi) >>> 3); + assertEquals(0x46536000, (neg_smi) << 4); + assertEquals(-0x73594000, (neg_smi) << 5); + assertEquals(neg_smi, (neg_smi - 0.5) >> 0); + assertEquals(neg_smi + 0x100000000, (neg_smi - 0.5) >>> 0); + assertEquals(neg_smi, (neg_smi - 0.5) << 0); + assertEquals(neg_smi / 2, (neg_smi - 0.5) >> 1); + assertEquals(neg_smi / 2 + 0x100000000 / 2, (neg_smi - 0.5) >>> 1); + assertEquals(neg_non_smi, (neg_smi - 0.5) << 1); + assertEquals(neg_smi / 8, (neg_smi - 0.5) >> 3); + assertEquals(neg_smi / 8 + 0x100000000 / 8, (neg_smi - 0.5) >>> 3); + assertEquals(0x46536000, (neg_smi - 0.5) << 4); + assertEquals(-0x73594000, (neg_smi - 0.5) << 5); + // End block A + + // Repeat block A with 2^32 added to positive numbers and + // 2^32 subtracted from negative numbers. + // Begin block A repeat 1 + var two_32 = 0x100000000; + var neg_32 = -two_32; + assertEquals(pos_non_smi, (two_32 + pos_non_smi) >> 0); + assertEquals(pos_non_smi, (two_32 + pos_non_smi) >>> 0); + assertEquals(pos_non_smi, (two_32 + pos_non_smi) << 0); + assertEquals(neg_non_smi, (neg_32 + neg_non_smi) >> 0); + assertEquals(neg_non_smi + 0x100000000, (neg_32 + neg_non_smi) >>> 0); + assertEquals(neg_non_smi, (neg_32 + neg_non_smi) << 0); + assertEquals(pos_smi, (two_32 + pos_smi) >> 0); + assertEquals(pos_smi, (two_32 + pos_smi) >>> 0); + assertEquals(pos_smi, (two_32 + pos_smi) << 0); + assertEquals(neg_smi, (neg_32 + neg_smi) >> 0); + assertEquals(neg_smi + 0x100000000, (neg_32 + neg_smi) >>> 0); + assertEquals(neg_smi, (neg_32 + neg_smi) << 0); + + assertEquals(pos_non_smi / 2, (two_32 + pos_non_smi) >> 1); + assertEquals(pos_non_smi / 2, (two_32 + pos_non_smi) >>> 1); + assertEquals(-0x1194D800, (two_32 + pos_non_smi) << 1); + assertEquals(pos_non_smi / 8, (two_32 + pos_non_smi) >> 3); + assertEquals(pos_non_smi / 8, (two_32 + pos_non_smi) >>> 3); + assertEquals(-0x46536000, (two_32 + pos_non_smi) << 3); + assertEquals(0x73594000, (two_32 + pos_non_smi) << 4); + assertEquals(pos_non_smi, (two_32 + pos_non_smi + 0.5) >> 0); + assertEquals(pos_non_smi, (two_32 + pos_non_smi + 0.5) >>> 0); + assertEquals(pos_non_smi, (two_32 + pos_non_smi + 0.5) << 0); + assertEquals(pos_non_smi / 2, (two_32 + pos_non_smi + 0.5) >> 1); + assertEquals(pos_non_smi / 2, (two_32 + pos_non_smi + 0.5) >>> 1); + assertEquals(-0x1194D800, (two_32 + pos_non_smi + 0.5) << 1); + assertEquals(pos_non_smi / 8, (two_32 + pos_non_smi + 0.5) >> 3); + assertEquals(pos_non_smi / 8, (two_32 + pos_non_smi + 0.5) >>> 3); + assertEquals(-0x46536000, (two_32 + pos_non_smi + 0.5) << 3); + assertEquals(0x73594000, (two_32 + pos_non_smi + 0.5) << 4); + + assertEquals(neg_non_smi / 2, (neg_32 + neg_non_smi) >> 1); + assertEquals(neg_non_smi / 2 + 0x100000000 / 2, (neg_32 + neg_non_smi) >>> 1); + assertEquals(0x1194D800, (neg_32 + neg_non_smi) << 1); + assertEquals(neg_non_smi / 8, (neg_32 + neg_non_smi) >> 3); + assertEquals(neg_non_smi / 8 + 0x100000000 / 8, (neg_32 + neg_non_smi) >>> 3); + assertEquals(0x46536000, (neg_32 + neg_non_smi) << 3); + assertEquals(-0x73594000, (neg_32 + neg_non_smi) << 4); + assertEquals(neg_non_smi, (neg_32 + neg_non_smi - 0.5) >> 0); + assertEquals(neg_non_smi + 0x100000000, (neg_32 + neg_non_smi - 0.5) >>> 0); + assertEquals(neg_non_smi, (neg_32 + neg_non_smi - 0.5) << 0); + assertEquals(neg_non_smi / 2, (neg_32 + neg_non_smi - 0.5) >> 1); + assertEquals(neg_non_smi / 2 + 0x100000000 / 2, (neg_32 + neg_non_smi - 0.5) + >>> 1); + assertEquals(0x1194D800, (neg_32 + neg_non_smi - 0.5) << 1); + assertEquals(neg_non_smi / 8, (neg_32 + neg_non_smi - 0.5) >> 3); + assertEquals(neg_non_smi / 8 + 0x100000000 / 8, (neg_32 + neg_non_smi - 0.5) + >>> 3); + assertEquals(0x46536000, (neg_32 + neg_non_smi - 0.5) << 3); + assertEquals(-0x73594000, (neg_32 + neg_non_smi - 0.5) << 4); + + assertEquals(pos_smi / 2, (two_32 + pos_smi) >> 1); + assertEquals(pos_smi / 2, (two_32 + pos_smi) >>> 1); + assertEquals(pos_non_smi, (two_32 + pos_smi) << 1); + assertEquals(pos_smi / 8, (two_32 + pos_smi) >> 3); + assertEquals(pos_smi / 8, (two_32 + pos_smi) >>> 3); + assertEquals(-0x2329b000, (two_32 + pos_smi) << 3); + assertEquals(0x73594000, (two_32 + pos_smi) << 5); + assertEquals(pos_smi, (two_32 + pos_smi + 0.5) >> 0); + assertEquals(pos_smi, (two_32 + pos_smi + 0.5) >>> 0); + assertEquals(pos_smi, (two_32 + pos_smi + 0.5) << 0); + assertEquals(pos_smi / 2, (two_32 + pos_smi + 0.5) >> 1); + assertEquals(pos_smi / 2, (two_32 + pos_smi + 0.5) >>> 1); + assertEquals(pos_non_smi, (two_32 + pos_smi + 0.5) << 1); + assertEquals(pos_smi / 8, (two_32 + pos_smi + 0.5) >> 3); + assertEquals(pos_smi / 8, (two_32 + pos_smi + 0.5) >>> 3); + assertEquals(-0x2329b000, (two_32 + pos_smi + 0.5) << 3); + assertEquals(0x73594000, (two_32 + pos_smi + 0.5) << 5); + + assertEquals(neg_smi / 2, (neg_32 + neg_smi) >> 1); + assertEquals(neg_smi / 2 + 0x100000000 / 2, (neg_32 + neg_smi) >>> 1); + assertEquals(neg_non_smi, (neg_32 + neg_smi) << 1); + assertEquals(neg_smi / 8, (neg_32 + neg_smi) >> 3); + assertEquals((neg_smi + 0x100000000) / 8, (neg_32 + neg_smi) >>> 3); + assertEquals(0x46536000, (neg_32 + neg_smi) << 4); + assertEquals(-0x73594000, (neg_32 + neg_smi) << 5); + assertEquals(neg_smi, (neg_32 + neg_smi - 0.5) >> 0); + assertEquals(neg_smi + 0x100000000, (neg_32 + neg_smi - 0.5) >>> 0); + assertEquals(neg_smi, (neg_32 + neg_smi - 0.5) << 0); + assertEquals(neg_smi / 2, (neg_32 + neg_smi - 0.5) >> 1); + assertEquals(neg_smi / 2 + 0x100000000 / 2, (neg_32 + neg_smi - 0.5) >>> 1); + assertEquals(neg_non_smi, (neg_32 + neg_smi - 0.5) << 1); + assertEquals(neg_smi / 8, (neg_32 + neg_smi - 0.5) >> 3); + assertEquals(neg_smi / 8 + 0x100000000 / 8, (neg_32 + neg_smi - 0.5) >>> 3); + assertEquals(0x46536000, (neg_32 + neg_smi - 0.5) << 4); + assertEquals(-0x73594000, (neg_32 + neg_smi - 0.5) << 5); + // End block A repeat 1 + // Repeat block A with shift amounts in variables intialized with + // a constant. + var zero = 0; + var one = 1; + var three = 3; + var four = 4; + var five = 5; + // Begin block A repeat 2 + assertEquals(pos_non_smi, (pos_non_smi) >> zero); + assertEquals(pos_non_smi, (pos_non_smi) >>> zero); + assertEquals(pos_non_smi, (pos_non_smi) << zero); + assertEquals(neg_non_smi, (neg_non_smi) >> zero); + assertEquals(neg_non_smi + 0x100000000, (neg_non_smi) >>> zero); + assertEquals(neg_non_smi, (neg_non_smi) << zero); + assertEquals(pos_smi, (pos_smi) >> zero); + assertEquals(pos_smi, (pos_smi) >>> zero); + assertEquals(pos_smi, (pos_smi) << zero); + assertEquals(neg_smi, (neg_smi) >> zero); + assertEquals(neg_smi + 0x100000000, (neg_smi) >>> zero); + assertEquals(neg_smi, (neg_smi) << zero); + + assertEquals(pos_non_smi / 2, (pos_non_smi) >> one); + assertEquals(pos_non_smi / 2, (pos_non_smi) >>> one); + assertEquals(-0x1194D800, (pos_non_smi) << one); + assertEquals(pos_non_smi / 8, (pos_non_smi) >> three); + assertEquals(pos_non_smi / 8, (pos_non_smi) >>> three); + assertEquals(-0x46536000, (pos_non_smi) << three); + assertEquals(0x73594000, (pos_non_smi) << four); + assertEquals(pos_non_smi, (pos_non_smi + 0.5) >> zero); + assertEquals(pos_non_smi, (pos_non_smi + 0.5) >>> zero); + assertEquals(pos_non_smi, (pos_non_smi + 0.5) << zero); + assertEquals(pos_non_smi / 2, (pos_non_smi + 0.5) >> one); + assertEquals(pos_non_smi / 2, (pos_non_smi + 0.5) >>> one); + assertEquals(-0x1194D800, (pos_non_smi + 0.5) << one); + assertEquals(pos_non_smi / 8, (pos_non_smi + 0.5) >> three); + assertEquals(pos_non_smi / 8, (pos_non_smi + 0.5) >>> three); + assertEquals(-0x46536000, (pos_non_smi + 0.5) << three); + assertEquals(0x73594000, (pos_non_smi + 0.5) << four); + + assertEquals(neg_non_smi / 2, (neg_non_smi) >> one); + assertEquals(neg_non_smi / 2 + 0x100000000 / 2, (neg_non_smi) >>> one); + assertEquals(0x1194D800, (neg_non_smi) << one); + assertEquals(neg_non_smi / 8, (neg_non_smi) >> three); + assertEquals(neg_non_smi / 8 + 0x100000000 / 8, (neg_non_smi) >>> three); + assertEquals(0x46536000, (neg_non_smi) << three); + assertEquals(-0x73594000, (neg_non_smi) << four); + assertEquals(neg_non_smi, (neg_non_smi - 0.5) >> zero); + assertEquals(neg_non_smi + 0x100000000, (neg_non_smi - 0.5) >>> zero); + assertEquals(neg_non_smi, (neg_non_smi - 0.5) << zero); + assertEquals(neg_non_smi / 2, (neg_non_smi - 0.5) >> one); + assertEquals(neg_non_smi / 2 + 0x100000000 / 2, (neg_non_smi - 0.5) >>> one); + assertEquals(0x1194D800, (neg_non_smi - 0.5) << one); + assertEquals(neg_non_smi / 8, (neg_non_smi - 0.5) >> three); + assertEquals(neg_non_smi / 8 + 0x100000000 / 8, (neg_non_smi - 0.5) + >>> three); + assertEquals(0x46536000, (neg_non_smi - 0.5) << three); + assertEquals(-0x73594000, (neg_non_smi - 0.5) << four); + + assertEquals(pos_smi / 2, (pos_smi) >> one); + assertEquals(pos_smi / 2, (pos_smi) >>> one); + assertEquals(pos_non_smi, (pos_smi) << one); + assertEquals(pos_smi / 8, (pos_smi) >> three); + assertEquals(pos_smi / 8, (pos_smi) >>> three); + assertEquals(-0x2329b000, (pos_smi) << three); + assertEquals(0x73594000, (pos_smi) << five); + assertEquals(pos_smi, (pos_smi + 0.5) >> zero); + assertEquals(pos_smi, (pos_smi + 0.5) >>> zero); + assertEquals(pos_smi, (pos_smi + 0.5) << zero); + assertEquals(pos_smi / 2, (pos_smi + 0.5) >> one); + assertEquals(pos_smi / 2, (pos_smi + 0.5) >>> one); + assertEquals(pos_non_smi, (pos_smi + 0.5) << one); + assertEquals(pos_smi / 8, (pos_smi + 0.5) >> three); + assertEquals(pos_smi / 8, (pos_smi + 0.5) >>> three); + assertEquals(-0x2329b000, (pos_smi + 0.5) << three); + assertEquals(0x73594000, (pos_smi + 0.5) << five); + + assertEquals(neg_smi / 2, (neg_smi) >> one); + assertEquals(neg_smi / 2 + 0x100000000 / 2, (neg_smi) >>> one); + assertEquals(neg_non_smi, (neg_smi) << one); + assertEquals(neg_smi / 8, (neg_smi) >> three); + assertEquals(neg_smi / 8 + 0x100000000 / 8, (neg_smi) >>> three); + assertEquals(0x46536000, (neg_smi) << four); + assertEquals(-0x73594000, (neg_smi) << five); + assertEquals(neg_smi, (neg_smi - 0.5) >> zero); + assertEquals(neg_smi + 0x100000000, (neg_smi - 0.5) >>> zero); + assertEquals(neg_smi, (neg_smi - 0.5) << zero); + assertEquals(neg_smi / 2, (neg_smi - 0.5) >> one); + assertEquals(neg_smi / 2 + 0x100000000 / 2, (neg_smi - 0.5) >>> one); + assertEquals(neg_non_smi, (neg_smi - 0.5) << one); + assertEquals(neg_smi / 8, (neg_smi - 0.5) >> three); + assertEquals(neg_smi / 8 + 0x100000000 / 8, (neg_smi - 0.5) >>> three); + assertEquals(0x46536000, (neg_smi - 0.5) << four); + assertEquals(-0x73594000, (neg_smi - 0.5) << five); + // End block A repeat 2 + + // Repeat previous block, with computed values in the shift variables. + five = 0; + while (five < 5 ) ++five; + four = five - one; + three = four - one; + one = four - three; + zero = one - one; + + // Begin block A repeat 3 + assertEquals(pos_non_smi, (pos_non_smi) >> zero); + assertEquals(pos_non_smi, (pos_non_smi) >>> zero); + assertEquals(pos_non_smi, (pos_non_smi) << zero); + assertEquals(neg_non_smi, (neg_non_smi) >> zero); + assertEquals(neg_non_smi + 0x100000000, (neg_non_smi) >>> zero); + assertEquals(neg_non_smi, (neg_non_smi) << zero); + assertEquals(pos_smi, (pos_smi) >> zero); + assertEquals(pos_smi, (pos_smi) >>> zero); + assertEquals(pos_smi, (pos_smi) << zero); + assertEquals(neg_smi, (neg_smi) >> zero); + assertEquals(neg_smi + 0x100000000, (neg_smi) >>> zero); + assertEquals(neg_smi, (neg_smi) << zero); + + assertEquals(pos_non_smi / 2, (pos_non_smi) >> one); + assertEquals(pos_non_smi / 2, (pos_non_smi) >>> one); + assertEquals(-0x1194D800, (pos_non_smi) << one); + assertEquals(pos_non_smi / 8, (pos_non_smi) >> three); + assertEquals(pos_non_smi / 8, (pos_non_smi) >>> three); + assertEquals(-0x46536000, (pos_non_smi) << three); + assertEquals(0x73594000, (pos_non_smi) << four); + assertEquals(pos_non_smi, (pos_non_smi + 0.5) >> zero); + assertEquals(pos_non_smi, (pos_non_smi + 0.5) >>> zero); + assertEquals(pos_non_smi, (pos_non_smi + 0.5) << zero); + assertEquals(pos_non_smi / 2, (pos_non_smi + 0.5) >> one); + assertEquals(pos_non_smi / 2, (pos_non_smi + 0.5) >>> one); + assertEquals(-0x1194D800, (pos_non_smi + 0.5) << one); + assertEquals(pos_non_smi / 8, (pos_non_smi + 0.5) >> three); + assertEquals(pos_non_smi / 8, (pos_non_smi + 0.5) >>> three); + assertEquals(-0x46536000, (pos_non_smi + 0.5) << three); + assertEquals(0x73594000, (pos_non_smi + 0.5) << four); + + assertEquals(neg_non_smi / 2, (neg_non_smi) >> one); + assertEquals(neg_non_smi / 2 + 0x100000000 / 2, (neg_non_smi) >>> one); + assertEquals(0x1194D800, (neg_non_smi) << one); + assertEquals(neg_non_smi / 8, (neg_non_smi) >> three); + assertEquals(neg_non_smi / 8 + 0x100000000 / 8, (neg_non_smi) >>> three); + assertEquals(0x46536000, (neg_non_smi) << three); + assertEquals(-0x73594000, (neg_non_smi) << four); + assertEquals(neg_non_smi, (neg_non_smi - 0.5) >> zero); + assertEquals(neg_non_smi + 0x100000000, (neg_non_smi - 0.5) >>> zero); + assertEquals(neg_non_smi, (neg_non_smi - 0.5) << zero); + assertEquals(neg_non_smi / 2, (neg_non_smi - 0.5) >> one); + assertEquals(neg_non_smi / 2 + 0x100000000 / 2, (neg_non_smi - 0.5) >>> one); + assertEquals(0x1194D800, (neg_non_smi - 0.5) << one); + assertEquals(neg_non_smi / 8, (neg_non_smi - 0.5) >> three); + assertEquals(neg_non_smi / 8 + 0x100000000 / 8, (neg_non_smi - 0.5) + >>> three); + assertEquals(0x46536000, (neg_non_smi - 0.5) << three); + assertEquals(-0x73594000, (neg_non_smi - 0.5) << four); + + assertEquals(pos_smi / 2, (pos_smi) >> one); + assertEquals(pos_smi / 2, (pos_smi) >>> one); + assertEquals(pos_non_smi, (pos_smi) << one); + assertEquals(pos_smi / 8, (pos_smi) >> three); + assertEquals(pos_smi / 8, (pos_smi) >>> three); + assertEquals(-0x2329b000, (pos_smi) << three); + assertEquals(0x73594000, (pos_smi) << five); + assertEquals(pos_smi, (pos_smi + 0.5) >> zero); + assertEquals(pos_smi, (pos_smi + 0.5) >>> zero); + assertEquals(pos_smi, (pos_smi + 0.5) << zero); + assertEquals(pos_smi / 2, (pos_smi + 0.5) >> one); + assertEquals(pos_smi / 2, (pos_smi + 0.5) >>> one); + assertEquals(pos_non_smi, (pos_smi + 0.5) << one); + assertEquals(pos_smi / 8, (pos_smi + 0.5) >> three); + assertEquals(pos_smi / 8, (pos_smi + 0.5) >>> three); + assertEquals(-0x2329b000, (pos_smi + 0.5) << three); + assertEquals(0x73594000, (pos_smi + 0.5) << five); + + assertEquals(neg_smi / 2, (neg_smi) >> one); + assertEquals(neg_smi / 2 + 0x100000000 / 2, (neg_smi) >>> one); + assertEquals(neg_non_smi, (neg_smi) << one); + assertEquals(neg_smi / 8, (neg_smi) >> three); + assertEquals(neg_smi / 8 + 0x100000000 / 8, (neg_smi) >>> three); + assertEquals(0x46536000, (neg_smi) << four); + assertEquals(-0x73594000, (neg_smi) << five); + assertEquals(neg_smi, (neg_smi - 0.5) >> zero); + assertEquals(neg_smi + 0x100000000, (neg_smi - 0.5) >>> zero); + assertEquals(neg_smi, (neg_smi - 0.5) << zero); + assertEquals(neg_smi / 2, (neg_smi - 0.5) >> one); + assertEquals(neg_smi / 2 + 0x100000000 / 2, (neg_smi - 0.5) >>> one); + assertEquals(neg_non_smi, (neg_smi - 0.5) << one); + assertEquals(neg_smi / 8, (neg_smi - 0.5) >> three); + assertEquals(neg_smi / 8 + 0x100000000 / 8, (neg_smi - 0.5) >>> three); + assertEquals(0x46536000, (neg_smi - 0.5) << four); + assertEquals(-0x73594000, (neg_smi - 0.5) << five); + // End block A repeat 3 + + // Test non-integer shift value + assertEquals(5, 20.5 >> 2.4); + assertEquals(5, 20.5 >> 2.7); + var shift = 2.4; + assertEquals(5, 20.5 >> shift); + assertEquals(5, 20.5 >> shift + 0.3); + shift = shift + zero; + assertEquals(5, 20.5 >> shift); + assertEquals(5, 20.5 >> shift + 0.3); +} + +testShiftNonSmis(); diff --git a/deps/v8/test/mjsunit/tools/codemap.js b/deps/v8/test/mjsunit/tools/codemap.js new file mode 100644 index 000000000..55b875883 --- /dev/null +++ b/deps/v8/test/mjsunit/tools/codemap.js @@ -0,0 +1,158 @@ +// Copyright 2009 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. + +// Load Splay tree and CodeMap implementations from <project root>/tools. +// Files: tools/splaytree.js tools/codemap.js + + +function newCodeEntry(size, name) { + return new devtools.profiler.CodeMap.CodeEntry(size, name); +}; + + +function assertEntry(codeMap, expected_name, addr) { + var entry = codeMap.findEntry(addr); + assertNotNull(entry, 'no entry at ' + addr.toString(16)); + assertEquals(expected_name, entry.name, 'at ' + addr.toString(16)); +}; + + +function assertNoEntry(codeMap, addr) { + assertNull(codeMap.findEntry(addr), 'at ' + addr.toString(16)); +}; + + +(function testStaticCode() { + var codeMap = new devtools.profiler.CodeMap(); + codeMap.addStaticCode(0x1500, newCodeEntry(0x3000, 'lib1')); + codeMap.addStaticCode(0x15500, newCodeEntry(0x5000, 'lib2')); + codeMap.addStaticCode(0x155500, newCodeEntry(0x10000, 'lib3')); + assertNoEntry(codeMap, 0); + assertNoEntry(codeMap, 0x1500 - 1); + assertEntry(codeMap, 'lib1', 0x1500); + assertEntry(codeMap, 'lib1', 0x1500 + 0x100); + assertEntry(codeMap, 'lib1', 0x1500 + 0x1000); + assertEntry(codeMap, 'lib1', 0x1500 + 0x3000 - 1); + assertNoEntry(codeMap, 0x1500 + 0x3000); + assertNoEntry(codeMap, 0x15500 - 1); + assertEntry(codeMap, 'lib2', 0x15500); + assertEntry(codeMap, 'lib2', 0x15500 + 0x100); + assertEntry(codeMap, 'lib2', 0x15500 + 0x1000); + assertEntry(codeMap, 'lib2', 0x15500 + 0x5000 - 1); + assertNoEntry(codeMap, 0x15500 + 0x5000); + assertNoEntry(codeMap, 0x155500 - 1); + assertEntry(codeMap, 'lib3', 0x155500); + assertEntry(codeMap, 'lib3', 0x155500 + 0x100); + assertEntry(codeMap, 'lib3', 0x155500 + 0x1000); + assertEntry(codeMap, 'lib3', 0x155500 + 0x10000 - 1); + assertNoEntry(codeMap, 0x155500 + 0x10000); + assertNoEntry(codeMap, 0xFFFFFFFF); +})(); + + +(function testDynamicCode() { + var codeMap = new devtools.profiler.CodeMap(); + codeMap.addCode(0x1500, newCodeEntry(0x200, 'code1')); + codeMap.addCode(0x1700, newCodeEntry(0x100, 'code2')); + codeMap.addCode(0x1900, newCodeEntry(0x50, 'code3')); + codeMap.addCode(0x1950, newCodeEntry(0x10, 'code4')); + assertNoEntry(codeMap, 0); + assertNoEntry(codeMap, 0x1500 - 1); + assertEntry(codeMap, 'code1', 0x1500); + assertEntry(codeMap, 'code1', 0x1500 + 0x100); + assertEntry(codeMap, 'code1', 0x1500 + 0x200 - 1); + assertEntry(codeMap, 'code2', 0x1700); + assertEntry(codeMap, 'code2', 0x1700 + 0x50); + assertEntry(codeMap, 'code2', 0x1700 + 0x100 - 1); + assertNoEntry(codeMap, 0x1700 + 0x100); + assertNoEntry(codeMap, 0x1900 - 1); + assertEntry(codeMap, 'code3', 0x1900); + assertEntry(codeMap, 'code3', 0x1900 + 0x28); + assertEntry(codeMap, 'code4', 0x1950); + assertEntry(codeMap, 'code4', 0x1950 + 0x7); + assertEntry(codeMap, 'code4', 0x1950 + 0x10 - 1); + assertNoEntry(codeMap, 0x1950 + 0x10); + assertNoEntry(codeMap, 0xFFFFFFFF); +})(); + + +(function testCodeMovesAndDeletions() { + var codeMap = new devtools.profiler.CodeMap(); + codeMap.addCode(0x1500, newCodeEntry(0x200, 'code1')); + codeMap.addCode(0x1700, newCodeEntry(0x100, 'code2')); + assertEntry(codeMap, 'code1', 0x1500); + assertEntry(codeMap, 'code2', 0x1700); + codeMap.moveCode(0x1500, 0x1800); + assertNoEntry(codeMap, 0x1500); + assertEntry(codeMap, 'code2', 0x1700); + assertEntry(codeMap, 'code1', 0x1800); + codeMap.deleteCode(0x1700); + assertNoEntry(codeMap, 0x1700); + assertEntry(codeMap, 'code1', 0x1800); +})(); + + +(function testDynamicNamesDuplicates() { + var codeMap = new devtools.profiler.CodeMap(); + // Code entries with same names but different addresses. + codeMap.addCode(0x1500, newCodeEntry(0x200, 'code')); + codeMap.addCode(0x1700, newCodeEntry(0x100, 'code')); + assertEntry(codeMap, 'code', 0x1500); + assertEntry(codeMap, 'code {1}', 0x1700); + // Test name stability. + assertEntry(codeMap, 'code', 0x1500); + assertEntry(codeMap, 'code {1}', 0x1700); +})(); + + +(function testStaticEntriesExport() { + var codeMap = new devtools.profiler.CodeMap(); + codeMap.addStaticCode(0x1500, newCodeEntry(0x3000, 'lib1')); + codeMap.addStaticCode(0x15500, newCodeEntry(0x5000, 'lib2')); + codeMap.addStaticCode(0x155500, newCodeEntry(0x10000, 'lib3')); + var allStatics = codeMap.getAllStaticEntries(); + allStatics.sort(); + assertEquals(['lib1: 3000', 'lib2: 5000', 'lib3: 10000'], allStatics); +})(); + + +(function testDynamicEntriesExport() { + var codeMap = new devtools.profiler.CodeMap(); + codeMap.addCode(0x1500, newCodeEntry(0x200, 'code1')); + codeMap.addCode(0x1700, newCodeEntry(0x100, 'code2')); + codeMap.addCode(0x1900, newCodeEntry(0x50, 'code3')); + var allDynamics = codeMap.getAllDynamicEntries(); + allDynamics.sort(); + assertEquals(['code1: 200', 'code2: 100', 'code3: 50'], allDynamics); + codeMap.deleteCode(0x1700); + var allDynamics2 = codeMap.getAllDynamicEntries(); + allDynamics2.sort(); + assertEquals(['code1: 200', 'code3: 50'], allDynamics2); + codeMap.deleteCode(0x1500); + var allDynamics3 = codeMap.getAllDynamicEntries(); + assertEquals(['code3: 50'], allDynamics3); +})(); diff --git a/deps/v8/test/mjsunit/tools/consarray.js b/deps/v8/test/mjsunit/tools/consarray.js new file mode 100644 index 000000000..8b2c59bea --- /dev/null +++ b/deps/v8/test/mjsunit/tools/consarray.js @@ -0,0 +1,60 @@ +// Copyright 2009 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. + +// Load ConsArray implementation from <project root>/tools. +// Files: tools/consarray.js + + +var arr1 = new ConsArray(); +assertTrue(arr1.atEnd()); + +arr1.concat([]); +assertTrue(arr1.atEnd()); + +arr1.concat([1]); +assertFalse(arr1.atEnd()); +assertEquals(1, arr1.next()); +assertTrue(arr1.atEnd()); + +arr1.concat([2, 3, 4]); +arr1.concat([5]); +arr1.concat([]); +arr1.concat([6, 7]); + +assertFalse(arr1.atEnd()); +assertEquals(2, arr1.next()); +assertFalse(arr1.atEnd()); +assertEquals(3, arr1.next()); +assertFalse(arr1.atEnd()); +assertEquals(4, arr1.next()); +assertFalse(arr1.atEnd()); +assertEquals(5, arr1.next()); +assertFalse(arr1.atEnd()); +assertEquals(6, arr1.next()); +assertFalse(arr1.atEnd()); +assertEquals(7, arr1.next()); +assertTrue(arr1.atEnd()); diff --git a/deps/v8/test/mjsunit/tools/csvparser.js b/deps/v8/test/mjsunit/tools/csvparser.js new file mode 100644 index 000000000..db3a2eba3 --- /dev/null +++ b/deps/v8/test/mjsunit/tools/csvparser.js @@ -0,0 +1,79 @@ +// Copyright 2009 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. + +// Load CSV parser implementation from <project root>/tools. +// Files: tools/csvparser.js + +var parser = new devtools.profiler.CsvParser(); + +assertEquals( + [], + parser.parseLine('')); + +assertEquals( + ['', ''], + parser.parseLine(',')); + +assertEquals( + ['1997','Ford','E350'], + parser.parseLine('1997,Ford,E350')); + +assertEquals( + ['1997','Ford','E350'], + parser.parseLine('"1997","Ford","E350"')); + +assertEquals( + ['1997','Ford','E350','Super, luxurious truck'], + parser.parseLine('1997,Ford,E350,"Super, luxurious truck"')); + +assertEquals( + ['1997','Ford','E350','Super "luxurious" truck'], + parser.parseLine('1997,Ford,E350,"Super ""luxurious"" truck"')); + +assertEquals( + ['1997','Ford','E350','Super "luxurious" "truck"'], + parser.parseLine('1997,Ford,E350,"Super ""luxurious"" ""truck"""')); + +assertEquals( + ['1997','Ford','E350','Super "luxurious""truck"'], + parser.parseLine('1997,Ford,E350,"Super ""luxurious""""truck"""')); + +assertEquals( + ['shared-library','/lib/ld-2.3.6.so','0x489a2000','0x489b7000'], + parser.parseLine('shared-library,"/lib/ld-2.3.6.so",0x489a2000,0x489b7000')); + +assertEquals( + ['code-creation','LazyCompile','0xf6fe2d20','1201','APPLY_PREPARE native runtime.js:165'], + parser.parseLine('code-creation,LazyCompile,0xf6fe2d20,1201,"APPLY_PREPARE native runtime.js:165"')); + +assertEquals( + ['code-creation','LazyCompile','0xf6fe4bc0','282',' native v8natives.js:69'], + parser.parseLine('code-creation,LazyCompile,0xf6fe4bc0,282," native v8natives.js:69"')); + +assertEquals( + ['code-creation','RegExp','0xf6c21c00','826','NccyrJroXvg\\/([^,]*)'], + parser.parseLine('code-creation,RegExp,0xf6c21c00,826,"NccyrJroXvg\\/([^,]*)"')); diff --git a/deps/v8/test/mjsunit/tools/profile.js b/deps/v8/test/mjsunit/tools/profile.js new file mode 100644 index 000000000..49eef3b0a --- /dev/null +++ b/deps/v8/test/mjsunit/tools/profile.js @@ -0,0 +1,348 @@ +// Copyright 2009 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. + +// Load source code files from <project root>/tools. +// Files: tools/splaytree.js tools/codemap.js tools/consarray.js tools/profile.js + + +function stackToString(stack) { + return stack.join(' -> '); +}; + + +function assertPathExists(root, path, opt_message) { + var message = opt_message ? ' (' + opt_message + ')' : ''; + assertNotNull(root.descendToChild(path, function(node, pos) { + assertNotNull(node, + stackToString(path.slice(0, pos)) + ' has no child ' + + path[pos] + message); + }), opt_message); +}; + + +function assertNoPathExists(root, path, opt_message) { + var message = opt_message ? ' (' + opt_message + ')' : ''; + assertNull(root.descendToChild(path), opt_message); +}; + + +function countNodes(profile, traverseFunc) { + var count = 0; + traverseFunc.call(profile, function () { count++; }); + return count; +}; + + +function ProfileTestDriver() { + this.profile = new devtools.profiler.Profile(); + this.stack_ = []; + this.addFunctions_(); +}; + + +// Addresses inside functions. +ProfileTestDriver.prototype.funcAddrs_ = { + 'lib1-f1': 0x11110, 'lib1-f2': 0x11210, + 'lib2-f1': 0x21110, 'lib2-f2': 0x21210, + 'T: F1': 0x50110, 'T: F2': 0x50210, 'T: F3': 0x50410 }; + + +ProfileTestDriver.prototype.addFunctions_ = function() { + this.profile.addStaticCode('lib1', 0x11000, 0x12000); + this.profile.addStaticCode('lib1-f1', 0x11100, 0x11900); + this.profile.addStaticCode('lib1-f2', 0x11200, 0x11500); + this.profile.addStaticCode('lib2', 0x21000, 0x22000); + this.profile.addStaticCode('lib2-f1', 0x21100, 0x21900); + this.profile.addStaticCode('lib2-f2', 0x21200, 0x21500); + this.profile.addCode('T', 'F1', 0x50100, 0x100); + this.profile.addCode('T', 'F2', 0x50200, 0x100); + this.profile.addCode('T', 'F3', 0x50400, 0x100); +}; + + +ProfileTestDriver.prototype.enter = function(funcName) { + // Stack looks like this: [pc, caller, ..., main]. + // Therefore, we are adding entries at the beginning. + this.stack_.unshift(this.funcAddrs_[funcName]); + this.profile.recordTick(this.stack_); +}; + + +ProfileTestDriver.prototype.stay = function() { + this.profile.recordTick(this.stack_); +}; + + +ProfileTestDriver.prototype.leave = function() { + this.stack_.shift(); +}; + + +ProfileTestDriver.prototype.execute = function() { + this.enter('lib1-f1'); + this.enter('lib1-f2'); + this.enter('T: F1'); + this.enter('T: F2'); + this.leave(); + this.stay(); + this.enter('lib2-f1'); + this.enter('lib2-f1'); + this.leave(); + this.stay(); + this.leave(); + this.enter('T: F3'); + this.enter('T: F3'); + this.enter('T: F3'); + this.leave(); + this.enter('T: F2'); + this.stay(); + this.leave(); + this.leave(); + this.leave(); + this.leave(); + this.enter('lib2-f1'); + this.enter('lib1-f1'); + this.leave(); + this.leave(); + this.stay(); + this.leave(); +}; + + +function Inherits(childCtor, parentCtor) { + function tempCtor() {}; + tempCtor.prototype = parentCtor.prototype; + childCtor.superClass_ = parentCtor.prototype; + childCtor.prototype = new tempCtor(); + childCtor.prototype.constructor = childCtor; +}; + + +(function testCallTreeBuilding() { + function Driver() { + ProfileTestDriver.call(this); + this.namesTopDown = []; + this.namesBottomUp = []; + }; + Inherits(Driver, ProfileTestDriver); + + Driver.prototype.enter = function(func) { + this.namesTopDown.push(func); + this.namesBottomUp.unshift(func); + assertNoPathExists(this.profile.getTopDownProfile().getRoot(), this.namesTopDown, + 'pre enter/topDown'); + assertNoPathExists(this.profile.getBottomUpProfile().getRoot(), this.namesBottomUp, + 'pre enter/bottomUp'); + Driver.superClass_.enter.call(this, func); + assertPathExists(this.profile.getTopDownProfile().getRoot(), this.namesTopDown, + 'post enter/topDown'); + assertPathExists(this.profile.getBottomUpProfile().getRoot(), this.namesBottomUp, + 'post enter/bottomUp'); + }; + + Driver.prototype.stay = function() { + var preTopDownNodes = countNodes(this.profile, this.profile.traverseTopDownTree); + var preBottomUpNodes = countNodes(this.profile, this.profile.traverseBottomUpTree); + Driver.superClass_.stay.call(this); + var postTopDownNodes = countNodes(this.profile, this.profile.traverseTopDownTree); + var postBottomUpNodes = countNodes(this.profile, this.profile.traverseBottomUpTree); + // Must be no changes in tree layout. + assertEquals(preTopDownNodes, postTopDownNodes, 'stay/topDown'); + assertEquals(preBottomUpNodes, postBottomUpNodes, 'stay/bottomUp'); + }; + + Driver.prototype.leave = function() { + Driver.superClass_.leave.call(this); + this.namesTopDown.pop(); + this.namesBottomUp.shift(); + }; + + var testDriver = new Driver(); + testDriver.execute(); +})(); + + +function assertNodeWeights(root, path, selfTicks, totalTicks) { + var node = root.descendToChild(path); + var stack = stackToString(path); + assertNotNull(node, 'node not found: ' + stack); + assertEquals(selfTicks, node.selfWeight, 'self of ' + stack); + assertEquals(totalTicks, node.totalWeight, 'total of ' + stack); +}; + + +(function testTopDownRootProfileTicks() { + var testDriver = new ProfileTestDriver(); + testDriver.execute(); + + var pathWeights = [ + [['lib1-f1'], 1, 16], + [['lib1-f1', 'lib1-f2'], 2, 15], + [['lib1-f1', 'lib1-f2', 'T: F1'], 2, 11], + [['lib1-f1', 'lib1-f2', 'T: F1', 'T: F2'], 1, 1], + [['lib1-f1', 'lib1-f2', 'T: F1', 'lib2-f1'], 2, 3], + [['lib1-f1', 'lib1-f2', 'T: F1', 'lib2-f1', 'lib2-f1'], 1, 1], + [['lib1-f1', 'lib1-f2', 'T: F1', 'T: F3'], 1, 5], + [['lib1-f1', 'lib1-f2', 'T: F1', 'T: F3', 'T: F3'], 1, 4], + [['lib1-f1', 'lib1-f2', 'T: F1', 'T: F3', 'T: F3', 'T: F3'], 1, 1], + [['lib1-f1', 'lib1-f2', 'T: F1', 'T: F3', 'T: F3', 'T: F2'], 2, 2], + [['lib1-f1', 'lib1-f2', 'lib2-f1'], 1, 2], + [['lib1-f1', 'lib1-f2', 'lib2-f1', 'lib1-f1'], 1, 1] + ]; + + var root = testDriver.profile.getTopDownProfile().getRoot(); + for (var i = 0; i < pathWeights.length; ++i) { + var data = pathWeights[i]; + assertNodeWeights(root, data[0], data[1], data[2]); + } +})(); + + +(function testRootFlatProfileTicks() { + function Driver() { + ProfileTestDriver.call(this); + this.namesTopDown = ['']; + this.counters = {}; + this.root = null; + }; + Inherits(Driver, ProfileTestDriver); + + Driver.prototype.increment = function(func, self, total) { + if (!(func in this.counters)) { + this.counters[func] = { self: 0, total: 0 }; + } + this.counters[func].self += self; + this.counters[func].total += total; + }; + + Driver.prototype.incrementTotals = function() { + // Only count each function in the stack once. + var met = {}; + for (var i = 0; i < this.namesTopDown.length; ++i) { + var name = this.namesTopDown[i]; + if (!(name in met)) { + this.increment(name, 0, 1); + } + met[name] = true; + } + }; + + Driver.prototype.enter = function(func) { + Driver.superClass_.enter.call(this, func); + this.namesTopDown.push(func); + this.increment(func, 1, 0); + this.incrementTotals(); + }; + + Driver.prototype.stay = function() { + Driver.superClass_.stay.call(this); + this.increment(this.namesTopDown[this.namesTopDown.length - 1], 1, 0); + this.incrementTotals(); + }; + + Driver.prototype.leave = function() { + Driver.superClass_.leave.call(this); + this.namesTopDown.pop(); + }; + + Driver.prototype.extractRoot = function() { + assertTrue('' in this.counters); + this.root = this.counters['']; + delete this.counters['']; + }; + + var testDriver = new Driver(); + testDriver.execute(); + testDriver.extractRoot(); + + var counted = 0; + for (var c in testDriver.counters) { + counted++; + } + + var flatProfileRoot = testDriver.profile.getFlatProfile().getRoot(); + assertEquals(testDriver.root.self, flatProfileRoot.selfWeight); + assertEquals(testDriver.root.total, flatProfileRoot.totalWeight); + + var flatProfile = flatProfileRoot.exportChildren(); + assertEquals(counted, flatProfile.length, 'counted vs. flatProfile'); + for (var i = 0; i < flatProfile.length; ++i) { + var rec = flatProfile[i]; + assertTrue(rec.label in testDriver.counters, 'uncounted: ' + rec.label); + var reference = testDriver.counters[rec.label]; + assertEquals(reference.self, rec.selfWeight, 'self of ' + rec.label); + assertEquals(reference.total, rec.totalWeight, 'total of ' + rec.label); + } + +})(); + + +(function testFunctionCalleesProfileTicks() { + var testDriver = new ProfileTestDriver(); + testDriver.execute(); + + var pathWeights = [ + [['lib2-f1'], 3, 5], + [['lib2-f1', 'lib2-f1'], 1, 1], + [['lib2-f1', 'lib1-f1'], 1, 1] + ]; + + var profile = testDriver.profile.getTopDownProfile('lib2-f1'); + var root = profile.getRoot(); + for (var i = 0; i < pathWeights.length; ++i) { + var data = pathWeights[i]; + assertNodeWeights(root, data[0], data[1], data[2]); + } +})(); + + +(function testFunctionFlatProfileTicks() { + var testDriver = new ProfileTestDriver(); + testDriver.execute(); + + var flatWeights = { + 'lib2-f1': [1, 1], + 'lib1-f1': [1, 1] + }; + + var flatProfileRoot = + testDriver.profile.getFlatProfile('lib2-f1').findOrAddChild('lib2-f1'); + assertEquals(3, flatProfileRoot.selfWeight); + assertEquals(5, flatProfileRoot.totalWeight); + + var flatProfile = flatProfileRoot.exportChildren(); + assertEquals(2, flatProfile.length, 'counted vs. flatProfile'); + for (var i = 0; i < flatProfile.length; ++i) { + var rec = flatProfile[i]; + assertTrue(rec.label in flatWeights, 'uncounted: ' + rec.label); + var reference = flatWeights[rec.label]; + assertEquals(reference[0], rec.selfWeight, 'self of ' + rec.label); + assertEquals(reference[1], rec.totalWeight, 'total of ' + rec.label); + } + +})(); + diff --git a/deps/v8/test/mjsunit/tools/profile_view.js b/deps/v8/test/mjsunit/tools/profile_view.js new file mode 100644 index 000000000..3ed1128b6 --- /dev/null +++ b/deps/v8/test/mjsunit/tools/profile_view.js @@ -0,0 +1,95 @@ +// Copyright 2009 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. + +// Load source code files from <project root>/tools. +// Files: tools/consarray.js tools/profile.js tools/profile_view.js + + +function createNode(name, time, opt_parent) { + var node = new devtools.profiler.ProfileView.Node(name, time, time, null); + if (opt_parent) { + opt_parent.addChild(node); + } + return node; +} + + +(function testSorting() { + // + // Build a tree: + // root +--c/5 + // | | + // +--a/2 +--b/3--+--d/4 + // | | | + // +--a/1--+--c/1 +--d/2 + // | | + // +--c/1 +--b/2 + // + // So we can sort it using 2 fields: name and time. + var root = createNode('root', 0); + createNode('a', 2, root); + var a1 = createNode('a', 1, root); + createNode('c', 1, root); + var b3 = createNode('b', 3, a1); + createNode('c', 1, a1); + createNode('b', 2, a1); + createNode('c', 5, b3); + createNode('d', 4, b3); + createNode('d', 2, b3); + + var view = new devtools.profiler.ProfileView(root); + var flatTree = []; + + function fillFlatTree(node) { + flatTree.push(node.internalFuncName); + flatTree.push(node.selfTime); + } + + view.traverse(fillFlatTree); + assertEquals( + ['root', 0, + 'a', 2, 'a', 1, 'c', 1, + 'b', 3, 'c', 1, 'b', 2, + 'c', 5, 'd', 4, 'd', 2], flatTree); + + function cmpStrs(s1, s2) { + return s1 == s2 ? 0 : (s1 < s2 ? -1 : 1); + } + + view.sort(function(n1, n2) { + return cmpStrs(n1.internalFuncName, n2.internalFuncName) || + (n1.selfTime - n2.selfTime); + }); + + flatTree = []; + view.traverse(fillFlatTree); + assertEquals( + ['root', 0, + 'a', 1, 'a', 2, 'c', 1, + 'b', 2, 'b', 3, 'c', 1, + 'c', 5, 'd', 2, 'd', 4], flatTree); +})(); diff --git a/deps/v8/test/mjsunit/undeletable-functions.js b/deps/v8/test/mjsunit/undeletable-functions.js new file mode 100644 index 000000000..86a74263e --- /dev/null +++ b/deps/v8/test/mjsunit/undeletable-functions.js @@ -0,0 +1,181 @@ +// Copyright 2009 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 we match JSC in making some functions undeletable. +// See http://code.google.com/p/chromium/issues/detail?id=1717 +// The functions on these prototypes are not just undeletable. It is +// possible to override them with new definitions, then get the old +// version back by deleting the new definition. + +var array; + +array = [ + "toString", "toLocaleString", "join", "pop", "push", "concat", "reverse", + "shift", "unshift", "slice", "splice", "sort", "filter", "forEach", "some", + "every", "map", "indexOf", "lastIndexOf", "reduce", "reduceRight"]; +CheckJSCSemantics(Array.prototype, array, "Array prototype"); + +array = [ + "toString", "toDateString", "toTimeString", "toLocaleString", + "toLocaleDateString", "toLocaleTimeString", "valueOf", "getTime", + "getFullYear", "getUTCFullYear", "getMonth", "getUTCMonth", "getDate", + "getUTCDate", "getDay", "getUTCDay", "getHours", "getUTCHours", "getMinutes", + "getUTCMinutes", "getSeconds", "getUTCSeconds", "getMilliseconds", + "getUTCMilliseconds", "getTimezoneOffset", "setTime", "setMilliseconds", + "setUTCMilliseconds", "setSeconds", "setUTCSeconds", "setMinutes", + "setUTCMinutes", "setHours", "setUTCHours", "setDate", "setUTCDate", + "setMonth", "setUTCMonth", "setFullYear", "setUTCFullYear", "toGMTString", + "toUTCString", "getYear", "setYear", "toISOString", "toJSON"]; +CheckJSCSemantics(Date.prototype, array, "Date prototype"); + +array = [ + "random", "abs", "acos", "asin", "atan", "ceil", "cos", "exp", "floor", "log", + "round", "sin", "sqrt", "tan", "atan2", "pow", "max", "min"]; +CheckJSCSemantics(Math, array, "Math1"); + +CheckEcmaSemantics(Date, ["UTC", "parse", "now"], "Date"); + +array = [ + "E", "LN10", "LN2", "LOG2E", "LOG10E", "PI", "SQRT1_2", "SQRT2"]; +CheckDontDelete(Math, array, "Math2"); + +array = [ + "escape", "unescape", "decodeURI", "decodeURIComponent", "encodeURI", + "encodeURIComponent", "isNaN", "isFinite", "parseInt", "parseFloat", "eval", + "execScript"]; +CheckEcmaSemantics(this, array, "Global"); +CheckReadOnlyAttr(this, "Infinity"); + +array = ["exec", "test", "toString", "compile"]; +CheckEcmaSemantics(RegExp.prototype, array, "RegExp prototype"); + +array = [ + "toString", "toLocaleString", "valueOf", "hasOwnProperty", + "isPrototypeOf", "propertyIsEnumerable", "__defineGetter__", + "__lookupGetter__", "__defineSetter__", "__lookupSetter__"]; +CheckEcmaSemantics(Object.prototype, array, "Object prototype"); + +array = [ + "toString", "valueOf", "toJSON"]; +CheckEcmaSemantics(Boolean.prototype, array, "Boolean prototype"); + +array = [ + "toString", "toLocaleString", "valueOf", "toFixed", "toExponential", + "toPrecision", "toJSON"]; +CheckEcmaSemantics(Number.prototype, array, "Number prototype"); + +CheckEcmaSemantics(Function.prototype, ["toString"], "Function prototype"); +CheckEcmaSemantics(Date.prototype, ["constructor"], "Date prototype constructor"); + +array = [ + "charAt", "charCodeAt", "concat", "indexOf", + "lastIndexOf", "localeCompare", "match", "replace", "search", "slice", + "split", "substring", "substr", "toLowerCase", "toLocaleLowerCase", + "toUpperCase", "toLocaleUpperCase", "link", "anchor", "fontcolor", "fontsize", + "big", "blink", "bold", "fixed", "italics", "small", "strike", "sub", "sup", + "toJSON", "toString", "valueOf"]; +CheckJSCSemantics(String.prototype, array, "String prototype"); +CheckEcmaSemantics(String, ["fromCharCode"], "String"); + + +function CheckEcmaSemantics(type, props, name) { + print(name); + for (var i = 0; i < props.length; i++) { + CheckDeletable(type, props[i]); + } +} + + +function CheckJSCSemantics(type, props, name) { + print(name); + for (var i = 0; i < props.length; i++) { + CheckNotDeletable(type, props[i]); + } +} + + +function CheckDontDelete(type, props, name) { + print(name); + for (var i = 0; i < props.length; i++) { + CheckDontDeleteAttr(type, props[i]); + } +} + + +function CheckDeletable(type, prop) { + var old = type[prop]; + var hasOwnProperty = Object.prototype.hasOwnProperty; + if (!type[prop]) return; + assertTrue(type.hasOwnProperty(prop), "inherited: " + prop); + var deleted = delete type[prop]; + assertTrue(deleted, "delete operator returned false: " + prop); + assertFalse(hasOwnProperty.call(type, prop), "still there after delete: " + prop); + type[prop] = "foo"; + assertEquals("foo", type[prop], "not overwritable: " + prop); + type[prop] = old; +} + + +function CheckNotDeletable(type, prop) { + var old = type[prop]; + if (!type[prop]) return; + assertTrue(type.hasOwnProperty(prop), "inherited: " + prop); + var deleted = delete type[prop]; + assertTrue(deleted, "delete operator returned false: " + prop); + assertTrue(type.hasOwnProperty(prop), "not there after delete: " + prop); + type[prop] = "foo"; + assertEquals("foo", type[prop], "not overwritable: " + prop); + deleted = delete type[prop]; + assertTrue(deleted, "delete operator returned false 2nd time: " + prop); + assertEquals(old.toString(), type[prop].toString(), "delete didn't restore the old value: " + prop); +} + + +function CheckDontDeleteAttr(type, prop) { + var old = type[prop]; + if (!type[prop]) return; + assertTrue(type.hasOwnProperty(prop), "inherited: " + prop); + var deleted = delete type[prop]; + assertFalse(deleted, "delete operator returned true: " + prop); + assertTrue(type.hasOwnProperty(prop), "not there after delete: " + prop); + type[prop] = "foo"; + assertFalse("foo" == type[prop], "overwritable: " + prop); +} + + +function CheckReadOnlyAttr(type, prop) { + var old = type[prop]; + if (!type[prop]) return; + assertTrue(type.hasOwnProperty(prop), "inherited: " + prop); + var deleted = delete type[prop]; + assertFalse(deleted, "delete operator returned true: " + prop); + assertTrue(type.hasOwnProperty(prop), "not there after delete: " + prop); + type[prop] = "foo"; + assertEquals("foo", type[prop], "overwritable: " + prop); +} + +print("OK"); diff --git a/deps/v8/tools/codemap.js b/deps/v8/tools/codemap.js new file mode 100644 index 000000000..3766db048 --- /dev/null +++ b/deps/v8/tools/codemap.js @@ -0,0 +1,230 @@ +// Copyright 2009 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. + + +// Initlialize namespaces +var devtools = devtools || {}; +devtools.profiler = devtools.profiler || {}; + + +/** + * Constructs a mapper that maps addresses into code entries. + * + * @constructor + */ +devtools.profiler.CodeMap = function() { + /** + * Dynamic code entries. Used for JIT compiled code. + */ + this.dynamics_ = new goog.structs.SplayTree(); + + /** + * Name generator for entries having duplicate names. + */ + this.dynamicsNameGen_ = new devtools.profiler.CodeMap.NameGenerator(); + + /** + * Static code entries. Used for libraries code. + */ + this.statics_ = new goog.structs.SplayTree(); + + /** + * Map of memory pages occupied with static code. + */ + this.pages_ = []; +}; + + +/** + * The number of alignment bits in a page address. + */ +devtools.profiler.CodeMap.PAGE_ALIGNMENT = 12; + + +/** + * Page size in bytes. + */ +devtools.profiler.CodeMap.PAGE_SIZE = + 1 << devtools.profiler.CodeMap.PAGE_ALIGNMENT; + + +/** + * Adds a dynamic (i.e. moveable and discardable) code entry. + * + * @param {number} start The starting address. + * @param {devtools.profiler.CodeMap.CodeEntry} codeEntry Code entry object. + */ +devtools.profiler.CodeMap.prototype.addCode = function(start, codeEntry) { + this.dynamics_.insert(start, codeEntry); +}; + + +/** + * Moves a dynamic code entry. Throws an exception if there is no dynamic + * code entry with the specified starting address. + * + * @param {number} from The starting address of the entry being moved. + * @param {number} to The destination address. + */ +devtools.profiler.CodeMap.prototype.moveCode = function(from, to) { + var removedNode = this.dynamics_.remove(from); + this.dynamics_.insert(to, removedNode.value); +}; + + +/** + * Discards a dynamic code entry. Throws an exception if there is no dynamic + * code entry with the specified starting address. + * + * @param {number} start The starting address of the entry being deleted. + */ +devtools.profiler.CodeMap.prototype.deleteCode = function(start) { + var removedNode = this.dynamics_.remove(start); +}; + + +/** + * Adds a static code entry. + * + * @param {number} start The starting address. + * @param {devtools.profiler.CodeMap.CodeEntry} codeEntry Code entry object. + */ +devtools.profiler.CodeMap.prototype.addStaticCode = function( + start, codeEntry) { + this.markPages_(start, start + codeEntry.size); + this.statics_.insert(start, codeEntry); +}; + + +/** + * @private + */ +devtools.profiler.CodeMap.prototype.markPages_ = function(start, end) { + for (var addr = start; addr <= end; + addr += devtools.profiler.CodeMap.PAGE_SIZE) { + this.pages_[addr >> devtools.profiler.CodeMap.PAGE_ALIGNMENT] = 1; + } +}; + + +/** + * @private + */ +devtools.profiler.CodeMap.prototype.isAddressBelongsTo_ = function(addr, node) { + return addr >= node.key && addr < (node.key + node.value.size); +}; + + +/** + * @private + */ +devtools.profiler.CodeMap.prototype.findInTree_ = function(tree, addr) { + var node = tree.findGreatestLessThan(addr); + return node && this.isAddressBelongsTo_(addr, node) ? node.value : null; +}; + + +/** + * Finds a code entry that contains the specified address. Both static and + * dynamic code entries are considered. + * + * @param {number} addr Address. + */ +devtools.profiler.CodeMap.prototype.findEntry = function(addr) { + var pageAddr = addr >> devtools.profiler.CodeMap.PAGE_ALIGNMENT; + if (pageAddr in this.pages_) { + return this.findInTree_(this.statics_, addr); + } + var min = this.dynamics_.findMin(); + var max = this.dynamics_.findMax(); + if (max != null && addr < (max.key + max.value.size) && addr >= min.key) { + var dynaEntry = this.findInTree_(this.dynamics_, addr); + if (dynaEntry == null) return null; + // Dedupe entry name. + if (!dynaEntry.nameUpdated_) { + dynaEntry.name = this.dynamicsNameGen_.getName(dynaEntry.name); + dynaEntry.nameUpdated_ = true; + } + return dynaEntry; + } + return null; +}; + + +/** + * Returns an array of all dynamic code entries, including deleted ones. + */ +devtools.profiler.CodeMap.prototype.getAllDynamicEntries = function() { + return this.dynamics_.exportValues(); +}; + + +/** + * Returns an array of all static code entries. + */ +devtools.profiler.CodeMap.prototype.getAllStaticEntries = function() { + return this.statics_.exportValues(); +}; + + +/** + * Creates a code entry object. + * + * @param {number} size Code entry size in bytes. + * @param {string} opt_name Code entry name. + * @constructor + */ +devtools.profiler.CodeMap.CodeEntry = function(size, opt_name) { + this.size = size; + this.name = opt_name || ''; + this.nameUpdated_ = false; +}; + + +devtools.profiler.CodeMap.CodeEntry.prototype.getName = function() { + return this.name; +}; + + +devtools.profiler.CodeMap.CodeEntry.prototype.toString = function() { + return this.name + ': ' + this.size.toString(16); +}; + + +devtools.profiler.CodeMap.NameGenerator = function() { + this.knownNames_ = []; +}; + + +devtools.profiler.CodeMap.NameGenerator.prototype.getName = function(name) { + if (!(name in this.knownNames_)) { + this.knownNames_[name] = 0; + return name; + } + var count = ++this.knownNames_[name]; + return name + ' {' + count + '}'; +}; diff --git a/deps/v8/tools/consarray.js b/deps/v8/tools/consarray.js new file mode 100644 index 000000000..c67abb797 --- /dev/null +++ b/deps/v8/tools/consarray.js @@ -0,0 +1,93 @@ +// Copyright 2009 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. + + +/** + * Constructs a ConsArray object. It is used mainly for tree traversal. + * In this use case we have lots of arrays that we need to iterate + * sequentally. The internal Array implementation is horribly slow + * when concatenating on large (10K items) arrays due to memory copying. + * That's why we avoid copying memory and insead build a linked list + * of arrays to iterate through. + * + * @constructor + */ +function ConsArray() { + this.tail_ = new ConsArray.Cell(null, null); + this.currCell_ = this.tail_; + this.currCellPos_ = 0; +}; + + +/** + * Concatenates another array for iterating. Empty arrays are ignored. + * This operation can be safely performed during ongoing ConsArray + * iteration. + * + * @param {Array} arr Array to concatenate. + */ +ConsArray.prototype.concat = function(arr) { + if (arr.length > 0) { + this.tail_.data = arr; + this.tail_ = this.tail_.next = new ConsArray.Cell(null, null); + } +}; + + +/** + * Whether the end of iteration is reached. + */ +ConsArray.prototype.atEnd = function() { + return this.currCell_ === null || + this.currCell_.data === null || + this.currCellPos_ >= this.currCell_.data.length; +}; + + +/** + * Returns the current item, moves to the next one. + */ +ConsArray.prototype.next = function() { + var result = this.currCell_.data[this.currCellPos_++]; + if (this.currCellPos_ >= this.currCell_.data.length) { + this.currCell_ = this.currCell_.next; + this.currCellPos_ = 0; + } + return result; +}; + + +/** + * A cell object used for constructing a list in ConsArray. + * + * @constructor + */ +ConsArray.Cell = function(data, next) { + this.data = data; + this.next = next; +}; + diff --git a/deps/v8/tools/csvparser.js b/deps/v8/tools/csvparser.js new file mode 100644 index 000000000..9e58deaea --- /dev/null +++ b/deps/v8/tools/csvparser.js @@ -0,0 +1,98 @@ +// Copyright 2009 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. + + +// Initlialize namespaces. +var devtools = devtools || {}; +devtools.profiler = devtools.profiler || {}; + + +/** + * Creates a CSV lines parser. + */ +devtools.profiler.CsvParser = function() { +}; + + +/** + * A regex for matching a trailing quote. + * @private + */ +devtools.profiler.CsvParser.TRAILING_QUOTE_RE_ = /\"$/; + + +/** + * A regex for matching a double quote. + * @private + */ +devtools.profiler.CsvParser.DOUBLE_QUOTE_RE_ = /\"\"/g; + + +/** + * Parses a line of CSV-encoded values. Returns an array of fields. + * + * @param {string} line Input line. + */ +devtools.profiler.CsvParser.prototype.parseLine = function(line) { + var insideQuotes = false; + var fields = []; + var prevPos = 0; + for (var i = 0, n = line.length; i < n; ++i) { + switch (line.charAt(i)) { + case ',': + if (!insideQuotes) { + fields.push(line.substring(prevPos, i)); + prevPos = i + 1; + } + break; + case '"': + if (!insideQuotes) { + insideQuotes = true; + // Skip the leading quote. + prevPos++; + } else { + if (i + 1 < n && line.charAt(i + 1) != '"') { + insideQuotes = false; + } else { + i++; + } + } + break; + } + } + if (n > 0) { + fields.push(line.substring(prevPos)); + } + + for (i = 0; i < fields.length; ++i) { + // Eliminate trailing quotes. + fields[i] = fields[i].replace(devtools.profiler.CsvParser.TRAILING_QUOTE_RE_, ''); + // Convert quoted quotes into single ones. + fields[i] = fields[i].replace(devtools.profiler.CsvParser.DOUBLE_QUOTE_RE_, '"'); + } + return fields; +}; diff --git a/deps/v8/tools/gyp/v8.gyp b/deps/v8/tools/gyp/v8.gyp new file mode 100644 index 000000000..e980ff167 --- /dev/null +++ b/deps/v8/tools/gyp/v8.gyp @@ -0,0 +1,726 @@ +# Copyright 2009 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. + +{ + 'variables': { + 'chromium_code': 1, + 'msvs_use_common_release': 0, + 'base_source_files': [ + '../../src/arm/assembler-arm-inl.h', + '../../src/arm/assembler-arm.cc', + '../../src/arm/assembler-arm.h', + '../../src/arm/builtins-arm.cc', + '../../src/arm/codegen-arm.cc', + '../../src/arm/codegen-arm.h', + '../../src/arm/constants-arm.h', + '../../src/arm/cpu-arm.cc', + '../../src/arm/debug-arm.cc', + '../../src/arm/disasm-arm.cc', + '../../src/arm/frames-arm.cc', + '../../src/arm/frames-arm.h', + '../../src/arm/ic-arm.cc', + '../../src/arm/jump-target-arm.cc', + '../../src/arm/macro-assembler-arm.cc', + '../../src/arm/macro-assembler-arm.h', + '../../src/arm/regexp-macro-assembler-arm.cc', + '../../src/arm/regexp-macro-assembler-arm.h', + '../../src/arm/register-allocator-arm.cc', + '../../src/arm/simulator-arm.cc', + '../../src/arm/stub-cache-arm.cc', + '../../src/arm/virtual-frame-arm.cc', + '../../src/arm/virtual-frame-arm.h', + '../../src/ia32/assembler-ia32-inl.h', + '../../src/ia32/assembler-ia32.cc', + '../../src/ia32/assembler-ia32.h', + '../../src/ia32/builtins-ia32.cc', + '../../src/ia32/codegen-ia32.cc', + '../../src/ia32/codegen-ia32.h', + '../../src/ia32/cpu-ia32.cc', + '../../src/ia32/debug-ia32.cc', + '../../src/ia32/disasm-ia32.cc', + '../../src/ia32/frames-ia32.cc', + '../../src/ia32/frames-ia32.h', + '../../src/ia32/ic-ia32.cc', + '../../src/ia32/jump-target-ia32.cc', + '../../src/ia32/macro-assembler-ia32.cc', + '../../src/ia32/macro-assembler-ia32.h', + '../../src/ia32/regexp-macro-assembler-ia32.cc', + '../../src/ia32/regexp-macro-assembler-ia32.h', + '../../src/ia32/register-allocator-ia32.cc', + '../../src/ia32/stub-cache-ia32.cc', + '../../src/ia32/virtual-frame-ia32.cc', + '../../src/ia32/virtual-frame-ia32.h', + '../../src/third_party/dtoa/dtoa.c', + '../../src/accessors.cc', + '../../src/accessors.h', + '../../src/allocation.cc', + '../../src/allocation.h', + '../../src/api.cc', + '../../src/api.h', + '../../src/apiutils.h', + '../../src/arguments.h', + '../../src/assembler.cc', + '../../src/assembler.h', + '../../src/ast.cc', + '../../src/ast.h', + '../../src/bootstrapper.cc', + '../../src/bootstrapper.h', + '../../src/builtins.cc', + '../../src/builtins.h', + '../../src/bytecodes-irregexp.h', + '../../src/char-predicates-inl.h', + '../../src/char-predicates.h', + '../../src/checks.cc', + '../../src/checks.h', + '../../src/code-stubs.cc', + '../../src/code-stubs.h', + '../../src/code.h', + '../../src/codegen-inl.h', + '../../src/codegen.cc', + '../../src/codegen.h', + '../../src/compilation-cache.cc', + '../../src/compilation-cache.h', + '../../src/compiler.cc', + '../../src/compiler.h', + '../../src/contexts.cc', + '../../src/contexts.h', + '../../src/conversions-inl.h', + '../../src/conversions.cc', + '../../src/conversions.h', + '../../src/counters.cc', + '../../src/counters.h', + '../../src/cpu.h', + '../../src/dateparser.cc', + '../../src/dateparser.h', + '../../src/dateparser-inl.h', + '../../src/debug.cc', + '../../src/debug.h', + '../../src/debug-agent.cc', + '../../src/debug-agent.h', + '../../src/disasm.h', + '../../src/disassembler.cc', + '../../src/disassembler.h', + '../../src/dtoa-config.c', + '../../src/execution.cc', + '../../src/execution.h', + '../../src/factory.cc', + '../../src/factory.h', + '../../src/flag-definitions.h', + '../../src/flags.cc', + '../../src/flags.h', + '../../src/frames-inl.h', + '../../src/frames.cc', + '../../src/frames.h', + '../../src/func-name-inferrer.cc', + '../../src/func-name-inferrer.h', + '../../src/global-handles.cc', + '../../src/global-handles.h', + '../../src/globals.h', + '../../src/handles-inl.h', + '../../src/handles.cc', + '../../src/handles.h', + '../../src/hashmap.cc', + '../../src/hashmap.h', + '../../src/heap-inl.h', + '../../src/heap.cc', + '../../src/heap.h', + '../../src/ic-inl.h', + '../../src/ic.cc', + '../../src/ic.h', + '../../src/interpreter-irregexp.cc', + '../../src/interpreter-irregexp.h', + '../../src/jump-target.cc', + '../../src/jump-target.h', + '../../src/jsregexp-inl.h', + '../../src/jsregexp.cc', + '../../src/jsregexp.h', + '../../src/list-inl.h', + '../../src/list.h', + '../../src/log.cc', + '../../src/log.h', + '../../src/macro-assembler.h', + '../../src/mark-compact.cc', + '../../src/mark-compact.h', + '../../src/memory.h', + '../../src/messages.cc', + '../../src/messages.h', + '../../src/natives.h', + '../../src/objects-debug.cc', + '../../src/objects-inl.h', + '../../src/objects.cc', + '../../src/objects.h', + '../../src/oprofile-agent.h', + '../../src/oprofile-agent.cc', + '../../src/parser.cc', + '../../src/parser.h', + '../../src/platform-freebsd.cc', + '../../src/platform-linux.cc', + '../../src/platform-macos.cc', + '../../src/platform-nullos.cc', + '../../src/platform-posix.cc', + '../../src/platform-win32.cc', + '../../src/platform.h', + '../../src/prettyprinter.cc', + '../../src/prettyprinter.h', + '../../src/property.cc', + '../../src/property.h', + '../../src/regexp-macro-assembler-irregexp-inl.h', + '../../src/regexp-macro-assembler-irregexp.cc', + '../../src/regexp-macro-assembler-irregexp.h', + '../../src/regexp-macro-assembler-tracer.cc', + '../../src/regexp-macro-assembler-tracer.h', + '../../src/regexp-macro-assembler.cc', + '../../src/regexp-macro-assembler.h', + '../../src/regexp-stack.cc', + '../../src/regexp-stack.h', + '../../src/register-allocator.h', + '../../src/register-allocator-inl.h', + '../../src/register-allocator.cc', + '../../src/rewriter.cc', + '../../src/rewriter.h', + '../../src/runtime.cc', + '../../src/runtime.h', + '../../src/scanner.cc', + '../../src/scanner.h', + '../../src/scopeinfo.cc', + '../../src/scopeinfo.h', + '../../src/scopes.cc', + '../../src/scopes.h', + '../../src/serialize.cc', + '../../src/serialize.h', + '../../src/shell.h', + '../../src/smart-pointer.h', + '../../src/snapshot-common.cc', + '../../src/snapshot.h', + '../../src/spaces-inl.h', + '../../src/spaces.cc', + '../../src/spaces.h', + '../../src/string-stream.cc', + '../../src/string-stream.h', + '../../src/stub-cache.cc', + '../../src/stub-cache.h', + '../../src/token.cc', + '../../src/token.h', + '../../src/top.cc', + '../../src/top.h', + '../../src/unicode-inl.h', + '../../src/unicode.cc', + '../../src/unicode.h', + '../../src/usage-analyzer.cc', + '../../src/usage-analyzer.h', + '../../src/utils.cc', + '../../src/utils.h', + '../../src/v8-counters.cc', + '../../src/v8-counters.h', + '../../src/v8.cc', + '../../src/v8.h', + '../../src/v8threads.cc', + '../../src/v8threads.h', + '../../src/variables.cc', + '../../src/variables.h', + '../../src/version.cc', + '../../src/version.h', + '../../src/virtual-frame.h', + '../../src/virtual-frame.cc', + '../../src/zone-inl.h', + '../../src/zone.cc', + '../../src/zone.h', + ], + 'not_base_source_files': [ + # These files are #included by others and are not meant to be compiled + # directly. + '../../src/third_party/dtoa/dtoa.c', + ], + 'd8_source_files': [ + '../../src/d8-debug.cc', + '../../src/d8-posix.cc', + '../../src/d8-readline.cc', + '../../src/d8-windows.cc', + '../../src/d8.cc', + ], + }, + 'includes': [ + '../../../build/common.gypi', + ], + 'target_defaults': { + 'defines': [ + 'ENABLE_LOGGING_AND_PROFILING', + ], + 'configurations': { + 'Debug': { + 'defines': [ + 'DEBUG', + '_DEBUG', + 'ENABLE_DISASSEMBLER', + ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'Optimizations': '0', + 'RuntimeLibrary': '1', + }, + 'VCLinkerTool': { + 'LinkIncremental': '2', + }, + }, + }, + 'Release': { + 'conditions': [ + ['OS=="linux"', { + 'cflags!': [ + '-O2', + ], + 'cflags': [ + '-fomit-frame-pointer', + '-O3', + ], + 'cflags_cc': [ + '-fno-rtti', + ], + }], + ['OS=="win"', { + 'msvs_configuration_attributes': { + 'OutputDirectory': '$(SolutionDir)$(ConfigurationName)', + 'IntermediateDirectory': '$(OutDir)\\obj\\$(ProjectName)', + 'CharacterSet': '1', + }, + 'msvs_settings': { + 'VCCLCompilerTool': { + 'RuntimeLibrary': '0', + 'Optimizations': '2', + 'InlineFunctionExpansion': '2', + 'EnableIntrinsicFunctions': 'true', + 'FavorSizeOrSpeed': '0', + 'OmitFramePointers': 'true', + 'StringPooling': 'true', + }, + 'VCLinkerTool': { + 'LinkIncremental': '1', + 'OptimizeReferences': '2', + 'OptimizeForWindows98': '1', + 'EnableCOMDATFolding': '2', + }, + }, + }], + ], + }, + }, + 'xcode_settings': { + 'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', + 'GCC_ENABLE_CPP_RTTI': 'NO', + }, + }, + 'targets': [ + # Targets that apply to any architecture. + { + 'target_name': 'js2c', + 'type': 'none', + 'variables': { + 'library_files': [ + '../../src/runtime.js', + '../../src/v8natives.js', + '../../src/array.js', + '../../src/string.js', + '../../src/uri.js', + '../../src/math.js', + '../../src/messages.js', + '../../src/apinatives.js', + '../../src/debug-delay.js', + '../../src/mirror-delay.js', + '../../src/date-delay.js', + '../../src/json-delay.js', + '../../src/regexp-delay.js', + '../../src/macros.py', + ], + }, + 'actions': [ + { + 'action_name': 'js2c', + 'inputs': [ + '../../tools/js2c.py', + '<@(library_files)', + ], + 'outputs': [ + '<(SHARED_INTERMEDIATE_DIR)/libraries.cc', + '<(SHARED_INTERMEDIATE_DIR)/libraries-empty.cc', + ], + 'action': ['python', '../../tools/js2c.py', '<@(_outputs)', 'CORE', '<@(library_files)'], + }, + ], + }, + { + 'target_name': 'd8_js2c', + 'type': 'none', + 'variables': { + 'library_files': [ + '../../src/d8.js', + '../../src/macros.py', + ], + }, + 'actions': [ + { + 'action_name': 'js2c', + 'inputs': [ + '../../tools/js2c.py', + '<@(library_files)', + ], + 'extra_inputs': [ + ], + 'outputs': [ + '<(SHARED_INTERMEDIATE_DIR)/d8-js.cc', + '<(SHARED_INTERMEDIATE_DIR)/d8-js-empty.cc', + ], + 'action': ['python', '../../tools/js2c.py', '<@(_outputs)', 'D8', '<@(library_files)'], + }, + ], + }, + + # Targets to build v8 for the native architecture (ia32). + { + 'target_name': 'v8_base', + 'type': '<(library)', + 'defines': [ + 'V8_TARGET_ARCH_IA32' + ], + 'include_dirs+': [ + '../../src', + '../../src/ia32', + ], + 'msvs_guid': 'EC8B7909-62AF-470D-A75D-E1D89C837142', + 'sources': [ + '<@(base_source_files)', + ], + 'sources!': [ + '<@(not_base_source_files)', + ], + 'sources/': [ + ['exclude', '-arm\\.cc$'], + ['exclude', 'src/platform-.*\\.cc$' ], + ], + 'conditions': [ + ['OS=="linux"', + { + 'link_settings': { + 'libraries': [ + # Needed for clock_gettime() used by src/platform-linux.cc. + '-lrt', + ], + }, + 'sources/': [ + ['include', 'src/platform-linux\\.cc$'], + ['include', 'src/platform-posix\\.cc$'] + ] + } + ], + ['OS=="mac"', + { + 'sources/': [ + ['include', 'src/platform-macos\\.cc$'], + ['include', 'src/platform-posix\\.cc$'] + ] + } + ], + ['OS=="win"', { + 'sources/': [['include', 'src/platform-win32\\.cc$']], + # 4355, 4800 came from common.vsprops + # 4018, 4244 were a per file config on dtoa-config.c + # TODO: It's probably possible and desirable to stop disabling the + # dtoa-specific warnings by modifying dtoa as was done in Chromium + # r9255. Refer to that revision for details. + 'msvs_disabled_warnings': [4355, 4800, 4018, 4244], + 'link_settings': { + 'libraries': [ '-lwinmm.lib' ], + }, + }], + ], + }, + { + 'target_name': 'v8_nosnapshot', + 'type': '<(library)', + 'defines': [ + 'V8_TARGET_ARCH_IA32' + ], + 'dependencies': [ + 'js2c', + 'v8_base', + ], + 'include_dirs': [ + '../../src', + ], + 'sources': [ + '<(SHARED_INTERMEDIATE_DIR)/libraries.cc', + '../../src/snapshot-empty.cc', + ], + 'export_dependent_settings': [ + 'v8_base', + ], + }, + { + 'target_name': 'mksnapshot', + 'type': 'executable', + 'dependencies': [ + 'v8_nosnapshot', + ], + 'msvs_guid': '865575D0-37E2-405E-8CBA-5F6C485B5A26', + 'sources': [ + '../../src/mksnapshot.cc', + ], + }, + { + 'target_name': 'v8', + 'type': '<(library)', + 'defines': [ + 'V8_TARGET_ARCH_IA32' + ], + 'dependencies': [ + 'js2c', + 'mksnapshot', + 'v8_base', + ], + 'msvs_guid': '21E22961-22BF-4493-BD3A-868F93DA5179', + 'actions': [ + { + 'action_name': 'mksnapshot', + 'inputs': [ + '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)mksnapshot<(EXECUTABLE_SUFFIX)', + ], + 'outputs': [ + '<(INTERMEDIATE_DIR)/snapshot.cc', + ], + 'action': ['<@(_inputs)', '<@(_outputs)'], + }, + ], + 'include_dirs': [ + '../../src', + ], + 'sources': [ + '<(SHARED_INTERMEDIATE_DIR)/libraries-empty.cc', + '<(INTERMEDIATE_DIR)/snapshot.cc', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '../../include', + ], + }, + 'export_dependent_settings': [ + 'v8_base', + ], + }, + { + 'target_name': 'v8_shell', + 'type': 'executable', + 'defines': [ + 'V8_TARGET_ARCH_IA32' + ], + 'dependencies': [ + 'v8', + ], + 'sources': [ + '../../samples/shell.cc', + ], + 'conditions': [ + [ 'OS=="win"', { + # This could be gotten by not setting chromium_code, if that's OK. + 'defines': ['_CRT_SECURE_NO_WARNINGS'], + }], + ], + }, + ], + + 'conditions': [ ['OS=="mac"', { 'targets': [ + # TODO(bradnelson): temporarily disable 'd8' target on Windows while + # we work fix the performance regressions. + # TODO(sgk): temporarily disable 'd8' target on Linux while + # we work out getting the readline library on all the systems. + { + 'target_name': 'd8', + 'type': 'executable', + 'dependencies': [ + 'd8_js2c', + 'v8', + ], + 'defines': [ + 'V8_TARGET_ARCH_IA32' + ], + 'include_dirs': [ + '../../src', + ], + 'sources': [ + '<(SHARED_INTERMEDIATE_DIR)/d8-js.cc', + '<@(d8_source_files)', + ], + 'conditions': [ + [ 'OS=="linux"', { + 'sources!': [ '../../src/d8-windows.cc' ], + 'link_settings': { 'libraries': [ '-lreadline' ] }, + }], + [ 'OS=="mac"', { + 'sources!': [ '../../src/d8-windows.cc' ], + 'link_settings': { 'libraries': [ + '$(SDKROOT)/usr/lib/libreadline.dylib' + ]}, + }], + [ 'OS=="win"', { + 'sources!': [ '../../src/d8-readline.cc', '../../src/d8-posix.cc' ], + }], + ], + }, + # TODO(sgk): temporarily disable the arm targets on Linux while + # we work out how to refactor the generator and/or add configuration + # settings to the .gyp file to handle building both variants in + # the same output directory. + # + # ARM targets, to test ARM code generation. These use an ARM simulator + # (src/simulator-arm.cc). The ARM targets are not snapshot-enabled. + { + 'target_name': 'v8_arm', + 'type': '<(library)', + 'dependencies': [ + 'js2c', + ], + 'defines': [ + 'V8_TARGET_ARCH_ARM', + ], + 'include_dirs+': [ + '../../src', + '../../src/arm', + ], + 'sources': [ + '<@(base_source_files)', + '<(SHARED_INTERMEDIATE_DIR)/libraries.cc', + '../../src/snapshot-empty.cc', + ], + 'sources!': [ + '<@(not_base_source_files)', + ], + 'sources/': [ + ['exclude', '-ia32\\.cc$'], + ['exclude', 'src/platform-.*\\.cc$' ], + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '../../include', + ], + }, + 'conditions': [ + ['OS=="linux"', + { + 'sources/': [ + ['include', 'src/platform-linux\\.cc$'], + ['include', 'src/platform-posix\\.cc$'] + ] + } + ], + ['OS=="mac"', + { + 'sources/': [ + ['include', 'src/platform-macos\\.cc$'], + ['include', 'src/platform-posix\\.cc$'] + ] + } + ], + ['OS=="win"', { + 'sources/': [['include', 'src/platform-win32\\.cc$']], + # 4355, 4800 came from common.vsprops + # 4018, 4244 were a per file config on dtoa-config.c + # TODO: It's probably possible and desirable to stop disabling the + # dtoa-specific warnings by modifying dtoa as was done in Chromium + # r9255. Refer to that revision for details. + 'msvs_disabled_warnings': [4355, 4800, 4018, 4244], + }], + ], + }, + { + 'target_name': 'v8_shell_arm', + 'type': 'executable', + 'dependencies': [ + 'v8_arm', + ], + 'defines': [ + 'V8_TARGET_ARCH_ARM', + ], + 'sources': [ + '../../samples/shell.cc', + ], + 'conditions': [ + [ 'OS=="win"', { + # This could be gotten by not setting chromium_code, if that's OK. + 'defines': ['_CRT_SECURE_NO_WARNINGS'], + }], + ], + }, + { + 'target_name': 'd8_arm', + 'type': 'executable', + 'dependencies': [ + 'd8_js2c', + 'v8_arm', + ], + 'defines': [ + 'V8_TARGET_ARCH_ARM', + ], + 'include_dirs': [ + '../../src', + ], + 'sources': [ + '<(SHARED_INTERMEDIATE_DIR)/d8-js.cc', + '<@(d8_source_files)', + ], + 'conditions': [ + [ 'OS=="linux"', { + 'sources!': [ '../../src/d8-windows.cc' ], + 'link_settings': { 'libraries': [ '-lreadline' ] }, + }], + [ 'OS=="mac"', { + 'sources!': [ '../../src/d8-windows.cc' ], + 'link_settings': { 'libraries': [ + '$(SDKROOT)/usr/lib/libreadline.dylib' + ]}, + }], + [ 'OS=="win"', { + 'sources!': [ '../../src/d8-readline.cc', '../../src/d8-posix.cc' ], + }], + ], + }, + ]}], # OS != "linux" (temporary, TODO(sgk)) + + + ['OS=="win"', { + 'target_defaults': { + 'defines': [ + '_USE_32BIT_TIME_T', + '_CRT_SECURE_NO_DEPRECATE', + '_CRT_NONSTDC_NO_DEPRECATE', + ], + 'msvs_settings': { + 'VCLinkerTool': { + 'AdditionalOptions': '/IGNORE:4221 /NXCOMPAT', + }, + }, + }, + }], + ], +} diff --git a/deps/v8/tools/linux-tick-processor b/deps/v8/tools/linux-tick-processor new file mode 100644 index 000000000..0ad295f14 --- /dev/null +++ b/deps/v8/tools/linux-tick-processor @@ -0,0 +1,16 @@ +#!/bin/sh + +tools_dir=$(dirname "$0") + +if [ "$1" != "--no-build" ] +then + scons -C $tools_dir/.. d8 +else + shift +fi + +# nm spits out 'no symbols found' messages on stderr +$tools_dir/../d8 $tools_dir/splaytree.js $tools_dir/codemap.js \ + $tools_dir/csvparser.js $tools_dir/consarray.js \ + $tools_dir/profile.js $tools_dir/profile_view.js \ + $tools_dir/tickprocessor.js -- $@ 2>/dev/null diff --git a/deps/v8/tools/profile.js b/deps/v8/tools/profile.js new file mode 100644 index 000000000..614c63557 --- /dev/null +++ b/deps/v8/tools/profile.js @@ -0,0 +1,605 @@ +// Copyright 2009 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. + + +// Initlialize namespaces +var devtools = devtools || {}; +devtools.profiler = devtools.profiler || {}; + + +/** + * Creates a profile object for processing profiling-related events + * and calculating function execution times. + * + * @constructor + */ +devtools.profiler.Profile = function() { + this.codeMap_ = new devtools.profiler.CodeMap(); + this.topDownTree_ = new devtools.profiler.CallTree(); + this.bottomUpTree_ = new devtools.profiler.CallTree(); +}; + + +/** + * Returns whether a function with the specified name must be skipped. + * Should be overriden by subclasses. + * + * @param {string} name Function name. + */ +devtools.profiler.Profile.prototype.skipThisFunction = function(name) { + return false; +}; + + +/** + * Enum for profiler operations that involve looking up existing + * code entries. + * + * @enum {number} + */ +devtools.profiler.Profile.Operation = { + MOVE: 0, + DELETE: 1, + TICK: 2 +}; + + +/** + * Called whenever the specified operation has failed finding a function + * containing the specified address. Should be overriden by subclasses. + * See the devtools.profiler.Profile.Operation enum for the list of + * possible operations. + * + * @param {number} operation Operation. + * @param {number} addr Address of the unknown code. + * @param {number} opt_stackPos If an unknown address is encountered + * during stack strace processing, specifies a position of the frame + * containing the address. + */ +devtools.profiler.Profile.prototype.handleUnknownCode = function( + operation, addr, opt_stackPos) { +}; + + +/** + * Registers static (library) code entry. + * + * @param {string} name Code entry name. + * @param {number} startAddr Starting address. + * @param {number} endAddr Ending address. + */ +devtools.profiler.Profile.prototype.addStaticCode = function( + name, startAddr, endAddr) { + var entry = new devtools.profiler.CodeMap.CodeEntry( + endAddr - startAddr, name); + this.codeMap_.addStaticCode(startAddr, entry); + return entry; +}; + + +/** + * Registers dynamic (JIT-compiled) code entry. + * + * @param {string} type Code entry type. + * @param {string} name Code entry name. + * @param {number} start Starting address. + * @param {number} size Code entry size. + */ +devtools.profiler.Profile.prototype.addCode = function( + type, name, start, size) { + var entry = new devtools.profiler.Profile.DynamicCodeEntry(size, type, name); + this.codeMap_.addCode(start, entry); + return entry; +}; + + +/** + * Reports about moving of a dynamic code entry. + * + * @param {number} from Current code entry address. + * @param {number} to New code entry address. + */ +devtools.profiler.Profile.prototype.moveCode = function(from, to) { + try { + this.codeMap_.moveCode(from, to); + } catch (e) { + this.handleUnknownCode(devtools.profiler.Profile.Operation.MOVE, from); + } +}; + + +/** + * Reports about deletion of a dynamic code entry. + * + * @param {number} start Starting address. + */ +devtools.profiler.Profile.prototype.deleteCode = function(start) { + try { + this.codeMap_.deleteCode(start); + } catch (e) { + this.handleUnknownCode(devtools.profiler.Profile.Operation.DELETE, start); + } +}; + + +/** + * Records a tick event. Stack must contain a sequence of + * addresses starting with the program counter value. + * + * @param {Array<number>} stack Stack sample. + */ +devtools.profiler.Profile.prototype.recordTick = function(stack) { + var processedStack = this.resolveAndFilterFuncs_(stack); + this.bottomUpTree_.addPath(processedStack); + processedStack.reverse(); + this.topDownTree_.addPath(processedStack); +}; + + +/** + * Translates addresses into function names and filters unneeded + * functions. + * + * @param {Array<number>} stack Stack sample. + */ +devtools.profiler.Profile.prototype.resolveAndFilterFuncs_ = function(stack) { + var result = []; + for (var i = 0; i < stack.length; ++i) { + var entry = this.codeMap_.findEntry(stack[i]); + if (entry) { + var name = entry.getName(); + if (!this.skipThisFunction(name)) { + result.push(name); + } + } else { + this.handleUnknownCode( + devtools.profiler.Profile.Operation.TICK, stack[i], i); + } + } + return result; +}; + + +/** + * Performs a BF traversal of the top down call graph. + * + * @param {function(devtools.profiler.CallTree.Node)} f Visitor function. + */ +devtools.profiler.Profile.prototype.traverseTopDownTree = function(f) { + this.topDownTree_.traverse(f); +}; + + +/** + * Performs a BF traversal of the bottom up call graph. + * + * @param {function(devtools.profiler.CallTree.Node)} f Visitor function. + */ +devtools.profiler.Profile.prototype.traverseBottomUpTree = function(f) { + this.bottomUpTree_.traverse(f); +}; + + +/** + * Calculates a top down profile for a node with the specified label. + * If no name specified, returns the whole top down calls tree. + * + * @param {string} opt_label Node label. + */ +devtools.profiler.Profile.prototype.getTopDownProfile = function(opt_label) { + return this.getTreeProfile_(this.topDownTree_, opt_label); +}; + + +/** + * Calculates a bottom up profile for a node with the specified label. + * If no name specified, returns the whole bottom up calls tree. + * + * @param {string} opt_label Node label. + */ +devtools.profiler.Profile.prototype.getBottomUpProfile = function(opt_label) { + return this.getTreeProfile_(this.bottomUpTree_, opt_label); +}; + + +/** + * Helper function for calculating a tree profile. + * + * @param {devtools.profiler.Profile.CallTree} tree Call tree. + * @param {string} opt_label Node label. + */ +devtools.profiler.Profile.prototype.getTreeProfile_ = function(tree, opt_label) { + if (!opt_label) { + tree.computeTotalWeights(); + return tree; + } else { + var subTree = tree.cloneSubtree(opt_label); + subTree.computeTotalWeights(); + return subTree; + } +}; + + +/** + * Calculates a flat profile of callees starting from a node with + * the specified label. If no name specified, starts from the root. + * + * @param {string} opt_label Starting node label. + */ +devtools.profiler.Profile.prototype.getFlatProfile = function(opt_label) { + var counters = new devtools.profiler.CallTree(); + var rootLabel = opt_label || devtools.profiler.CallTree.ROOT_NODE_LABEL; + var precs = {}; + precs[rootLabel] = 0; + var root = counters.findOrAddChild(rootLabel); + + this.topDownTree_.computeTotalWeights(); + this.topDownTree_.traverseInDepth( + function onEnter(node) { + if (!(node.label in precs)) { + precs[node.label] = 0; + } + var nodeLabelIsRootLabel = node.label == rootLabel; + if (nodeLabelIsRootLabel || precs[rootLabel] > 0) { + if (precs[rootLabel] == 0) { + root.selfWeight += node.selfWeight; + root.totalWeight += node.totalWeight; + } else { + var rec = root.findOrAddChild(node.label); + rec.selfWeight += node.selfWeight; + if (nodeLabelIsRootLabel || precs[node.label] == 0) { + rec.totalWeight += node.totalWeight; + } + } + precs[node.label]++; + } + }, + function onExit(node) { + if (node.label == rootLabel || precs[rootLabel] > 0) { + precs[node.label]--; + } + }, + null); + + if (!opt_label) { + // If we have created a flat profile for the whole program, we don't + // need an explicit root in it. Thus, replace the counters tree + // root with the node corresponding to the whole program. + counters.root_ = root; + } else { + // Propagate weights so percents can be calculated correctly. + counters.getRoot().selfWeight = root.selfWeight; + counters.getRoot().totalWeight = root.totalWeight; + } + return counters; +}; + + +/** + * Creates a dynamic code entry. + * + * @param {number} size Code size. + * @param {string} type Code type. + * @param {string} name Function name. + * @constructor + */ +devtools.profiler.Profile.DynamicCodeEntry = function(size, type, name) { + devtools.profiler.CodeMap.CodeEntry.call(this, size, name); + this.type = type; +}; + + +/** + * Returns node name. + */ +devtools.profiler.Profile.DynamicCodeEntry.prototype.getName = function() { + var name = this.name; + if (name.length == 0) { + name = '<anonymous>'; + } else if (name.charAt(0) == ' ') { + // An anonymous function with location: " aaa.js:10". + name = '<anonymous>' + name; + } + return this.type + ': ' + name; +}; + + +/** + * Constructs a call graph. + * + * @constructor + */ +devtools.profiler.CallTree = function() { + this.root_ = new devtools.profiler.CallTree.Node( + devtools.profiler.CallTree.ROOT_NODE_LABEL); +}; + + +/** + * The label of the root node. + */ +devtools.profiler.CallTree.ROOT_NODE_LABEL = ''; + + +/** + * @private + */ +devtools.profiler.CallTree.prototype.totalsComputed_ = false; + + +/** + * Returns the tree root. + */ +devtools.profiler.CallTree.prototype.getRoot = function() { + return this.root_; +}; + + +/** + * Adds the specified call path, constructing nodes as necessary. + * + * @param {Array<string>} path Call path. + */ +devtools.profiler.CallTree.prototype.addPath = function(path) { + if (path.length == 0) { + return; + } + var curr = this.root_; + for (var i = 0; i < path.length; ++i) { + curr = curr.findOrAddChild(path[i]); + } + curr.selfWeight++; + this.totalsComputed_ = false; +}; + + +/** + * Finds an immediate child of the specified parent with the specified + * label, creates a child node if necessary. If a parent node isn't + * specified, uses tree root. + * + * @param {string} label Child node label. + */ +devtools.profiler.CallTree.prototype.findOrAddChild = function(label) { + return this.root_.findOrAddChild(label); +}; + + +/** + * Creates a subtree by cloning and merging all subtrees rooted at nodes + * with a given label. E.g. cloning the following call tree on label 'A' + * will give the following result: + * + * <A>--<B> <B> + * / / + * <root> == clone on 'A' ==> <root>--<A> + * \ \ + * <C>--<A>--<D> <D> + * + * And <A>'s selfWeight will be the sum of selfWeights of <A>'s from the + * source call tree. + * + * @param {string} label The label of the new root node. + */ +devtools.profiler.CallTree.prototype.cloneSubtree = function(label) { + var subTree = new devtools.profiler.CallTree(); + this.traverse(function(node, parent) { + if (!parent && node.label != label) { + return null; + } + var child = (parent ? parent : subTree).findOrAddChild(node.label); + child.selfWeight += node.selfWeight; + return child; + }); + return subTree; +}; + + +/** + * Computes total weights in the call graph. + */ +devtools.profiler.CallTree.prototype.computeTotalWeights = function() { + if (this.totalsComputed_) { + return; + } + this.root_.computeTotalWeight(); + this.totalsComputed_ = true; +}; + + +/** + * Traverses the call graph in preorder. This function can be used for + * building optionally modified tree clones. This is the boilerplate code + * for this scenario: + * + * callTree.traverse(function(node, parentClone) { + * var nodeClone = cloneNode(node); + * if (parentClone) + * parentClone.addChild(nodeClone); + * return nodeClone; + * }); + * + * @param {function(devtools.profiler.CallTree.Node, *)} f Visitor function. + * The second parameter is the result of calling 'f' on the parent node. + */ +devtools.profiler.CallTree.prototype.traverse = function(f) { + var pairsToProcess = new ConsArray(); + pairsToProcess.concat([{node: this.root_, param: null}]); + while (!pairsToProcess.atEnd()) { + var pair = pairsToProcess.next(); + var node = pair.node; + var newParam = f(node, pair.param); + var morePairsToProcess = []; + node.forEachChild(function (child) { + morePairsToProcess.push({node: child, param: newParam}); }); + pairsToProcess.concat(morePairsToProcess); + } +}; + + +/** + * Performs an indepth call graph traversal. + * + * @param {function(devtools.profiler.CallTree.Node)} enter A function called + * prior to visiting node's children. + * @param {function(devtools.profiler.CallTree.Node)} exit A function called + * after visiting node's children. + */ +devtools.profiler.CallTree.prototype.traverseInDepth = function(enter, exit) { + function traverse(node) { + enter(node); + node.forEachChild(traverse); + exit(node); + } + traverse(this.root_); +}; + + +/** + * Constructs a call graph node. + * + * @param {string} label Node label. + * @param {devtools.profiler.CallTree.Node} opt_parent Node parent. + */ +devtools.profiler.CallTree.Node = function(label, opt_parent) { + this.label = label; + this.parent = opt_parent; + this.children = {}; +}; + + +/** + * Node self weight (how many times this node was the last node in + * a call path). + * @type {number} + */ +devtools.profiler.CallTree.Node.prototype.selfWeight = 0; + + +/** + * Node total weight (includes weights of all children). + * @type {number} + */ +devtools.profiler.CallTree.Node.prototype.totalWeight = 0; + + +/** + * Adds a child node. + * + * @param {string} label Child node label. + */ +devtools.profiler.CallTree.Node.prototype.addChild = function(label) { + var child = new devtools.profiler.CallTree.Node(label, this); + this.children[label] = child; + return child; +}; + + +/** + * Computes node's total weight. + */ +devtools.profiler.CallTree.Node.prototype.computeTotalWeight = + function() { + var totalWeight = this.selfWeight; + this.forEachChild(function(child) { + totalWeight += child.computeTotalWeight(); }); + return this.totalWeight = totalWeight; +}; + + +/** + * Returns all node's children as an array. + */ +devtools.profiler.CallTree.Node.prototype.exportChildren = function() { + var result = []; + this.forEachChild(function (node) { result.push(node); }); + return result; +}; + + +/** + * Finds an immediate child with the specified label. + * + * @param {string} label Child node label. + */ +devtools.profiler.CallTree.Node.prototype.findChild = function(label) { + return this.children[label] || null; +}; + + +/** + * Finds an immediate child with the specified label, creates a child + * node if necessary. + * + * @param {string} label Child node label. + */ +devtools.profiler.CallTree.Node.prototype.findOrAddChild = function(label) { + return this.findChild(label) || this.addChild(label); +}; + + +/** + * Calls the specified function for every child. + * + * @param {function(devtools.profiler.CallTree.Node)} f Visitor function. + */ +devtools.profiler.CallTree.Node.prototype.forEachChild = function(f) { + for (var c in this.children) { + f(this.children[c]); + } +}; + + +/** + * Walks up from the current node up to the call tree root. + * + * @param {function(devtools.profiler.CallTree.Node)} f Visitor function. + */ +devtools.profiler.CallTree.Node.prototype.walkUpToRoot = function(f) { + for (var curr = this; curr != null; curr = curr.parent) { + f(curr); + } +}; + + +/** + * Tries to find a node with the specified path. + * + * @param {Array<string>} labels The path. + * @param {function(devtools.profiler.CallTree.Node)} opt_f Visitor function. + */ +devtools.profiler.CallTree.Node.prototype.descendToChild = function( + labels, opt_f) { + for (var pos = 0, curr = this; pos < labels.length && curr != null; pos++) { + var child = curr.findChild(labels[pos]); + if (opt_f) { + opt_f(child, pos); + } + curr = child; + } + return curr; +}; diff --git a/deps/v8/tools/profile_view.js b/deps/v8/tools/profile_view.js new file mode 100644 index 000000000..cd0511f6b --- /dev/null +++ b/deps/v8/tools/profile_view.js @@ -0,0 +1,323 @@ +// Copyright 2009 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. + + +// Initlialize namespaces +var devtools = devtools || {}; +devtools.profiler = devtools.profiler || {}; + + +/** + * Creates a Profile View builder object. + * + * @param {number} samplingRate Number of ms between profiler ticks. + * @constructor + */ +devtools.profiler.ViewBuilder = function(samplingRate) { + this.samplingRate = samplingRate; +}; + + +/** + * Builds a profile view for the specified call tree. + * + * @param {devtools.profiler.CallTree} callTree A call tree. + */ +devtools.profiler.ViewBuilder.prototype.buildView = function( + callTree) { + var head; + var samplingRate = this.samplingRate; + callTree.traverse(function(node, viewParent) { + var viewNode = new devtools.profiler.ProfileView.Node( + node.label, node.totalWeight * samplingRate, + node.selfWeight * samplingRate, head); + if (viewParent) { + viewParent.addChild(viewNode); + } else { + head = viewNode; + } + return viewNode; + }); + var view = new devtools.profiler.ProfileView(head); + return view; +}; + + +/** + * Creates a Profile View object. It allows to perform sorting + * and filtering actions on the profile. Profile View mimicks + * the Profile object from WebKit's JSC profiler. + * + * @param {devtools.profiler.ProfileView.Node} head Head (root) node. + * @constructor + */ +devtools.profiler.ProfileView = function(head) { + this.head = head; + this.title = ''; + this.uid = ''; + this.heavyProfile = null; + this.treeProfile = null; + this.flatProfile = null; +}; + + +/** + * Updates references between profiles. This is needed for WebKit + * ProfileView. + */ +devtools.profiler.ProfileView.prototype.updateProfilesRefs = function() { + var profileNames = ["treeProfile", "heavyProfile", "flatProfile"]; + for (var i = 0; i < profileNames.length; ++i) { + var destProfile = this[profileNames[i]]; + for (var j = 0; j < profileNames.length; ++j) { + destProfile[profileNames[j]] = this[profileNames[j]]; + } + } +}; + + +/** + * Sorts the profile view using the specified sort function. + * + * @param {function(devtools.profiler.ProfileView.Node, + * devtools.profiler.ProfileView.Node):number} sortFunc A sorting + * functions. Must comply with Array.sort sorting function requirements. + */ +devtools.profiler.ProfileView.prototype.sort = function(sortFunc) { + this.traverse(function (node) { + node.sortChildren(sortFunc); + }); +}; + + +/** + * Sorts the profile view by self time, ascending. + */ +devtools.profiler.ProfileView.prototype.sortSelfTimeAscending = function() { + this.sort(function (node1, node2) { + return node1.selfTime - node2.selfTime; }); +}; + + +/** + * Sorts the profile view by self time, descending. + */ +devtools.profiler.ProfileView.prototype.sortSelfTimeDescending = function() { + this.sort(function (node1, node2) { + return node2.selfTime - node1.selfTime; }); +}; + + +/** + * Sorts the profile view by total time, ascending. + */ +devtools.profiler.ProfileView.prototype.sortTotalTimeAscending = function() { + this.sort(function (node1, node2) { + return node1.totalTime - node2.totalTime; }); +}; + + +/** + * Sorts the profile view by total time, descending. + */ +devtools.profiler.ProfileView.prototype.sortTotalTimeDescending = function() { + this.sort(function (node1, node2) { + return node2.totalTime - node1.totalTime; }); +}; + + +/** + * String comparator compatible with Array.sort requirements. + * + * @param {string} s1 First string. + * @param {string} s2 Second string. + */ +devtools.profiler.ProfileView.compareStrings = function(s1, s2) { + return s1 < s2 ? -1 : (s1 > s2 ? 1 : 0); +}; + + +/** + * Sorts the profile view by function name, ascending. + */ +devtools.profiler.ProfileView.prototype.sortFunctionNameAscending = function() { + this.sort(function (node1, node2) { + return devtools.profiler.ProfileView.compareStrings( + node1.functionName, node2.functionName); }); +}; + + +/** + * Sorts the profile view by function name, descending. + */ +devtools.profiler.ProfileView.prototype.sortFunctionNameDescending = function() { + this.sort(function (node1, node2) { + return devtools.profiler.ProfileView.compareStrings( + node2.functionName, node1.functionName); }); +}; + + +/** + * Traverses profile view nodes in preorder. + * + * @param {function(devtools.profiler.ProfileView.Node)} f Visitor function. + */ +devtools.profiler.ProfileView.prototype.traverse = function(f) { + var nodesToTraverse = new ConsArray(); + nodesToTraverse.concat([this.head]); + while (!nodesToTraverse.atEnd()) { + var node = nodesToTraverse.next(); + f(node); + nodesToTraverse.concat(node.children); + } +}; + + +/** + * Constructs a Profile View node object. Each node object corresponds to + * a function call. + * + * @param {string} internalFuncName A fully qualified function name. + * @param {number} totalTime Amount of time that application spent in the + * corresponding function and its descendants (not that depending on + * profile they can be either callees or callers.) + * @param {number} selfTime Amount of time that application spent in the + * corresponding function only. + * @param {devtools.profiler.ProfileView.Node} head Profile view head. + * @constructor + */ +devtools.profiler.ProfileView.Node = function( + internalFuncName, totalTime, selfTime, head) { + this.callIdentifier = 0; + this.internalFuncName = internalFuncName; + this.initFuncInfo(); + this.totalTime = totalTime; + this.selfTime = selfTime; + this.head = head; + this.parent = null; + this.children = []; + this.visible = true; +}; + + +/** + * RegEx for stripping V8's prefixes of compiled functions. + */ +devtools.profiler.ProfileView.Node.FUNC_NAME_STRIP_RE = + /^(?:LazyCompile|Function): (.*)$/; + + +/** + * RegEx for extracting script source URL and line number. + */ +devtools.profiler.ProfileView.Node.FUNC_NAME_PARSE_RE = /^([^ ]+) (.*):(\d+)$/; + + +/** + * RegEx for removing protocol name from URL. + */ +devtools.profiler.ProfileView.Node.URL_PARSE_RE = /^(?:http:\/)?.*\/([^/]+)$/; + + +/** + * Inits 'functionName', 'url', and 'lineNumber' fields using 'internalFuncName' + * field. + */ +devtools.profiler.ProfileView.Node.prototype.initFuncInfo = function() { + var nodeAlias = devtools.profiler.ProfileView.Node; + this.functionName = this.internalFuncName; + + var strippedName = nodeAlias.FUNC_NAME_STRIP_RE.exec(this.functionName); + if (strippedName) { + this.functionName = strippedName[1]; + } + + var parsedName = nodeAlias.FUNC_NAME_PARSE_RE.exec(this.functionName); + if (parsedName) { + this.url = parsedName[2]; + var parsedUrl = nodeAlias.URL_PARSE_RE.exec(this.url); + if (parsedUrl) { + this.url = parsedUrl[1]; + } + this.functionName = parsedName[1]; + this.lineNumber = parsedName[3]; + } else { + this.url = ''; + this.lineNumber = 0; + } +}; + + +/** + * Returns a share of the function's total time in application's total time. + */ +devtools.profiler.ProfileView.Node.prototype.__defineGetter__( + 'totalPercent', + function() { return this.totalTime / + (this.head ? this.head.totalTime : this.totalTime) * 100.0; }); + + +/** + * Returns a share of the function's self time in application's total time. + */ +devtools.profiler.ProfileView.Node.prototype.__defineGetter__( + 'selfPercent', + function() { return this.selfTime / + (this.head ? this.head.totalTime : this.totalTime) * 100.0; }); + + +/** + * Returns a share of the function's total time in its parent's total time. + */ +devtools.profiler.ProfileView.Node.prototype.__defineGetter__( + 'parentTotalPercent', + function() { return this.totalTime / + (this.parent ? this.parent.totalTime : this.totalTime) * 100.0; }); + + +/** + * Adds a child to the node. + * + * @param {devtools.profiler.ProfileView.Node} node Child node. + */ +devtools.profiler.ProfileView.Node.prototype.addChild = function(node) { + node.parent = this; + this.children.push(node); +}; + + +/** + * Sorts all the node's children recursively. + * + * @param {function(devtools.profiler.ProfileView.Node, + * devtools.profiler.ProfileView.Node):number} sortFunc A sorting + * functions. Must comply with Array.sort sorting function requirements. + */ +devtools.profiler.ProfileView.Node.prototype.sortChildren = function( + sortFunc) { + this.children.sort(sortFunc); +}; diff --git a/deps/v8/tools/splaytree.js b/deps/v8/tools/splaytree.js index 3045456dc..7b3af8b99 100644 --- a/deps/v8/tools/splaytree.js +++ b/deps/v8/tools/splaytree.js @@ -28,7 +28,8 @@ // A namespace stub. It will become more clear how to declare it properly // during integration of this script into Dev Tools. -goog = { structs: {} }; +var goog = goog || {}; +goog.structs = goog.structs || {}; /** @@ -94,7 +95,6 @@ goog.structs.SplayTree.prototype.insert = function(key, value) { }; - /** * Removes a node with the specified key from the tree if the tree * contains a node with this key. The removed node is returned. If the diff --git a/deps/v8/tools/tickprocessor.js b/deps/v8/tools/tickprocessor.js new file mode 100644 index 000000000..196daa984 --- /dev/null +++ b/deps/v8/tools/tickprocessor.js @@ -0,0 +1,646 @@ +// Copyright 2009 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. + + +function Profile(separateIc) { + devtools.profiler.Profile.call(this); + if (!separateIc) { + this.skipThisFunction = function(name) { return Profile.IC_RE.test(name); }; + } +}; +Profile.prototype = devtools.profiler.Profile.prototype; + + +Profile.IC_RE = + /^(?:CallIC|LoadIC|StoreIC)|(?:Builtin: (?:Keyed)?(?:Call|Load|Store)IC_)/; + + +/** + * A thin wrapper around shell's 'read' function showing a file name on error. + */ +function readFile(fileName) { + try { + return read(fileName); + } catch (e) { + print(fileName + ': ' + (e.message || e)); + throw e; + } +} + + +function TickProcessor( + cppEntriesProvider, separateIc, ignoreUnknown, stateFilter) { + this.cppEntriesProvider_ = cppEntriesProvider; + this.ignoreUnknown_ = ignoreUnknown; + this.stateFilter_ = stateFilter; + var ticks = this.ticks_ = + { total: 0, unaccounted: 0, excluded: 0, gc: 0 }; + + Profile.prototype.handleUnknownCode = function( + operation, addr, opt_stackPos) { + var op = devtools.profiler.Profile.Operation; + switch (operation) { + case op.MOVE: + print('Code move event for unknown code: 0x' + addr.toString(16)); + break; + case op.DELETE: + print('Code delete event for unknown code: 0x' + addr.toString(16)); + break; + case op.TICK: + // Only unknown PCs (the first frame) are reported as unaccounted, + // otherwise tick balance will be corrupted (this behavior is compatible + // with the original tickprocessor.py script.) + if (opt_stackPos == 0) { + ticks.unaccounted++; + } + break; + } + }; + + this.profile_ = new Profile(separateIc); + this.codeTypes_ = {}; + // Count each tick as a time unit. + this.viewBuilder_ = new devtools.profiler.ViewBuilder(1); + this.lastLogFileName_ = null; +}; + + +TickProcessor.VmStates = { + JS: 0, + GC: 1, + COMPILER: 2, + OTHER: 3, + EXTERNAL: 4 +}; + + +TickProcessor.CodeTypes = { + CPP: 0, + SHARED_LIB: 1 +}; +// Otherwise, this is JS-related code. We are not adding it to +// codeTypes_ map because there can be zillions of them. + + +TickProcessor.RecordsDispatch = { + 'shared-library': { parsers: [null, parseInt, parseInt], + processor: 'processSharedLibrary' }, + 'code-creation': { parsers: [null, parseInt, parseInt, null], + processor: 'processCodeCreation' }, + 'code-move': { parsers: [parseInt, parseInt], + processor: 'processCodeMove' }, + 'code-delete': { parsers: [parseInt], processor: 'processCodeDelete' }, + 'tick': { parsers: [parseInt, parseInt, parseInt, 'var-args'], + processor: 'processTick' }, + 'profiler': null, + // Obsolete row types. + 'code-allocate': null, + 'begin-code-region': null, + 'end-code-region': null +}; + + +TickProcessor.CALL_PROFILE_CUTOFF_PCT = 2.0; + + +TickProcessor.prototype.setCodeType = function(name, type) { + this.codeTypes_[name] = TickProcessor.CodeTypes[type]; +}; + + +TickProcessor.prototype.isSharedLibrary = function(name) { + return this.codeTypes_[name] == TickProcessor.CodeTypes.SHARED_LIB; +}; + + +TickProcessor.prototype.isCppCode = function(name) { + return this.codeTypes_[name] == TickProcessor.CodeTypes.CPP; +}; + + +TickProcessor.prototype.isJsCode = function(name) { + return !(name in this.codeTypes_); +}; + + +TickProcessor.prototype.processLogFile = function(fileName) { + this.lastLogFileName_ = fileName; + var contents = readFile(fileName); + this.processLog(contents.split('\n')); +}; + + +TickProcessor.prototype.processLog = function(lines) { + var csvParser = new devtools.profiler.CsvParser(); + try { + for (var i = 0, n = lines.length; i < n; ++i) { + var line = lines[i]; + if (!line) { + continue; + } + var fields = csvParser.parseLine(line); + this.dispatchLogRow(fields); + } + } catch (e) { + print('line ' + (i + 1) + ': ' + (e.message || e)); + throw e; + } +}; + + +TickProcessor.prototype.dispatchLogRow = function(fields) { + // Obtain the dispatch. + var command = fields[0]; + if (!(command in TickProcessor.RecordsDispatch)) { + throw new Error('unknown command: ' + command); + } + var dispatch = TickProcessor.RecordsDispatch[command]; + + if (dispatch === null) { + return; + } + + // Parse fields. + var parsedFields = []; + for (var i = 0; i < dispatch.parsers.length; ++i) { + var parser = dispatch.parsers[i]; + if (parser === null) { + parsedFields.push(fields[1 + i]); + } else if (typeof parser == 'function') { + parsedFields.push(parser(fields[1 + i])); + } else { + // var-args + parsedFields.push(fields.slice(1 + i)); + break; + } + } + + // Run the processor. + this[dispatch.processor].apply(this, parsedFields); +}; + + +TickProcessor.prototype.processSharedLibrary = function( + name, startAddr, endAddr) { + var entry = this.profile_.addStaticCode(name, startAddr, endAddr); + this.setCodeType(entry.getName(), 'SHARED_LIB'); + + var self = this; + var libFuncs = this.cppEntriesProvider_.parseVmSymbols( + name, startAddr, endAddr, function(fName, fStart, fEnd) { + self.profile_.addStaticCode(fName, fStart, fEnd); + self.setCodeType(fName, 'CPP'); + }); +}; + + +TickProcessor.prototype.processCodeCreation = function( + type, start, size, name) { + var entry = this.profile_.addCode(type, name, start, size); +}; + + +TickProcessor.prototype.processCodeMove = function(from, to) { + this.profile_.moveCode(from, to); +}; + + +TickProcessor.prototype.processCodeDelete = function(start) { + this.profile_.deleteCode(start); +}; + + +TickProcessor.prototype.includeTick = function(vmState) { + return this.stateFilter_ == null || this.stateFilter_ == vmState; +}; + + +TickProcessor.prototype.processTick = function(pc, sp, vmState, stack) { + this.ticks_.total++; + if (vmState == TickProcessor.VmStates.GC) this.ticks_.gc++; + if (!this.includeTick(vmState)) { + this.ticks_.excluded++; + return; + } + + var fullStack = [pc]; + for (var i = 0, n = stack.length; i < n; ++i) { + var frame = stack[i]; + // Leave only numbers starting with 0x. Filter possible 'overflow' string. + if (frame.charAt(0) == '0') { + fullStack.push(parseInt(frame, 16)); + } + } + this.profile_.recordTick(fullStack); +}; + + +TickProcessor.prototype.printStatistics = function() { + print('Statistical profiling result from ' + this.lastLogFileName_ + + ', (' + this.ticks_.total + + ' ticks, ' + this.ticks_.unaccounted + ' unaccounted, ' + + this.ticks_.excluded + ' excluded).'); + + if (this.ticks_.total == 0) return; + + // Print the unknown ticks percentage if they are not ignored. + if (!this.ignoreUnknown_ && this.ticks_.unaccounted > 0) { + this.printHeader('Unknown'); + this.printCounter(this.ticks_.unaccounted, this.ticks_.total); + } + + // Disable initialization of 'funcName', 'url', 'lineNumber' as + // we don't use it and it just wastes time. + devtools.profiler.ProfileView.Node.prototype.initFuncInfo = function() {}; + + var flatProfile = this.profile_.getFlatProfile(); + var flatView = this.viewBuilder_.buildView(flatProfile); + // Sort by self time, desc, then by name, desc. + flatView.sort(function(rec1, rec2) { + return rec2.selfTime - rec1.selfTime || + (rec2.internalFuncName < rec1.internalFuncName ? -1 : 1); }); + var totalTicks = this.ticks_.total; + if (this.ignoreUnknown_) { + totalTicks -= this.ticks_.unaccounted; + } + // Our total time contains all the ticks encountered, + // while profile only knows about the filtered ticks. + flatView.head.totalTime = totalTicks; + + // Count library ticks + var flatViewNodes = flatView.head.children; + var self = this; + var libraryTicks = 0; + this.processProfile(flatViewNodes, + function(name) { return self.isSharedLibrary(name); }, + function(rec) { libraryTicks += rec.selfTime; }); + var nonLibraryTicks = totalTicks - libraryTicks; + + this.printHeader('Shared libraries'); + this.printEntries(flatViewNodes, null, + function(name) { return self.isSharedLibrary(name); }); + + this.printHeader('JavaScript'); + this.printEntries(flatViewNodes, nonLibraryTicks, + function(name) { return self.isJsCode(name); }); + + this.printHeader('C++'); + this.printEntries(flatViewNodes, nonLibraryTicks, + function(name) { return self.isCppCode(name); }); + + this.printHeader('GC'); + this.printCounter(this.ticks_.gc, totalTicks); + + this.printHeavyProfHeader(); + var heavyProfile = this.profile_.getBottomUpProfile(); + var heavyView = this.viewBuilder_.buildView(heavyProfile); + // To show the same percentages as in the flat profile. + heavyView.head.totalTime = totalTicks; + // Sort by total time, desc, then by name, desc. + heavyView.sort(function(rec1, rec2) { + return rec2.totalTime - rec1.totalTime || + (rec2.internalFuncName < rec1.internalFuncName ? -1 : 1); }); + this.printHeavyProfile(heavyView.head.children); +}; + + +function padLeft(s, len) { + s = s.toString(); + if (s.length < len) { + s = (new Array(len - s.length + 1).join(' ')) + s; + } + return s; +}; + + +TickProcessor.prototype.printHeader = function(headerTitle) { + print('\n [' + headerTitle + ']:'); + print(' ticks total nonlib name'); +}; + + +TickProcessor.prototype.printHeavyProfHeader = function() { + print('\n [Bottom up (heavy) profile]:'); + print(' Note: percentage shows a share of a particular caller in the ' + + 'total\n' + + ' amount of its parent calls.'); + print(' Callers occupying less than ' + + TickProcessor.CALL_PROFILE_CUTOFF_PCT.toFixed(1) + + '% are not shown.\n'); + print(' ticks parent name'); +}; + + +TickProcessor.prototype.printCounter = function(ticksCount, totalTicksCount) { + var pct = ticksCount * 100.0 / totalTicksCount; + print(' ' + padLeft(ticksCount, 5) + ' ' + padLeft(pct.toFixed(1), 5) + '%'); +}; + + +TickProcessor.prototype.processProfile = function( + profile, filterP, func) { + for (var i = 0, n = profile.length; i < n; ++i) { + var rec = profile[i]; + if (!filterP(rec.internalFuncName)) { + continue; + } + func(rec); + } +}; + + +TickProcessor.prototype.printEntries = function( + profile, nonLibTicks, filterP) { + this.processProfile(profile, filterP, function (rec) { + if (rec.selfTime == 0) return; + var nonLibPct = nonLibTicks != null ? + rec.selfTime * 100.0 / nonLibTicks : 0.0; + print(' ' + padLeft(rec.selfTime, 5) + ' ' + + padLeft(rec.selfPercent.toFixed(1), 5) + '% ' + + padLeft(nonLibPct.toFixed(1), 5) + '% ' + + rec.internalFuncName); + }); +}; + + +TickProcessor.prototype.printHeavyProfile = function(profile, opt_indent) { + var self = this; + var indent = opt_indent || 0; + var indentStr = padLeft('', indent); + this.processProfile(profile, function() { return true; }, function (rec) { + // Cut off too infrequent callers. + if (rec.parentTotalPercent < TickProcessor.CALL_PROFILE_CUTOFF_PCT) return; + print(' ' + padLeft(rec.totalTime, 5) + ' ' + + padLeft(rec.parentTotalPercent.toFixed(1), 5) + '% ' + + indentStr + rec.internalFuncName); + // Limit backtrace depth. + if (indent < 10) { + self.printHeavyProfile(rec.children, indent + 2); + } + // Delimit top-level functions. + if (indent == 0) { + print(''); + } + }); +}; + + +function CppEntriesProvider() { +}; + + +CppEntriesProvider.prototype.parseVmSymbols = function( + libName, libStart, libEnd, processorFunc) { + this.loadSymbols(libName); + + var prevEntry; + + function addPrevEntry(end) { + // Several functions can be mapped onto the same address. To avoid + // creating zero-sized entries, skip such duplicates. + if (prevEntry && prevEntry.start != end) { + processorFunc(prevEntry.name, prevEntry.start, end); + } + } + + while (true) { + var funcInfo = this.parseNextLine(); + if (funcInfo === null) { + continue; + } else if (funcInfo === false) { + break; + } + if (funcInfo.start < libStart && funcInfo.start < libEnd - libStart) { + funcInfo.start += libStart; + } + addPrevEntry(funcInfo.start); + prevEntry = funcInfo; + } + addPrevEntry(libEnd); +}; + + +CppEntriesProvider.prototype.loadSymbols = function(libName) { +}; + + +CppEntriesProvider.prototype.parseNextLine = function() { + return false; +}; + + +function inherits(childCtor, parentCtor) { + function tempCtor() {}; + tempCtor.prototype = parentCtor.prototype; + childCtor.prototype = new tempCtor(); +}; + + +function UnixCppEntriesProvider() { + this.symbols = []; + this.parsePos = 0; +}; +inherits(UnixCppEntriesProvider, CppEntriesProvider); + + +UnixCppEntriesProvider.FUNC_RE = /^([0-9a-fA-F]{8}) . (.*)$/; + + +UnixCppEntriesProvider.prototype.loadSymbols = function(libName) { + this.symbols = [ + os.system('nm', ['-C', '-n', libName], -1, -1), + os.system('nm', ['-C', '-n', '-D', libName], -1, -1) + ]; + this.parsePos = 0; +}; + + +UnixCppEntriesProvider.prototype.parseNextLine = function() { + if (this.symbols.length == 0) { + return false; + } + var lineEndPos = this.symbols[0].indexOf('\n', this.parsePos); + if (lineEndPos == -1) { + this.symbols.shift(); + this.parsePos = 0; + return this.parseNextLine(); + } + + var line = this.symbols[0].substring(this.parsePos, lineEndPos); + this.parsePos = lineEndPos + 1; + var fields = line.match(UnixCppEntriesProvider.FUNC_RE); + return fields ? { name: fields[2], start: parseInt(fields[1], 16) } : null; +}; + + +function WindowsCppEntriesProvider() { + this.symbols = ''; + this.parsePos = 0; +}; +inherits(WindowsCppEntriesProvider, CppEntriesProvider); + + +WindowsCppEntriesProvider.FILENAME_RE = /^(.*)\.exe$/; + + +WindowsCppEntriesProvider.FUNC_RE = + /^ 0001:[0-9a-fA-F]{8}\s+([_\?@$0-9a-zA-Z]+)\s+([0-9a-fA-F]{8}).*$/; + + +WindowsCppEntriesProvider.prototype.loadSymbols = function(libName) { + var fileNameFields = libName.match(WindowsCppEntriesProvider.FILENAME_RE); + // Only try to load symbols for the .exe file. + if (!fileNameFields) return; + var mapFileName = fileNameFields[1] + '.map'; + this.symbols = readFile(mapFileName); +}; + + +WindowsCppEntriesProvider.prototype.parseNextLine = function() { + var lineEndPos = this.symbols.indexOf('\r\n', this.parsePos); + if (lineEndPos == -1) { + return false; + } + + var line = this.symbols.substring(this.parsePos, lineEndPos); + this.parsePos = lineEndPos + 2; + var fields = line.match(WindowsCppEntriesProvider.FUNC_RE); + return fields ? + { name: this.unmangleName(fields[1]), start: parseInt(fields[2], 16) } : + null; +}; + + +/** + * Performs very simple unmangling of C++ names. + * + * Does not handle arguments and template arguments. The mangled names have + * the form: + * + * ?LookupInDescriptor@JSObject@internal@v8@@...arguments info... + */ +WindowsCppEntriesProvider.prototype.unmangleName = function(name) { + // Empty or non-mangled name. + if (name.length < 1 || name.charAt(0) != '?') return name; + var nameEndPos = name.indexOf('@@'); + var components = name.substring(1, nameEndPos).split('@'); + components.reverse(); + return components.join('::'); +}; + + +function padRight(s, len) { + s = s.toString(); + if (s.length < len) { + s = s + (new Array(len - s.length + 1).join(' ')); + } + return s; +}; + + +function processArguments(args) { + var result = { + logFileName: 'v8.log', + platform: 'unix', + stateFilter: null, + ignoreUnknown: false, + separateIc: false + }; + var argsDispatch = { + '-j': ['stateFilter', TickProcessor.VmStates.JS, + 'Show only ticks from JS VM state'], + '-g': ['stateFilter', TickProcessor.VmStates.GC, + 'Show only ticks from GC VM state'], + '-c': ['stateFilter', TickProcessor.VmStates.COMPILER, + 'Show only ticks from COMPILER VM state'], + '-o': ['stateFilter', TickProcessor.VmStates.OTHER, + 'Show only ticks from OTHER VM state'], + '-e': ['stateFilter', TickProcessor.VmStates.EXTERNAL, + 'Show only ticks from EXTERNAL VM state'], + '--ignore-unknown': ['ignoreUnknown', true, + 'Exclude ticks of unknown code entries from processing'], + '--separate-ic': ['separateIc', true, + 'Separate IC entries'], + '--unix': ['platform', 'unix', + 'Specify that we are running on *nix platform'], + '--windows': ['platform', 'windows', + 'Specify that we are running on Windows platform'] + }; + argsDispatch['--js'] = argsDispatch['-j']; + argsDispatch['--gc'] = argsDispatch['-g']; + argsDispatch['--compiler'] = argsDispatch['-c']; + argsDispatch['--other'] = argsDispatch['-o']; + argsDispatch['--external'] = argsDispatch['-e']; + + function printUsageAndExit() { + print('Cmdline args: [options] [log-file-name]\n' + + 'Default log file name is "v8.log".\n'); + print('Options:'); + for (var arg in argsDispatch) { + var synonims = [arg]; + var dispatch = argsDispatch[arg]; + for (var synArg in argsDispatch) { + if (arg !== synArg && dispatch === argsDispatch[synArg]) { + synonims.push(synArg); + delete argsDispatch[synArg]; + } + } + print(' ' + padRight(synonims.join(', '), 20) + dispatch[2]); + } + quit(2); + } + + while (args.length) { + var arg = args[0]; + if (arg.charAt(0) != '-') { + break; + } + args.shift(); + if (arg in argsDispatch) { + var dispatch = argsDispatch[arg]; + result[dispatch[0]] = dispatch[1]; + } else { + printUsageAndExit(); + } + } + + if (args.length >= 1) { + result.logFileName = args.shift(); + } + return result; +}; + + +var params = processArguments(arguments); +var tickProcessor = new TickProcessor( + params.platform == 'unix' ? new UnixCppEntriesProvider() : + new WindowsCppEntriesProvider(), + params.separateIc, + params.ignoreUnknown, + params.stateFilter); +tickProcessor.processLogFile(params.logFileName); +tickProcessor.printStatistics(); diff --git a/deps/v8/tools/tickprocessor.py b/deps/v8/tools/tickprocessor.py index 95e6e50f9..cc540d3db 100644 --- a/deps/v8/tools/tickprocessor.py +++ b/deps/v8/tools/tickprocessor.py @@ -411,7 +411,7 @@ class TickProcessor(object): number_of_accounted_ticks -= self.unaccounted_number_of_ticks number_of_non_library_ticks = number_of_accounted_ticks - self.number_of_library_ticks - entries.sort(key=lambda e:e.tick_count, reverse=True) + entries.sort(key=lambda e: (e.tick_count, e.ToString()), reverse=True) for entry in entries: if entry.tick_count > 0 and condition(entry): total_percentage = entry.tick_count * 100.0 / number_of_accounted_ticks diff --git a/deps/v8/tools/v8.xcodeproj/project.pbxproj b/deps/v8/tools/v8.xcodeproj/project.pbxproj index eba4ec771..83212fb42 100644..100755 --- a/deps/v8/tools/v8.xcodeproj/project.pbxproj +++ b/deps/v8/tools/v8.xcodeproj/project.pbxproj @@ -132,6 +132,8 @@ 89A88E2C0E71A6D20043BA31 /* v8threads.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF19D0E719B8F00D62E90 /* v8threads.cc */; }; 89A88E2D0E71A6D50043BA31 /* variables.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF19F0E719B8F00D62E90 /* variables.cc */; }; 89A88E2E0E71A6D60043BA31 /* zone.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1A20E719B8F00D62E90 /* zone.cc */; }; + 89B933AF0FAA0F9600201304 /* version.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF32F0FAA0ED200136CF6 /* version.cc */; }; + 89B933B00FAA0F9D00201304 /* version.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF32F0FAA0ED200136CF6 /* version.cc */; }; 89F23C3F0E78D5B2006B2466 /* accessors.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF0F60E719B8F00D62E90 /* accessors.cc */; }; 89F23C400E78D5B2006B2466 /* allocation.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF0F80E719B8F00D62E90 /* allocation.cc */; }; 89F23C410E78D5B2006B2466 /* api.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF0FA0E719B8F00D62E90 /* api.cc */; }; @@ -269,18 +271,19 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 58950D4E0F55514900F3E8BA /* jump-target-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "jump-target-arm.cc"; sourceTree = "<group>"; }; - 58950D4F0F55514900F3E8BA /* jump-target-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "jump-target-ia32.cc"; sourceTree = "<group>"; }; + 58242A1E0FA1F14D00BD6F59 /* json-delay.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "json-delay.js"; sourceTree = "<group>"; }; + 58950D4E0F55514900F3E8BA /* jump-target-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "jump-target-arm.cc"; path = "arm/jump-target-arm.cc"; sourceTree = "<group>"; }; + 58950D4F0F55514900F3E8BA /* jump-target-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "jump-target-ia32.cc"; path = "ia32/jump-target-ia32.cc"; sourceTree = "<group>"; }; 58950D500F55514900F3E8BA /* jump-target.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "jump-target.cc"; sourceTree = "<group>"; }; 58950D510F55514900F3E8BA /* jump-target.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "jump-target.h"; sourceTree = "<group>"; }; - 58950D520F55514900F3E8BA /* register-allocator-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "register-allocator-arm.cc"; sourceTree = "<group>"; }; - 58950D530F55514900F3E8BA /* register-allocator-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "register-allocator-ia32.cc"; sourceTree = "<group>"; }; + 58950D520F55514900F3E8BA /* register-allocator-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "register-allocator-arm.cc"; path = "arm/register-allocator-arm.cc"; sourceTree = "<group>"; }; + 58950D530F55514900F3E8BA /* register-allocator-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "register-allocator-ia32.cc"; path = "ia32/register-allocator-ia32.cc"; sourceTree = "<group>"; }; 58950D540F55514900F3E8BA /* register-allocator.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "register-allocator.cc"; sourceTree = "<group>"; }; 58950D550F55514900F3E8BA /* register-allocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "register-allocator.h"; sourceTree = "<group>"; }; - 58950D560F55514900F3E8BA /* virtual-frame-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "virtual-frame-arm.cc"; sourceTree = "<group>"; }; - 58950D570F55514900F3E8BA /* virtual-frame-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "virtual-frame-arm.h"; sourceTree = "<group>"; }; - 58950D580F55514900F3E8BA /* virtual-frame-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "virtual-frame-ia32.cc"; sourceTree = "<group>"; }; - 58950D590F55514900F3E8BA /* virtual-frame-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "virtual-frame-ia32.h"; sourceTree = "<group>"; }; + 58950D560F55514900F3E8BA /* virtual-frame-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "virtual-frame-arm.cc"; path = "arm/virtual-frame-arm.cc"; sourceTree = "<group>"; }; + 58950D570F55514900F3E8BA /* virtual-frame-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "virtual-frame-arm.h"; path = "arm/virtual-frame-arm.h"; sourceTree = "<group>"; }; + 58950D580F55514900F3E8BA /* virtual-frame-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "virtual-frame-ia32.cc"; path = "ia32/virtual-frame-ia32.cc"; sourceTree = "<group>"; }; + 58950D590F55514900F3E8BA /* virtual-frame-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "virtual-frame-ia32.h"; path = "ia32/virtual-frame-ia32.h"; sourceTree = "<group>"; }; 58950D5A0F55514900F3E8BA /* virtual-frame.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "virtual-frame.cc"; sourceTree = "<group>"; }; 58950D5B0F55514900F3E8BA /* virtual-frame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "virtual-frame.h"; sourceTree = "<group>"; }; 8900116B0E71CA2300F91F35 /* libraries.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = libraries.cc; sourceTree = "<group>"; }; @@ -299,8 +302,8 @@ 89495E470E79FC23001F68C3 /* compilation-cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "compilation-cache.h"; sourceTree = "<group>"; }; 8956B6CD0F5D86570033B5A2 /* debug-agent.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "debug-agent.cc"; sourceTree = "<group>"; }; 8956B6CE0F5D86570033B5A2 /* debug-agent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "debug-agent.h"; sourceTree = "<group>"; }; - 8964482B0E9C00F700E7C516 /* codegen-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "codegen-ia32.h"; sourceTree = "<group>"; }; - 896448BC0E9D530500E7C516 /* codegen-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "codegen-arm.h"; sourceTree = "<group>"; }; + 8964482B0E9C00F700E7C516 /* codegen-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "codegen-ia32.h"; path = "ia32/codegen-ia32.h"; sourceTree = "<group>"; }; + 896448BC0E9D530500E7C516 /* codegen-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "codegen-arm.h"; path = "arm/codegen-arm.h"; sourceTree = "<group>"; }; 8970F2F00E719FB2006AE7B5 /* libv8.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libv8.a; sourceTree = BUILT_PRODUCTS_DIR; }; 897F767A0E71B4CC007ACF34 /* v8_shell */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = v8_shell; sourceTree = BUILT_PRODUCTS_DIR; }; 897FF0D40E719A8500D62E90 /* v8-debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "v8-debug.h"; sourceTree = "<group>"; }; @@ -314,20 +317,20 @@ 897FF0FA0E719B8F00D62E90 /* api.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = api.cc; sourceTree = "<group>"; }; 897FF0FB0E719B8F00D62E90 /* api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = api.h; sourceTree = "<group>"; }; 897FF0FC0E719B8F00D62E90 /* arguments.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arguments.h; sourceTree = "<group>"; }; - 897FF0FD0E719B8F00D62E90 /* assembler-arm-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "assembler-arm-inl.h"; sourceTree = "<group>"; }; - 897FF0FE0E719B8F00D62E90 /* assembler-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "assembler-arm.cc"; sourceTree = "<group>"; }; - 897FF0FF0E719B8F00D62E90 /* assembler-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "assembler-arm.h"; sourceTree = "<group>"; }; - 897FF1000E719B8F00D62E90 /* assembler-ia32-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "assembler-ia32-inl.h"; sourceTree = "<group>"; }; - 897FF1010E719B8F00D62E90 /* assembler-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "assembler-ia32.cc"; sourceTree = "<group>"; }; - 897FF1020E719B8F00D62E90 /* assembler-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "assembler-ia32.h"; sourceTree = "<group>"; }; + 897FF0FD0E719B8F00D62E90 /* assembler-arm-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "assembler-arm-inl.h"; path = "arm/assembler-arm-inl.h"; sourceTree = "<group>"; }; + 897FF0FE0E719B8F00D62E90 /* assembler-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "assembler-arm.cc"; path = "arm/assembler-arm.cc"; sourceTree = "<group>"; }; + 897FF0FF0E719B8F00D62E90 /* assembler-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "assembler-arm.h"; path = "arm/assembler-arm.h"; sourceTree = "<group>"; }; + 897FF1000E719B8F00D62E90 /* assembler-ia32-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "assembler-ia32-inl.h"; path = "ia32/assembler-ia32-inl.h"; sourceTree = "<group>"; }; + 897FF1010E719B8F00D62E90 /* assembler-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "assembler-ia32.cc"; path = "ia32/assembler-ia32.cc"; sourceTree = "<group>"; }; + 897FF1020E719B8F00D62E90 /* assembler-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "assembler-ia32.h"; path = "ia32/assembler-ia32.h"; sourceTree = "<group>"; }; 897FF1030E719B8F00D62E90 /* assembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = assembler.cc; sourceTree = "<group>"; }; 897FF1040E719B8F00D62E90 /* assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assembler.h; sourceTree = "<group>"; }; 897FF1050E719B8F00D62E90 /* ast.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ast.cc; sourceTree = "<group>"; }; 897FF1060E719B8F00D62E90 /* ast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ast.h; sourceTree = "<group>"; }; 897FF1070E719B8F00D62E90 /* bootstrapper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bootstrapper.cc; sourceTree = "<group>"; }; 897FF1080E719B8F00D62E90 /* bootstrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bootstrapper.h; sourceTree = "<group>"; }; - 897FF1090E719B8F00D62E90 /* builtins-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "builtins-arm.cc"; sourceTree = "<group>"; }; - 897FF10A0E719B8F00D62E90 /* builtins-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "builtins-ia32.cc"; sourceTree = "<group>"; }; + 897FF1090E719B8F00D62E90 /* builtins-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "builtins-arm.cc"; path = "arm/builtins-arm.cc"; sourceTree = "<group>"; }; + 897FF10A0E719B8F00D62E90 /* builtins-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "builtins-ia32.cc"; path = "ia32/builtins-ia32.cc"; sourceTree = "<group>"; }; 897FF10B0E719B8F00D62E90 /* builtins.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = builtins.cc; sourceTree = "<group>"; }; 897FF10C0E719B8F00D62E90 /* builtins.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtins.h; sourceTree = "<group>"; }; 897FF10D0E719B8F00D62E90 /* char-predicates-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "char-predicates-inl.h"; sourceTree = "<group>"; }; @@ -337,14 +340,14 @@ 897FF1110E719B8F00D62E90 /* code-stubs.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "code-stubs.cc"; sourceTree = "<group>"; }; 897FF1120E719B8F00D62E90 /* code-stubs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "code-stubs.h"; sourceTree = "<group>"; }; 897FF1130E719B8F00D62E90 /* code.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = code.h; sourceTree = "<group>"; }; - 897FF1140E719B8F00D62E90 /* codegen-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "codegen-arm.cc"; sourceTree = "<group>"; }; - 897FF1150E719B8F00D62E90 /* codegen-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "codegen-ia32.cc"; sourceTree = "<group>"; }; + 897FF1140E719B8F00D62E90 /* codegen-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "codegen-arm.cc"; path = "arm/codegen-arm.cc"; sourceTree = "<group>"; }; + 897FF1150E719B8F00D62E90 /* codegen-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "codegen-ia32.cc"; path = "ia32/codegen-ia32.cc"; sourceTree = "<group>"; }; 897FF1160E719B8F00D62E90 /* codegen-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "codegen-inl.h"; sourceTree = "<group>"; }; 897FF1170E719B8F00D62E90 /* codegen.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = codegen.cc; sourceTree = "<group>"; }; 897FF1180E719B8F00D62E90 /* codegen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = codegen.h; sourceTree = "<group>"; }; 897FF1190E719B8F00D62E90 /* compiler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = compiler.cc; sourceTree = "<group>"; }; 897FF11A0E719B8F00D62E90 /* compiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = compiler.h; sourceTree = "<group>"; }; - 897FF11B0E719B8F00D62E90 /* constants-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "constants-arm.h"; sourceTree = "<group>"; }; + 897FF11B0E719B8F00D62E90 /* constants-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "constants-arm.h"; path = "arm/constants-arm.h"; sourceTree = "<group>"; }; 897FF11C0E719B8F00D62E90 /* contexts.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = contexts.cc; sourceTree = "<group>"; }; 897FF11D0E719B8F00D62E90 /* contexts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = contexts.h; sourceTree = "<group>"; }; 897FF11E0E719B8F00D62E90 /* conversions-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "conversions-inl.h"; sourceTree = "<group>"; }; @@ -352,15 +355,15 @@ 897FF1200E719B8F00D62E90 /* conversions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conversions.h; sourceTree = "<group>"; }; 897FF1210E719B8F00D62E90 /* counters.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = counters.cc; sourceTree = "<group>"; }; 897FF1220E719B8F00D62E90 /* counters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = counters.h; sourceTree = "<group>"; }; - 897FF1230E719B8F00D62E90 /* cpu-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "cpu-arm.cc"; sourceTree = "<group>"; }; - 897FF1240E719B8F00D62E90 /* cpu-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "cpu-ia32.cc"; sourceTree = "<group>"; }; + 897FF1230E719B8F00D62E90 /* cpu-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "cpu-arm.cc"; path = "arm/cpu-arm.cc"; sourceTree = "<group>"; }; + 897FF1240E719B8F00D62E90 /* cpu-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "cpu-ia32.cc"; path = "ia32/cpu-ia32.cc"; sourceTree = "<group>"; }; 897FF1250E719B8F00D62E90 /* cpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cpu.h; sourceTree = "<group>"; }; 897FF1260E719B8F00D62E90 /* dateparser.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dateparser.cc; sourceTree = "<group>"; }; 897FF1270E719B8F00D62E90 /* dateparser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dateparser.h; sourceTree = "<group>"; }; 897FF1280E719B8F00D62E90 /* debug.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = debug.cc; sourceTree = "<group>"; }; 897FF1290E719B8F00D62E90 /* debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = debug.h; sourceTree = "<group>"; }; - 897FF12A0E719B8F00D62E90 /* disasm-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "disasm-arm.cc"; sourceTree = "<group>"; }; - 897FF12B0E719B8F00D62E90 /* disasm-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "disasm-ia32.cc"; sourceTree = "<group>"; }; + 897FF12A0E719B8F00D62E90 /* disasm-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "disasm-arm.cc"; path = "arm/disasm-arm.cc"; sourceTree = "<group>"; }; + 897FF12B0E719B8F00D62E90 /* disasm-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "disasm-ia32.cc"; path = "ia32/disasm-ia32.cc"; sourceTree = "<group>"; }; 897FF12C0E719B8F00D62E90 /* disasm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = disasm.h; sourceTree = "<group>"; }; 897FF12D0E719B8F00D62E90 /* disassembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = disassembler.cc; sourceTree = "<group>"; }; 897FF12E0E719B8F00D62E90 /* disassembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = disassembler.h; sourceTree = "<group>"; }; @@ -371,10 +374,10 @@ 897FF1330E719B8F00D62E90 /* factory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = factory.h; sourceTree = "<group>"; }; 897FF1350E719B8F00D62E90 /* flags.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = flags.cc; sourceTree = "<group>"; }; 897FF1360E719B8F00D62E90 /* flags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = flags.h; sourceTree = "<group>"; }; - 897FF1370E719B8F00D62E90 /* frames-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "frames-arm.cc"; sourceTree = "<group>"; }; - 897FF1380E719B8F00D62E90 /* frames-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "frames-arm.h"; sourceTree = "<group>"; }; - 897FF1390E719B8F00D62E90 /* frames-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "frames-ia32.cc"; sourceTree = "<group>"; }; - 897FF13A0E719B8F00D62E90 /* frames-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "frames-ia32.h"; sourceTree = "<group>"; }; + 897FF1370E719B8F00D62E90 /* frames-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "frames-arm.cc"; path = "arm/frames-arm.cc"; sourceTree = "<group>"; }; + 897FF1380E719B8F00D62E90 /* frames-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "frames-arm.h"; path = "arm/frames-arm.h"; sourceTree = "<group>"; }; + 897FF1390E719B8F00D62E90 /* frames-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "frames-ia32.cc"; path = "ia32/frames-ia32.cc"; sourceTree = "<group>"; }; + 897FF13A0E719B8F00D62E90 /* frames-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "frames-ia32.h"; path = "ia32/frames-ia32.h"; sourceTree = "<group>"; }; 897FF13B0E719B8F00D62E90 /* frames-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "frames-inl.h"; sourceTree = "<group>"; }; 897FF13C0E719B8F00D62E90 /* frames.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = frames.cc; sourceTree = "<group>"; }; 897FF13D0E719B8F00D62E90 /* frames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = frames.h; sourceTree = "<group>"; }; @@ -389,8 +392,8 @@ 897FF1460E719B8F00D62E90 /* heap-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "heap-inl.h"; sourceTree = "<group>"; }; 897FF1470E719B8F00D62E90 /* heap.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = heap.cc; sourceTree = "<group>"; }; 897FF1480E719B8F00D62E90 /* heap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = heap.h; sourceTree = "<group>"; }; - 897FF1490E719B8F00D62E90 /* ic-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "ic-arm.cc"; sourceTree = "<group>"; }; - 897FF14A0E719B8F00D62E90 /* ic-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "ic-ia32.cc"; sourceTree = "<group>"; }; + 897FF1490E719B8F00D62E90 /* ic-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ic-arm.cc"; path = "arm/ic-arm.cc"; sourceTree = "<group>"; }; + 897FF14A0E719B8F00D62E90 /* ic-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ic-ia32.cc"; path = "ia32/ic-ia32.cc"; sourceTree = "<group>"; }; 897FF14B0E719B8F00D62E90 /* ic-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ic-inl.h"; sourceTree = "<group>"; }; 897FF14C0E719B8F00D62E90 /* ic.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ic.cc; sourceTree = "<group>"; }; 897FF14D0E719B8F00D62E90 /* ic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ic.h; sourceTree = "<group>"; }; @@ -400,10 +403,10 @@ 897FF1510E719B8F00D62E90 /* list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = list.h; sourceTree = "<group>"; }; 897FF1520E719B8F00D62E90 /* log.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = log.cc; sourceTree = "<group>"; }; 897FF1530E719B8F00D62E90 /* log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = log.h; sourceTree = "<group>"; }; - 897FF1540E719B8F00D62E90 /* macro-assembler-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "macro-assembler-arm.cc"; sourceTree = "<group>"; }; - 897FF1550E719B8F00D62E90 /* macro-assembler-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "macro-assembler-arm.h"; sourceTree = "<group>"; }; - 897FF1560E719B8F00D62E90 /* macro-assembler-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "macro-assembler-ia32.cc"; sourceTree = "<group>"; }; - 897FF1570E719B8F00D62E90 /* macro-assembler-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "macro-assembler-ia32.h"; sourceTree = "<group>"; }; + 897FF1540E719B8F00D62E90 /* macro-assembler-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "macro-assembler-arm.cc"; path = "arm/macro-assembler-arm.cc"; sourceTree = "<group>"; }; + 897FF1550E719B8F00D62E90 /* macro-assembler-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "macro-assembler-arm.h"; path = "arm/macro-assembler-arm.h"; sourceTree = "<group>"; }; + 897FF1560E719B8F00D62E90 /* macro-assembler-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "macro-assembler-ia32.cc"; path = "ia32/macro-assembler-ia32.cc"; sourceTree = "<group>"; }; + 897FF1570E719B8F00D62E90 /* macro-assembler-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "macro-assembler-ia32.h"; path = "ia32/macro-assembler-ia32.h"; sourceTree = "<group>"; }; 897FF1580E719B8F00D62E90 /* macro-assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "macro-assembler.h"; sourceTree = "<group>"; }; 897FF1590E719B8F00D62E90 /* mark-compact.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "mark-compact.cc"; sourceTree = "<group>"; }; 897FF15A0E719B8F00D62E90 /* mark-compact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mark-compact.h"; sourceTree = "<group>"; }; @@ -441,10 +444,10 @@ 897FF17A0E719B8F00D62E90 /* serialize.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = serialize.cc; sourceTree = "<group>"; }; 897FF17B0E719B8F00D62E90 /* serialize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = serialize.h; sourceTree = "<group>"; }; 897FF17C0E719B8F00D62E90 /* shell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shell.h; sourceTree = "<group>"; }; - 897FF17D0E719B8F00D62E90 /* simulator-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "simulator-arm.cc"; sourceTree = "<group>"; }; - 897FF17E0E719B8F00D62E90 /* simulator-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "simulator-arm.h"; sourceTree = "<group>"; }; - 897FF17F0E719B8F00D62E90 /* simulator-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "simulator-ia32.cc"; sourceTree = "<group>"; }; - 897FF1800E719B8F00D62E90 /* simulator-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "simulator-ia32.h"; sourceTree = "<group>"; }; + 897FF17D0E719B8F00D62E90 /* simulator-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "simulator-arm.cc"; path = "arm/simulator-arm.cc"; sourceTree = "<group>"; }; + 897FF17E0E719B8F00D62E90 /* simulator-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "simulator-arm.h"; path = "arm/simulator-arm.h"; sourceTree = "<group>"; }; + 897FF17F0E719B8F00D62E90 /* simulator-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "simulator-ia32.cc"; path = "ia32/simulator-ia32.cc"; sourceTree = "<group>"; }; + 897FF1800E719B8F00D62E90 /* simulator-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "simulator-ia32.h"; path = "ia32/simulator-ia32.h"; sourceTree = "<group>"; }; 897FF1810E719B8F00D62E90 /* smart-pointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "smart-pointer.h"; sourceTree = "<group>"; }; 897FF1820E719B8F00D62E90 /* snapshot-common.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "snapshot-common.cc"; sourceTree = "<group>"; }; 897FF1830E719B8F00D62E90 /* snapshot-empty.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "snapshot-empty.cc"; sourceTree = "<group>"; }; @@ -454,8 +457,8 @@ 897FF1870E719B8F00D62E90 /* spaces.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spaces.h; sourceTree = "<group>"; }; 897FF1880E719B8F00D62E90 /* string-stream.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "string-stream.cc"; sourceTree = "<group>"; }; 897FF1890E719B8F00D62E90 /* string-stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "string-stream.h"; sourceTree = "<group>"; }; - 897FF18A0E719B8F00D62E90 /* stub-cache-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "stub-cache-arm.cc"; sourceTree = "<group>"; }; - 897FF18B0E719B8F00D62E90 /* stub-cache-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "stub-cache-ia32.cc"; sourceTree = "<group>"; }; + 897FF18A0E719B8F00D62E90 /* stub-cache-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "stub-cache-arm.cc"; path = "arm/stub-cache-arm.cc"; sourceTree = "<group>"; }; + 897FF18B0E719B8F00D62E90 /* stub-cache-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "stub-cache-ia32.cc"; path = "ia32/stub-cache-ia32.cc"; sourceTree = "<group>"; }; 897FF18C0E719B8F00D62E90 /* stub-cache.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "stub-cache.cc"; sourceTree = "<group>"; }; 897FF18D0E719B8F00D62E90 /* stub-cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "stub-cache.h"; sourceTree = "<group>"; }; 897FF18E0E719B8F00D62E90 /* token.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = token.cc; sourceTree = "<group>"; }; @@ -495,17 +498,19 @@ 897FF1B50E719C0900D62E90 /* shell.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = shell.cc; sourceTree = "<group>"; }; 897FF1B60E719C2300D62E90 /* js2c.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = js2c.py; sourceTree = "<group>"; }; 897FF1B70E719C2E00D62E90 /* macros.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; name = macros.py; path = ../src/macros.py; sourceTree = "<group>"; }; - 898BD20C0EF6CC850068B00A /* debug-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "debug-arm.cc"; sourceTree = "<group>"; }; - 898BD20D0EF6CC850068B00A /* debug-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "debug-ia32.cc"; sourceTree = "<group>"; }; + 897FF32F0FAA0ED200136CF6 /* version.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = version.cc; sourceTree = "<group>"; }; + 897FF3300FAA0ED200136CF6 /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = "<group>"; }; + 898BD20C0EF6CC850068B00A /* debug-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "debug-arm.cc"; path = "arm/debug-arm.cc"; sourceTree = "<group>"; }; + 898BD20D0EF6CC850068B00A /* debug-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "debug-ia32.cc"; path = "ia32/debug-ia32.cc"; sourceTree = "<group>"; }; 89A15C630EE4661A00B48DEB /* bytecodes-irregexp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "bytecodes-irregexp.h"; sourceTree = "<group>"; }; 89A15C660EE4665300B48DEB /* interpreter-irregexp.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "interpreter-irregexp.cc"; sourceTree = "<group>"; }; 89A15C670EE4665300B48DEB /* interpreter-irregexp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "interpreter-irregexp.h"; sourceTree = "<group>"; }; 89A15C680EE4665300B48DEB /* jsregexp-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "jsregexp-inl.h"; sourceTree = "<group>"; }; 89A15C6D0EE466A900B48DEB /* platform-freebsd.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "platform-freebsd.cc"; sourceTree = "<group>"; }; - 89A15C700EE466D000B48DEB /* regexp-macro-assembler-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "regexp-macro-assembler-arm.cc"; sourceTree = "<group>"; }; - 89A15C710EE466D000B48DEB /* regexp-macro-assembler-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "regexp-macro-assembler-arm.h"; sourceTree = "<group>"; }; - 89A15C720EE466D000B48DEB /* regexp-macro-assembler-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "regexp-macro-assembler-ia32.cc"; sourceTree = "<group>"; }; - 89A15C730EE466D000B48DEB /* regexp-macro-assembler-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "regexp-macro-assembler-ia32.h"; sourceTree = "<group>"; }; + 89A15C700EE466D000B48DEB /* regexp-macro-assembler-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "regexp-macro-assembler-arm.cc"; path = "arm/regexp-macro-assembler-arm.cc"; sourceTree = "<group>"; }; + 89A15C710EE466D000B48DEB /* regexp-macro-assembler-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "regexp-macro-assembler-arm.h"; path = "arm/regexp-macro-assembler-arm.h"; sourceTree = "<group>"; }; + 89A15C720EE466D000B48DEB /* regexp-macro-assembler-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "regexp-macro-assembler-ia32.cc"; path = "ia32/regexp-macro-assembler-ia32.cc"; sourceTree = "<group>"; }; + 89A15C730EE466D000B48DEB /* regexp-macro-assembler-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "regexp-macro-assembler-ia32.h"; path = "ia32/regexp-macro-assembler-ia32.h"; sourceTree = "<group>"; }; 89A15C740EE466D000B48DEB /* regexp-macro-assembler-irregexp-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "regexp-macro-assembler-irregexp-inl.h"; sourceTree = "<group>"; }; 89A15C750EE466D000B48DEB /* regexp-macro-assembler-irregexp.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "regexp-macro-assembler-irregexp.cc"; sourceTree = "<group>"; }; 89A15C760EE466D000B48DEB /* regexp-macro-assembler-irregexp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "regexp-macro-assembler-irregexp.h"; sourceTree = "<group>"; }; @@ -826,6 +831,8 @@ 897FF19E0E719B8F00D62E90 /* v8threads.h */, 897FF19F0E719B8F00D62E90 /* variables.cc */, 897FF1A00E719B8F00D62E90 /* variables.h */, + 897FF32F0FAA0ED200136CF6 /* version.cc */, + 897FF3300FAA0ED200136CF6 /* version.h */, 58950D560F55514900F3E8BA /* virtual-frame-arm.cc */, 58950D570F55514900F3E8BA /* virtual-frame-arm.h */, 58950D580F55514900F3E8BA /* virtual-frame-ia32.cc */, @@ -846,6 +853,7 @@ 897FF1A70E719BC100D62E90 /* array.js */, 897FF1A80E719BC100D62E90 /* date-delay.js */, 897FF1A90E719BC100D62E90 /* debug-delay.js */, + 58242A1E0FA1F14D00BD6F59 /* json-delay.js */, 897FF1AA0E719BC100D62E90 /* math.js */, 897FF1AB0E719BC100D62E90 /* messages.js */, 897FF1AC0E719BC100D62E90 /* mirror-delay.js */, @@ -1059,7 +1067,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "set -ex\nJS_FILES=\"runtime.js\"\\\n\" v8natives.js\"\\\n\" array.js\"\\\n\" string.js\"\\\n\" uri.js\"\\\n\" math.js\"\\\n\" messages.js\"\\\n\" apinatives.js\"\\\n\" debug-delay.js\"\\\n\" mirror-delay.js\"\\\n\" date-delay.js\"\\\n\" regexp-delay.js\"\\\n\" macros.py\"\n\nV8ROOT=\"${SRCROOT}/..\"\n\nSRC_DIR=\"${V8ROOT}/src\"\n\nNATIVE_JS_FILES=\"\"\n\nfor i in ${JS_FILES} ; do\n NATIVE_JS_FILES+=\"${SRC_DIR}/${i} \"\ndone\n\nV8_GENERATED_SOURCES_DIR=\"${CONFIGURATION_TEMP_DIR}/generated\"\nmkdir -p \"${V8_GENERATED_SOURCES_DIR}\"\n\nLIBRARIES_CC=\"${V8_GENERATED_SOURCES_DIR}/libraries.cc\"\nLIBRARIES_EMPTY_CC=\"${V8_GENERATED_SOURCES_DIR}/libraries-empty.cc\"\n\npython \"${V8ROOT}/tools/js2c.py\" \\\n \"${LIBRARIES_CC}.new\" \\\n \"${LIBRARIES_EMPTY_CC}.new\" \\\n \"CORE\" \\\n ${NATIVE_JS_FILES}\n\n# Only use the new files if they're different from the existing files (if any),\n# preserving the existing files' timestamps when there are no changes. This\n# minimizes unnecessary build activity for a no-change build.\n\nif ! diff -q \"${LIBRARIES_CC}.new\" \"${LIBRARIES_CC}\" >& /dev/null ; then\n mv \"${LIBRARIES_CC}.new\" \"${LIBRARIES_CC}\"\nelse\n rm \"${LIBRARIES_CC}.new\"\nfi\n\nif ! diff -q \"${LIBRARIES_EMPTY_CC}.new\" \"${LIBRARIES_EMPTY_CC}\" >& /dev/null ; then\n mv \"${LIBRARIES_EMPTY_CC}.new\" \"${LIBRARIES_EMPTY_CC}\"\nelse\n rm \"${LIBRARIES_EMPTY_CC}.new\"\nfi\n"; + shellScript = "set -ex\nJS_FILES=\"runtime.js\"\\\n\" v8natives.js\"\\\n\" array.js\"\\\n\" string.js\"\\\n\" uri.js\"\\\n\" math.js\"\\\n\" messages.js\"\\\n\" apinatives.js\"\\\n\" debug-delay.js\"\\\n\" mirror-delay.js\"\\\n\" date-delay.js\"\\\n\" json-delay.js\"\\\n\" regexp-delay.js\"\\\n\" macros.py\"\n\nV8ROOT=\"${SRCROOT}/..\"\n\nSRC_DIR=\"${V8ROOT}/src\"\n\nNATIVE_JS_FILES=\"\"\n\nfor i in ${JS_FILES} ; do\n NATIVE_JS_FILES+=\"${SRC_DIR}/${i} \"\ndone\n\nV8_GENERATED_SOURCES_DIR=\"${CONFIGURATION_TEMP_DIR}/generated\"\nmkdir -p \"${V8_GENERATED_SOURCES_DIR}\"\n\nLIBRARIES_CC=\"${V8_GENERATED_SOURCES_DIR}/libraries.cc\"\nLIBRARIES_EMPTY_CC=\"${V8_GENERATED_SOURCES_DIR}/libraries-empty.cc\"\n\npython \"${V8ROOT}/tools/js2c.py\" \\\n \"${LIBRARIES_CC}.new\" \\\n \"${LIBRARIES_EMPTY_CC}.new\" \\\n \"CORE\" \\\n ${NATIVE_JS_FILES}\n\n# Only use the new files if they're different from the existing files (if any),\n# preserving the existing files' timestamps when there are no changes. This\n# minimizes unnecessary build activity for a no-change build.\n\nif ! diff -q \"${LIBRARIES_CC}.new\" \"${LIBRARIES_CC}\" >& /dev/null ; then\n mv \"${LIBRARIES_CC}.new\" \"${LIBRARIES_CC}\"\nelse\n rm \"${LIBRARIES_CC}.new\"\nfi\n\nif ! diff -q \"${LIBRARIES_EMPTY_CC}.new\" \"${LIBRARIES_EMPTY_CC}\" >& /dev/null ; then\n mv \"${LIBRARIES_EMPTY_CC}.new\" \"${LIBRARIES_EMPTY_CC}\"\nelse\n rm \"${LIBRARIES_EMPTY_CC}.new\"\nfi\n"; }; 89F23C3D0E78D5B2006B2466 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -1072,7 +1080,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "set -ex\nJS_FILES=\"runtime.js\"\\\n\" v8natives.js\"\\\n\" array.js\"\\\n\" string.js\"\\\n\" uri.js\"\\\n\" math.js\"\\\n\" messages.js\"\\\n\" apinatives.js\"\\\n\" debug-delay.js\"\\\n\" mirror-delay.js\"\\\n\" date-delay.js\"\\\n\" regexp-delay.js\"\\\n\" macros.py\"\n\nV8ROOT=\"${SRCROOT}/..\"\n\nSRC_DIR=\"${V8ROOT}/src\"\n\nNATIVE_JS_FILES=\"\"\n\nfor i in ${JS_FILES} ; do\n NATIVE_JS_FILES+=\"${SRC_DIR}/${i} \"\ndone\n\nV8_GENERATED_SOURCES_DIR=\"${CONFIGURATION_TEMP_DIR}/generated\"\nmkdir -p \"${V8_GENERATED_SOURCES_DIR}\"\n\nLIBRARIES_CC=\"${V8_GENERATED_SOURCES_DIR}/libraries.cc\"\nLIBRARIES_EMPTY_CC=\"${V8_GENERATED_SOURCES_DIR}/libraries-empty.cc\"\n\npython \"${V8ROOT}/tools/js2c.py\" \\\n \"${LIBRARIES_CC}.new\" \\\n \"${LIBRARIES_EMPTY_CC}.new\" \\\n \"CORE\" \\\n ${NATIVE_JS_FILES}\n\n# Only use the new files if they're different from the existing files (if any),\n# preserving the existing files' timestamps when there are no changes. This\n# minimizes unnecessary build activity for a no-change build.\n\nif ! diff -q \"${LIBRARIES_CC}.new\" \"${LIBRARIES_CC}\" >& /dev/null ; then\n mv \"${LIBRARIES_CC}.new\" \"${LIBRARIES_CC}\"\nelse\n rm \"${LIBRARIES_CC}.new\"\nfi\n\nif ! diff -q \"${LIBRARIES_EMPTY_CC}.new\" \"${LIBRARIES_EMPTY_CC}\" >& /dev/null ; then\n mv \"${LIBRARIES_EMPTY_CC}.new\" \"${LIBRARIES_EMPTY_CC}\"\nelse\n rm \"${LIBRARIES_EMPTY_CC}.new\"\nfi\n"; + shellScript = "set -ex\nJS_FILES=\"runtime.js\"\\\n\" v8natives.js\"\\\n\" array.js\"\\\n\" string.js\"\\\n\" uri.js\"\\\n\" math.js\"\\\n\" messages.js\"\\\n\" apinatives.js\"\\\n\" debug-delay.js\"\\\n\" mirror-delay.js\"\\\n\" date-delay.js\"\\\n\" json-delay.js\"\\\n\" regexp-delay.js\"\\\n\" macros.py\"\n\nV8ROOT=\"${SRCROOT}/..\"\n\nSRC_DIR=\"${V8ROOT}/src\"\n\nNATIVE_JS_FILES=\"\"\n\nfor i in ${JS_FILES} ; do\n NATIVE_JS_FILES+=\"${SRC_DIR}/${i} \"\ndone\n\nV8_GENERATED_SOURCES_DIR=\"${CONFIGURATION_TEMP_DIR}/generated\"\nmkdir -p \"${V8_GENERATED_SOURCES_DIR}\"\n\nLIBRARIES_CC=\"${V8_GENERATED_SOURCES_DIR}/libraries.cc\"\nLIBRARIES_EMPTY_CC=\"${V8_GENERATED_SOURCES_DIR}/libraries-empty.cc\"\n\npython \"${V8ROOT}/tools/js2c.py\" \\\n \"${LIBRARIES_CC}.new\" \\\n \"${LIBRARIES_EMPTY_CC}.new\" \\\n \"CORE\" \\\n ${NATIVE_JS_FILES}\n\n# Only use the new files if they're different from the existing files (if any),\n# preserving the existing files' timestamps when there are no changes. This\n# minimizes unnecessary build activity for a no-change build.\n\nif ! diff -q \"${LIBRARIES_CC}.new\" \"${LIBRARIES_CC}\" >& /dev/null ; then\n mv \"${LIBRARIES_CC}.new\" \"${LIBRARIES_CC}\"\nelse\n rm \"${LIBRARIES_CC}.new\"\nfi\n\nif ! diff -q \"${LIBRARIES_EMPTY_CC}.new\" \"${LIBRARIES_EMPTY_CC}\" >& /dev/null ; then\n mv \"${LIBRARIES_EMPTY_CC}.new\" \"${LIBRARIES_EMPTY_CC}\"\nelse\n rm \"${LIBRARIES_EMPTY_CC}.new\"\nfi\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -1175,6 +1183,7 @@ 89A88E2B0E71A6D10043BA31 /* v8.cc in Sources */, 89A88E2C0E71A6D20043BA31 /* v8threads.cc in Sources */, 89A88E2D0E71A6D50043BA31 /* variables.cc in Sources */, + 89B933AF0FAA0F9600201304 /* version.cc in Sources */, 58950D660F5551C200F3E8BA /* virtual-frame.cc in Sources */, 58950D670F5551C400F3E8BA /* virtual-frame-ia32.cc in Sources */, 89A88E2E0E71A6D60043BA31 /* zone.cc in Sources */, @@ -1277,6 +1286,7 @@ 89F23C7F0E78D5B2006B2466 /* v8.cc in Sources */, 89F23C800E78D5B2006B2466 /* v8threads.cc in Sources */, 89F23C810E78D5B2006B2466 /* variables.cc in Sources */, + 89B933B00FAA0F9D00201304 /* version.cc in Sources */, 58950D680F5551CB00F3E8BA /* virtual-frame.cc in Sources */, 58950D690F5551CE00F3E8BA /* virtual-frame-arm.cc in Sources */, 89F23C820E78D5B2006B2466 /* zone.cc in Sources */, @@ -1426,6 +1436,11 @@ 893988090F2A35FA007D5254 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(GCC_PREPROCESSOR_DEFINITIONS)", + V8_TARGET_ARCH_IA32, + DEBUG, + ); HEADER_SEARCH_PATHS = ../src; PRODUCT_NAME = v8_shell; }; @@ -1434,6 +1449,11 @@ 8939880A0F2A35FA007D5254 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(GCC_PREPROCESSOR_DEFINITIONS)", + V8_TARGET_ARCH_IA32, + NDEBUG, + ); HEADER_SEARCH_PATHS = ../src; PRODUCT_NAME = v8_shell; }; @@ -1446,6 +1466,7 @@ GCC_PREPROCESSOR_DEFINITIONS = ( "$(GCC_PREPROCESSOR_DEFINITIONS)", ENABLE_DISASSEMBLER, + V8_TARGET_ARCH_IA32, ENABLE_LOGGING_AND_PROFILING, ); HEADER_SEARCH_PATHS = ../src; @@ -1458,6 +1479,11 @@ isa = XCBuildConfiguration; buildSettings = { DEPLOYMENT_POSTPROCESSING = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(GCC_PREPROCESSOR_DEFINITIONS)", + V8_TARGET_ARCH_IA32, + NDEBUG, + ); HEADER_SEARCH_PATHS = ../src; PRODUCT_NAME = v8; STRIP_STYLE = debugging; @@ -1486,7 +1512,7 @@ DEPLOYMENT_POSTPROCESSING = NO; GCC_PREPROCESSOR_DEFINITIONS = ( "$(GCC_PREPROCESSOR_DEFINITIONS)", - ARM, + V8_TARGET_ARCH_ARM, ENABLE_DISASSEMBLER, ENABLE_LOGGING_AND_PROFILING, ); @@ -1502,7 +1528,7 @@ DEPLOYMENT_POSTPROCESSING = NO; GCC_PREPROCESSOR_DEFINITIONS = ( "$(GCC_PREPROCESSOR_DEFINITIONS)", - ARM, + V8_TARGET_ARCH_ARM, ); HEADER_SEARCH_PATHS = ../src; PRODUCT_NAME = "v8-arm"; diff --git a/deps/v8/tools/visual_studio/arm.vsprops b/deps/v8/tools/visual_studio/arm.vsprops index 0e37d4179..3aa937448 100644 --- a/deps/v8/tools/visual_studio/arm.vsprops +++ b/deps/v8/tools/visual_studio/arm.vsprops @@ -6,7 +6,7 @@ > <Tool Name="VCCLCompilerTool" - PreprocessorDefinitions="ARM" + PreprocessorDefinitions="V8_TARGET_ARCH_ARM" DisableSpecificWarnings="4996" /> </VisualStudioPropertySheet> diff --git a/deps/v8/tools/visual_studio/d8.vcproj b/deps/v8/tools/visual_studio/d8.vcproj index a05a3f39e..21636ba35 100644 --- a/deps/v8/tools/visual_studio/d8.vcproj +++ b/deps/v8/tools/visual_studio/d8.vcproj @@ -18,7 +18,7 @@ <Configuration Name="Debug|Win32" ConfigurationType="1" - InheritedPropertySheets=".\common.vsprops;.\debug.vsprops" + InheritedPropertySheets=".\common.vsprops;.\ia32.vsprops;.\debug.vsprops" > <Tool Name="VCPreBuildEventTool" @@ -79,7 +79,7 @@ <Configuration Name="Release|Win32" ConfigurationType="1" - InheritedPropertySheets=".\common.vsprops;.\release.vsprops" + InheritedPropertySheets=".\common.vsprops;.\ia32.vsprops;.\release.vsprops" > <Tool Name="VCPreBuildEventTool" diff --git a/deps/v8/tools/visual_studio/ia32.vsprops b/deps/v8/tools/visual_studio/ia32.vsprops new file mode 100644 index 000000000..fda6c32a8 --- /dev/null +++ b/deps/v8/tools/visual_studio/ia32.vsprops @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="ia32" + > + <Tool + Name="VCCLCompilerTool" + PreprocessorDefinitions="V8_TARGET_ARCH_IA32" + /> +</VisualStudioPropertySheet> diff --git a/deps/v8/tools/visual_studio/js2c.cmd b/deps/v8/tools/visual_studio/js2c.cmd index b6a46a2a6..df5293ba5 100644 --- a/deps/v8/tools/visual_studio/js2c.cmd +++ b/deps/v8/tools/visual_studio/js2c.cmd @@ -3,4 +3,4 @@ set SOURCE_DIR=%1 set TARGET_DIR=%2 set PYTHON="..\..\..\third_party\python_24\python.exe" if not exist %PYTHON% set PYTHON=python.exe -%PYTHON% ..\js2c.py %TARGET_DIR%\natives.cc %TARGET_DIR%\natives-empty.cc CORE %SOURCE_DIR%\macros.py %SOURCE_DIR%\runtime.js %SOURCE_DIR%\v8natives.js %SOURCE_DIR%\array.js %SOURCE_DIR%\string.js %SOURCE_DIR%\uri.js %SOURCE_DIR%\math.js %SOURCE_DIR%\messages.js %SOURCE_DIR%\apinatives.js %SOURCE_DIR%\debug-delay.js %SOURCE_DIR%\mirror-delay.js %SOURCE_DIR%\date-delay.js %SOURCE_DIR%\regexp-delay.js +%PYTHON% ..\js2c.py %TARGET_DIR%\natives.cc %TARGET_DIR%\natives-empty.cc CORE %SOURCE_DIR%\macros.py %SOURCE_DIR%\runtime.js %SOURCE_DIR%\v8natives.js %SOURCE_DIR%\array.js %SOURCE_DIR%\string.js %SOURCE_DIR%\uri.js %SOURCE_DIR%\math.js %SOURCE_DIR%\messages.js %SOURCE_DIR%\apinatives.js %SOURCE_DIR%\debug-delay.js %SOURCE_DIR%\mirror-delay.js %SOURCE_DIR%\date-delay.js %SOURCE_DIR%\regexp-delay.js %SOURCE_DIR%\json-delay.js diff --git a/deps/v8/tools/visual_studio/v8.vcproj b/deps/v8/tools/visual_studio/v8.vcproj index 212fd07c0..47ba8c1f4 100644 --- a/deps/v8/tools/visual_studio/v8.vcproj +++ b/deps/v8/tools/visual_studio/v8.vcproj @@ -18,7 +18,7 @@ <Configuration Name="Debug|Win32" ConfigurationType="4" - InheritedPropertySheets=".\common.vsprops;.\debug.vsprops" + InheritedPropertySheets=".\common.vsprops;.\ia32.vsprops;.\debug.vsprops" > <Tool Name="VCPreBuildEventTool" @@ -70,7 +70,7 @@ <Configuration Name="Release|Win32" ConfigurationType="4" - InheritedPropertySheets=".\common.vsprops;.\release.vsprops" + InheritedPropertySheets=".\common.vsprops;.\ia32.vsprops;.\release.vsprops" > <Tool Name="VCPreBuildEventTool" @@ -163,6 +163,10 @@ > </File> <File + RelativePath="..\..\src\json-delay.js" + > + </File> + <File RelativePath="..\..\src\runtime.js" > </File> @@ -184,7 +188,7 @@ Name="VCCustomBuildTool" Description="Processing js files..." CommandLine=".\js2c.cmd ..\..\src "$(IntDir)\DerivedSources"" - AdditionalDependencies="..\..\src\macros.py;..\..\src\runtime.js;..\..\src\v8natives.js;..\..\src\array.js;..\..\src\string.js;..\..\src\uri.js;..\..\src\math.js;..\..\src\messages.js;..\..\src\apinatives.js;..\..\src\debug-delay.js;..\..\src\mirror-delay.js;..\..\src\date-delay.js;..\..\src\regexp-delay.js" + AdditionalDependencies="..\..\src\macros.py;..\..\src\runtime.js;..\..\src\v8natives.js;..\..\src\array.js;..\..\src\string.js;..\..\src\uri.js;..\..\src\math.js;..\..\src\messages.js;..\..\src\apinatives.js;..\..\src\debug-delay.js;..\..\src\mirror-delay.js;..\..\src\date-delay.js;..\..\src\regexp-delay.js;..\..\src\json-delay.js" Outputs="$(IntDir)\DerivedSources\natives.cc;$(IntDir)\DerivedSources\natives-empty.cc" /> </FileConfiguration> @@ -195,7 +199,7 @@ Name="VCCustomBuildTool" Description="Processing js files..." CommandLine=".\js2c.cmd ..\..\src "$(IntDir)\DerivedSources"" - AdditionalDependencies="..\..\src\macros.py;..\..\src\runtime.js;..\..\src\v8natives.js;..\..\src\array.js;..\..\src\string.js;..\..\src\uri.js;..\..\src\math.js;..\..\src\messages.js;..\..\src\apinatives.js;..\..\src\debug-delay.js;..\..\src\mirror-delay.js;..\..\src\date-delay.js;..\..\src\regexp-delay.js" + AdditionalDependencies="..\..\src\macros.py;..\..\src\runtime.js;..\..\src\v8natives.js;..\..\src\array.js;..\..\src\string.js;..\..\src\uri.js;..\..\src\math.js;..\..\src\messages.js;..\..\src\apinatives.js;..\..\src\debug-delay.js;..\..\src\mirror-delay.js;..\..\src\date-delay.js;..\..\src\regexp-delay.js;..\..\src\json-delay.js" Outputs="$(IntDir)\DerivedSources\natives.cc;$(IntDir)\DerivedSources\natives-empty.cc" /> </FileConfiguration> diff --git a/deps/v8/tools/visual_studio/v8_base.vcproj b/deps/v8/tools/visual_studio/v8_base.vcproj index 776e628d0..b1802eff7 100644 --- a/deps/v8/tools/visual_studio/v8_base.vcproj +++ b/deps/v8/tools/visual_studio/v8_base.vcproj @@ -18,7 +18,7 @@ <Configuration Name="Debug|Win32" ConfigurationType="4" - InheritedPropertySheets=".\common.vsprops;.\debug.vsprops" + InheritedPropertySheets=".\common.vsprops;.\ia32.vsprops;.\debug.vsprops" > <Tool Name="VCPreBuildEventTool" @@ -69,7 +69,7 @@ <Configuration Name="Release|Win32" ConfigurationType="4" - InheritedPropertySheets=".\common.vsprops;.\release.vsprops" + InheritedPropertySheets=".\common.vsprops;.\ia32.vsprops;.\release.vsprops" > <Tool Name="VCPreBuildEventTool" @@ -177,15 +177,15 @@ > </File> <File - RelativePath="..\..\src\assembler-ia32-inl.h" + RelativePath="..\..\src\ia32\assembler-ia32-inl.h" > </File> <File - RelativePath="..\..\src\assembler-ia32.cc" + RelativePath="..\..\src\ia32\assembler-ia32.cc" > </File> <File - RelativePath="..\..\src\assembler-ia32.h" + RelativePath="..\..\src\ia32\assembler-ia32.h" > </File> <File @@ -221,7 +221,7 @@ > </File> <File - RelativePath="..\..\src\builtins-ia32.cc" + RelativePath="..\..\src\ia32\builtins-ia32.cc" > </File> <File @@ -265,11 +265,11 @@ > </File> <File - RelativePath="..\..\src\codegen-ia32.cc" + RelativePath="..\..\src\ia32\codegen-ia32.cc" > </File> <File - RelativePath="..\..\src\codegen-ia32.h" + RelativePath="..\..\src\ia32\codegen-ia32.h" > </File> <File @@ -329,7 +329,7 @@ > </File> <File - RelativePath="..\..\src\cpu-ia32.cc" + RelativePath="..\..\src\ia32\cpu-ia32.cc" > </File> <File @@ -353,7 +353,7 @@ > </File> <File - RelativePath="..\..\src\debug-ia32.cc" + RelativePath="..\..\src\ia32\debug-ia32.cc" > </File> <File @@ -397,11 +397,11 @@ > </File> <File - RelativePath="..\..\src\frames-ia32.cc" + RelativePath="..\..\src\ia32\frames-ia32.cc" > </File> <File - RelativePath="..\..\src\frames-ia32.h" + RelativePath="..\..\src\ia32\frames-ia32.h" > </File> <File @@ -469,7 +469,7 @@ > </File> <File - RelativePath="..\..\src\ic-ia32.cc" + RelativePath="..\..\src\ia32\ic-ia32.cc" > </File> <File @@ -505,7 +505,7 @@ > </File> <File - RelativePath="..\..\src\jump-target-ia32.cc" + RelativePath="..\..\src\ia32\jump-target-ia32.cc" > </File> <File @@ -537,11 +537,11 @@ > </File> <File - RelativePath="..\..\src\macro-assembler-ia32.cc" + RelativePath="..\..\src\ia32\macro-assembler-ia32.cc" > </File> <File - RelativePath="..\..\src\macro-assembler-ia32.h" + RelativePath="..\..\src\ia32\macro-assembler-ia32.h" > </File> <File @@ -645,11 +645,11 @@ > </File> <File - RelativePath="..\..\src\regexp-macro-assembler-ia32.cc" + RelativePath="..\..\src\ia32\regexp-macro-assembler-ia32.cc" > </File> <File - RelativePath="..\..\src\regexp-macro-assembler-ia32.h" + RelativePath="..\..\src\ia32\regexp-macro-assembler-ia32.h" > </File> <File @@ -689,7 +689,7 @@ > </File> <File - RelativePath="..\..\src\register-allocator-ia32.cc" + RelativePath="..\..\src\ia32\register-allocator-ia32.cc" > </File> <File @@ -773,7 +773,7 @@ > </File> <File - RelativePath="..\..\src\stub-cache-ia32.cc" + RelativePath="..\..\src\ia32\stub-cache-ia32.cc" > </File> <File @@ -857,11 +857,19 @@ > </File> <File + RelativePath="..\..\src\version.cc" + > + </File> + <File + RelativePath="..\..\src\version.h" + > + </File> + <File RelativePath="..\..\src\virtual-frame.h" > </File> <File - RelativePath="..\..\src\virtual-frame-ia32.h" + RelativePath="..\..\src\ia32\virtual-frame-ia32.h" > </File> <File @@ -869,7 +877,7 @@ > </File> <File - RelativePath="..\..\src\virtual-frame-ia32.cc" + RelativePath="..\..\src\ia32\virtual-frame-ia32.cc" > </File> <File @@ -888,7 +896,7 @@ Name="third party" > <File - RelativePath="..\..\src\disasm-ia32.cc" + RelativePath="..\..\src\ia32\disasm-ia32.cc" > </File> <File diff --git a/deps/v8/tools/visual_studio/v8_base_arm.vcproj b/deps/v8/tools/visual_studio/v8_base_arm.vcproj index a91d63ace..35a08d5ae 100644 --- a/deps/v8/tools/visual_studio/v8_base_arm.vcproj +++ b/deps/v8/tools/visual_studio/v8_base_arm.vcproj @@ -177,15 +177,15 @@ > </File> <File - RelativePath="..\..\src\assembler-arm-inl.h" + RelativePath="..\..\src\arm\assembler-arm-inl.h" > </File> <File - RelativePath="..\..\src\assembler-arm.cc" + RelativePath="..\..\src\arm\assembler-arm.cc" > </File> <File - RelativePath="..\..\src\assembler-arm.h" + RelativePath="..\..\src\arm\assembler-arm.h" > </File> <File @@ -221,7 +221,7 @@ > </File> <File - RelativePath="..\..\src\builtins-arm.cc" + RelativePath="..\..\src\arm\builtins-arm.cc" > </File> <File @@ -265,11 +265,11 @@ > </File> <File - RelativePath="..\..\src\codegen-arm.cc" + RelativePath="..\..\src\arm\codegen-arm.cc" > </File> <File - RelativePath="..\..\src\codegen-arm.h" + RelativePath="..\..\src\arm\codegen-arm.h" > </File> <File @@ -301,7 +301,7 @@ > </File> <File - RelativePath="..\..\src\constants-arm.h" + RelativePath="..\..\src\arm\constants-arm.h" > </File> <File @@ -333,7 +333,7 @@ > </File> <File - RelativePath="..\..\src\cpu-arm.cc" + RelativePath="..\..\src\arm\cpu-arm.cc" > </File> <File @@ -349,7 +349,15 @@ > </File> <File - RelativePath="..\..\src\debug-arm.cc" + RelativePath="..\..\src\debug-agent.cc" + > + </File> + <File + RelativePath="..\..\src\debug-agent.h" + > + </File> + <File + RelativePath="..\..\src\arm\debug-arm.cc" > </File> <File @@ -393,11 +401,11 @@ > </File> <File - RelativePath="..\..\src\frames-arm.cc" + RelativePath="..\..\src\arm\frames-arm.cc" > </File> <File - RelativePath="..\..\src\frames-arm.h" + RelativePath="..\..\src\arm\frames-arm.h" > </File> <File @@ -465,7 +473,7 @@ > </File> <File - RelativePath="..\..\src\ic-arm.cc" + RelativePath="..\..\src\arm\ic-arm.cc" > </File> <File @@ -501,7 +509,7 @@ > </File> <File - RelativePath="..\..\src\jump-target-arm.cc" + RelativePath="..\..\src\arm\jump-target-arm.cc" > </File> <File @@ -533,11 +541,11 @@ > </File> <File - RelativePath="..\..\src\macro-assembler-arm.cc" + RelativePath="..\..\src\arm\macro-assembler-arm.cc" > </File> <File - RelativePath="..\..\src\macro-assembler-arm.h" + RelativePath="..\..\src\arm\macro-assembler-arm.h" > </File> <File @@ -593,6 +601,14 @@ > </File> <File + RelativePath="..\..\src\oprofile-agent.cc" + > + </File> + <File + RelativePath="..\..\src\oprofile-agent.h" + > + </File> + <File RelativePath="..\..\src\parser.cc" > </File> @@ -633,11 +649,11 @@ > </File> <File - RelativePath="..\..\src\regexp-macro-assembler-arm.cc" + RelativePath="..\..\src\arm\regexp-macro-assembler-arm.cc" > </File> <File - RelativePath="..\..\src\regexp-macro-assembler-arm.h" + RelativePath="..\..\src\arm\regexp-macro-assembler-arm.h" > </File> <File @@ -677,7 +693,7 @@ > </File> <File - RelativePath="..\..\src\register-allocator-arm.cc" + RelativePath="..\..\src\arm\register-allocator-arm.cc" > </File> <File @@ -741,11 +757,11 @@ > </File> <File - RelativePath="..\..\src\simulator-arm.cc" + RelativePath="..\..\src\arm\simulator-arm.cc" > </File> <File - RelativePath="..\..\src\simulator-arm.h" + RelativePath="..\..\src\arm\simulator-arm.h" > </File> <File @@ -769,7 +785,7 @@ > </File> <File - RelativePath="..\..\src\stub-cache-arm.cc" + RelativePath="..\..\src\arm\stub-cache-arm.cc" > </File> <File @@ -853,11 +869,19 @@ > </File> <File + RelativePath="..\..\src\version.cc" + > + </File> + <File + RelativePath="..\..\src\version.h" + > + </File> + <File RelativePath="..\..\src\virtual-frame.h" > </File> <File - RelativePath="..\..\src\virtual-frame-arm.h" + RelativePath="..\..\src\arm\virtual-frame-arm.h" > </File> <File @@ -865,7 +889,7 @@ > </File> <File - RelativePath="..\..\src\virtual-frame-arm.cc" + RelativePath="..\..\src\arm\virtual-frame-arm.cc" > </File> <File @@ -884,7 +908,7 @@ Name="third party" > <File - RelativePath="..\..\src\disasm-arm.cc" + RelativePath="..\..\src\arm\disasm-arm.cc" > </File> <File diff --git a/deps/v8/tools/visual_studio/v8_cctest.vcproj b/deps/v8/tools/visual_studio/v8_cctest.vcproj index 5d49d2487..6aa090ad0 100644 --- a/deps/v8/tools/visual_studio/v8_cctest.vcproj +++ b/deps/v8/tools/visual_studio/v8_cctest.vcproj @@ -18,7 +18,7 @@ <Configuration Name="Debug|Win32" ConfigurationType="1" - InheritedPropertySheets=".\common.vsprops;.\debug.vsprops" + InheritedPropertySheets=".\common.vsprops;.\ia32.vsprops;.\debug.vsprops" > <Tool Name="VCPreBuildEventTool" @@ -79,7 +79,7 @@ <Configuration Name="Release|Win32" ConfigurationType="1" - InheritedPropertySheets=".\common.vsprops;.\release.vsprops" + InheritedPropertySheets=".\common.vsprops;.\ia32.vsprops;.\release.vsprops" > <Tool Name="VCPreBuildEventTool" @@ -202,6 +202,10 @@ > </File> <File + RelativePath="..\..\test\cctest\test-log.cc" + > + </File> + <File RelativePath="..\..\test\cctest\test-log-ia32.cc" > </File> @@ -233,6 +237,10 @@ RelativePath="..\..\test\cctest\test-utils.cc" > </File> + <File + RelativePath="..\..\test\cctest\test-version.cc" + > + </File> </Files> <Globals> </Globals> diff --git a/deps/v8/tools/visual_studio/v8_cctest_arm.vcproj b/deps/v8/tools/visual_studio/v8_cctest_arm.vcproj index 44812f018..566d75eef 100644 --- a/deps/v8/tools/visual_studio/v8_cctest_arm.vcproj +++ b/deps/v8/tools/visual_studio/v8_cctest_arm.vcproj @@ -196,6 +196,10 @@ > </File> <File + RelativePath="..\..\test\cctest\test-log.cc" + > + </File> + <File RelativePath="..\..\test\cctest\test-mark-compact.cc" > </File> @@ -219,6 +223,10 @@ RelativePath="..\..\test\cctest\test-utils.cc" > </File> + <File + RelativePath="..\..\test\cctest\test-version.cc" + > + </File> </Files> <Globals> </Globals> diff --git a/deps/v8/tools/visual_studio/v8_mksnapshot.vcproj b/deps/v8/tools/visual_studio/v8_mksnapshot.vcproj index 4d5d84f75..00950b069 100644 --- a/deps/v8/tools/visual_studio/v8_mksnapshot.vcproj +++ b/deps/v8/tools/visual_studio/v8_mksnapshot.vcproj @@ -18,7 +18,7 @@ <Configuration Name="Debug|Win32" ConfigurationType="1" - InheritedPropertySheets=".\common.vsprops;.\debug.vsprops" + InheritedPropertySheets=".\common.vsprops;.\ia32.vsprops;.\debug.vsprops" > <Tool Name="VCPreBuildEventTool" @@ -79,7 +79,7 @@ <Configuration Name="Release|Win32" ConfigurationType="1" - InheritedPropertySheets=".\common.vsprops;.\release.vsprops" + InheritedPropertySheets=".\common.vsprops;.\ia32.vsprops;.\release.vsprops" > <Tool Name="VCPreBuildEventTool" diff --git a/deps/v8/tools/visual_studio/v8_process_sample.vcproj b/deps/v8/tools/visual_studio/v8_process_sample.vcproj index ea8c97d4e..d94966b33 100644 --- a/deps/v8/tools/visual_studio/v8_process_sample.vcproj +++ b/deps/v8/tools/visual_studio/v8_process_sample.vcproj @@ -18,7 +18,7 @@ <Configuration Name="Debug|Win32" ConfigurationType="1" - InheritedPropertySheets=".\common.vsprops;.\debug.vsprops" + InheritedPropertySheets=".\common.vsprops;.\ia32.vsprops;.\debug.vsprops" > <Tool Name="VCPreBuildEventTool" @@ -79,7 +79,7 @@ <Configuration Name="Release|Win32" ConfigurationType="1" - InheritedPropertySheets=".\common.vsprops;.\release.vsprops" + InheritedPropertySheets=".\common.vsprops;.\ia32.vsprops;.\release.vsprops" > <Tool Name="VCPreBuildEventTool" diff --git a/deps/v8/tools/visual_studio/v8_shell_sample.vcproj b/deps/v8/tools/visual_studio/v8_shell_sample.vcproj index b5d9c612a..2cbd22df6 100644 --- a/deps/v8/tools/visual_studio/v8_shell_sample.vcproj +++ b/deps/v8/tools/visual_studio/v8_shell_sample.vcproj @@ -18,7 +18,7 @@ <Configuration Name="Debug|Win32" ConfigurationType="1" - InheritedPropertySheets=".\common.vsprops;.\debug.vsprops" + InheritedPropertySheets=".\common.vsprops;.\ia32.vsprops;.\debug.vsprops" > <Tool Name="VCPreBuildEventTool" @@ -79,7 +79,7 @@ <Configuration Name="Release|Win32" ConfigurationType="1" - InheritedPropertySheets=".\common.vsprops;.\release.vsprops" + InheritedPropertySheets=".\common.vsprops;.\ia32.vsprops;.\release.vsprops" > <Tool Name="VCPreBuildEventTool" diff --git a/deps/v8/tools/visual_studio/v8_snapshot.vcproj b/deps/v8/tools/visual_studio/v8_snapshot.vcproj index 25d922f15..29db4f8d0 100644 --- a/deps/v8/tools/visual_studio/v8_snapshot.vcproj +++ b/deps/v8/tools/visual_studio/v8_snapshot.vcproj @@ -18,7 +18,7 @@ <Configuration Name="Debug|Win32" ConfigurationType="4" - InheritedPropertySheets=".\common.vsprops;.\debug.vsprops" + InheritedPropertySheets=".\common.vsprops;.\ia32.vsprops;.\debug.vsprops" > <Tool Name="VCPreBuildEventTool" @@ -70,7 +70,7 @@ <Configuration Name="Release|Win32" ConfigurationType="4" - InheritedPropertySheets=".\common.vsprops;.\release.vsprops" + InheritedPropertySheets=".\common.vsprops;.\ia32.vsprops;.\release.vsprops" > <Tool Name="VCPreBuildEventTool" diff --git a/deps/v8/tools/visual_studio/v8_snapshot_cc.vcproj b/deps/v8/tools/visual_studio/v8_snapshot_cc.vcproj index 1cfac247c..7c4799afd 100644 --- a/deps/v8/tools/visual_studio/v8_snapshot_cc.vcproj +++ b/deps/v8/tools/visual_studio/v8_snapshot_cc.vcproj @@ -18,7 +18,7 @@ <Configuration Name="Debug|Win32" ConfigurationType="10" - InheritedPropertySheets=".\common.vsprops;.\debug.vsprops" + InheritedPropertySheets=".\common.vsprops;.\ia32.vsprops;.\debug.vsprops" > <Tool Name="VCPreBuildEventTool" @@ -36,7 +36,7 @@ <Configuration Name="Release|Win32" ConfigurationType="10" - InheritedPropertySheets=".\common.vsprops;.\release.vsprops" + InheritedPropertySheets=".\common.vsprops;.\ia32.vsprops;.\release.vsprops" > <Tool Name="VCPreBuildEventTool" diff --git a/deps/v8/tools/windows-tick-processor.bat b/deps/v8/tools/windows-tick-processor.bat new file mode 100644 index 000000000..52454e34b --- /dev/null +++ b/deps/v8/tools/windows-tick-processor.bat @@ -0,0 +1,5 @@ +@echo off + +SET tools_dir=%~dp0 + +%tools_dir%..\d8 %tools_dir%splaytree.js %tools_dir%codemap.js %tools_dir%csvparser.js %tools_dir%consarray.js %tools_dir%profile.js %tools_dir%profile_view.js %tools_dir%tickprocessor.js -- --windows %* |